Initial check in
Bug: 137197907
diff --git a/src/libstd/Cargo.toml b/src/libstd/Cargo.toml
new file mode 100644
index 0000000..86ad334
--- /dev/null
+++ b/src/libstd/Cargo.toml
@@ -0,0 +1,79 @@
+[package]
+authors = ["The Rust Project Developers"]
+name = "std"
+version = "0.0.0"
+build = "build.rs"
+license = "MIT/Apache-2.0"
+repository = "https://github.com/rust-lang/rust.git"
+description = "The Rust Standard Library"
+edition = "2018"
+
+[lib]
+name = "std"
+path = "lib.rs"
+crate-type = ["dylib", "rlib"]
+
+[dependencies]
+alloc = { path = "../liballoc" }
+panic_unwind = { path = "../libpanic_unwind", optional = true }
+panic_abort = { path = "../libpanic_abort" }
+core = { path = "../libcore" }
+libc = { version = "0.2.51", default-features = false, features = ['rustc-dep-of-std'] }
+compiler_builtins = { version = "0.1.9" }
+profiler_builtins = { path = "../libprofiler_builtins", optional = true }
+unwind = { path = "../libunwind" }
+rustc-demangle = { version = "0.1.10", features = ['rustc-dep-of-std'] }
+backtrace-sys = { version = "0.1.24", features = ["rustc-dep-of-std"], optional = true }
+
+[dev-dependencies]
+rand = "0.6.1"
+
+[target.x86_64-apple-darwin.dependencies]
+rustc_asan = { path = "../librustc_asan" }
+rustc_tsan = { path = "../librustc_tsan" }
+
+[target.x86_64-unknown-linux-gnu.dependencies]
+rustc_asan = { path = "../librustc_asan" }
+rustc_lsan = { path = "../librustc_lsan" }
+rustc_msan = { path = "../librustc_msan" }
+rustc_tsan = { path = "../librustc_tsan" }
+
+[target.'cfg(any(all(target_arch = "wasm32", not(target_os = "emscripten")), all(target_vendor = "fortanix", target_env = "sgx")))'.dependencies]
+dlmalloc = { version = "0.1", features = ['rustc-dep-of-std'] }
+
+[target.x86_64-fortanix-unknown-sgx.dependencies]
+fortanix-sgx-abi = { version = "0.3.2", features = ['rustc-dep-of-std'] }
+
+[build-dependencies]
+cc = "1.0"
+
+[features]
+default = ["compiler_builtins_c", "std_detect_file_io", "std_detect_dlsym_getauxval"]
+
+backtrace = ["backtrace-sys"]
+panic-unwind = ["panic_unwind"]
+profiler = ["profiler_builtins"]
+compiler_builtins_c = ["compiler_builtins/c"]
+llvm-libunwind = ["unwind/llvm-libunwind"]
+
+# Make panics and failed asserts immediately abort without formatting any message
+panic_immediate_abort = ["core/panic_immediate_abort"]
+
+# An off-by-default feature which enables a linux-syscall-like ABI for libstd to
+# interoperate with the host environment. Currently not well documented and
+# requires rebuilding the standard library to use it.
+wasm_syscall = []
+
+# An off-by-default features to enable libstd to assume that wasm-bindgen is in
+# the environment for hooking up some thread-related information like the
+# current thread id and accessing/getting the current thread's TCB
+wasm-bindgen-threads = []
+
+# Enable std_detect default features for stdsimd:
+# https://github.com/rust-lang-nursery/stdsimd/blob/master/crates/std_detect/Cargo.toml
+std_detect_file_io = []
+std_detect_dlsym_getauxval = []
+
+[package.metadata.fortanix-sgx]
+# Maximum possible number of threads when testing
+threads = 125
diff --git a/src/libstd/alloc.rs b/src/libstd/alloc.rs
new file mode 100644
index 0000000..4241f47
--- /dev/null
+++ b/src/libstd/alloc.rs
@@ -0,0 +1,258 @@
+//! 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. Libraries, however,
+//! like `cdylib`s and `staticlib`s are guaranteed to use the [`System`] by
+//! default.
+//!
+//! [`System`]: struct.System.html
+//!
+//! # The `#[global_allocator]` attribute
+//!
+//! This attribute allows configuring the choice of global allocator.
+//! You can use this to implement a completely custom global allocator
+//! to route all default allocation requests to a custom object.
+//!
+//! ```rust
+//! use std::alloc::{GlobalAlloc, System, Layout};
+//!
+//! struct MyAllocator;
+//!
+//! unsafe impl GlobalAlloc for MyAllocator {
+//! unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
+//! System.alloc(layout)
+//! }
+//!
+//! unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
+//! System.dealloc(ptr, layout)
+//! }
+//! }
+//!
+//! #[global_allocator]
+//! static GLOBAL: MyAllocator = MyAllocator;
+//!
+//! fn main() {
+//! // This `Vec` will allocate memory through `GLOBAL` above
+//! let mut v = Vec::new();
+//! v.push(1);
+//! }
+//! ```
+//!
+//! The attribute is used on a `static` item whose type implements the
+//! [`GlobalAlloc`] trait. This type can be provided by an external library:
+//!
+//! [`GlobalAlloc`]: ../../core/alloc/trait.GlobalAlloc.html
+//!
+//! ```rust,ignore (demonstrates crates.io usage)
+//! extern crate jemallocator;
+//!
+//! use jemallocator::Jemalloc;
+//!
+//! #[global_allocator]
+//! static GLOBAL: Jemalloc = Jemalloc;
+//!
+//! fn main() {}
+//! ```
+//!
+//! The `#[global_allocator]` can only be used once in a crate
+//! or its recursive dependencies.
+
+#![stable(feature = "alloc_module", since = "1.28.0")]
+
+use core::sync::atomic::{AtomicPtr, Ordering};
+use core::{mem, ptr};
+use core::ptr::NonNull;
+
+use crate::sys_common::util::dumb_print;
+
+#[stable(feature = "alloc_module", since = "1.28.0")]
+#[doc(inline)]
+pub use alloc_crate::alloc::*;
+
+/// The default memory allocator provided by the operating system.
+///
+/// This is based on `malloc` on Unix platforms and `HeapAlloc` on Windows,
+/// plus related functions.
+///
+/// This type implements the `GlobalAlloc` trait and Rust programs by default
+/// work as if they had this definition:
+///
+/// ```rust
+/// use std::alloc::System;
+///
+/// #[global_allocator]
+/// static A: System = System;
+///
+/// fn main() {
+/// let a = Box::new(4); // Allocates from the system allocator.
+/// println!("{}", a);
+/// }
+/// ```
+///
+/// You can also define your own wrapper around `System` if you'd like, such as
+/// keeping track of the number of all bytes allocated:
+///
+/// ```rust
+/// use std::alloc::{System, GlobalAlloc, Layout};
+/// use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
+///
+/// struct Counter;
+///
+/// static ALLOCATED: AtomicUsize = AtomicUsize::new(0);
+///
+/// unsafe impl GlobalAlloc for Counter {
+/// unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
+/// let ret = System.alloc(layout);
+/// if !ret.is_null() {
+/// ALLOCATED.fetch_add(layout.size(), SeqCst);
+/// }
+/// return ret
+/// }
+///
+/// unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
+/// System.dealloc(ptr, layout);
+/// ALLOCATED.fetch_sub(layout.size(), SeqCst);
+/// }
+/// }
+///
+/// #[global_allocator]
+/// static A: Counter = Counter;
+///
+/// fn main() {
+/// println!("allocated bytes before main: {}", ALLOCATED.load(SeqCst));
+/// }
+/// ```
+///
+/// It can also be used directly to allocate memory independently of whatever
+/// global allocator has been selected for a Rust program. For example if a Rust
+/// program opts in to using jemalloc as the global allocator, `System` will
+/// still allocate memory using `malloc` and `HeapAlloc`.
+#[stable(feature = "alloc_system_type", since = "1.28.0")]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct System;
+
+// The Alloc impl just forwards to the GlobalAlloc impl, which is in `std::sys::*::alloc`.
+#[unstable(feature = "allocator_api", issue = "32838")]
+unsafe impl Alloc for System {
+ #[inline]
+ unsafe fn alloc(&mut self, layout: Layout) -> Result<NonNull<u8>, AllocErr> {
+ NonNull::new(GlobalAlloc::alloc(self, layout)).ok_or(AllocErr)
+ }
+
+ #[inline]
+ unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<NonNull<u8>, AllocErr> {
+ NonNull::new(GlobalAlloc::alloc_zeroed(self, layout)).ok_or(AllocErr)
+ }
+
+ #[inline]
+ unsafe fn dealloc(&mut self, ptr: NonNull<u8>, layout: Layout) {
+ GlobalAlloc::dealloc(self, ptr.as_ptr(), layout)
+ }
+
+ #[inline]
+ unsafe fn realloc(&mut self,
+ ptr: NonNull<u8>,
+ layout: Layout,
+ new_size: usize) -> Result<NonNull<u8>, AllocErr> {
+ NonNull::new(GlobalAlloc::realloc(self, ptr.as_ptr(), layout, new_size)).ok_or(AllocErr)
+ }
+}
+
+static HOOK: AtomicPtr<()> = AtomicPtr::new(ptr::null_mut());
+
+/// Registers a custom allocation error hook, replacing any that was previously registered.
+///
+/// The allocation error hook is invoked when an infallible memory allocation fails, before
+/// the runtime aborts. The default hook prints a message to standard error,
+/// but this behavior can be customized with the [`set_alloc_error_hook`] and
+/// [`take_alloc_error_hook`] functions.
+///
+/// The hook is provided with a `Layout` struct which contains information
+/// about the allocation that failed.
+///
+/// The allocation error hook is a global resource.
+#[unstable(feature = "alloc_error_hook", issue = "51245")]
+pub fn set_alloc_error_hook(hook: fn(Layout)) {
+ HOOK.store(hook as *mut (), Ordering::SeqCst);
+}
+
+/// Unregisters the current allocation error hook, returning it.
+///
+/// *See also the function [`set_alloc_error_hook`].*
+///
+/// If no custom hook is registered, the default hook will be returned.
+#[unstable(feature = "alloc_error_hook", issue = "51245")]
+pub fn take_alloc_error_hook() -> fn(Layout) {
+ let hook = HOOK.swap(ptr::null_mut(), Ordering::SeqCst);
+ if hook.is_null() {
+ default_alloc_error_hook
+ } else {
+ unsafe { mem::transmute(hook) }
+ }
+}
+
+fn default_alloc_error_hook(layout: Layout) {
+ dumb_print(format_args!("memory allocation of {} bytes failed", layout.size()));
+}
+
+#[cfg(not(test))]
+#[doc(hidden)]
+#[alloc_error_handler]
+#[unstable(feature = "alloc_internals", issue = "0")]
+pub fn rust_oom(layout: Layout) -> ! {
+ let hook = HOOK.load(Ordering::SeqCst);
+ let hook: fn(Layout) = if hook.is_null() {
+ default_alloc_error_hook
+ } else {
+ unsafe { mem::transmute(hook) }
+ };
+ hook(layout);
+ unsafe { crate::sys::abort_internal(); }
+}
+
+#[cfg(not(test))]
+#[doc(hidden)]
+#[allow(unused_attributes)]
+#[unstable(feature = "alloc_internals", issue = "0")]
+pub mod __default_lib_allocator {
+ use super::{System, Layout, GlobalAlloc};
+ // These magic symbol names are used as a fallback for implementing the
+ // `__rust_alloc` etc symbols (see `src/liballoc/alloc.rs) when there is
+ // no `#[global_allocator]` attribute.
+
+ // for symbol names src/librustc/middle/allocator.rs
+ // for signatures src/librustc_allocator/lib.rs
+
+ // linkage directives are provided as part of the current compiler allocator
+ // ABI
+
+ #[rustc_std_internal_symbol]
+ pub unsafe extern fn __rdl_alloc(size: usize, align: usize) -> *mut u8 {
+ let layout = Layout::from_size_align_unchecked(size, align);
+ System.alloc(layout)
+ }
+
+ #[rustc_std_internal_symbol]
+ pub unsafe extern fn __rdl_dealloc(ptr: *mut u8,
+ size: usize,
+ align: usize) {
+ System.dealloc(ptr, Layout::from_size_align_unchecked(size, align))
+ }
+
+ #[rustc_std_internal_symbol]
+ pub unsafe extern fn __rdl_realloc(ptr: *mut u8,
+ old_size: usize,
+ align: usize,
+ new_size: usize) -> *mut u8 {
+ let old_layout = Layout::from_size_align_unchecked(old_size, align);
+ System.realloc(ptr, old_layout, new_size)
+ }
+
+ #[rustc_std_internal_symbol]
+ pub unsafe extern fn __rdl_alloc_zeroed(size: usize, align: usize) -> *mut u8 {
+ let layout = Layout::from_size_align_unchecked(size, align);
+ System.alloc_zeroed(layout)
+ }
+}
diff --git a/src/libstd/ascii.rs b/src/libstd/ascii.rs
new file mode 100644
index 0000000..7db0aad
--- /dev/null
+++ b/src/libstd/ascii.rs
@@ -0,0 +1,201 @@
+//! Operations on ASCII strings and characters.
+//!
+//! Most string operations in Rust act on UTF-8 strings. However, at times it
+//! makes more sense to only consider the ASCII character set for a specific
+//! operation.
+//!
+//! The [`AsciiExt`] trait provides methods that allow for character
+//! operations that only act on the ASCII subset and leave non-ASCII characters
+//! alone.
+//!
+//! The [`escape_default`] function provides an iterator over the bytes of an
+//! escaped version of the character given.
+//!
+//! [`AsciiExt`]: trait.AsciiExt.html
+//! [`escape_default`]: fn.escape_default.html
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use core::ascii::{EscapeDefault, escape_default};
+
+/// Extension methods for ASCII-subset only operations.
+///
+/// Be aware that operations on seemingly non-ASCII characters can sometimes
+/// have unexpected results. Consider this example:
+///
+/// ```
+/// use std::ascii::AsciiExt;
+///
+/// assert_eq!(AsciiExt::to_ascii_uppercase("café"), "CAFÉ");
+/// assert_eq!(AsciiExt::to_ascii_uppercase("café"), "CAFé");
+/// ```
+///
+/// In the first example, the lowercased string is represented `"cafe\u{301}"`
+/// (the last character is an acute accent [combining character]). Unlike the
+/// other characters in the string, the combining character will not get mapped
+/// to an uppercase variant, resulting in `"CAFE\u{301}"`. In the second
+/// example, the lowercased string is represented `"caf\u{e9}"` (the last
+/// character is a single Unicode character representing an 'e' with an acute
+/// accent). Since the last character is defined outside the scope of ASCII,
+/// it will not get mapped to an uppercase variant, resulting in `"CAF\u{e9}"`.
+///
+/// [combining character]: https://en.wikipedia.org/wiki/Combining_character
+#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_deprecated(since = "1.26.0", reason = "use inherent methods instead")]
+pub trait AsciiExt {
+ /// Container type for copied ASCII characters.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ type Owned;
+
+ /// Checks if the value is within the ASCII range.
+ ///
+ /// # Note
+ ///
+ /// This method will be deprecated in favor of the identically-named
+ /// inherent methods on `u8`, `char`, `[u8]` and `str`.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ fn is_ascii(&self) -> bool;
+
+ /// Makes a copy of the value in its ASCII upper case equivalent.
+ ///
+ /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z',
+ /// but non-ASCII letters are unchanged.
+ ///
+ /// To uppercase the value in-place, use [`make_ascii_uppercase`].
+ ///
+ /// To uppercase ASCII characters in addition to non-ASCII characters, use
+ /// [`str::to_uppercase`].
+ ///
+ /// # Note
+ ///
+ /// This method will be deprecated in favor of the identically-named
+ /// inherent methods on `u8`, `char`, `[u8]` and `str`.
+ ///
+ /// [`make_ascii_uppercase`]: #tymethod.make_ascii_uppercase
+ /// [`str::to_uppercase`]: ../primitive.str.html#method.to_uppercase
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[allow(deprecated)]
+ fn to_ascii_uppercase(&self) -> Self::Owned;
+
+ /// Makes a copy of the value in its ASCII lower case equivalent.
+ ///
+ /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z',
+ /// but non-ASCII letters are unchanged.
+ ///
+ /// To lowercase the value in-place, use [`make_ascii_lowercase`].
+ ///
+ /// To lowercase ASCII characters in addition to non-ASCII characters, use
+ /// [`str::to_lowercase`].
+ ///
+ /// # Note
+ ///
+ /// This method will be deprecated in favor of the identically-named
+ /// inherent methods on `u8`, `char`, `[u8]` and `str`.
+ ///
+ /// [`make_ascii_lowercase`]: #tymethod.make_ascii_lowercase
+ /// [`str::to_lowercase`]: ../primitive.str.html#method.to_lowercase
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[allow(deprecated)]
+ fn to_ascii_lowercase(&self) -> Self::Owned;
+
+ /// Checks that two values are an ASCII case-insensitive match.
+ ///
+ /// Same as `to_ascii_lowercase(a) == to_ascii_lowercase(b)`,
+ /// but without allocating and copying temporaries.
+ ///
+ /// # Note
+ ///
+ /// This method will be deprecated in favor of the identically-named
+ /// inherent methods on `u8`, `char`, `[u8]` and `str`.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ fn eq_ignore_ascii_case(&self, other: &Self) -> bool;
+
+ /// Converts this type to its ASCII upper case equivalent in-place.
+ ///
+ /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z',
+ /// but non-ASCII letters are unchanged.
+ ///
+ /// To return a new uppercased value without modifying the existing one, use
+ /// [`to_ascii_uppercase`].
+ ///
+ /// # Note
+ ///
+ /// This method will be deprecated in favor of the identically-named
+ /// inherent methods on `u8`, `char`, `[u8]` and `str`.
+ ///
+ /// [`to_ascii_uppercase`]: #tymethod.to_ascii_uppercase
+ #[stable(feature = "ascii", since = "1.9.0")]
+ fn make_ascii_uppercase(&mut self);
+
+ /// Converts this type to its ASCII lower case equivalent in-place.
+ ///
+ /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z',
+ /// but non-ASCII letters are unchanged.
+ ///
+ /// To return a new lowercased value without modifying the existing one, use
+ /// [`to_ascii_lowercase`].
+ ///
+ /// # Note
+ ///
+ /// This method will be deprecated in favor of the identically-named
+ /// inherent methods on `u8`, `char`, `[u8]` and `str`.
+ ///
+ /// [`to_ascii_lowercase`]: #tymethod.to_ascii_lowercase
+ #[stable(feature = "ascii", since = "1.9.0")]
+ fn make_ascii_lowercase(&mut self);
+}
+
+macro_rules! delegating_ascii_methods {
+ () => {
+ #[inline]
+ fn is_ascii(&self) -> bool { self.is_ascii() }
+
+ #[inline]
+ fn to_ascii_uppercase(&self) -> Self::Owned { self.to_ascii_uppercase() }
+
+ #[inline]
+ fn to_ascii_lowercase(&self) -> Self::Owned { self.to_ascii_lowercase() }
+
+ #[inline]
+ fn eq_ignore_ascii_case(&self, o: &Self) -> bool { self.eq_ignore_ascii_case(o) }
+
+ #[inline]
+ fn make_ascii_uppercase(&mut self) { self.make_ascii_uppercase(); }
+
+ #[inline]
+ fn make_ascii_lowercase(&mut self) { self.make_ascii_lowercase(); }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+#[allow(deprecated)]
+impl AsciiExt for u8 {
+ type Owned = u8;
+
+ delegating_ascii_methods!();
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+#[allow(deprecated)]
+impl AsciiExt for char {
+ type Owned = char;
+
+ delegating_ascii_methods!();
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+#[allow(deprecated)]
+impl AsciiExt for [u8] {
+ type Owned = Vec<u8>;
+
+ delegating_ascii_methods!();
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+#[allow(deprecated)]
+impl AsciiExt for str {
+ type Owned = String;
+
+ delegating_ascii_methods!();
+}
diff --git a/src/libstd/build.rs b/src/libstd/build.rs
new file mode 100644
index 0000000..726c273
--- /dev/null
+++ b/src/libstd/build.rs
@@ -0,0 +1,57 @@
+#![deny(warnings)]
+
+use std::env;
+
+fn main() {
+ let target = env::var("TARGET").expect("TARGET was not set");
+ if target.contains("linux") {
+ if target.contains("android") {
+ println!("cargo:rustc-link-lib=dl");
+ println!("cargo:rustc-link-lib=log");
+ println!("cargo:rustc-link-lib=gcc");
+ } else if !target.contains("musl") {
+ println!("cargo:rustc-link-lib=dl");
+ println!("cargo:rustc-link-lib=rt");
+ println!("cargo:rustc-link-lib=pthread");
+ }
+ } else if target.contains("freebsd") {
+ println!("cargo:rustc-link-lib=execinfo");
+ println!("cargo:rustc-link-lib=pthread");
+ } else if target.contains("netbsd") {
+ println!("cargo:rustc-link-lib=pthread");
+ println!("cargo:rustc-link-lib=rt");
+ } else if target.contains("dragonfly") || target.contains("bitrig") ||
+ target.contains("openbsd") {
+ println!("cargo:rustc-link-lib=pthread");
+ } else if target.contains("solaris") {
+ println!("cargo:rustc-link-lib=socket");
+ println!("cargo:rustc-link-lib=posix4");
+ println!("cargo:rustc-link-lib=pthread");
+ println!("cargo:rustc-link-lib=resolv");
+ } else if target.contains("apple-darwin") {
+ println!("cargo:rustc-link-lib=System");
+
+ // res_init and friends require -lresolv on macOS/iOS.
+ // See #41582 and http://blog.achernya.com/2013/03/os-x-has-silly-libsystem.html
+ println!("cargo:rustc-link-lib=resolv");
+ } else if target.contains("apple-ios") {
+ println!("cargo:rustc-link-lib=System");
+ println!("cargo:rustc-link-lib=objc");
+ println!("cargo:rustc-link-lib=framework=Security");
+ println!("cargo:rustc-link-lib=framework=Foundation");
+ println!("cargo:rustc-link-lib=resolv");
+ } else if target.contains("windows") {
+ println!("cargo:rustc-link-lib=advapi32");
+ println!("cargo:rustc-link-lib=ws2_32");
+ println!("cargo:rustc-link-lib=userenv");
+ } else if target.contains("fuchsia") {
+ println!("cargo:rustc-link-lib=zircon");
+ println!("cargo:rustc-link-lib=fdio");
+ } else if target.contains("cloudabi") {
+ if cfg!(feature = "backtrace") {
+ println!("cargo:rustc-link-lib=unwind");
+ }
+ println!("cargo:rustc-link-lib=c");
+ println!("cargo:rustc-link-lib=compiler_rt");
+ }
+}
diff --git a/src/libstd/collections/hash/bench.rs b/src/libstd/collections/hash/bench.rs
new file mode 100644
index 0000000..7f5add0
--- /dev/null
+++ b/src/libstd/collections/hash/bench.rs
@@ -0,0 +1,116 @@
+#![cfg(test)]
+
+use test::Bencher;
+
+#[bench]
+fn new_drop(b: &mut Bencher) {
+ use super::map::HashMap;
+
+ b.iter(|| {
+ let m: HashMap<i32, i32> = HashMap::new();
+ assert_eq!(m.len(), 0);
+ })
+}
+
+#[bench]
+fn new_insert_drop(b: &mut Bencher) {
+ use super::map::HashMap;
+
+ b.iter(|| {
+ let mut m = HashMap::new();
+ m.insert(0, 0);
+ assert_eq!(m.len(), 1);
+ })
+}
+
+#[bench]
+fn grow_by_insertion(b: &mut Bencher) {
+ use super::map::HashMap;
+
+ let mut m = HashMap::new();
+
+ for i in 1..1001 {
+ m.insert(i, i);
+ }
+
+ let mut k = 1001;
+
+ b.iter(|| {
+ m.insert(k, k);
+ k += 1;
+ });
+}
+
+#[bench]
+fn find_existing(b: &mut Bencher) {
+ use super::map::HashMap;
+
+ let mut m = HashMap::new();
+
+ for i in 1..1001 {
+ m.insert(i, i);
+ }
+
+ b.iter(|| {
+ for i in 1..1001 {
+ m.contains_key(&i);
+ }
+ });
+}
+
+#[bench]
+fn find_nonexisting(b: &mut Bencher) {
+ use super::map::HashMap;
+
+ let mut m = HashMap::new();
+
+ for i in 1..1001 {
+ m.insert(i, i);
+ }
+
+ b.iter(|| {
+ for i in 1001..2001 {
+ m.contains_key(&i);
+ }
+ });
+}
+
+#[bench]
+fn hashmap_as_queue(b: &mut Bencher) {
+ use super::map::HashMap;
+
+ let mut m = HashMap::new();
+
+ for i in 1..1001 {
+ m.insert(i, i);
+ }
+
+ let mut k = 1;
+
+ b.iter(|| {
+ m.remove(&k);
+ m.insert(k + 1000, k + 1000);
+ k += 1;
+ });
+}
+
+#[bench]
+fn get_remove_insert(b: &mut Bencher) {
+ use super::map::HashMap;
+
+ let mut m = HashMap::new();
+
+ for i in 1..1001 {
+ m.insert(i, i);
+ }
+
+ let mut k = 1;
+
+ b.iter(|| {
+ m.get(&(k + 400));
+ m.get(&(k + 2000));
+ m.remove(&k);
+ m.insert(k + 1000, k + 1000);
+ k += 1;
+ })
+}
diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs
new file mode 100644
index 0000000..ac3cfde
--- /dev/null
+++ b/src/libstd/collections/hash/map.rs
@@ -0,0 +1,4357 @@
+use self::Entry::*;
+use self::VacantEntryState::*;
+
+use crate::intrinsics::unlikely;
+use crate::collections::CollectionAllocErr;
+use crate::cell::Cell;
+use crate::borrow::Borrow;
+use crate::cmp::max;
+use crate::fmt::{self, Debug};
+#[allow(deprecated)]
+use crate::hash::{Hash, Hasher, BuildHasher, SipHasher13};
+use crate::iter::{FromIterator, FusedIterator};
+use crate::mem::{self, replace};
+use crate::ops::{Deref, DerefMut, Index};
+use crate::sys;
+
+use super::table::{self, Bucket, EmptyBucket, Fallibility, FullBucket, FullBucketMut, RawTable,
+ SafeHash};
+use super::table::BucketState::{Empty, Full};
+use super::table::Fallibility::{Fallible, Infallible};
+
+const MIN_NONZERO_RAW_CAPACITY: usize = 32; // must be a power of two
+
+/// The default behavior of HashMap implements a maximum load factor of 90.9%.
+#[derive(Clone)]
+struct DefaultResizePolicy;
+
+impl DefaultResizePolicy {
+ #[inline]
+ fn new() -> DefaultResizePolicy {
+ DefaultResizePolicy
+ }
+
+ /// A hash map's "capacity" is the number of elements it can hold without
+ /// being resized. Its "raw capacity" is the number of slots required to
+ /// provide that capacity, accounting for maximum loading. The raw capacity
+ /// is always zero or a power of two.
+ #[inline]
+ fn try_raw_capacity(&self, len: usize) -> Result<usize, CollectionAllocErr> {
+ if len == 0 {
+ Ok(0)
+ } else {
+ // 1. Account for loading: `raw_capacity >= len * 1.1`.
+ // 2. Ensure it is a power of two.
+ // 3. Ensure it is at least the minimum size.
+ let mut raw_cap = len.checked_mul(11)
+ .map(|l| l / 10)
+ .and_then(|l| l.checked_next_power_of_two())
+ .ok_or(CollectionAllocErr::CapacityOverflow)?;
+
+ raw_cap = max(MIN_NONZERO_RAW_CAPACITY, raw_cap);
+ Ok(raw_cap)
+ }
+ }
+
+ #[inline]
+ fn raw_capacity(&self, len: usize) -> usize {
+ self.try_raw_capacity(len).expect("raw_capacity overflow")
+ }
+
+ /// The capacity of the given raw capacity.
+ #[inline]
+ fn capacity(&self, raw_cap: usize) -> usize {
+ // This doesn't have to be checked for overflow since allocation size
+ // in bytes will overflow earlier than multiplication by 10.
+ //
+ // As per https://github.com/rust-lang/rust/pull/30991 this is updated
+ // to be: (raw_cap * den + den - 1) / num
+ (raw_cap * 10 + 10 - 1) / 11
+ }
+}
+
+// The main performance trick in this hashmap is called Robin Hood Hashing.
+// It gains its excellent performance from one essential operation:
+//
+// If an insertion collides with an existing element, and that element's
+// "probe distance" (how far away the element is from its ideal location)
+// is higher than how far we've already probed, swap the elements.
+//
+// This massively lowers variance in probe distance, and allows us to get very
+// high load factors with good performance. The 90% load factor I use is rather
+// conservative.
+//
+// > Why a load factor of approximately 90%?
+//
+// In general, all the distances to initial buckets will converge on the mean.
+// At a load factor of α, the odds of finding the target bucket after k
+// probes is approximately 1-α^k. If we set this equal to 50% (since we converge
+// on the mean) and set k=8 (64-byte cache line / 8-byte hash), α=0.92. I round
+// this down to make the math easier on the CPU and avoid its FPU.
+// Since on average we start the probing in the middle of a cache line, this
+// strategy pulls in two cache lines of hashes on every lookup. I think that's
+// pretty good, but if you want to trade off some space, it could go down to one
+// cache line on average with an α of 0.84.
+//
+// > Wait, what? Where did you get 1-α^k from?
+//
+// On the first probe, your odds of a collision with an existing element is α.
+// The odds of doing this twice in a row is approximately α^2. For three times,
+// α^3, etc. Therefore, the odds of colliding k times is α^k. The odds of NOT
+// colliding after k tries is 1-α^k.
+//
+// The paper from 1986 cited below mentions an implementation which keeps track
+// of the distance-to-initial-bucket histogram. This approach is not suitable
+// for modern architectures because it requires maintaining an internal data
+// structure. This allows very good first guesses, but we are most concerned
+// with guessing entire cache lines, not individual indexes. Furthermore, array
+// accesses are no longer linear and in one direction, as we have now. There
+// is also memory and cache pressure that this would entail that would be very
+// difficult to properly see in a microbenchmark.
+//
+// ## Future Improvements (FIXME!)
+//
+// Allow the load factor to be changed dynamically and/or at initialization.
+//
+// Also, would it be possible for us to reuse storage when growing the
+// underlying table? This is exactly the use case for 'realloc', and may
+// be worth exploring.
+//
+// ## Future Optimizations (FIXME!)
+//
+// Another possible design choice that I made without any real reason is
+// parameterizing the raw table over keys and values. Technically, all we need
+// is the size and alignment of keys and values, and the code should be just as
+// efficient (well, we might need one for power-of-two size and one for not...).
+// This has the potential to reduce code bloat in rust executables, without
+// really losing anything except 4 words (key size, key alignment, val size,
+// val alignment) which can be passed in to every call of a `RawTable` function.
+// This would definitely be an avenue worth exploring if people start complaining
+// about the size of rust executables.
+//
+// Annotate exceedingly likely branches in `table::make_hash`
+// and `search_hashed` to reduce instruction cache pressure
+// and mispredictions once it becomes possible (blocked on issue #11092).
+//
+// Shrinking the table could simply reallocate in place after moving buckets
+// to the first half.
+//
+// The growth algorithm (fragment of the Proof of Correctness)
+// --------------------
+//
+// The growth algorithm is basically a fast path of the naive reinsertion-
+// during-resize algorithm. Other paths should never be taken.
+//
+// Consider growing a robin hood hashtable of capacity n. Normally, we do this
+// by allocating a new table of capacity `2n`, and then individually reinsert
+// each element in the old table into the new one. This guarantees that the
+// new table is a valid robin hood hashtable with all the desired statistical
+// properties. Remark that the order we reinsert the elements in should not
+// matter. For simplicity and efficiency, we will consider only linear
+// reinsertions, which consist of reinserting all elements in the old table
+// into the new one by increasing order of index. However we will not be
+// starting our reinsertions from index 0 in general. If we start from index
+// i, for the purpose of reinsertion we will consider all elements with real
+// index j < i to have virtual index n + j.
+//
+// Our hash generation scheme consists of generating a 64-bit hash and
+// truncating the most significant bits. When moving to the new table, we
+// simply introduce a new bit to the front of the hash. Therefore, if an
+// element has ideal index i in the old table, it can have one of two ideal
+// locations in the new table. If the new bit is 0, then the new ideal index
+// is i. If the new bit is 1, then the new ideal index is n + i. Intuitively,
+// we are producing two independent tables of size n, and for each element we
+// independently choose which table to insert it into with equal probability.
+// However, rather than wrapping around themselves on overflowing their
+// indexes, the first table overflows into the second, and the second into the
+// first. Visually, our new table will look something like:
+//
+// [yy_xxx_xxxx_xxx|xx_yyy_yyyy_yyy]
+//
+// Where x's are elements inserted into the first table, y's are elements
+// inserted into the second, and _'s are empty sections. We now define a few
+// key concepts that we will use later. Note that this is a very abstract
+// perspective of the table. A real resized table would be at least half
+// empty.
+//
+// Theorem: A linear robin hood reinsertion from the first ideal element
+// produces identical results to a linear naive reinsertion from the same
+// element.
+//
+// FIXME(Gankro, pczarn): review the proof and put it all in a separate README.md
+//
+// Adaptive early resizing
+// ----------------------
+// To protect against degenerate performance scenarios (including DOS attacks),
+// the implementation includes an adaptive behavior that can resize the map
+// early (before its capacity is exceeded) when suspiciously long probe sequences
+// are encountered.
+//
+// With this algorithm in place it would be possible to turn a CPU attack into
+// a memory attack due to the aggressive resizing. To prevent that the
+// adaptive behavior only triggers when the map is at least half full.
+// This reduces the effectiveness of the algorithm but also makes it completely safe.
+//
+// The previous safety measure also prevents degenerate interactions with
+// really bad quality hash algorithms that can make normal inputs look like a
+// DOS attack.
+//
+const DISPLACEMENT_THRESHOLD: usize = 128;
+//
+// The threshold of 128 is chosen to minimize the chance of exceeding it.
+// In particular, we want that chance to be less than 10^-8 with a load of 90%.
+// For displacement, the smallest constant that fits our needs is 90,
+// so we round that up to 128.
+//
+// At a load factor of α, the odds of finding the target bucket after exactly n
+// unsuccessful probes[1] are
+//
+// Pr_α{displacement = n} =
+// (1 - α) / α * ∑_{k≥1} e^(-kα) * (kα)^(k+n) / (k + n)! * (1 - kα / (k + n + 1))
+//
+// We use this formula to find the probability of triggering the adaptive behavior
+//
+// Pr_0.909{displacement > 128} = 1.601 * 10^-11
+//
+// 1. Alfredo Viola (2005). Distributional analysis of Robin Hood linear probing
+// hashing with buckets.
+
+/// A hash map implemented with linear probing and Robin Hood bucket stealing.
+///
+/// By default, `HashMap` uses a hashing algorithm selected to provide
+/// resistance against HashDoS attacks. The algorithm is randomly seeded, and a
+/// reasonable best-effort is made to generate this seed from a high quality,
+/// secure source of randomness provided by the host without blocking the
+/// program. Because of this, the randomness of the seed depends on the output
+/// quality of the system's random number generator when the seed is created.
+/// In particular, seeds generated when the system's entropy pool is abnormally
+/// low such as during system boot may be of a lower quality.
+///
+/// The default hashing algorithm is currently SipHash 1-3, though this is
+/// subject to change at any point in the future. While its performance is very
+/// competitive for medium sized keys, other hashing algorithms will outperform
+/// it for small keys such as integers as well as large keys such as long
+/// strings, though those algorithms will typically *not* protect against
+/// attacks such as HashDoS.
+///
+/// The hashing algorithm can be replaced on a per-`HashMap` basis using the
+/// [`default`], [`with_hasher`], and [`with_capacity_and_hasher`] methods. Many
+/// alternative algorithms are available on crates.io, such as the [`fnv`] crate.
+///
+/// It is required that the keys implement the [`Eq`] and [`Hash`] traits, although
+/// this can frequently be achieved by using `#[derive(PartialEq, Eq, Hash)]`.
+/// If you implement these yourself, it is important that the following
+/// property holds:
+///
+/// ```text
+/// k1 == k2 -> hash(k1) == hash(k2)
+/// ```
+///
+/// In other words, if two keys are equal, their hashes must be equal.
+///
+/// It is a logic error for a key to be modified in such a way that the key's
+/// hash, as determined by the [`Hash`] trait, or its equality, as determined by
+/// the [`Eq`] trait, changes while it is in the map. This is normally only
+/// possible through [`Cell`], [`RefCell`], global state, I/O, or unsafe code.
+///
+/// Relevant papers/articles:
+///
+/// 1. Pedro Celis. ["Robin Hood Hashing"](https://cs.uwaterloo.ca/research/tr/1986/CS-86-14.pdf)
+/// 2. Emmanuel Goossaert. ["Robin Hood
+/// hashing"](http://codecapsule.com/2013/11/11/robin-hood-hashing/)
+/// 3. Emmanuel Goossaert. ["Robin Hood hashing: backward shift
+/// deletion"](http://codecapsule.com/2013/11/17/robin-hood-hashing-backward-shift-deletion/)
+///
+/// # Examples
+///
+/// ```
+/// use std::collections::HashMap;
+///
+/// // Type inference lets us omit an explicit type signature (which
+/// // would be `HashMap<String, String>` in this example).
+/// let mut book_reviews = HashMap::new();
+///
+/// // Review some books.
+/// book_reviews.insert(
+/// "Adventures of Huckleberry Finn".to_string(),
+/// "My favorite book.".to_string(),
+/// );
+/// book_reviews.insert(
+/// "Grimms' Fairy Tales".to_string(),
+/// "Masterpiece.".to_string(),
+/// );
+/// book_reviews.insert(
+/// "Pride and Prejudice".to_string(),
+/// "Very enjoyable.".to_string(),
+/// );
+/// book_reviews.insert(
+/// "The Adventures of Sherlock Holmes".to_string(),
+/// "Eye lyked it alot.".to_string(),
+/// );
+///
+/// // Check for a specific one.
+/// // When collections store owned values (String), they can still be
+/// // queried using references (&str).
+/// if !book_reviews.contains_key("Les Misérables") {
+/// println!("We've got {} reviews, but Les Misérables ain't one.",
+/// book_reviews.len());
+/// }
+///
+/// // oops, this review has a lot of spelling mistakes, let's delete it.
+/// book_reviews.remove("The Adventures of Sherlock Holmes");
+///
+/// // Look up the values associated with some keys.
+/// let to_find = ["Pride and Prejudice", "Alice's Adventure in Wonderland"];
+/// for &book in &to_find {
+/// match book_reviews.get(book) {
+/// Some(review) => println!("{}: {}", book, review),
+/// None => println!("{} is unreviewed.", book)
+/// }
+/// }
+///
+/// // Look up the value for a key (will panic if the key is not found).
+/// println!("Review for Jane: {}", book_reviews["Pride and Prejudice"]);
+///
+/// // Iterate over everything.
+/// for (book, review) in &book_reviews {
+/// println!("{}: \"{}\"", book, review);
+/// }
+/// ```
+///
+/// `HashMap` also implements an [`Entry API`](#method.entry), which allows
+/// for more complex methods of getting, setting, updating and removing keys and
+/// their values:
+///
+/// ```
+/// use std::collections::HashMap;
+///
+/// // type inference lets us omit an explicit type signature (which
+/// // would be `HashMap<&str, u8>` in this example).
+/// let mut player_stats = HashMap::new();
+///
+/// fn random_stat_buff() -> u8 {
+/// // could actually return some random value here - let's just return
+/// // some fixed value for now
+/// 42
+/// }
+///
+/// // insert a key only if it doesn't already exist
+/// player_stats.entry("health").or_insert(100);
+///
+/// // insert a key using a function that provides a new value only if it
+/// // doesn't already exist
+/// player_stats.entry("defence").or_insert_with(random_stat_buff);
+///
+/// // update a key, guarding against the key possibly not being set
+/// let stat = player_stats.entry("attack").or_insert(100);
+/// *stat += random_stat_buff();
+/// ```
+///
+/// The easiest way to use `HashMap` with a custom key type is to derive [`Eq`] and [`Hash`].
+/// We must also derive [`PartialEq`].
+///
+/// [`Eq`]: ../../std/cmp/trait.Eq.html
+/// [`Hash`]: ../../std/hash/trait.Hash.html
+/// [`PartialEq`]: ../../std/cmp/trait.PartialEq.html
+/// [`RefCell`]: ../../std/cell/struct.RefCell.html
+/// [`Cell`]: ../../std/cell/struct.Cell.html
+/// [`default`]: #method.default
+/// [`with_hasher`]: #method.with_hasher
+/// [`with_capacity_and_hasher`]: #method.with_capacity_and_hasher
+/// [`fnv`]: https://crates.io/crates/fnv
+///
+/// ```
+/// use std::collections::HashMap;
+///
+/// #[derive(Hash, Eq, PartialEq, Debug)]
+/// struct Viking {
+/// name: String,
+/// country: String,
+/// }
+///
+/// impl Viking {
+/// /// Creates a new Viking.
+/// fn new(name: &str, country: &str) -> Viking {
+/// Viking { name: name.to_string(), country: country.to_string() }
+/// }
+/// }
+///
+/// // Use a HashMap to store the vikings' health points.
+/// let mut vikings = HashMap::new();
+///
+/// vikings.insert(Viking::new("Einar", "Norway"), 25);
+/// vikings.insert(Viking::new("Olaf", "Denmark"), 24);
+/// vikings.insert(Viking::new("Harald", "Iceland"), 12);
+///
+/// // Use derived implementation to print the status of the vikings.
+/// for (viking, health) in &vikings {
+/// println!("{:?} has {} hp", viking, health);
+/// }
+/// ```
+///
+/// A `HashMap` with fixed list of elements can be initialized from an array:
+///
+/// ```
+/// use std::collections::HashMap;
+///
+/// fn main() {
+/// let timber_resources: HashMap<&str, i32> =
+/// [("Norway", 100),
+/// ("Denmark", 50),
+/// ("Iceland", 10)]
+/// .iter().cloned().collect();
+/// // use the values stored in map
+/// }
+/// ```
+
+#[derive(Clone)]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct HashMap<K, V, S = RandomState> {
+ // All hashes are keyed on these values, to prevent hash collision attacks.
+ hash_builder: S,
+
+ table: RawTable<K, V>,
+
+ resize_policy: DefaultResizePolicy,
+}
+
+/// Search for a pre-hashed key.
+/// If you don't already know the hash, use search or search_mut instead
+#[inline]
+fn search_hashed<K, V, M, F>(table: M, hash: SafeHash, is_match: F) -> InternalEntry<K, V, M>
+ where M: Deref<Target = RawTable<K, V>>,
+ F: FnMut(&K) -> bool
+{
+ // This is the only function where capacity can be zero. To avoid
+ // undefined behavior when Bucket::new gets the raw bucket in this
+ // case, immediately return the appropriate search result.
+ if table.capacity() == 0 {
+ return InternalEntry::TableIsEmpty;
+ }
+
+ search_hashed_nonempty(table, hash, is_match, true)
+}
+
+/// Search for a pre-hashed key when the hash map is known to be non-empty.
+#[inline]
+fn search_hashed_nonempty<K, V, M, F>(table: M, hash: SafeHash, mut is_match: F,
+ compare_hashes: bool)
+ -> InternalEntry<K, V, M>
+ where M: Deref<Target = RawTable<K, V>>,
+ F: FnMut(&K) -> bool
+{
+ // Do not check the capacity as an extra branch could slow the lookup.
+
+ let size = table.size();
+ let mut probe = Bucket::new(table, hash);
+ let mut displacement = 0;
+
+ loop {
+ let full = match probe.peek() {
+ Empty(bucket) => {
+ // Found a hole!
+ return InternalEntry::Vacant {
+ hash,
+ elem: NoElem(bucket, displacement),
+ };
+ }
+ Full(bucket) => bucket,
+ };
+
+ let probe_displacement = full.displacement();
+
+ if probe_displacement < displacement {
+ // Found a luckier bucket than me.
+ // We can finish the search early if we hit any bucket
+ // with a lower distance to initial bucket than we've probed.
+ return InternalEntry::Vacant {
+ hash,
+ elem: NeqElem(full, probe_displacement),
+ };
+ }
+
+ // If the hash doesn't match, it can't be this one..
+ if !compare_hashes || hash == full.hash() {
+ // If the key doesn't match, it can't be this one..
+ if is_match(full.read().0) {
+ return InternalEntry::Occupied { elem: full };
+ }
+ }
+ displacement += 1;
+ probe = full.next();
+ debug_assert!(displacement <= size);
+ }
+}
+
+/// Same as `search_hashed_nonempty` but for mutable access.
+#[inline]
+fn search_hashed_nonempty_mut<K, V, M, F>(table: M, hash: SafeHash, mut is_match: F,
+ compare_hashes: bool)
+ -> InternalEntry<K, V, M>
+ where M: DerefMut<Target = RawTable<K, V>>,
+ F: FnMut(&K) -> bool
+{
+ // Do not check the capacity as an extra branch could slow the lookup.
+
+ let size = table.size();
+ let mut probe = Bucket::new(table, hash);
+ let mut displacement = 0;
+
+ loop {
+ let mut full = match probe.peek() {
+ Empty(bucket) => {
+ // Found a hole!
+ return InternalEntry::Vacant {
+ hash,
+ elem: NoElem(bucket, displacement),
+ };
+ }
+ Full(bucket) => bucket,
+ };
+
+ let probe_displacement = full.displacement();
+
+ if probe_displacement < displacement {
+ // Found a luckier bucket than me.
+ // We can finish the search early if we hit any bucket
+ // with a lower distance to initial bucket than we've probed.
+ return InternalEntry::Vacant {
+ hash,
+ elem: NeqElem(full, probe_displacement),
+ };
+ }
+
+ // If the hash doesn't match, it can't be this one..
+ if hash == full.hash() || !compare_hashes {
+ // If the key doesn't match, it can't be this one..
+ if is_match(full.read_mut().0) {
+ return InternalEntry::Occupied { elem: full };
+ }
+ }
+ displacement += 1;
+ probe = full.next();
+ debug_assert!(displacement <= size);
+ }
+}
+
+fn pop_internal<K, V>(starting_bucket: FullBucketMut<'_, K, V>)
+ -> (K, V, &mut RawTable<K, V>)
+{
+ let (empty, retkey, retval) = starting_bucket.take();
+ let mut gap = match empty.gap_peek() {
+ Ok(b) => b,
+ Err(b) => return (retkey, retval, b.into_table()),
+ };
+
+ while gap.full().displacement() != 0 {
+ gap = match gap.shift() {
+ Ok(b) => b,
+ Err(b) => {
+ return (retkey, retval, b.into_table());
+ },
+ };
+ }
+
+ // Now we've done all our shifting. Return the value we grabbed earlier.
+ (retkey, retval, gap.into_table())
+}
+
+/// Performs robin hood bucket stealing at the given `bucket`. You must
+/// also pass that bucket's displacement so we don't have to recalculate it.
+///
+/// `hash`, `key`, and `val` are the elements to "robin hood" into the hashtable.
+fn robin_hood<'a, K: 'a, V: 'a>(bucket: FullBucketMut<'a, K, V>,
+ mut displacement: usize,
+ mut hash: SafeHash,
+ mut key: K,
+ mut val: V)
+ -> FullBucketMut<'a, K, V> {
+ let size = bucket.table().size();
+ let raw_capacity = bucket.table().capacity();
+ // There can be at most `size - dib` buckets to displace, because
+ // in the worst case, there are `size` elements and we already are
+ // `displacement` buckets away from the initial one.
+ let idx_end = (bucket.index() + size - bucket.displacement()) % raw_capacity;
+ // Save the *starting point*.
+ let mut bucket = bucket.stash();
+
+ loop {
+ let (old_hash, old_key, old_val) = bucket.replace(hash, key, val);
+ hash = old_hash;
+ key = old_key;
+ val = old_val;
+
+ loop {
+ displacement += 1;
+ let probe = bucket.next();
+ debug_assert!(probe.index() != idx_end);
+
+ let full_bucket = match probe.peek() {
+ Empty(bucket) => {
+ // Found a hole!
+ let bucket = bucket.put(hash, key, val);
+ // Now that it's stolen, just read the value's pointer
+ // right out of the table! Go back to the *starting point*.
+ //
+ // This use of `into_table` is misleading. It turns the
+ // bucket, which is a FullBucket on top of a
+ // FullBucketMut, into just one FullBucketMut. The "table"
+ // refers to the inner FullBucketMut in this context.
+ return bucket.into_table();
+ }
+ Full(bucket) => bucket,
+ };
+
+ let probe_displacement = full_bucket.displacement();
+
+ bucket = full_bucket;
+
+ // Robin hood! Steal the spot.
+ if probe_displacement < displacement {
+ displacement = probe_displacement;
+ break;
+ }
+ }
+ }
+}
+
+impl<K, V, S> HashMap<K, V, S>
+ where K: Eq + Hash,
+ S: BuildHasher
+{
+ fn make_hash<X: ?Sized>(&self, x: &X) -> SafeHash
+ where X: Hash
+ {
+ table::make_hash(&self.hash_builder, x)
+ }
+
+ /// Search for a key, yielding the index if it's found in the hashtable.
+ /// If you already have the hash for the key lying around, or if you need an
+ /// InternalEntry, use search_hashed or search_hashed_nonempty.
+ #[inline]
+ fn search<'a, Q: ?Sized>(&'a self, q: &Q)
+ -> Option<FullBucket<K, V, &'a RawTable<K, V>>>
+ where K: Borrow<Q>,
+ Q: Eq + Hash
+ {
+ if self.is_empty() {
+ return None;
+ }
+
+ let hash = self.make_hash(q);
+ search_hashed_nonempty(&self.table, hash, |k| q.eq(k.borrow()), true)
+ .into_occupied_bucket()
+ }
+
+ #[inline]
+ fn search_mut<'a, Q: ?Sized>(&'a mut self, q: &Q)
+ -> Option<FullBucket<K, V, &'a mut RawTable<K, V>>>
+ where K: Borrow<Q>,
+ Q: Eq + Hash
+ {
+ if self.is_empty() {
+ return None;
+ }
+
+ let hash = self.make_hash(q);
+ search_hashed_nonempty(&mut self.table, hash, |k| q.eq(k.borrow()), true)
+ .into_occupied_bucket()
+ }
+
+ // The caller should ensure that invariants by Robin Hood Hashing hold
+ // and that there's space in the underlying table.
+ fn insert_hashed_ordered(&mut self, hash: SafeHash, k: K, v: V) {
+ let mut buckets = Bucket::new(&mut self.table, hash);
+ let start_index = buckets.index();
+
+ loop {
+ // We don't need to compare hashes for value swap.
+ // Not even DIBs for Robin Hood.
+ buckets = match buckets.peek() {
+ Empty(empty) => {
+ empty.put(hash, k, v);
+ return;
+ }
+ Full(b) => b.into_bucket(),
+ };
+ buckets.next();
+ debug_assert!(buckets.index() != start_index);
+ }
+ }
+}
+
+impl<K: Hash + Eq, V> HashMap<K, V, RandomState> {
+ /// Creates an empty `HashMap`.
+ ///
+ /// The hash map is initially created with a capacity of 0, so it will not allocate until it
+ /// is first inserted into.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::HashMap;
+ /// let mut map: HashMap<&str, i32> = HashMap::new();
+ /// ```
+ #[inline]
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn new() -> HashMap<K, V, RandomState> {
+ Default::default()
+ }
+
+ /// Creates an empty `HashMap` with the specified capacity.
+ ///
+ /// The hash map will be able to hold at least `capacity` elements without
+ /// reallocating. If `capacity` is 0, the hash map will not allocate.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::HashMap;
+ /// let mut map: HashMap<&str, i32> = HashMap::with_capacity(10);
+ /// ```
+ #[inline]
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn with_capacity(capacity: usize) -> HashMap<K, V, RandomState> {
+ HashMap::with_capacity_and_hasher(capacity, Default::default())
+ }
+}
+
+impl<K, V, S> HashMap<K, V, S> {
+ /// Returns the number of elements the map can hold without reallocating.
+ ///
+ /// This number is a lower bound; the `HashMap<K, V>` might be able to hold
+ /// more, but is guaranteed to be able to hold at least this many.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::HashMap;
+ /// let map: HashMap<i32, i32> = HashMap::with_capacity(100);
+ /// assert!(map.capacity() >= 100);
+ /// ```
+ #[inline]
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn capacity(&self) -> usize {
+ self.resize_policy.capacity(self.raw_capacity())
+ }
+
+ /// Returns the hash map's raw capacity.
+ #[inline]
+ fn raw_capacity(&self) -> usize {
+ self.table.capacity()
+ }
+
+ /// An iterator visiting all keys in arbitrary order.
+ /// The iterator element type is `&'a K`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::HashMap;
+ ///
+ /// let mut map = HashMap::new();
+ /// map.insert("a", 1);
+ /// map.insert("b", 2);
+ /// map.insert("c", 3);
+ ///
+ /// for key in map.keys() {
+ /// println!("{}", key);
+ /// }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn keys(&self) -> Keys<'_, K, V> {
+ Keys { inner: self.iter() }
+ }
+
+ /// An iterator visiting all values in arbitrary order.
+ /// The iterator element type is `&'a V`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::HashMap;
+ ///
+ /// let mut map = HashMap::new();
+ /// map.insert("a", 1);
+ /// map.insert("b", 2);
+ /// map.insert("c", 3);
+ ///
+ /// for val in map.values() {
+ /// println!("{}", val);
+ /// }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn values(&self) -> Values<'_, K, V> {
+ Values { inner: self.iter() }
+ }
+
+ /// An iterator visiting all values mutably in arbitrary order.
+ /// The iterator element type is `&'a mut V`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::HashMap;
+ ///
+ /// let mut map = HashMap::new();
+ ///
+ /// map.insert("a", 1);
+ /// map.insert("b", 2);
+ /// map.insert("c", 3);
+ ///
+ /// for val in map.values_mut() {
+ /// *val = *val + 10;
+ /// }
+ ///
+ /// for val in map.values() {
+ /// println!("{}", val);
+ /// }
+ /// ```
+ #[stable(feature = "map_values_mut", since = "1.10.0")]
+ pub fn values_mut(&mut self) -> ValuesMut<'_, K, V> {
+ ValuesMut { inner: self.iter_mut() }
+ }
+
+ /// An iterator visiting all key-value pairs in arbitrary order.
+ /// The iterator element type is `(&'a K, &'a V)`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::HashMap;
+ ///
+ /// let mut map = HashMap::new();
+ /// map.insert("a", 1);
+ /// map.insert("b", 2);
+ /// map.insert("c", 3);
+ ///
+ /// for (key, val) in map.iter() {
+ /// println!("key: {} val: {}", key, val);
+ /// }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn iter(&self) -> Iter<'_, K, V> {
+ Iter { inner: self.table.iter() }
+ }
+
+ /// An iterator visiting all key-value pairs in arbitrary order,
+ /// with mutable references to the values.
+ /// The iterator element type is `(&'a K, &'a mut V)`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::HashMap;
+ ///
+ /// let mut map = HashMap::new();
+ /// map.insert("a", 1);
+ /// map.insert("b", 2);
+ /// map.insert("c", 3);
+ ///
+ /// // Update all values
+ /// for (_, val) in map.iter_mut() {
+ /// *val *= 2;
+ /// }
+ ///
+ /// for (key, val) in &map {
+ /// println!("key: {} val: {}", key, val);
+ /// }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn iter_mut(&mut self) -> IterMut<'_, K, V> {
+ IterMut { inner: self.table.iter_mut() }
+ }
+
+ /// Returns the number of elements in the map.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::HashMap;
+ ///
+ /// let mut a = HashMap::new();
+ /// assert_eq!(a.len(), 0);
+ /// a.insert(1, "a");
+ /// assert_eq!(a.len(), 1);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn len(&self) -> usize {
+ self.table.size()
+ }
+
+ /// Returns `true` if the map contains no elements.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::HashMap;
+ ///
+ /// let mut a = HashMap::new();
+ /// assert!(a.is_empty());
+ /// a.insert(1, "a");
+ /// assert!(!a.is_empty());
+ /// ```
+ #[inline]
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn is_empty(&self) -> bool {
+ self.len() == 0
+ }
+
+ /// Clears the map, returning all key-value pairs as an iterator. Keeps the
+ /// allocated memory for reuse.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::HashMap;
+ ///
+ /// let mut a = HashMap::new();
+ /// a.insert(1, "a");
+ /// a.insert(2, "b");
+ ///
+ /// for (k, v) in a.drain().take(1) {
+ /// assert!(k == 1 || k == 2);
+ /// assert!(v == "a" || v == "b");
+ /// }
+ ///
+ /// assert!(a.is_empty());
+ /// ```
+ #[inline]
+ #[stable(feature = "drain", since = "1.6.0")]
+ pub fn drain(&mut self) -> Drain<'_, K, V> {
+ Drain { inner: self.table.drain() }
+ }
+
+ /// Clears the map, removing all key-value pairs. Keeps the allocated memory
+ /// for reuse.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::HashMap;
+ ///
+ /// let mut a = HashMap::new();
+ /// a.insert(1, "a");
+ /// a.clear();
+ /// assert!(a.is_empty());
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn clear(&mut self) {
+ self.drain();
+ }
+}
+
+impl<K, V, S> HashMap<K, V, S>
+ where K: Eq + Hash,
+ S: BuildHasher
+{
+ /// Creates an empty `HashMap` which will use the given hash builder to hash
+ /// keys.
+ ///
+ /// The created map has the default initial capacity.
+ ///
+ /// Warning: `hash_builder` is normally randomly generated, and
+ /// is designed to allow HashMaps to be resistant to attacks that
+ /// cause many collisions and very poor performance. Setting it
+ /// manually using this function can expose a DoS attack vector.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::HashMap;
+ /// use std::collections::hash_map::RandomState;
+ ///
+ /// let s = RandomState::new();
+ /// let mut map = HashMap::with_hasher(s);
+ /// map.insert(1, 2);
+ /// ```
+ #[inline]
+ #[stable(feature = "hashmap_build_hasher", since = "1.7.0")]
+ pub fn with_hasher(hash_builder: S) -> HashMap<K, V, S> {
+ HashMap {
+ hash_builder,
+ resize_policy: DefaultResizePolicy::new(),
+ table: RawTable::new(0),
+ }
+ }
+
+ /// Creates an empty `HashMap` with the specified capacity, using `hash_builder`
+ /// to hash the keys.
+ ///
+ /// The hash map will be able to hold at least `capacity` elements without
+ /// reallocating. If `capacity` is 0, the hash map will not allocate.
+ ///
+ /// Warning: `hash_builder` is normally randomly generated, and
+ /// is designed to allow HashMaps to be resistant to attacks that
+ /// cause many collisions and very poor performance. Setting it
+ /// manually using this function can expose a DoS attack vector.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::HashMap;
+ /// use std::collections::hash_map::RandomState;
+ ///
+ /// let s = RandomState::new();
+ /// let mut map = HashMap::with_capacity_and_hasher(10, s);
+ /// map.insert(1, 2);
+ /// ```
+ #[inline]
+ #[stable(feature = "hashmap_build_hasher", since = "1.7.0")]
+ pub fn with_capacity_and_hasher(capacity: usize, hash_builder: S) -> HashMap<K, V, S> {
+ let resize_policy = DefaultResizePolicy::new();
+ let raw_cap = resize_policy.raw_capacity(capacity);
+ HashMap {
+ hash_builder,
+ resize_policy,
+ table: RawTable::new(raw_cap),
+ }
+ }
+
+ /// Returns a reference to the map's [`BuildHasher`].
+ ///
+ /// [`BuildHasher`]: ../../std/hash/trait.BuildHasher.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::HashMap;
+ /// use std::collections::hash_map::RandomState;
+ ///
+ /// let hasher = RandomState::new();
+ /// let map: HashMap<i32, i32> = HashMap::with_hasher(hasher);
+ /// let hasher: &RandomState = map.hasher();
+ /// ```
+ #[stable(feature = "hashmap_public_hasher", since = "1.9.0")]
+ pub fn hasher(&self) -> &S {
+ &self.hash_builder
+ }
+
+ /// Reserves capacity for at least `additional` more elements to be inserted
+ /// in the `HashMap`. The collection may reserve more space to avoid
+ /// frequent reallocations.
+ ///
+ /// # Panics
+ ///
+ /// Panics if the new allocation size overflows [`usize`].
+ ///
+ /// [`usize`]: ../../std/primitive.usize.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::HashMap;
+ /// let mut map: HashMap<&str, i32> = HashMap::new();
+ /// map.reserve(10);
+ /// ```
+ #[inline]
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn reserve(&mut self, additional: usize) {
+ match self.reserve_internal(additional, Infallible) {
+ Err(CollectionAllocErr::CapacityOverflow) => panic!("capacity overflow"),
+ Err(CollectionAllocErr::AllocErr) => unreachable!(),
+ Ok(()) => { /* yay */ }
+ }
+ }
+
+ /// Tries to reserve capacity for at least `additional` more elements to be inserted
+ /// in the given `HashMap<K,V>`. The collection may reserve more space to avoid
+ /// frequent reallocations.
+ ///
+ /// # Errors
+ ///
+ /// If the capacity overflows, or the allocator reports a failure, then an error
+ /// is returned.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(try_reserve)]
+ /// use std::collections::HashMap;
+ /// let mut map: HashMap<&str, isize> = HashMap::new();
+ /// map.try_reserve(10).expect("why is the test harness OOMing on 10 bytes?");
+ /// ```
+ #[unstable(feature = "try_reserve", reason = "new API", issue="48043")]
+ pub fn try_reserve(&mut self, additional: usize) -> Result<(), CollectionAllocErr> {
+ self.reserve_internal(additional, Fallible)
+ }
+
+ #[inline]
+ fn reserve_internal(&mut self, additional: usize, fallibility: Fallibility)
+ -> Result<(), CollectionAllocErr> {
+
+ let remaining = self.capacity() - self.len(); // this can't overflow
+ if remaining < additional {
+ let min_cap = self.len()
+ .checked_add(additional)
+ .ok_or(CollectionAllocErr::CapacityOverflow)?;
+ let raw_cap = self.resize_policy.try_raw_capacity(min_cap)?;
+ self.try_resize(raw_cap, fallibility)?;
+ } else if self.table.tag() && remaining <= self.len() {
+ // Probe sequence is too long and table is half full,
+ // resize early to reduce probing length.
+ let new_capacity = self.table.capacity() * 2;
+ self.try_resize(new_capacity, fallibility)?;
+ }
+ Ok(())
+ }
+
+ /// Resizes the internal vectors to a new capacity. It's your
+ /// responsibility to:
+ /// 1) Ensure `new_raw_cap` is enough for all the elements, accounting
+ /// for the load factor.
+ /// 2) Ensure `new_raw_cap` is a power of two or zero.
+ #[inline(never)]
+ #[cold]
+ fn try_resize(
+ &mut self,
+ new_raw_cap: usize,
+ fallibility: Fallibility,
+ ) -> Result<(), CollectionAllocErr> {
+ assert!(self.table.size() <= new_raw_cap);
+ assert!(new_raw_cap.is_power_of_two() || new_raw_cap == 0);
+
+ let mut old_table = replace(
+ &mut self.table,
+ match fallibility {
+ Infallible => RawTable::new(new_raw_cap),
+ Fallible => RawTable::try_new(new_raw_cap)?,
+ }
+ );
+ let old_size = old_table.size();
+
+ if old_table.size() == 0 {
+ return Ok(());
+ }
+
+ let mut bucket = Bucket::head_bucket(&mut old_table);
+
+ // This is how the buckets might be laid out in memory:
+ // ($ marks an initialized bucket)
+ // ________________
+ // |$$$_$$$$$$_$$$$$|
+ //
+ // But we've skipped the entire initial cluster of buckets
+ // and will continue iteration in this order:
+ // ________________
+ // |$$$$$$_$$$$$
+ // ^ wrap around once end is reached
+ // ________________
+ // $$$_____________|
+ // ^ exit once table.size == 0
+ loop {
+ bucket = match bucket.peek() {
+ Full(bucket) => {
+ let h = bucket.hash();
+ let (b, k, v) = bucket.take();
+ self.insert_hashed_ordered(h, k, v);
+ if b.table().size() == 0 {
+ break;
+ }
+ b.into_bucket()
+ }
+ Empty(b) => b.into_bucket(),
+ };
+ bucket.next();
+ }
+
+ assert_eq!(self.table.size(), old_size);
+ Ok(())
+ }
+
+ /// Shrinks the capacity of the map as much as possible. It will drop
+ /// down as much as possible while maintaining the internal rules
+ /// and possibly leaving some space in accordance with the resize policy.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::HashMap;
+ ///
+ /// let mut map: HashMap<i32, i32> = HashMap::with_capacity(100);
+ /// map.insert(1, 2);
+ /// map.insert(3, 4);
+ /// assert!(map.capacity() >= 100);
+ /// map.shrink_to_fit();
+ /// assert!(map.capacity() >= 2);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn shrink_to_fit(&mut self) {
+ let new_raw_cap = self.resize_policy.raw_capacity(self.len());
+ if self.raw_capacity() != new_raw_cap {
+ let old_table = replace(&mut self.table, RawTable::new(new_raw_cap));
+ let old_size = old_table.size();
+
+ // Shrink the table. Naive algorithm for resizing:
+ for (h, k, v) in old_table.into_iter() {
+ self.insert_hashed_nocheck(h, k, v);
+ }
+
+ debug_assert_eq!(self.table.size(), old_size);
+ }
+ }
+
+ /// Shrinks the capacity of the map with a lower limit. It will drop
+ /// down no lower than the supplied limit while maintaining the internal rules
+ /// and possibly leaving some space in accordance with the resize policy.
+ ///
+ /// Panics if the current capacity is smaller than the supplied
+ /// minimum capacity.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(shrink_to)]
+ /// use std::collections::HashMap;
+ ///
+ /// let mut map: HashMap<i32, i32> = HashMap::with_capacity(100);
+ /// map.insert(1, 2);
+ /// map.insert(3, 4);
+ /// assert!(map.capacity() >= 100);
+ /// map.shrink_to(10);
+ /// assert!(map.capacity() >= 10);
+ /// map.shrink_to(0);
+ /// assert!(map.capacity() >= 2);
+ /// ```
+ #[unstable(feature = "shrink_to", reason = "new API", issue="56431")]
+ pub fn shrink_to(&mut self, min_capacity: usize) {
+ assert!(self.capacity() >= min_capacity, "Tried to shrink to a larger capacity");
+
+ let new_raw_cap = self.resize_policy.raw_capacity(max(self.len(), min_capacity));
+ if self.raw_capacity() != new_raw_cap {
+ let old_table = replace(&mut self.table, RawTable::new(new_raw_cap));
+ let old_size = old_table.size();
+
+ // Shrink the table. Naive algorithm for resizing:
+ for (h, k, v) in old_table.into_iter() {
+ self.insert_hashed_nocheck(h, k, v);
+ }
+
+ debug_assert_eq!(self.table.size(), old_size);
+ }
+ }
+
+ /// Insert a pre-hashed key-value pair, without first checking
+ /// that there's enough room in the buckets. Returns a reference to the
+ /// newly insert value.
+ ///
+ /// If the key already exists, the hashtable will be returned untouched
+ /// and a reference to the existing element will be returned.
+ fn insert_hashed_nocheck(&mut self, hash: SafeHash, k: K, v: V) -> Option<V> {
+ let entry = search_hashed(&mut self.table, hash, |key| *key == k).into_entry(k);
+ match entry {
+ Some(Occupied(mut elem)) => Some(elem.insert(v)),
+ Some(Vacant(elem)) => {
+ elem.insert(v);
+ None
+ }
+ None => unreachable!(),
+ }
+ }
+
+ /// Gets the given key's corresponding entry in the map for in-place manipulation.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::HashMap;
+ ///
+ /// let mut letters = HashMap::new();
+ ///
+ /// for ch in "a short treatise on fungi".chars() {
+ /// let counter = letters.entry(ch).or_insert(0);
+ /// *counter += 1;
+ /// }
+ ///
+ /// assert_eq!(letters[&'s'], 2);
+ /// assert_eq!(letters[&'t'], 3);
+ /// assert_eq!(letters[&'u'], 1);
+ /// assert_eq!(letters.get(&'y'), None);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn entry(&mut self, key: K) -> Entry<'_, K, V> {
+ // Gotta resize now.
+ self.reserve(1);
+ let hash = self.make_hash(&key);
+ search_hashed(&mut self.table, hash, |q| q.eq(&key))
+ .into_entry(key).expect("unreachable")
+ }
+
+ /// Returns a reference to the value corresponding to the key.
+ ///
+ /// The key may be any borrowed form of the map's key type, but
+ /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for
+ /// the key type.
+ ///
+ /// [`Eq`]: ../../std/cmp/trait.Eq.html
+ /// [`Hash`]: ../../std/hash/trait.Hash.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::HashMap;
+ ///
+ /// let mut map = HashMap::new();
+ /// map.insert(1, "a");
+ /// assert_eq!(map.get(&1), Some(&"a"));
+ /// assert_eq!(map.get(&2), None);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn get<Q: ?Sized>(&self, k: &Q) -> Option<&V>
+ where K: Borrow<Q>,
+ Q: Hash + Eq
+ {
+ self.search(k).map(|bucket| bucket.into_refs().1)
+ }
+
+ /// Returns the key-value pair corresponding to the supplied key.
+ ///
+ /// The supplied key may be any borrowed form of the map's key type, but
+ /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for
+ /// the key type.
+ ///
+ /// [`Eq`]: ../../std/cmp/trait.Eq.html
+ /// [`Hash`]: ../../std/hash/trait.Hash.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(map_get_key_value)]
+ /// use std::collections::HashMap;
+ ///
+ /// let mut map = HashMap::new();
+ /// map.insert(1, "a");
+ /// assert_eq!(map.get_key_value(&1), Some((&1, &"a")));
+ /// assert_eq!(map.get_key_value(&2), None);
+ /// ```
+ #[unstable(feature = "map_get_key_value", issue = "49347")]
+ pub fn get_key_value<Q: ?Sized>(&self, k: &Q) -> Option<(&K, &V)>
+ where K: Borrow<Q>,
+ Q: Hash + Eq
+ {
+ self.search(k).map(|bucket| bucket.into_refs())
+ }
+
+ /// Returns `true` if the map contains a value for the specified key.
+ ///
+ /// The key may be any borrowed form of the map's key type, but
+ /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for
+ /// the key type.
+ ///
+ /// [`Eq`]: ../../std/cmp/trait.Eq.html
+ /// [`Hash`]: ../../std/hash/trait.Hash.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::HashMap;
+ ///
+ /// let mut map = HashMap::new();
+ /// map.insert(1, "a");
+ /// assert_eq!(map.contains_key(&1), true);
+ /// assert_eq!(map.contains_key(&2), false);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn contains_key<Q: ?Sized>(&self, k: &Q) -> bool
+ where K: Borrow<Q>,
+ Q: Hash + Eq
+ {
+ self.search(k).is_some()
+ }
+
+ /// Returns a mutable reference to the value corresponding to the key.
+ ///
+ /// The key may be any borrowed form of the map's key type, but
+ /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for
+ /// the key type.
+ ///
+ /// [`Eq`]: ../../std/cmp/trait.Eq.html
+ /// [`Hash`]: ../../std/hash/trait.Hash.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::HashMap;
+ ///
+ /// let mut map = HashMap::new();
+ /// map.insert(1, "a");
+ /// if let Some(x) = map.get_mut(&1) {
+ /// *x = "b";
+ /// }
+ /// assert_eq!(map[&1], "b");
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn get_mut<Q: ?Sized>(&mut self, k: &Q) -> Option<&mut V>
+ where K: Borrow<Q>,
+ Q: Hash + Eq
+ {
+ self.search_mut(k).map(|bucket| bucket.into_mut_refs().1)
+ }
+
+ /// Inserts a key-value pair into the map.
+ ///
+ /// If the map did not have this key present, [`None`] is returned.
+ ///
+ /// If the map did have this key present, the value is updated, and the old
+ /// value is returned. The key is not updated, though; this matters for
+ /// types that can be `==` without being identical. See the [module-level
+ /// documentation] for more.
+ ///
+ /// [`None`]: ../../std/option/enum.Option.html#variant.None
+ /// [module-level documentation]: index.html#insert-and-complex-keys
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::HashMap;
+ ///
+ /// let mut map = HashMap::new();
+ /// assert_eq!(map.insert(37, "a"), None);
+ /// assert_eq!(map.is_empty(), false);
+ ///
+ /// map.insert(37, "b");
+ /// assert_eq!(map.insert(37, "c"), Some("b"));
+ /// assert_eq!(map[&37], "c");
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn insert(&mut self, k: K, v: V) -> Option<V> {
+ let hash = self.make_hash(&k);
+ self.reserve(1);
+ self.insert_hashed_nocheck(hash, k, v)
+ }
+
+ /// Removes a key from the map, returning the value at the key if the key
+ /// was previously in the map.
+ ///
+ /// The key may be any borrowed form of the map's key type, but
+ /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for
+ /// the key type.
+ ///
+ /// [`Eq`]: ../../std/cmp/trait.Eq.html
+ /// [`Hash`]: ../../std/hash/trait.Hash.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::HashMap;
+ ///
+ /// let mut map = HashMap::new();
+ /// map.insert(1, "a");
+ /// assert_eq!(map.remove(&1), Some("a"));
+ /// assert_eq!(map.remove(&1), None);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn remove<Q: ?Sized>(&mut self, k: &Q) -> Option<V>
+ where K: Borrow<Q>,
+ Q: Hash + Eq
+ {
+ self.search_mut(k).map(|bucket| pop_internal(bucket).1)
+ }
+
+ /// Removes a key from the map, returning the stored key and value if the
+ /// key was previously in the map.
+ ///
+ /// The key may be any borrowed form of the map's key type, but
+ /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for
+ /// the key type.
+ ///
+ /// [`Eq`]: ../../std/cmp/trait.Eq.html
+ /// [`Hash`]: ../../std/hash/trait.Hash.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::HashMap;
+ ///
+ /// # fn main() {
+ /// let mut map = HashMap::new();
+ /// map.insert(1, "a");
+ /// assert_eq!(map.remove_entry(&1), Some((1, "a")));
+ /// assert_eq!(map.remove(&1), None);
+ /// # }
+ /// ```
+ #[stable(feature = "hash_map_remove_entry", since = "1.27.0")]
+ pub fn remove_entry<Q: ?Sized>(&mut self, k: &Q) -> Option<(K, V)>
+ where K: Borrow<Q>,
+ Q: Hash + Eq
+ {
+ self.search_mut(k)
+ .map(|bucket| {
+ let (k, v, _) = pop_internal(bucket);
+ (k, v)
+ })
+ }
+
+ /// Retains only the elements specified by the predicate.
+ ///
+ /// In other words, remove all pairs `(k, v)` such that `f(&k,&mut v)` returns `false`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::HashMap;
+ ///
+ /// let mut map: HashMap<i32, i32> = (0..8).map(|x|(x, x*10)).collect();
+ /// map.retain(|&k, _| k % 2 == 0);
+ /// assert_eq!(map.len(), 4);
+ /// ```
+ #[stable(feature = "retain_hash_collection", since = "1.18.0")]
+ pub fn retain<F>(&mut self, mut f: F)
+ where F: FnMut(&K, &mut V) -> bool
+ {
+ if self.table.size() == 0 {
+ return;
+ }
+ let mut elems_left = self.table.size();
+ let mut bucket = Bucket::head_bucket(&mut self.table);
+ bucket.prev();
+ let start_index = bucket.index();
+ while elems_left != 0 {
+ bucket = match bucket.peek() {
+ Full(mut full) => {
+ elems_left -= 1;
+ let should_remove = {
+ let (k, v) = full.read_mut();
+ !f(k, v)
+ };
+ if should_remove {
+ let prev_raw = full.raw();
+ let (_, _, t) = pop_internal(full);
+ Bucket::new_from(prev_raw, t)
+ } else {
+ full.into_bucket()
+ }
+ },
+ Empty(b) => {
+ b.into_bucket()
+ }
+ };
+ bucket.prev(); // reverse iteration
+ debug_assert!(elems_left == 0 || bucket.index() != start_index);
+ }
+ }
+}
+
+impl<K, V, S> HashMap<K, V, S>
+ where K: Eq + Hash,
+ S: BuildHasher
+{
+ /// Creates a raw entry builder for the HashMap.
+ ///
+ /// Raw entries provide the lowest level of control for searching and
+ /// manipulating a map. They must be manually initialized with a hash and
+ /// then manually searched. After this, insertions into a vacant entry
+ /// still require an owned key to be provided.
+ ///
+ /// Raw entries are useful for such exotic situations as:
+ ///
+ /// * Hash memoization
+ /// * Deferring the creation of an owned key until it is known to be required
+ /// * Using a search key that doesn't work with the Borrow trait
+ /// * Using custom comparison logic without newtype wrappers
+ ///
+ /// Because raw entries provide much more low-level control, it's much easier
+ /// to put the HashMap into an inconsistent state which, while memory-safe,
+ /// will cause the map to produce seemingly random results. Higher-level and
+ /// more foolproof APIs like `entry` should be preferred when possible.
+ ///
+ /// In particular, the hash used to initialized the raw entry must still be
+ /// consistent with the hash of the key that is ultimately stored in the entry.
+ /// This is because implementations of HashMap may need to recompute hashes
+ /// when resizing, at which point only the keys are available.
+ ///
+ /// Raw entries give mutable access to the keys. This must not be used
+ /// to modify how the key would compare or hash, as the map will not re-evaluate
+ /// where the key should go, meaning the keys may become "lost" if their
+ /// location does not reflect their state. For instance, if you change a key
+ /// so that the map now contains keys which compare equal, search may start
+ /// acting erratically, with two keys randomly masking each other. Implementations
+ /// are free to assume this doesn't happen (within the limits of memory-safety).
+ #[inline(always)]
+ #[unstable(feature = "hash_raw_entry", issue = "56167")]
+ pub fn raw_entry_mut(&mut self) -> RawEntryBuilderMut<'_, K, V, S> {
+ self.reserve(1);
+ RawEntryBuilderMut { map: self }
+ }
+
+ /// Creates a raw immutable entry builder for the HashMap.
+ ///
+ /// Raw entries provide the lowest level of control for searching and
+ /// manipulating a map. They must be manually initialized with a hash and
+ /// then manually searched.
+ ///
+ /// This is useful for
+ /// * Hash memoization
+ /// * Using a search key that doesn't work with the Borrow trait
+ /// * Using custom comparison logic without newtype wrappers
+ ///
+ /// Unless you are in such a situation, higher-level and more foolproof APIs like
+ /// `get` should be preferred.
+ ///
+ /// Immutable raw entries have very limited use; you might instead want `raw_entry_mut`.
+ #[unstable(feature = "hash_raw_entry", issue = "56167")]
+ pub fn raw_entry(&self) -> RawEntryBuilder<'_, K, V, S> {
+ RawEntryBuilder { map: self }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<K, V, S> PartialEq for HashMap<K, V, S>
+ where K: Eq + Hash,
+ V: PartialEq,
+ S: BuildHasher
+{
+ fn eq(&self, other: &HashMap<K, V, S>) -> bool {
+ if self.len() != other.len() {
+ return false;
+ }
+
+ self.iter().all(|(key, value)| other.get(key).map_or(false, |v| *value == *v))
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<K, V, S> Eq for HashMap<K, V, S>
+ where K: Eq + Hash,
+ V: Eq,
+ S: BuildHasher
+{
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<K, V, S> Debug for HashMap<K, V, S>
+ where K: Eq + Hash + Debug,
+ V: Debug,
+ S: BuildHasher
+{
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_map().entries(self.iter()).finish()
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<K, V, S> Default for HashMap<K, V, S>
+ where K: Eq + Hash,
+ S: BuildHasher + Default
+{
+ /// Creates an empty `HashMap<K, V, S>`, with the `Default` value for the hasher.
+ fn default() -> HashMap<K, V, S> {
+ HashMap::with_hasher(Default::default())
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<K, Q: ?Sized, V, S> Index<&Q> for HashMap<K, V, S>
+ where K: Eq + Hash + Borrow<Q>,
+ Q: Eq + Hash,
+ S: BuildHasher
+{
+ type Output = V;
+
+ /// Returns a reference to the value corresponding to the supplied key.
+ ///
+ /// # Panics
+ ///
+ /// Panics if the key is not present in the `HashMap`.
+ #[inline]
+ fn index(&self, key: &Q) -> &V {
+ self.get(key).expect("no entry found for key")
+ }
+}
+
+/// An iterator over the entries of a `HashMap`.
+///
+/// This `struct` is created by the [`iter`] method on [`HashMap`]. See its
+/// documentation for more.
+///
+/// [`iter`]: struct.HashMap.html#method.iter
+/// [`HashMap`]: struct.HashMap.html
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct Iter<'a, K: 'a, V: 'a> {
+ inner: table::Iter<'a, K, V>,
+}
+
+// FIXME(#26925) Remove in favor of `#[derive(Clone)]`
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<K, V> Clone for Iter<'_, K, V> {
+ fn clone(&self) -> Self {
+ Iter { inner: self.inner.clone() }
+ }
+}
+
+#[stable(feature = "std_debug", since = "1.16.0")]
+impl<K: Debug, V: Debug> fmt::Debug for Iter<'_, K, V> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_list()
+ .entries(self.clone())
+ .finish()
+ }
+}
+
+/// A mutable iterator over the entries of a `HashMap`.
+///
+/// This `struct` is created by the [`iter_mut`] method on [`HashMap`]. See its
+/// documentation for more.
+///
+/// [`iter_mut`]: struct.HashMap.html#method.iter_mut
+/// [`HashMap`]: struct.HashMap.html
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct IterMut<'a, K: 'a, V: 'a> {
+ inner: table::IterMut<'a, K, V>,
+}
+
+/// An owning iterator over the entries of a `HashMap`.
+///
+/// This `struct` is created by the [`into_iter`] method on [`HashMap`][`HashMap`]
+/// (provided by the `IntoIterator` trait). See its documentation for more.
+///
+/// [`into_iter`]: struct.HashMap.html#method.into_iter
+/// [`HashMap`]: struct.HashMap.html
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct IntoIter<K, V> {
+ pub(super) inner: table::IntoIter<K, V>,
+}
+
+/// An iterator over the keys of a `HashMap`.
+///
+/// This `struct` is created by the [`keys`] method on [`HashMap`]. See its
+/// documentation for more.
+///
+/// [`keys`]: struct.HashMap.html#method.keys
+/// [`HashMap`]: struct.HashMap.html
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct Keys<'a, K: 'a, V: 'a> {
+ inner: Iter<'a, K, V>,
+}
+
+// FIXME(#26925) Remove in favor of `#[derive(Clone)]`
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<K, V> Clone for Keys<'_, K, V> {
+ fn clone(&self) -> Self {
+ Keys { inner: self.inner.clone() }
+ }
+}
+
+#[stable(feature = "std_debug", since = "1.16.0")]
+impl<K: Debug, V> fmt::Debug for Keys<'_, K, V> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_list()
+ .entries(self.clone())
+ .finish()
+ }
+}
+
+/// An iterator over the values of a `HashMap`.
+///
+/// This `struct` is created by the [`values`] method on [`HashMap`]. See its
+/// documentation for more.
+///
+/// [`values`]: struct.HashMap.html#method.values
+/// [`HashMap`]: struct.HashMap.html
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct Values<'a, K: 'a, V: 'a> {
+ inner: Iter<'a, K, V>,
+}
+
+// FIXME(#26925) Remove in favor of `#[derive(Clone)]`
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<K, V> Clone for Values<'_, K, V> {
+ fn clone(&self) -> Self {
+ Values { inner: self.inner.clone() }
+ }
+}
+
+#[stable(feature = "std_debug", since = "1.16.0")]
+impl<K, V: Debug> fmt::Debug for Values<'_, K, V> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_list()
+ .entries(self.clone())
+ .finish()
+ }
+}
+
+/// A draining iterator over the entries of a `HashMap`.
+///
+/// This `struct` is created by the [`drain`] method on [`HashMap`]. See its
+/// documentation for more.
+///
+/// [`drain`]: struct.HashMap.html#method.drain
+/// [`HashMap`]: struct.HashMap.html
+#[stable(feature = "drain", since = "1.6.0")]
+pub struct Drain<'a, K: 'a, V: 'a> {
+ pub(super) inner: table::Drain<'a, K, V>,
+}
+
+/// A mutable iterator over the values of a `HashMap`.
+///
+/// This `struct` is created by the [`values_mut`] method on [`HashMap`]. See its
+/// documentation for more.
+///
+/// [`values_mut`]: struct.HashMap.html#method.values_mut
+/// [`HashMap`]: struct.HashMap.html
+#[stable(feature = "map_values_mut", since = "1.10.0")]
+pub struct ValuesMut<'a, K: 'a, V: 'a> {
+ inner: IterMut<'a, K, V>,
+}
+
+enum InternalEntry<K, V, M> {
+ Occupied { elem: FullBucket<K, V, M> },
+ Vacant {
+ hash: SafeHash,
+ elem: VacantEntryState<K, V, M>,
+ },
+ TableIsEmpty,
+}
+
+impl<K, V, M> InternalEntry<K, V, M> {
+ #[inline]
+ fn into_occupied_bucket(self) -> Option<FullBucket<K, V, M>> {
+ match self {
+ InternalEntry::Occupied { elem } => Some(elem),
+ _ => None,
+ }
+ }
+}
+
+impl<'a, K, V> InternalEntry<K, V, &'a mut RawTable<K, V>> {
+ #[inline]
+ fn into_entry(self, key: K) -> Option<Entry<'a, K, V>> {
+ match self {
+ InternalEntry::Occupied { elem } => {
+ Some(Occupied(OccupiedEntry {
+ key: Some(key),
+ elem,
+ }))
+ }
+ InternalEntry::Vacant { hash, elem } => {
+ Some(Vacant(VacantEntry {
+ hash,
+ key,
+ elem,
+ }))
+ }
+ InternalEntry::TableIsEmpty => None,
+ }
+ }
+}
+
+/// A builder for computing where in a HashMap a key-value pair would be stored.
+///
+/// See the [`HashMap::raw_entry_mut`] docs for usage examples.
+///
+/// [`HashMap::raw_entry_mut`]: struct.HashMap.html#method.raw_entry_mut
+
+#[unstable(feature = "hash_raw_entry", issue = "56167")]
+pub struct RawEntryBuilderMut<'a, K: 'a, V: 'a, S: 'a> {
+ map: &'a mut HashMap<K, V, S>,
+}
+
+/// A view into a single entry in a map, which may either be vacant or occupied.
+///
+/// This is a lower-level version of [`Entry`].
+///
+/// This `enum` is constructed from the [`raw_entry`] method on [`HashMap`].
+///
+/// [`HashMap`]: struct.HashMap.html
+/// [`Entry`]: enum.Entry.html
+/// [`raw_entry`]: struct.HashMap.html#method.raw_entry
+#[unstable(feature = "hash_raw_entry", issue = "56167")]
+pub enum RawEntryMut<'a, K: 'a, V: 'a, S: 'a> {
+ /// An occupied entry.
+ Occupied(RawOccupiedEntryMut<'a, K, V>),
+ /// A vacant entry.
+ Vacant(RawVacantEntryMut<'a, K, V, S>),
+}
+
+/// A view into an occupied entry in a `HashMap`.
+/// It is part of the [`RawEntryMut`] enum.
+///
+/// [`RawEntryMut`]: enum.RawEntryMut.html
+#[unstable(feature = "hash_raw_entry", issue = "56167")]
+pub struct RawOccupiedEntryMut<'a, K: 'a, V: 'a> {
+ elem: FullBucket<K, V, &'a mut RawTable<K, V>>,
+}
+
+/// A view into a vacant entry in a `HashMap`.
+/// It is part of the [`RawEntryMut`] enum.
+///
+/// [`RawEntryMut`]: enum.RawEntryMut.html
+#[unstable(feature = "hash_raw_entry", issue = "56167")]
+pub struct RawVacantEntryMut<'a, K: 'a, V: 'a, S: 'a> {
+ elem: VacantEntryState<K, V, &'a mut RawTable<K, V>>,
+ hash_builder: &'a S,
+}
+
+/// A builder for computing where in a HashMap a key-value pair would be stored.
+///
+/// See the [`HashMap::raw_entry`] docs for usage examples.
+///
+/// [`HashMap::raw_entry`]: struct.HashMap.html#method.raw_entry
+#[unstable(feature = "hash_raw_entry", issue = "56167")]
+pub struct RawEntryBuilder<'a, K: 'a, V: 'a, S: 'a> {
+ map: &'a HashMap<K, V, S>,
+}
+
+impl<'a, K, V, S> RawEntryBuilderMut<'a, K, V, S>
+ where S: BuildHasher,
+ K: Eq + Hash,
+{
+ /// Creates a `RawEntryMut` from the given key.
+ #[unstable(feature = "hash_raw_entry", issue = "56167")]
+ pub fn from_key<Q: ?Sized>(self, k: &Q) -> RawEntryMut<'a, K, V, S>
+ where K: Borrow<Q>,
+ Q: Hash + Eq
+ {
+ let mut hasher = self.map.hash_builder.build_hasher();
+ k.hash(&mut hasher);
+ self.from_key_hashed_nocheck(hasher.finish(), k)
+ }
+
+ /// Creates a `RawEntryMut` from the given key and its hash.
+ #[inline]
+ #[unstable(feature = "hash_raw_entry", issue = "56167")]
+ pub fn from_key_hashed_nocheck<Q: ?Sized>(self, hash: u64, k: &Q) -> RawEntryMut<'a, K, V, S>
+ where K: Borrow<Q>,
+ Q: Eq
+ {
+ self.from_hash(hash, |q| q.borrow().eq(k))
+ }
+
+ #[inline]
+ fn search<F>(self, hash: u64, is_match: F, compare_hashes: bool) -> RawEntryMut<'a, K, V, S>
+ where for<'b> F: FnMut(&'b K) -> bool,
+ {
+ match search_hashed_nonempty_mut(&mut self.map.table,
+ SafeHash::new(hash),
+ is_match,
+ compare_hashes) {
+ InternalEntry::Occupied { elem } => {
+ RawEntryMut::Occupied(RawOccupiedEntryMut { elem })
+ }
+ InternalEntry::Vacant { elem, .. } => {
+ RawEntryMut::Vacant(RawVacantEntryMut {
+ elem,
+ hash_builder: &self.map.hash_builder,
+ })
+ }
+ InternalEntry::TableIsEmpty => {
+ unreachable!()
+ }
+ }
+ }
+ /// Creates a `RawEntryMut` from the given hash.
+ #[inline]
+ #[unstable(feature = "hash_raw_entry", issue = "56167")]
+ pub fn from_hash<F>(self, hash: u64, is_match: F) -> RawEntryMut<'a, K, V, S>
+ where for<'b> F: FnMut(&'b K) -> bool,
+ {
+ self.search(hash, is_match, true)
+ }
+
+ /// Search possible locations for an element with hash `hash` until `is_match` returns true for
+ /// one of them. There is no guarantee that all keys passed to `is_match` will have the provided
+ /// hash.
+ #[unstable(feature = "hash_raw_entry", issue = "56167")]
+ pub fn search_bucket<F>(self, hash: u64, is_match: F) -> RawEntryMut<'a, K, V, S>
+ where for<'b> F: FnMut(&'b K) -> bool,
+ {
+ self.search(hash, is_match, false)
+ }
+}
+
+impl<'a, K, V, S> RawEntryBuilder<'a, K, V, S>
+ where S: BuildHasher,
+{
+ /// Access an entry by key.
+ #[unstable(feature = "hash_raw_entry", issue = "56167")]
+ pub fn from_key<Q: ?Sized>(self, k: &Q) -> Option<(&'a K, &'a V)>
+ where K: Borrow<Q>,
+ Q: Hash + Eq
+ {
+ let mut hasher = self.map.hash_builder.build_hasher();
+ k.hash(&mut hasher);
+ self.from_key_hashed_nocheck(hasher.finish(), k)
+ }
+
+ /// Access an entry by a key and its hash.
+ #[unstable(feature = "hash_raw_entry", issue = "56167")]
+ pub fn from_key_hashed_nocheck<Q: ?Sized>(self, hash: u64, k: &Q) -> Option<(&'a K, &'a V)>
+ where K: Borrow<Q>,
+ Q: Hash + Eq
+
+ {
+ self.from_hash(hash, |q| q.borrow().eq(k))
+ }
+
+ fn search<F>(self, hash: u64, is_match: F, compare_hashes: bool) -> Option<(&'a K, &'a V)>
+ where F: FnMut(&K) -> bool
+ {
+ if unsafe { unlikely(self.map.table.size() == 0) } {
+ return None;
+ }
+ match search_hashed_nonempty(&self.map.table,
+ SafeHash::new(hash),
+ is_match,
+ compare_hashes) {
+ InternalEntry::Occupied { elem } => Some(elem.into_refs()),
+ InternalEntry::Vacant { .. } => None,
+ InternalEntry::TableIsEmpty => unreachable!(),
+ }
+ }
+
+ /// Access an entry by hash.
+ #[unstable(feature = "hash_raw_entry", issue = "56167")]
+ pub fn from_hash<F>(self, hash: u64, is_match: F) -> Option<(&'a K, &'a V)>
+ where F: FnMut(&K) -> bool
+ {
+ self.search(hash, is_match, true)
+ }
+
+ /// Search possible locations for an element with hash `hash` until `is_match` returns true for
+ /// one of them. There is no guarantee that all keys passed to `is_match` will have the provided
+ /// hash.
+ #[unstable(feature = "hash_raw_entry", issue = "56167")]
+ pub fn search_bucket<F>(self, hash: u64, is_match: F) -> Option<(&'a K, &'a V)>
+ where F: FnMut(&K) -> bool
+ {
+ self.search(hash, is_match, false)
+ }
+}
+
+impl<'a, K, V, S> RawEntryMut<'a, K, V, S> {
+ /// Ensures a value is in the entry by inserting the default if empty, and returns
+ /// mutable references to the key and value in the entry.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(hash_raw_entry)]
+ /// use std::collections::HashMap;
+ ///
+ /// let mut map: HashMap<&str, u32> = HashMap::new();
+ ///
+ /// map.raw_entry_mut().from_key("poneyland").or_insert("poneyland", 3);
+ /// assert_eq!(map["poneyland"], 3);
+ ///
+ /// *map.raw_entry_mut().from_key("poneyland").or_insert("poneyland", 10).1 *= 2;
+ /// assert_eq!(map["poneyland"], 6);
+ /// ```
+ #[unstable(feature = "hash_raw_entry", issue = "56167")]
+ pub fn or_insert(self, default_key: K, default_val: V) -> (&'a mut K, &'a mut V)
+ where K: Hash,
+ S: BuildHasher,
+ {
+ match self {
+ RawEntryMut::Occupied(entry) => entry.into_key_value(),
+ RawEntryMut::Vacant(entry) => entry.insert(default_key, default_val),
+ }
+ }
+
+ /// Ensures a value is in the entry by inserting the result of the default function if empty,
+ /// and returns mutable references to the key and value in the entry.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(hash_raw_entry)]
+ /// use std::collections::HashMap;
+ ///
+ /// let mut map: HashMap<&str, String> = HashMap::new();
+ ///
+ /// map.raw_entry_mut().from_key("poneyland").or_insert_with(|| {
+ /// ("poneyland", "hoho".to_string())
+ /// });
+ ///
+ /// assert_eq!(map["poneyland"], "hoho".to_string());
+ /// ```
+ #[unstable(feature = "hash_raw_entry", issue = "56167")]
+ pub fn or_insert_with<F>(self, default: F) -> (&'a mut K, &'a mut V)
+ where F: FnOnce() -> (K, V),
+ K: Hash,
+ S: BuildHasher,
+ {
+ match self {
+ RawEntryMut::Occupied(entry) => entry.into_key_value(),
+ RawEntryMut::Vacant(entry) => {
+ let (k, v) = default();
+ entry.insert(k, v)
+ }
+ }
+ }
+
+ /// Provides in-place mutable access to an occupied entry before any
+ /// potential inserts into the map.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(hash_raw_entry)]
+ /// use std::collections::HashMap;
+ ///
+ /// let mut map: HashMap<&str, u32> = HashMap::new();
+ ///
+ /// map.raw_entry_mut()
+ /// .from_key("poneyland")
+ /// .and_modify(|_k, v| { *v += 1 })
+ /// .or_insert("poneyland", 42);
+ /// assert_eq!(map["poneyland"], 42);
+ ///
+ /// map.raw_entry_mut()
+ /// .from_key("poneyland")
+ /// .and_modify(|_k, v| { *v += 1 })
+ /// .or_insert("poneyland", 0);
+ /// assert_eq!(map["poneyland"], 43);
+ /// ```
+ #[unstable(feature = "hash_raw_entry", issue = "56167")]
+ pub fn and_modify<F>(self, f: F) -> Self
+ where F: FnOnce(&mut K, &mut V)
+ {
+ match self {
+ RawEntryMut::Occupied(mut entry) => {
+ {
+ let (k, v) = entry.get_key_value_mut();
+ f(k, v);
+ }
+ RawEntryMut::Occupied(entry)
+ },
+ RawEntryMut::Vacant(entry) => RawEntryMut::Vacant(entry),
+ }
+ }
+}
+
+impl<'a, K, V> RawOccupiedEntryMut<'a, K, V> {
+ /// Gets a reference to the key in the entry.
+ #[unstable(feature = "hash_raw_entry", issue = "56167")]
+ pub fn key(&self) -> &K {
+ self.elem.read().0
+ }
+
+ /// Gets a mutable reference to the key in the entry.
+ #[unstable(feature = "hash_raw_entry", issue = "56167")]
+ pub fn key_mut(&mut self) -> &mut K {
+ self.elem.read_mut().0
+ }
+
+ /// Converts the entry into a mutable reference to the key in the entry
+ /// with a lifetime bound to the map itself.
+ #[unstable(feature = "hash_raw_entry", issue = "56167")]
+ pub fn into_key(self) -> &'a mut K {
+ self.elem.into_mut_refs().0
+ }
+
+ /// Gets a reference to the value in the entry.
+ #[unstable(feature = "hash_raw_entry", issue = "56167")]
+ pub fn get(&self) -> &V {
+ self.elem.read().1
+ }
+
+ /// Converts the OccupiedEntry into a mutable reference to the value in the entry
+ /// with a lifetime bound to the map itself.
+ #[unstable(feature = "hash_raw_entry", issue = "56167")]
+ pub fn into_mut(self) -> &'a mut V {
+ self.elem.into_mut_refs().1
+ }
+
+ /// Gets a mutable reference to the value in the entry.
+ #[unstable(feature = "hash_raw_entry", issue = "56167")]
+ pub fn get_mut(&mut self) -> &mut V {
+ self.elem.read_mut().1
+ }
+
+ /// Gets a reference to the key and value in the entry.
+ #[unstable(feature = "hash_raw_entry", issue = "56167")]
+ pub fn get_key_value(&mut self) -> (&K, &V) {
+ self.elem.read()
+ }
+
+ /// Gets a mutable reference to the key and value in the entry.
+ #[unstable(feature = "hash_raw_entry", issue = "56167")]
+ pub fn get_key_value_mut(&mut self) -> (&mut K, &mut V) {
+ self.elem.read_mut()
+ }
+
+ /// Converts the OccupiedEntry into a mutable reference to the key and value in the entry
+ /// with a lifetime bound to the map itself.
+ #[unstable(feature = "hash_raw_entry", issue = "56167")]
+ pub fn into_key_value(self) -> (&'a mut K, &'a mut V) {
+ self.elem.into_mut_refs()
+ }
+
+ /// Sets the value of the entry, and returns the entry's old value.
+ #[unstable(feature = "hash_raw_entry", issue = "56167")]
+ pub fn insert(&mut self, value: V) -> V {
+ mem::replace(self.get_mut(), value)
+ }
+
+ /// Sets the value of the entry, and returns the entry's old value.
+ #[unstable(feature = "hash_raw_entry", issue = "56167")]
+ pub fn insert_key(&mut self, key: K) -> K {
+ mem::replace(self.key_mut(), key)
+ }
+
+ /// Takes the value out of the entry, and returns it.
+ #[unstable(feature = "hash_raw_entry", issue = "56167")]
+ pub fn remove(self) -> V {
+ pop_internal(self.elem).1
+ }
+
+ /// Take the ownership of the key and value from the map.
+ #[unstable(feature = "hash_raw_entry", issue = "56167")]
+ pub fn remove_entry(self) -> (K, V) {
+ let (k, v, _) = pop_internal(self.elem);
+ (k, v)
+ }
+}
+
+impl<'a, K, V, S> RawVacantEntryMut<'a, K, V, S> {
+ /// Sets the value of the entry with the VacantEntry's key,
+ /// and returns a mutable reference to it.
+ #[unstable(feature = "hash_raw_entry", issue = "56167")]
+ pub fn insert(self, key: K, value: V) -> (&'a mut K, &'a mut V)
+ where K: Hash,
+ S: BuildHasher,
+ {
+ let mut hasher = self.hash_builder.build_hasher();
+ key.hash(&mut hasher);
+ self.insert_hashed_nocheck(hasher.finish(), key, value)
+ }
+
+ /// Sets the value of the entry with the VacantEntry's key,
+ /// and returns a mutable reference to it.
+ #[inline]
+ #[unstable(feature = "hash_raw_entry", issue = "56167")]
+ pub fn insert_hashed_nocheck(self, hash: u64, key: K, value: V) -> (&'a mut K, &'a mut V) {
+ let hash = SafeHash::new(hash);
+ let b = match self.elem {
+ NeqElem(mut bucket, disp) => {
+ if disp >= DISPLACEMENT_THRESHOLD {
+ bucket.table_mut().set_tag(true);
+ }
+ robin_hood(bucket, disp, hash, key, value)
+ },
+ NoElem(mut bucket, disp) => {
+ if disp >= DISPLACEMENT_THRESHOLD {
+ bucket.table_mut().set_tag(true);
+ }
+ bucket.put(hash, key, value)
+ },
+ };
+ b.into_mut_refs()
+ }
+}
+
+#[unstable(feature = "hash_raw_entry", issue = "56167")]
+impl<K, V, S> Debug for RawEntryBuilderMut<'_, K, V, S> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("RawEntryBuilder")
+ .finish()
+ }
+}
+
+#[unstable(feature = "hash_raw_entry", issue = "56167")]
+impl<K: Debug, V: Debug, S> Debug for RawEntryMut<'_, K, V, S> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match *self {
+ RawEntryMut::Vacant(ref v) => {
+ f.debug_tuple("RawEntry")
+ .field(v)
+ .finish()
+ }
+ RawEntryMut::Occupied(ref o) => {
+ f.debug_tuple("RawEntry")
+ .field(o)
+ .finish()
+ }
+ }
+ }
+}
+
+#[unstable(feature = "hash_raw_entry", issue = "56167")]
+impl<K: Debug, V: Debug> Debug for RawOccupiedEntryMut<'_, K, V> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("RawOccupiedEntryMut")
+ .field("key", self.key())
+ .field("value", self.get())
+ .finish()
+ }
+}
+
+#[unstable(feature = "hash_raw_entry", issue = "56167")]
+impl<K, V, S> Debug for RawVacantEntryMut<'_, K, V, S> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("RawVacantEntryMut")
+ .finish()
+ }
+}
+
+#[unstable(feature = "hash_raw_entry", issue = "56167")]
+impl<K, V, S> Debug for RawEntryBuilder<'_, K, V, S> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("RawEntryBuilder")
+ .finish()
+ }
+}
+
+/// A view into a single entry in a map, which may either be vacant or occupied.
+///
+/// This `enum` is constructed from the [`entry`] method on [`HashMap`].
+///
+/// [`HashMap`]: struct.HashMap.html
+/// [`entry`]: struct.HashMap.html#method.entry
+#[stable(feature = "rust1", since = "1.0.0")]
+pub enum Entry<'a, K: 'a, V: 'a> {
+ /// An occupied entry.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ Occupied(#[stable(feature = "rust1", since = "1.0.0")]
+ OccupiedEntry<'a, K, V>),
+
+ /// A vacant entry.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ Vacant(#[stable(feature = "rust1", since = "1.0.0")]
+ VacantEntry<'a, K, V>),
+}
+
+#[stable(feature= "debug_hash_map", since = "1.12.0")]
+impl<K: Debug, V: Debug> Debug for Entry<'_, K, V> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match *self {
+ Vacant(ref v) => {
+ f.debug_tuple("Entry")
+ .field(v)
+ .finish()
+ }
+ Occupied(ref o) => {
+ f.debug_tuple("Entry")
+ .field(o)
+ .finish()
+ }
+ }
+ }
+}
+
+/// A view into an occupied entry in a `HashMap`.
+/// It is part of the [`Entry`] enum.
+///
+/// [`Entry`]: enum.Entry.html
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct OccupiedEntry<'a, K: 'a, V: 'a> {
+ key: Option<K>,
+ elem: FullBucket<K, V, &'a mut RawTable<K, V>>,
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+unsafe impl<'a, K: 'a + Send, V: 'a + Send> Send for OccupiedEntry<'a, K, V> {}
+#[stable(feature = "rust1", since = "1.0.0")]
+unsafe impl<'a, K: 'a + Sync, V: 'a + Sync> Sync for OccupiedEntry<'a, K, V> {}
+
+#[stable(feature= "debug_hash_map", since = "1.12.0")]
+impl<K: Debug, V: Debug> Debug for OccupiedEntry<'_, K, V> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("OccupiedEntry")
+ .field("key", self.key())
+ .field("value", self.get())
+ .finish()
+ }
+}
+
+/// A view into a vacant entry in a `HashMap`.
+/// It is part of the [`Entry`] enum.
+///
+/// [`Entry`]: enum.Entry.html
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct VacantEntry<'a, K: 'a, V: 'a> {
+ hash: SafeHash,
+ key: K,
+ elem: VacantEntryState<K, V, &'a mut RawTable<K, V>>,
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+unsafe impl<'a, K: 'a + Send, V: 'a + Send> Send for VacantEntry<'a, K, V> {}
+#[stable(feature = "rust1", since = "1.0.0")]
+unsafe impl<'a, K: 'a + Sync, V: 'a + Sync> Sync for VacantEntry<'a, K, V> {}
+
+#[stable(feature= "debug_hash_map", since = "1.12.0")]
+impl<K: Debug, V> Debug for VacantEntry<'_, K, V> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_tuple("VacantEntry")
+ .field(self.key())
+ .finish()
+ }
+}
+
+/// Possible states of a VacantEntry.
+enum VacantEntryState<K, V, M> {
+ /// The index is occupied, but the key to insert has precedence,
+ /// and will kick the current one out on insertion.
+ NeqElem(FullBucket<K, V, M>, usize),
+ /// The index is genuinely vacant.
+ NoElem(EmptyBucket<K, V, M>, usize),
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a, K, V, S> IntoIterator for &'a HashMap<K, V, S> {
+ type Item = (&'a K, &'a V);
+ type IntoIter = Iter<'a, K, V>;
+
+ fn into_iter(self) -> Iter<'a, K, V> {
+ self.iter()
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a, K, V, S> IntoIterator for &'a mut HashMap<K, V, S> {
+ type Item = (&'a K, &'a mut V);
+ type IntoIter = IterMut<'a, K, V>;
+
+ fn into_iter(self) -> IterMut<'a, K, V> {
+ self.iter_mut()
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<K, V, S> IntoIterator for HashMap<K, V, S> {
+ type Item = (K, V);
+ type IntoIter = IntoIter<K, V>;
+
+ /// Creates a consuming iterator, that is, one that moves each key-value
+ /// pair out of the map in arbitrary order. The map cannot be used after
+ /// calling this.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::HashMap;
+ ///
+ /// let mut map = HashMap::new();
+ /// map.insert("a", 1);
+ /// map.insert("b", 2);
+ /// map.insert("c", 3);
+ ///
+ /// // Not possible with .iter()
+ /// let vec: Vec<(&str, i32)> = map.into_iter().collect();
+ /// ```
+ fn into_iter(self) -> IntoIter<K, V> {
+ IntoIter { inner: self.table.into_iter() }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a, K, V> Iterator for Iter<'a, K, V> {
+ type Item = (&'a K, &'a V);
+
+ #[inline]
+ fn next(&mut self) -> Option<(&'a K, &'a V)> {
+ self.inner.next()
+ }
+ #[inline]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ self.inner.size_hint()
+ }
+}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<K, V> ExactSizeIterator for Iter<'_, K, V> {
+ #[inline]
+ fn len(&self) -> usize {
+ self.inner.len()
+ }
+}
+
+#[stable(feature = "fused", since = "1.26.0")]
+impl<K, V> FusedIterator for Iter<'_, K, V> {}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a, K, V> Iterator for IterMut<'a, K, V> {
+ type Item = (&'a K, &'a mut V);
+
+ #[inline]
+ fn next(&mut self) -> Option<(&'a K, &'a mut V)> {
+ self.inner.next()
+ }
+ #[inline]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ self.inner.size_hint()
+ }
+}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<K, V> ExactSizeIterator for IterMut<'_, K, V> {
+ #[inline]
+ fn len(&self) -> usize {
+ self.inner.len()
+ }
+}
+#[stable(feature = "fused", since = "1.26.0")]
+impl<K, V> FusedIterator for IterMut<'_, K, V> {}
+
+#[stable(feature = "std_debug", since = "1.16.0")]
+impl<K, V> fmt::Debug for IterMut<'_, K, V>
+ where K: fmt::Debug,
+ V: fmt::Debug,
+{
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_list()
+ .entries(self.inner.iter())
+ .finish()
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<K, V> Iterator for IntoIter<K, V> {
+ type Item = (K, V);
+
+ #[inline]
+ fn next(&mut self) -> Option<(K, V)> {
+ self.inner.next().map(|(_, k, v)| (k, v))
+ }
+ #[inline]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ self.inner.size_hint()
+ }
+}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<K, V> ExactSizeIterator for IntoIter<K, V> {
+ #[inline]
+ fn len(&self) -> usize {
+ self.inner.len()
+ }
+}
+#[stable(feature = "fused", since = "1.26.0")]
+impl<K, V> FusedIterator for IntoIter<K, V> {}
+
+#[stable(feature = "std_debug", since = "1.16.0")]
+impl<K: Debug, V: Debug> fmt::Debug for IntoIter<K, V> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_list()
+ .entries(self.inner.iter())
+ .finish()
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a, K, V> Iterator for Keys<'a, K, V> {
+ type Item = &'a K;
+
+ #[inline]
+ fn next(&mut self) -> Option<(&'a K)> {
+ self.inner.next().map(|(k, _)| k)
+ }
+ #[inline]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ self.inner.size_hint()
+ }
+}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<K, V> ExactSizeIterator for Keys<'_, K, V> {
+ #[inline]
+ fn len(&self) -> usize {
+ self.inner.len()
+ }
+}
+#[stable(feature = "fused", since = "1.26.0")]
+impl<K, V> FusedIterator for Keys<'_, K, V> {}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a, K, V> Iterator for Values<'a, K, V> {
+ type Item = &'a V;
+
+ #[inline]
+ fn next(&mut self) -> Option<(&'a V)> {
+ self.inner.next().map(|(_, v)| v)
+ }
+ #[inline]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ self.inner.size_hint()
+ }
+}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<K, V> ExactSizeIterator for Values<'_, K, V> {
+ #[inline]
+ fn len(&self) -> usize {
+ self.inner.len()
+ }
+}
+#[stable(feature = "fused", since = "1.26.0")]
+impl<K, V> FusedIterator for Values<'_, K, V> {}
+
+#[stable(feature = "map_values_mut", since = "1.10.0")]
+impl<'a, K, V> Iterator for ValuesMut<'a, K, V> {
+ type Item = &'a mut V;
+
+ #[inline]
+ fn next(&mut self) -> Option<(&'a mut V)> {
+ self.inner.next().map(|(_, v)| v)
+ }
+ #[inline]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ self.inner.size_hint()
+ }
+}
+#[stable(feature = "map_values_mut", since = "1.10.0")]
+impl<K, V> ExactSizeIterator for ValuesMut<'_, K, V> {
+ #[inline]
+ fn len(&self) -> usize {
+ self.inner.len()
+ }
+}
+#[stable(feature = "fused", since = "1.26.0")]
+impl<K, V> FusedIterator for ValuesMut<'_, K, V> {}
+
+#[stable(feature = "std_debug", since = "1.16.0")]
+impl<K, V> fmt::Debug for ValuesMut<'_, K, V>
+ where K: fmt::Debug,
+ V: fmt::Debug,
+{
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_list()
+ .entries(self.inner.inner.iter())
+ .finish()
+ }
+}
+
+#[stable(feature = "drain", since = "1.6.0")]
+impl<'a, K, V> Iterator for Drain<'a, K, V> {
+ type Item = (K, V);
+
+ #[inline]
+ fn next(&mut self) -> Option<(K, V)> {
+ self.inner.next().map(|(_, k, v)| (k, v))
+ }
+ #[inline]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ self.inner.size_hint()
+ }
+}
+#[stable(feature = "drain", since = "1.6.0")]
+impl<K, V> ExactSizeIterator for Drain<'_, K, V> {
+ #[inline]
+ fn len(&self) -> usize {
+ self.inner.len()
+ }
+}
+#[stable(feature = "fused", since = "1.26.0")]
+impl<K, V> FusedIterator for Drain<'_, K, V> {}
+
+#[stable(feature = "std_debug", since = "1.16.0")]
+impl<K, V> fmt::Debug for Drain<'_, K, V>
+ where K: fmt::Debug,
+ V: fmt::Debug,
+{
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_list()
+ .entries(self.inner.iter())
+ .finish()
+ }
+}
+
+impl<'a, K, V> Entry<'a, K, V> {
+ #[stable(feature = "rust1", since = "1.0.0")]
+ /// Ensures a value is in the entry by inserting the default if empty, and returns
+ /// a mutable reference to the value in the entry.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::HashMap;
+ ///
+ /// let mut map: HashMap<&str, u32> = HashMap::new();
+ ///
+ /// map.entry("poneyland").or_insert(3);
+ /// assert_eq!(map["poneyland"], 3);
+ ///
+ /// *map.entry("poneyland").or_insert(10) *= 2;
+ /// assert_eq!(map["poneyland"], 6);
+ /// ```
+ pub fn or_insert(self, default: V) -> &'a mut V {
+ match self {
+ Occupied(entry) => entry.into_mut(),
+ Vacant(entry) => entry.insert(default),
+ }
+ }
+
+ #[stable(feature = "rust1", since = "1.0.0")]
+ /// Ensures a value is in the entry by inserting the result of the default function if empty,
+ /// and returns a mutable reference to the value in the entry.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::HashMap;
+ ///
+ /// let mut map: HashMap<&str, String> = HashMap::new();
+ /// let s = "hoho".to_string();
+ ///
+ /// map.entry("poneyland").or_insert_with(|| s);
+ ///
+ /// assert_eq!(map["poneyland"], "hoho".to_string());
+ /// ```
+ pub fn or_insert_with<F: FnOnce() -> V>(self, default: F) -> &'a mut V {
+ match self {
+ Occupied(entry) => entry.into_mut(),
+ Vacant(entry) => entry.insert(default()),
+ }
+ }
+
+ /// Returns a reference to this entry's key.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::HashMap;
+ ///
+ /// let mut map: HashMap<&str, u32> = HashMap::new();
+ /// assert_eq!(map.entry("poneyland").key(), &"poneyland");
+ /// ```
+ #[stable(feature = "map_entry_keys", since = "1.10.0")]
+ pub fn key(&self) -> &K {
+ match *self {
+ Occupied(ref entry) => entry.key(),
+ Vacant(ref entry) => entry.key(),
+ }
+ }
+
+ /// Provides in-place mutable access to an occupied entry before any
+ /// potential inserts into the map.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::HashMap;
+ ///
+ /// let mut map: HashMap<&str, u32> = HashMap::new();
+ ///
+ /// map.entry("poneyland")
+ /// .and_modify(|e| { *e += 1 })
+ /// .or_insert(42);
+ /// assert_eq!(map["poneyland"], 42);
+ ///
+ /// map.entry("poneyland")
+ /// .and_modify(|e| { *e += 1 })
+ /// .or_insert(42);
+ /// assert_eq!(map["poneyland"], 43);
+ /// ```
+ #[stable(feature = "entry_and_modify", since = "1.26.0")]
+ pub fn and_modify<F>(self, f: F) -> Self
+ where F: FnOnce(&mut V)
+ {
+ match self {
+ Occupied(mut entry) => {
+ f(entry.get_mut());
+ Occupied(entry)
+ },
+ Vacant(entry) => Vacant(entry),
+ }
+ }
+
+}
+
+impl<'a, K, V: Default> Entry<'a, K, V> {
+ #[stable(feature = "entry_or_default", since = "1.28.0")]
+ /// Ensures a value is in the entry by inserting the default value if empty,
+ /// and returns a mutable reference to the value in the entry.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// # fn main() {
+ /// use std::collections::HashMap;
+ ///
+ /// let mut map: HashMap<&str, Option<u32>> = HashMap::new();
+ /// map.entry("poneyland").or_default();
+ ///
+ /// assert_eq!(map["poneyland"], None);
+ /// # }
+ /// ```
+ pub fn or_default(self) -> &'a mut V {
+ match self {
+ Occupied(entry) => entry.into_mut(),
+ Vacant(entry) => entry.insert(Default::default()),
+ }
+ }
+}
+
+impl<'a, K, V> OccupiedEntry<'a, K, V> {
+ /// Gets a reference to the key in the entry.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::HashMap;
+ ///
+ /// let mut map: HashMap<&str, u32> = HashMap::new();
+ /// map.entry("poneyland").or_insert(12);
+ /// assert_eq!(map.entry("poneyland").key(), &"poneyland");
+ /// ```
+ #[stable(feature = "map_entry_keys", since = "1.10.0")]
+ pub fn key(&self) -> &K {
+ self.elem.read().0
+ }
+
+ /// Take the ownership of the key and value from the map.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::HashMap;
+ /// use std::collections::hash_map::Entry;
+ ///
+ /// let mut map: HashMap<&str, u32> = HashMap::new();
+ /// map.entry("poneyland").or_insert(12);
+ ///
+ /// if let Entry::Occupied(o) = map.entry("poneyland") {
+ /// // We delete the entry from the map.
+ /// o.remove_entry();
+ /// }
+ ///
+ /// assert_eq!(map.contains_key("poneyland"), false);
+ /// ```
+ #[stable(feature = "map_entry_recover_keys2", since = "1.12.0")]
+ pub fn remove_entry(self) -> (K, V) {
+ let (k, v, _) = pop_internal(self.elem);
+ (k, v)
+ }
+
+ /// Gets a reference to the value in the entry.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::HashMap;
+ /// use std::collections::hash_map::Entry;
+ ///
+ /// let mut map: HashMap<&str, u32> = HashMap::new();
+ /// map.entry("poneyland").or_insert(12);
+ ///
+ /// if let Entry::Occupied(o) = map.entry("poneyland") {
+ /// assert_eq!(o.get(), &12);
+ /// }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn get(&self) -> &V {
+ self.elem.read().1
+ }
+
+ /// Gets a mutable reference to the value in the entry.
+ ///
+ /// If you need a reference to the `OccupiedEntry` which may outlive the
+ /// destruction of the `Entry` value, see [`into_mut`].
+ ///
+ /// [`into_mut`]: #method.into_mut
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::HashMap;
+ /// use std::collections::hash_map::Entry;
+ ///
+ /// let mut map: HashMap<&str, u32> = HashMap::new();
+ /// map.entry("poneyland").or_insert(12);
+ ///
+ /// assert_eq!(map["poneyland"], 12);
+ /// if let Entry::Occupied(mut o) = map.entry("poneyland") {
+ /// *o.get_mut() += 10;
+ /// assert_eq!(*o.get(), 22);
+ ///
+ /// // We can use the same Entry multiple times.
+ /// *o.get_mut() += 2;
+ /// }
+ ///
+ /// assert_eq!(map["poneyland"], 24);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn get_mut(&mut self) -> &mut V {
+ self.elem.read_mut().1
+ }
+
+ /// Converts the OccupiedEntry into a mutable reference to the value in the entry
+ /// with a lifetime bound to the map itself.
+ ///
+ /// If you need multiple references to the `OccupiedEntry`, see [`get_mut`].
+ ///
+ /// [`get_mut`]: #method.get_mut
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::HashMap;
+ /// use std::collections::hash_map::Entry;
+ ///
+ /// let mut map: HashMap<&str, u32> = HashMap::new();
+ /// map.entry("poneyland").or_insert(12);
+ ///
+ /// assert_eq!(map["poneyland"], 12);
+ /// if let Entry::Occupied(o) = map.entry("poneyland") {
+ /// *o.into_mut() += 10;
+ /// }
+ ///
+ /// assert_eq!(map["poneyland"], 22);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn into_mut(self) -> &'a mut V {
+ self.elem.into_mut_refs().1
+ }
+
+ /// Sets the value of the entry, and returns the entry's old value.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::HashMap;
+ /// use std::collections::hash_map::Entry;
+ ///
+ /// let mut map: HashMap<&str, u32> = HashMap::new();
+ /// map.entry("poneyland").or_insert(12);
+ ///
+ /// if let Entry::Occupied(mut o) = map.entry("poneyland") {
+ /// assert_eq!(o.insert(15), 12);
+ /// }
+ ///
+ /// assert_eq!(map["poneyland"], 15);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn insert(&mut self, mut value: V) -> V {
+ let old_value = self.get_mut();
+ mem::swap(&mut value, old_value);
+ value
+ }
+
+ /// Takes the value out of the entry, and returns it.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::HashMap;
+ /// use std::collections::hash_map::Entry;
+ ///
+ /// let mut map: HashMap<&str, u32> = HashMap::new();
+ /// map.entry("poneyland").or_insert(12);
+ ///
+ /// if let Entry::Occupied(o) = map.entry("poneyland") {
+ /// assert_eq!(o.remove(), 12);
+ /// }
+ ///
+ /// assert_eq!(map.contains_key("poneyland"), false);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn remove(self) -> V {
+ pop_internal(self.elem).1
+ }
+
+ /// Returns a key that was used for search.
+ ///
+ /// The key was retained for further use.
+ fn take_key(&mut self) -> Option<K> {
+ self.key.take()
+ }
+
+ /// Replaces the entry, returning the old key and value. The new key in the hash map will be
+ /// the key used to create this entry.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(map_entry_replace)]
+ /// use std::collections::hash_map::{Entry, HashMap};
+ /// use std::rc::Rc;
+ ///
+ /// let mut map: HashMap<Rc<String>, u32> = HashMap::new();
+ /// map.insert(Rc::new("Stringthing".to_string()), 15);
+ ///
+ /// let my_key = Rc::new("Stringthing".to_string());
+ ///
+ /// if let Entry::Occupied(entry) = map.entry(my_key) {
+ /// // Also replace the key with a handle to our other key.
+ /// let (old_key, old_value): (Rc<String>, u32) = entry.replace_entry(16);
+ /// }
+ ///
+ /// ```
+ #[unstable(feature = "map_entry_replace", issue = "44286")]
+ pub fn replace_entry(mut self, value: V) -> (K, V) {
+ let (old_key, old_value) = self.elem.read_mut();
+
+ let old_key = mem::replace(old_key, self.key.unwrap());
+ let old_value = mem::replace(old_value, value);
+
+ (old_key, old_value)
+ }
+
+ /// Replaces the key in the hash map with the key used to create this entry.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(map_entry_replace)]
+ /// use std::collections::hash_map::{Entry, HashMap};
+ /// use std::rc::Rc;
+ ///
+ /// let mut map: HashMap<Rc<String>, u32> = HashMap::new();
+ /// let mut known_strings: Vec<Rc<String>> = Vec::new();
+ ///
+ /// // Initialise known strings, run program, etc.
+ ///
+ /// reclaim_memory(&mut map, &known_strings);
+ ///
+ /// fn reclaim_memory(map: &mut HashMap<Rc<String>, u32>, known_strings: &[Rc<String>] ) {
+ /// for s in known_strings {
+ /// if let Entry::Occupied(entry) = map.entry(s.clone()) {
+ /// // Replaces the entry's key with our version of it in `known_strings`.
+ /// entry.replace_key();
+ /// }
+ /// }
+ /// }
+ /// ```
+ #[unstable(feature = "map_entry_replace", issue = "44286")]
+ pub fn replace_key(mut self) -> K {
+ let (old_key, _) = self.elem.read_mut();
+ mem::replace(old_key, self.key.unwrap())
+ }
+}
+
+impl<'a, K: 'a, V: 'a> VacantEntry<'a, K, V> {
+ /// Gets a reference to the key that would be used when inserting a value
+ /// through the `VacantEntry`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::HashMap;
+ ///
+ /// let mut map: HashMap<&str, u32> = HashMap::new();
+ /// assert_eq!(map.entry("poneyland").key(), &"poneyland");
+ /// ```
+ #[stable(feature = "map_entry_keys", since = "1.10.0")]
+ pub fn key(&self) -> &K {
+ &self.key
+ }
+
+ /// Take ownership of the key.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::HashMap;
+ /// use std::collections::hash_map::Entry;
+ ///
+ /// let mut map: HashMap<&str, u32> = HashMap::new();
+ ///
+ /// if let Entry::Vacant(v) = map.entry("poneyland") {
+ /// v.into_key();
+ /// }
+ /// ```
+ #[stable(feature = "map_entry_recover_keys2", since = "1.12.0")]
+ pub fn into_key(self) -> K {
+ self.key
+ }
+
+ /// Sets the value of the entry with the VacantEntry's key,
+ /// and returns a mutable reference to it.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::HashMap;
+ /// use std::collections::hash_map::Entry;
+ ///
+ /// let mut map: HashMap<&str, u32> = HashMap::new();
+ ///
+ /// if let Entry::Vacant(o) = map.entry("poneyland") {
+ /// o.insert(37);
+ /// }
+ /// assert_eq!(map["poneyland"], 37);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn insert(self, value: V) -> &'a mut V {
+ let b = match self.elem {
+ NeqElem(mut bucket, disp) => {
+ if disp >= DISPLACEMENT_THRESHOLD {
+ bucket.table_mut().set_tag(true);
+ }
+ robin_hood(bucket, disp, self.hash, self.key, value)
+ },
+ NoElem(mut bucket, disp) => {
+ if disp >= DISPLACEMENT_THRESHOLD {
+ bucket.table_mut().set_tag(true);
+ }
+ bucket.put(self.hash, self.key, value)
+ },
+ };
+ b.into_mut_refs().1
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<K, V, S> FromIterator<(K, V)> for HashMap<K, V, S>
+ where K: Eq + Hash,
+ S: BuildHasher + Default
+{
+ fn from_iter<T: IntoIterator<Item = (K, V)>>(iter: T) -> HashMap<K, V, S> {
+ let mut map = HashMap::with_hasher(Default::default());
+ map.extend(iter);
+ map
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<K, V, S> Extend<(K, V)> for HashMap<K, V, S>
+ where K: Eq + Hash,
+ S: BuildHasher
+{
+ fn extend<T: IntoIterator<Item = (K, V)>>(&mut self, iter: T) {
+ // Keys may be already present or show multiple times in the iterator.
+ // Reserve the entire hint lower bound if the map is empty.
+ // Otherwise reserve half the hint (rounded up), so the map
+ // will only resize twice in the worst case.
+ let iter = iter.into_iter();
+ let reserve = if self.is_empty() {
+ iter.size_hint().0
+ } else {
+ (iter.size_hint().0 + 1) / 2
+ };
+ self.reserve(reserve);
+ for (k, v) in iter {
+ self.insert(k, v);
+ }
+ }
+}
+
+#[stable(feature = "hash_extend_copy", since = "1.4.0")]
+impl<'a, K, V, S> Extend<(&'a K, &'a V)> for HashMap<K, V, S>
+ where K: Eq + Hash + Copy,
+ V: Copy,
+ S: BuildHasher
+{
+ fn extend<T: IntoIterator<Item = (&'a K, &'a V)>>(&mut self, iter: T) {
+ self.extend(iter.into_iter().map(|(&key, &value)| (key, value)));
+ }
+}
+
+/// `RandomState` is the default state for [`HashMap`] types.
+///
+/// A particular instance `RandomState` will create the same instances of
+/// [`Hasher`], but the hashers created by two different `RandomState`
+/// instances are unlikely to produce the same result for the same values.
+///
+/// [`HashMap`]: struct.HashMap.html
+/// [`Hasher`]: ../../hash/trait.Hasher.html
+///
+/// # Examples
+///
+/// ```
+/// use std::collections::HashMap;
+/// use std::collections::hash_map::RandomState;
+///
+/// let s = RandomState::new();
+/// let mut map = HashMap::with_hasher(s);
+/// map.insert(1, 2);
+/// ```
+#[derive(Clone)]
+#[stable(feature = "hashmap_build_hasher", since = "1.7.0")]
+pub struct RandomState {
+ k0: u64,
+ k1: u64,
+}
+
+impl RandomState {
+ /// Constructs a new `RandomState` that is initialized with random keys.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::hash_map::RandomState;
+ ///
+ /// let s = RandomState::new();
+ /// ```
+ #[inline]
+ #[allow(deprecated)]
+ // rand
+ #[stable(feature = "hashmap_build_hasher", since = "1.7.0")]
+ pub fn new() -> RandomState {
+ // Historically this function did not cache keys from the OS and instead
+ // simply always called `rand::thread_rng().gen()` twice. In #31356 it
+ // was discovered, however, that because we re-seed the thread-local RNG
+ // from the OS periodically that this can cause excessive slowdown when
+ // many hash maps are created on a thread. To solve this performance
+ // trap we cache the first set of randomly generated keys per-thread.
+ //
+ // Later in #36481 it was discovered that exposing a deterministic
+ // iteration order allows a form of DOS attack. To counter that we
+ // increment one of the seeds on every RandomState creation, giving
+ // every corresponding HashMap a different iteration order.
+ thread_local!(static KEYS: Cell<(u64, u64)> = {
+ Cell::new(sys::hashmap_random_keys())
+ });
+
+ KEYS.with(|keys| {
+ let (k0, k1) = keys.get();
+ keys.set((k0.wrapping_add(1), k1));
+ RandomState { k0: k0, k1: k1 }
+ })
+ }
+}
+
+#[stable(feature = "hashmap_build_hasher", since = "1.7.0")]
+impl BuildHasher for RandomState {
+ type Hasher = DefaultHasher;
+ #[inline]
+ #[allow(deprecated)]
+ fn build_hasher(&self) -> DefaultHasher {
+ DefaultHasher(SipHasher13::new_with_keys(self.k0, self.k1))
+ }
+}
+
+/// The default [`Hasher`] used by [`RandomState`].
+///
+/// The internal algorithm is not specified, and so it and its hashes should
+/// not be relied upon over releases.
+///
+/// [`RandomState`]: struct.RandomState.html
+/// [`Hasher`]: ../../hash/trait.Hasher.html
+#[stable(feature = "hashmap_default_hasher", since = "1.13.0")]
+#[allow(deprecated)]
+#[derive(Clone, Debug)]
+pub struct DefaultHasher(SipHasher13);
+
+impl DefaultHasher {
+ /// Creates a new `DefaultHasher`.
+ ///
+ /// This hasher is not guaranteed to be the same as all other
+ /// `DefaultHasher` instances, but is the same as all other `DefaultHasher`
+ /// instances created through `new` or `default`.
+ #[stable(feature = "hashmap_default_hasher", since = "1.13.0")]
+ #[allow(deprecated)]
+ pub fn new() -> DefaultHasher {
+ DefaultHasher(SipHasher13::new_with_keys(0, 0))
+ }
+}
+
+#[stable(feature = "hashmap_default_hasher", since = "1.13.0")]
+impl Default for DefaultHasher {
+ /// Creates a new `DefaultHasher` using [`new`][DefaultHasher::new].
+ /// See its documentation for more.
+ fn default() -> DefaultHasher {
+ DefaultHasher::new()
+ }
+}
+
+#[stable(feature = "hashmap_default_hasher", since = "1.13.0")]
+impl Hasher for DefaultHasher {
+ #[inline]
+ fn write(&mut self, msg: &[u8]) {
+ self.0.write(msg)
+ }
+
+ #[inline]
+ fn finish(&self) -> u64 {
+ self.0.finish()
+ }
+}
+
+#[stable(feature = "hashmap_build_hasher", since = "1.7.0")]
+impl Default for RandomState {
+ /// Constructs a new `RandomState`.
+ #[inline]
+ fn default() -> RandomState {
+ RandomState::new()
+ }
+}
+
+#[stable(feature = "std_debug", since = "1.16.0")]
+impl fmt::Debug for RandomState {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.pad("RandomState { .. }")
+ }
+}
+
+impl<K, S, Q: ?Sized> super::Recover<Q> for HashMap<K, (), S>
+ where K: Eq + Hash + Borrow<Q>,
+ S: BuildHasher,
+ Q: Eq + Hash
+{
+ type Key = K;
+
+ #[inline]
+ fn get(&self, key: &Q) -> Option<&K> {
+ self.search(key).map(|bucket| bucket.into_refs().0)
+ }
+
+ fn take(&mut self, key: &Q) -> Option<K> {
+ self.search_mut(key).map(|bucket| pop_internal(bucket).0)
+ }
+
+ #[inline]
+ fn replace(&mut self, key: K) -> Option<K> {
+ self.reserve(1);
+
+ match self.entry(key) {
+ Occupied(mut occupied) => {
+ let key = occupied.take_key().unwrap();
+ Some(mem::replace(occupied.elem.read_mut().0, key))
+ }
+ Vacant(vacant) => {
+ vacant.insert(());
+ None
+ }
+ }
+ }
+}
+
+#[allow(dead_code)]
+fn assert_covariance() {
+ fn map_key<'new>(v: HashMap<&'static str, u8>) -> HashMap<&'new str, u8> {
+ v
+ }
+ fn map_val<'new>(v: HashMap<u8, &'static str>) -> HashMap<u8, &'new str> {
+ v
+ }
+ fn iter_key<'a, 'new>(v: Iter<'a, &'static str, u8>) -> Iter<'a, &'new str, u8> {
+ v
+ }
+ fn iter_val<'a, 'new>(v: Iter<'a, u8, &'static str>) -> Iter<'a, u8, &'new str> {
+ v
+ }
+ fn into_iter_key<'new>(v: IntoIter<&'static str, u8>) -> IntoIter<&'new str, u8> {
+ v
+ }
+ fn into_iter_val<'new>(v: IntoIter<u8, &'static str>) -> IntoIter<u8, &'new str> {
+ v
+ }
+ fn keys_key<'a, 'new>(v: Keys<'a, &'static str, u8>) -> Keys<'a, &'new str, u8> {
+ v
+ }
+ fn keys_val<'a, 'new>(v: Keys<'a, u8, &'static str>) -> Keys<'a, u8, &'new str> {
+ v
+ }
+ fn values_key<'a, 'new>(v: Values<'a, &'static str, u8>) -> Values<'a, &'new str, u8> {
+ v
+ }
+ fn values_val<'a, 'new>(v: Values<'a, u8, &'static str>) -> Values<'a, u8, &'new str> {
+ v
+ }
+ fn drain<'new>(d: Drain<'static, &'static str, &'static str>)
+ -> Drain<'new, &'new str, &'new str> {
+ d
+ }
+}
+
+#[cfg(test)]
+mod test_map {
+ use super::HashMap;
+ use super::Entry::{Occupied, Vacant};
+ use super::RandomState;
+ use crate::cell::RefCell;
+ use rand::{thread_rng, Rng};
+ use realstd::collections::CollectionAllocErr::*;
+ use realstd::mem::size_of;
+ use realstd::usize;
+
+ #[test]
+ fn test_zero_capacities() {
+ type HM = HashMap<i32, i32>;
+
+ let m = HM::new();
+ assert_eq!(m.capacity(), 0);
+
+ let m = HM::default();
+ assert_eq!(m.capacity(), 0);
+
+ let m = HM::with_hasher(RandomState::new());
+ assert_eq!(m.capacity(), 0);
+
+ let m = HM::with_capacity(0);
+ assert_eq!(m.capacity(), 0);
+
+ let m = HM::with_capacity_and_hasher(0, RandomState::new());
+ assert_eq!(m.capacity(), 0);
+
+ let mut m = HM::new();
+ m.insert(1, 1);
+ m.insert(2, 2);
+ m.remove(&1);
+ m.remove(&2);
+ m.shrink_to_fit();
+ assert_eq!(m.capacity(), 0);
+
+ let mut m = HM::new();
+ m.reserve(0);
+ assert_eq!(m.capacity(), 0);
+ }
+
+ #[test]
+ fn test_create_capacity_zero() {
+ let mut m = HashMap::with_capacity(0);
+
+ assert!(m.insert(1, 1).is_none());
+
+ assert!(m.contains_key(&1));
+ assert!(!m.contains_key(&0));
+ }
+
+ #[test]
+ fn test_insert() {
+ let mut m = HashMap::new();
+ assert_eq!(m.len(), 0);
+ assert!(m.insert(1, 2).is_none());
+ assert_eq!(m.len(), 1);
+ assert!(m.insert(2, 4).is_none());
+ assert_eq!(m.len(), 2);
+ assert_eq!(*m.get(&1).unwrap(), 2);
+ assert_eq!(*m.get(&2).unwrap(), 4);
+ }
+
+ #[test]
+ fn test_clone() {
+ let mut m = HashMap::new();
+ assert_eq!(m.len(), 0);
+ assert!(m.insert(1, 2).is_none());
+ assert_eq!(m.len(), 1);
+ assert!(m.insert(2, 4).is_none());
+ assert_eq!(m.len(), 2);
+ let m2 = m.clone();
+ assert_eq!(*m2.get(&1).unwrap(), 2);
+ assert_eq!(*m2.get(&2).unwrap(), 4);
+ assert_eq!(m2.len(), 2);
+ }
+
+ thread_local! { static DROP_VECTOR: RefCell<Vec<i32>> = RefCell::new(Vec::new()) }
+
+ #[derive(Hash, PartialEq, Eq)]
+ struct Droppable {
+ k: usize,
+ }
+
+ impl Droppable {
+ fn new(k: usize) -> Droppable {
+ DROP_VECTOR.with(|slot| {
+ slot.borrow_mut()[k] += 1;
+ });
+
+ Droppable { k }
+ }
+ }
+
+ impl Drop for Droppable {
+ fn drop(&mut self) {
+ DROP_VECTOR.with(|slot| {
+ slot.borrow_mut()[self.k] -= 1;
+ });
+ }
+ }
+
+ impl Clone for Droppable {
+ fn clone(&self) -> Droppable {
+ Droppable::new(self.k)
+ }
+ }
+
+ #[test]
+ fn test_drops() {
+ DROP_VECTOR.with(|slot| {
+ *slot.borrow_mut() = vec![0; 200];
+ });
+
+ {
+ let mut m = HashMap::new();
+
+ DROP_VECTOR.with(|v| {
+ for i in 0..200 {
+ assert_eq!(v.borrow()[i], 0);
+ }
+ });
+
+ for i in 0..100 {
+ let d1 = Droppable::new(i);
+ let d2 = Droppable::new(i + 100);
+ m.insert(d1, d2);
+ }
+
+ DROP_VECTOR.with(|v| {
+ for i in 0..200 {
+ assert_eq!(v.borrow()[i], 1);
+ }
+ });
+
+ for i in 0..50 {
+ let k = Droppable::new(i);
+ let v = m.remove(&k);
+
+ assert!(v.is_some());
+
+ DROP_VECTOR.with(|v| {
+ assert_eq!(v.borrow()[i], 1);
+ assert_eq!(v.borrow()[i+100], 1);
+ });
+ }
+
+ DROP_VECTOR.with(|v| {
+ for i in 0..50 {
+ assert_eq!(v.borrow()[i], 0);
+ assert_eq!(v.borrow()[i+100], 0);
+ }
+
+ for i in 50..100 {
+ assert_eq!(v.borrow()[i], 1);
+ assert_eq!(v.borrow()[i+100], 1);
+ }
+ });
+ }
+
+ DROP_VECTOR.with(|v| {
+ for i in 0..200 {
+ assert_eq!(v.borrow()[i], 0);
+ }
+ });
+ }
+
+ #[test]
+ fn test_into_iter_drops() {
+ DROP_VECTOR.with(|v| {
+ *v.borrow_mut() = vec![0; 200];
+ });
+
+ let hm = {
+ let mut hm = HashMap::new();
+
+ DROP_VECTOR.with(|v| {
+ for i in 0..200 {
+ assert_eq!(v.borrow()[i], 0);
+ }
+ });
+
+ for i in 0..100 {
+ let d1 = Droppable::new(i);
+ let d2 = Droppable::new(i + 100);
+ hm.insert(d1, d2);
+ }
+
+ DROP_VECTOR.with(|v| {
+ for i in 0..200 {
+ assert_eq!(v.borrow()[i], 1);
+ }
+ });
+
+ hm
+ };
+
+ // By the way, ensure that cloning doesn't screw up the dropping.
+ drop(hm.clone());
+
+ {
+ let mut half = hm.into_iter().take(50);
+
+ DROP_VECTOR.with(|v| {
+ for i in 0..200 {
+ assert_eq!(v.borrow()[i], 1);
+ }
+ });
+
+ for _ in half.by_ref() {}
+
+ DROP_VECTOR.with(|v| {
+ let nk = (0..100)
+ .filter(|&i| v.borrow()[i] == 1)
+ .count();
+
+ let nv = (0..100)
+ .filter(|&i| v.borrow()[i + 100] == 1)
+ .count();
+
+ assert_eq!(nk, 50);
+ assert_eq!(nv, 50);
+ });
+ };
+
+ DROP_VECTOR.with(|v| {
+ for i in 0..200 {
+ assert_eq!(v.borrow()[i], 0);
+ }
+ });
+ }
+
+ #[test]
+ fn test_empty_remove() {
+ let mut m: HashMap<i32, bool> = HashMap::new();
+ assert_eq!(m.remove(&0), None);
+ }
+
+ #[test]
+ fn test_empty_entry() {
+ let mut m: HashMap<i32, bool> = HashMap::new();
+ match m.entry(0) {
+ Occupied(_) => panic!(),
+ Vacant(_) => {}
+ }
+ assert!(*m.entry(0).or_insert(true));
+ assert_eq!(m.len(), 1);
+ }
+
+ #[test]
+ fn test_empty_iter() {
+ let mut m: HashMap<i32, bool> = HashMap::new();
+ assert_eq!(m.drain().next(), None);
+ assert_eq!(m.keys().next(), None);
+ assert_eq!(m.values().next(), None);
+ assert_eq!(m.values_mut().next(), None);
+ assert_eq!(m.iter().next(), None);
+ assert_eq!(m.iter_mut().next(), None);
+ assert_eq!(m.len(), 0);
+ assert!(m.is_empty());
+ assert_eq!(m.into_iter().next(), None);
+ }
+
+ #[test]
+ fn test_lots_of_insertions() {
+ let mut m = HashMap::new();
+
+ // Try this a few times to make sure we never screw up the hashmap's
+ // internal state.
+ for _ in 0..10 {
+ assert!(m.is_empty());
+
+ for i in 1..1001 {
+ assert!(m.insert(i, i).is_none());
+
+ for j in 1..=i {
+ let r = m.get(&j);
+ assert_eq!(r, Some(&j));
+ }
+
+ for j in i + 1..1001 {
+ let r = m.get(&j);
+ assert_eq!(r, None);
+ }
+ }
+
+ for i in 1001..2001 {
+ assert!(!m.contains_key(&i));
+ }
+
+ // remove forwards
+ for i in 1..1001 {
+ assert!(m.remove(&i).is_some());
+
+ for j in 1..=i {
+ assert!(!m.contains_key(&j));
+ }
+
+ for j in i + 1..1001 {
+ assert!(m.contains_key(&j));
+ }
+ }
+
+ for i in 1..1001 {
+ assert!(!m.contains_key(&i));
+ }
+
+ for i in 1..1001 {
+ assert!(m.insert(i, i).is_none());
+ }
+
+ // remove backwards
+ for i in (1..1001).rev() {
+ assert!(m.remove(&i).is_some());
+
+ for j in i..1001 {
+ assert!(!m.contains_key(&j));
+ }
+
+ for j in 1..i {
+ assert!(m.contains_key(&j));
+ }
+ }
+ }
+ }
+
+ #[test]
+ fn test_find_mut() {
+ let mut m = HashMap::new();
+ assert!(m.insert(1, 12).is_none());
+ assert!(m.insert(2, 8).is_none());
+ assert!(m.insert(5, 14).is_none());
+ let new = 100;
+ match m.get_mut(&5) {
+ None => panic!(),
+ Some(x) => *x = new,
+ }
+ assert_eq!(m.get(&5), Some(&new));
+ }
+
+ #[test]
+ fn test_insert_overwrite() {
+ let mut m = HashMap::new();
+ assert!(m.insert(1, 2).is_none());
+ assert_eq!(*m.get(&1).unwrap(), 2);
+ assert!(!m.insert(1, 3).is_none());
+ assert_eq!(*m.get(&1).unwrap(), 3);
+ }
+
+ #[test]
+ fn test_insert_conflicts() {
+ let mut m = HashMap::with_capacity(4);
+ assert!(m.insert(1, 2).is_none());
+ assert!(m.insert(5, 3).is_none());
+ assert!(m.insert(9, 4).is_none());
+ assert_eq!(*m.get(&9).unwrap(), 4);
+ assert_eq!(*m.get(&5).unwrap(), 3);
+ assert_eq!(*m.get(&1).unwrap(), 2);
+ }
+
+ #[test]
+ fn test_conflict_remove() {
+ let mut m = HashMap::with_capacity(4);
+ assert!(m.insert(1, 2).is_none());
+ assert_eq!(*m.get(&1).unwrap(), 2);
+ assert!(m.insert(5, 3).is_none());
+ assert_eq!(*m.get(&1).unwrap(), 2);
+ assert_eq!(*m.get(&5).unwrap(), 3);
+ assert!(m.insert(9, 4).is_none());
+ assert_eq!(*m.get(&1).unwrap(), 2);
+ assert_eq!(*m.get(&5).unwrap(), 3);
+ assert_eq!(*m.get(&9).unwrap(), 4);
+ assert!(m.remove(&1).is_some());
+ assert_eq!(*m.get(&9).unwrap(), 4);
+ assert_eq!(*m.get(&5).unwrap(), 3);
+ }
+
+ #[test]
+ fn test_is_empty() {
+ let mut m = HashMap::with_capacity(4);
+ assert!(m.insert(1, 2).is_none());
+ assert!(!m.is_empty());
+ assert!(m.remove(&1).is_some());
+ assert!(m.is_empty());
+ }
+
+ #[test]
+ fn test_remove() {
+ let mut m = HashMap::new();
+ m.insert(1, 2);
+ assert_eq!(m.remove(&1), Some(2));
+ assert_eq!(m.remove(&1), None);
+ }
+
+ #[test]
+ fn test_remove_entry() {
+ let mut m = HashMap::new();
+ m.insert(1, 2);
+ assert_eq!(m.remove_entry(&1), Some((1, 2)));
+ assert_eq!(m.remove(&1), None);
+ }
+
+ #[test]
+ fn test_iterate() {
+ let mut m = HashMap::with_capacity(4);
+ for i in 0..32 {
+ assert!(m.insert(i, i*2).is_none());
+ }
+ assert_eq!(m.len(), 32);
+
+ let mut observed: u32 = 0;
+
+ for (k, v) in &m {
+ assert_eq!(*v, *k * 2);
+ observed |= 1 << *k;
+ }
+ assert_eq!(observed, 0xFFFF_FFFF);
+ }
+
+ #[test]
+ fn test_keys() {
+ let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')];
+ let map: HashMap<_, _> = vec.into_iter().collect();
+ let keys: Vec<_> = map.keys().cloned().collect();
+ assert_eq!(keys.len(), 3);
+ assert!(keys.contains(&1));
+ assert!(keys.contains(&2));
+ assert!(keys.contains(&3));
+ }
+
+ #[test]
+ fn test_values() {
+ let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')];
+ let map: HashMap<_, _> = vec.into_iter().collect();
+ let values: Vec<_> = map.values().cloned().collect();
+ assert_eq!(values.len(), 3);
+ assert!(values.contains(&'a'));
+ assert!(values.contains(&'b'));
+ assert!(values.contains(&'c'));
+ }
+
+ #[test]
+ fn test_values_mut() {
+ let vec = vec![(1, 1), (2, 2), (3, 3)];
+ let mut map: HashMap<_, _> = vec.into_iter().collect();
+ for value in map.values_mut() {
+ *value = (*value) * 2
+ }
+ let values: Vec<_> = map.values().cloned().collect();
+ assert_eq!(values.len(), 3);
+ assert!(values.contains(&2));
+ assert!(values.contains(&4));
+ assert!(values.contains(&6));
+ }
+
+ #[test]
+ fn test_find() {
+ let mut m = HashMap::new();
+ assert!(m.get(&1).is_none());
+ m.insert(1, 2);
+ match m.get(&1) {
+ None => panic!(),
+ Some(v) => assert_eq!(*v, 2),
+ }
+ }
+
+ #[test]
+ fn test_eq() {
+ let mut m1 = HashMap::new();
+ m1.insert(1, 2);
+ m1.insert(2, 3);
+ m1.insert(3, 4);
+
+ let mut m2 = HashMap::new();
+ m2.insert(1, 2);
+ m2.insert(2, 3);
+
+ assert!(m1 != m2);
+
+ m2.insert(3, 4);
+
+ assert_eq!(m1, m2);
+ }
+
+ #[test]
+ fn test_show() {
+ let mut map = HashMap::new();
+ let empty: HashMap<i32, i32> = HashMap::new();
+
+ map.insert(1, 2);
+ map.insert(3, 4);
+
+ let map_str = format!("{:?}", map);
+
+ assert!(map_str == "{1: 2, 3: 4}" ||
+ map_str == "{3: 4, 1: 2}");
+ assert_eq!(format!("{:?}", empty), "{}");
+ }
+
+ #[test]
+ fn test_expand() {
+ let mut m = HashMap::new();
+
+ assert_eq!(m.len(), 0);
+ assert!(m.is_empty());
+
+ let mut i = 0;
+ let old_raw_cap = m.raw_capacity();
+ while old_raw_cap == m.raw_capacity() {
+ m.insert(i, i);
+ i += 1;
+ }
+
+ assert_eq!(m.len(), i);
+ assert!(!m.is_empty());
+ }
+
+ #[test]
+ fn test_behavior_resize_policy() {
+ let mut m = HashMap::new();
+
+ assert_eq!(m.len(), 0);
+ assert_eq!(m.raw_capacity(), 0);
+ assert!(m.is_empty());
+
+ m.insert(0, 0);
+ m.remove(&0);
+ assert!(m.is_empty());
+ let initial_raw_cap = m.raw_capacity();
+ m.reserve(initial_raw_cap);
+ let raw_cap = m.raw_capacity();
+
+ assert_eq!(raw_cap, initial_raw_cap * 2);
+
+ let mut i = 0;
+ for _ in 0..raw_cap * 3 / 4 {
+ m.insert(i, i);
+ i += 1;
+ }
+ // three quarters full
+
+ assert_eq!(m.len(), i);
+ assert_eq!(m.raw_capacity(), raw_cap);
+
+ for _ in 0..raw_cap / 4 {
+ m.insert(i, i);
+ i += 1;
+ }
+ // half full
+
+ let new_raw_cap = m.raw_capacity();
+ assert_eq!(new_raw_cap, raw_cap * 2);
+
+ for _ in 0..raw_cap / 2 - 1 {
+ i -= 1;
+ m.remove(&i);
+ assert_eq!(m.raw_capacity(), new_raw_cap);
+ }
+ // A little more than one quarter full.
+ m.shrink_to_fit();
+ assert_eq!(m.raw_capacity(), raw_cap);
+ // again, a little more than half full
+ for _ in 0..raw_cap / 2 - 1 {
+ i -= 1;
+ m.remove(&i);
+ }
+ m.shrink_to_fit();
+
+ assert_eq!(m.len(), i);
+ assert!(!m.is_empty());
+ assert_eq!(m.raw_capacity(), initial_raw_cap);
+ }
+
+ #[test]
+ fn test_reserve_shrink_to_fit() {
+ let mut m = HashMap::new();
+ m.insert(0, 0);
+ m.remove(&0);
+ assert!(m.capacity() >= m.len());
+ for i in 0..128 {
+ m.insert(i, i);
+ }
+ m.reserve(256);
+
+ let usable_cap = m.capacity();
+ for i in 128..(128 + 256) {
+ m.insert(i, i);
+ assert_eq!(m.capacity(), usable_cap);
+ }
+
+ for i in 100..(128 + 256) {
+ assert_eq!(m.remove(&i), Some(i));
+ }
+ m.shrink_to_fit();
+
+ assert_eq!(m.len(), 100);
+ assert!(!m.is_empty());
+ assert!(m.capacity() >= m.len());
+
+ for i in 0..100 {
+ assert_eq!(m.remove(&i), Some(i));
+ }
+ m.shrink_to_fit();
+ m.insert(0, 0);
+
+ assert_eq!(m.len(), 1);
+ assert!(m.capacity() >= m.len());
+ assert_eq!(m.remove(&0), Some(0));
+ }
+
+ #[test]
+ fn test_from_iter() {
+ let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)];
+
+ let map: HashMap<_, _> = xs.iter().cloned().collect();
+
+ for &(k, v) in &xs {
+ assert_eq!(map.get(&k), Some(&v));
+ }
+ }
+
+ #[test]
+ fn test_size_hint() {
+ let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)];
+
+ let map: HashMap<_, _> = xs.iter().cloned().collect();
+
+ let mut iter = map.iter();
+
+ for _ in iter.by_ref().take(3) {}
+
+ assert_eq!(iter.size_hint(), (3, Some(3)));
+ }
+
+ #[test]
+ fn test_iter_len() {
+ let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)];
+
+ let map: HashMap<_, _> = xs.iter().cloned().collect();
+
+ let mut iter = map.iter();
+
+ for _ in iter.by_ref().take(3) {}
+
+ assert_eq!(iter.len(), 3);
+ }
+
+ #[test]
+ fn test_mut_size_hint() {
+ let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)];
+
+ let mut map: HashMap<_, _> = xs.iter().cloned().collect();
+
+ let mut iter = map.iter_mut();
+
+ for _ in iter.by_ref().take(3) {}
+
+ assert_eq!(iter.size_hint(), (3, Some(3)));
+ }
+
+ #[test]
+ fn test_iter_mut_len() {
+ let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)];
+
+ let mut map: HashMap<_, _> = xs.iter().cloned().collect();
+
+ let mut iter = map.iter_mut();
+
+ for _ in iter.by_ref().take(3) {}
+
+ assert_eq!(iter.len(), 3);
+ }
+
+ #[test]
+ fn test_index() {
+ let mut map = HashMap::new();
+
+ map.insert(1, 2);
+ map.insert(2, 1);
+ map.insert(3, 4);
+
+ assert_eq!(map[&2], 1);
+ }
+
+ #[test]
+ #[should_panic]
+ fn test_index_nonexistent() {
+ let mut map = HashMap::new();
+
+ map.insert(1, 2);
+ map.insert(2, 1);
+ map.insert(3, 4);
+
+ map[&4];
+ }
+
+ #[test]
+ fn test_entry() {
+ let xs = [(1, 10), (2, 20), (3, 30), (4, 40), (5, 50), (6, 60)];
+
+ let mut map: HashMap<_, _> = xs.iter().cloned().collect();
+
+ // Existing key (insert)
+ match map.entry(1) {
+ Vacant(_) => unreachable!(),
+ Occupied(mut view) => {
+ assert_eq!(view.get(), &10);
+ assert_eq!(view.insert(100), 10);
+ }
+ }
+ assert_eq!(map.get(&1).unwrap(), &100);
+ assert_eq!(map.len(), 6);
+
+
+ // Existing key (update)
+ match map.entry(2) {
+ Vacant(_) => unreachable!(),
+ Occupied(mut view) => {
+ let v = view.get_mut();
+ let new_v = (*v) * 10;
+ *v = new_v;
+ }
+ }
+ assert_eq!(map.get(&2).unwrap(), &200);
+ assert_eq!(map.len(), 6);
+
+ // Existing key (take)
+ match map.entry(3) {
+ Vacant(_) => unreachable!(),
+ Occupied(view) => {
+ assert_eq!(view.remove(), 30);
+ }
+ }
+ assert_eq!(map.get(&3), None);
+ assert_eq!(map.len(), 5);
+
+
+ // Inexistent key (insert)
+ match map.entry(10) {
+ Occupied(_) => unreachable!(),
+ Vacant(view) => {
+ assert_eq!(*view.insert(1000), 1000);
+ }
+ }
+ assert_eq!(map.get(&10).unwrap(), &1000);
+ assert_eq!(map.len(), 6);
+ }
+
+ #[test]
+ fn test_entry_take_doesnt_corrupt() {
+ #![allow(deprecated)] //rand
+ // Test for #19292
+ fn check(m: &HashMap<i32, ()>) {
+ for k in m.keys() {
+ assert!(m.contains_key(k),
+ "{} is in keys() but not in the map?", k);
+ }
+ }
+
+ let mut m = HashMap::new();
+ let mut rng = thread_rng();
+
+ // Populate the map with some items.
+ for _ in 0..50 {
+ let x = rng.gen_range(-10, 10);
+ m.insert(x, ());
+ }
+
+ for _ in 0..1000 {
+ let x = rng.gen_range(-10, 10);
+ match m.entry(x) {
+ Vacant(_) => {}
+ Occupied(e) => {
+ e.remove();
+ }
+ }
+
+ check(&m);
+ }
+ }
+
+ #[test]
+ fn test_extend_ref() {
+ let mut a = HashMap::new();
+ a.insert(1, "one");
+ let mut b = HashMap::new();
+ b.insert(2, "two");
+ b.insert(3, "three");
+
+ a.extend(&b);
+
+ assert_eq!(a.len(), 3);
+ assert_eq!(a[&1], "one");
+ assert_eq!(a[&2], "two");
+ assert_eq!(a[&3], "three");
+ }
+
+ #[test]
+ fn test_capacity_not_less_than_len() {
+ let mut a = HashMap::new();
+ let mut item = 0;
+
+ for _ in 0..116 {
+ a.insert(item, 0);
+ item += 1;
+ }
+
+ assert!(a.capacity() > a.len());
+
+ let free = a.capacity() - a.len();
+ for _ in 0..free {
+ a.insert(item, 0);
+ item += 1;
+ }
+
+ assert_eq!(a.len(), a.capacity());
+
+ // Insert at capacity should cause allocation.
+ a.insert(item, 0);
+ assert!(a.capacity() > a.len());
+ }
+
+ #[test]
+ fn test_occupied_entry_key() {
+ let mut a = HashMap::new();
+ let key = "hello there";
+ let value = "value goes here";
+ assert!(a.is_empty());
+ a.insert(key.clone(), value.clone());
+ assert_eq!(a.len(), 1);
+ assert_eq!(a[key], value);
+
+ match a.entry(key.clone()) {
+ Vacant(_) => panic!(),
+ Occupied(e) => assert_eq!(key, *e.key()),
+ }
+ assert_eq!(a.len(), 1);
+ assert_eq!(a[key], value);
+ }
+
+ #[test]
+ fn test_vacant_entry_key() {
+ let mut a = HashMap::new();
+ let key = "hello there";
+ let value = "value goes here";
+
+ assert!(a.is_empty());
+ match a.entry(key.clone()) {
+ Occupied(_) => panic!(),
+ Vacant(e) => {
+ assert_eq!(key, *e.key());
+ e.insert(value.clone());
+ }
+ }
+ assert_eq!(a.len(), 1);
+ assert_eq!(a[key], value);
+ }
+
+ #[test]
+ fn test_retain() {
+ let mut map: HashMap<i32, i32> = (0..100).map(|x|(x, x*10)).collect();
+
+ map.retain(|&k, _| k % 2 == 0);
+ assert_eq!(map.len(), 50);
+ assert_eq!(map[&2], 20);
+ assert_eq!(map[&4], 40);
+ assert_eq!(map[&6], 60);
+ }
+
+ #[test]
+ fn test_adaptive() {
+ const TEST_LEN: usize = 5000;
+ // by cloning we get maps with the same hasher seed
+ let mut first = HashMap::new();
+ let mut second = first.clone();
+ first.extend((0..TEST_LEN).map(|i| (i, i)));
+ second.extend((TEST_LEN..TEST_LEN * 2).map(|i| (i, i)));
+
+ for (&k, &v) in &second {
+ let prev_cap = first.capacity();
+ let expect_grow = first.len() == prev_cap;
+ first.insert(k, v);
+ if !expect_grow && first.capacity() != prev_cap {
+ return;
+ }
+ }
+ panic!("Adaptive early resize failed");
+ }
+
+ #[test]
+ fn test_try_reserve() {
+
+ let mut empty_bytes: HashMap<u8,u8> = HashMap::new();
+
+ const MAX_USIZE: usize = usize::MAX;
+
+ // HashMap and RawTables use complicated size calculations
+ // hashes_size is sizeof(HashUint) * capacity;
+ // pairs_size is sizeof((K. V)) * capacity;
+ // alignment_hashes_size is 8
+ // alignment_pairs size is 4
+ let size_of_multiplier = (size_of::<usize>() + size_of::<(u8, u8)>()).next_power_of_two();
+ // The following formula is used to calculate the new capacity
+ let max_no_ovf = ((MAX_USIZE / 11) * 10) / size_of_multiplier - 1;
+
+ if let Err(CapacityOverflow) = empty_bytes.try_reserve(MAX_USIZE) {
+ } else { panic!("usize::MAX should trigger an overflow!"); }
+
+ if size_of::<usize>() < 8 {
+ if let Err(CapacityOverflow) = empty_bytes.try_reserve(max_no_ovf) {
+ } else { panic!("isize::MAX + 1 should trigger a CapacityOverflow!") }
+ } else {
+ if let Err(AllocErr) = empty_bytes.try_reserve(max_no_ovf) {
+ } else { panic!("isize::MAX + 1 should trigger an OOM!") }
+ }
+ }
+
+ #[test]
+ fn test_raw_entry() {
+ use super::RawEntryMut::{Occupied, Vacant};
+
+ let xs = [(1i32, 10i32), (2, 20), (3, 30), (4, 40), (5, 50), (6, 60)];
+
+ let mut map: HashMap<_, _> = xs.iter().cloned().collect();
+
+ let compute_hash = |map: &HashMap<i32, i32>, k: i32| -> u64 {
+ use core::hash::{BuildHasher, Hash, Hasher};
+
+ let mut hasher = map.hasher().build_hasher();
+ k.hash(&mut hasher);
+ hasher.finish()
+ };
+
+ // Existing key (insert)
+ match map.raw_entry_mut().from_key(&1) {
+ Vacant(_) => unreachable!(),
+ Occupied(mut view) => {
+ assert_eq!(view.get(), &10);
+ assert_eq!(view.insert(100), 10);
+ }
+ }
+ let hash1 = compute_hash(&map, 1);
+ assert_eq!(map.raw_entry().from_key(&1).unwrap(), (&1, &100));
+ assert_eq!(map.raw_entry().from_hash(hash1, |k| *k == 1).unwrap(), (&1, &100));
+ assert_eq!(map.raw_entry().from_key_hashed_nocheck(hash1, &1).unwrap(), (&1, &100));
+ assert_eq!(map.raw_entry().search_bucket(hash1, |k| *k == 1).unwrap(), (&1, &100));
+ assert_eq!(map.len(), 6);
+
+ // Existing key (update)
+ match map.raw_entry_mut().from_key(&2) {
+ Vacant(_) => unreachable!(),
+ Occupied(mut view) => {
+ let v = view.get_mut();
+ let new_v = (*v) * 10;
+ *v = new_v;
+ }
+ }
+ let hash2 = compute_hash(&map, 2);
+ assert_eq!(map.raw_entry().from_key(&2).unwrap(), (&2, &200));
+ assert_eq!(map.raw_entry().from_hash(hash2, |k| *k == 2).unwrap(), (&2, &200));
+ assert_eq!(map.raw_entry().from_key_hashed_nocheck(hash2, &2).unwrap(), (&2, &200));
+ assert_eq!(map.raw_entry().search_bucket(hash2, |k| *k == 2).unwrap(), (&2, &200));
+ assert_eq!(map.len(), 6);
+
+ // Existing key (take)
+ let hash3 = compute_hash(&map, 3);
+ match map.raw_entry_mut().from_key_hashed_nocheck(hash3, &3) {
+ Vacant(_) => unreachable!(),
+ Occupied(view) => {
+ assert_eq!(view.remove_entry(), (3, 30));
+ }
+ }
+ assert_eq!(map.raw_entry().from_key(&3), None);
+ assert_eq!(map.raw_entry().from_hash(hash3, |k| *k == 3), None);
+ assert_eq!(map.raw_entry().from_key_hashed_nocheck(hash3, &3), None);
+ assert_eq!(map.raw_entry().search_bucket(hash3, |k| *k == 3), None);
+ assert_eq!(map.len(), 5);
+
+
+ // Nonexistent key (insert)
+ match map.raw_entry_mut().from_key(&10) {
+ Occupied(_) => unreachable!(),
+ Vacant(view) => {
+ assert_eq!(view.insert(10, 1000), (&mut 10, &mut 1000));
+ }
+ }
+ assert_eq!(map.raw_entry().from_key(&10).unwrap(), (&10, &1000));
+ assert_eq!(map.len(), 6);
+
+ // Ensure all lookup methods produce equivalent results.
+ for k in 0..12 {
+ let hash = compute_hash(&map, k);
+ let v = map.get(&k).cloned();
+ let kv = v.as_ref().map(|v| (&k, v));
+
+ assert_eq!(map.raw_entry().from_key(&k), kv);
+ assert_eq!(map.raw_entry().from_hash(hash, |q| *q == k), kv);
+ assert_eq!(map.raw_entry().from_key_hashed_nocheck(hash, &k), kv);
+ assert_eq!(map.raw_entry().search_bucket(hash, |q| *q == k), kv);
+
+ match map.raw_entry_mut().from_key(&k) {
+ Occupied(mut o) => assert_eq!(Some(o.get_key_value()), kv),
+ Vacant(_) => assert_eq!(v, None),
+ }
+ match map.raw_entry_mut().from_key_hashed_nocheck(hash, &k) {
+ Occupied(mut o) => assert_eq!(Some(o.get_key_value()), kv),
+ Vacant(_) => assert_eq!(v, None),
+ }
+ match map.raw_entry_mut().from_hash(hash, |q| *q == k) {
+ Occupied(mut o) => assert_eq!(Some(o.get_key_value()), kv),
+ Vacant(_) => assert_eq!(v, None),
+ }
+ match map.raw_entry_mut().search_bucket(hash, |q| *q == k) {
+ Occupied(mut o) => assert_eq!(Some(o.get_key_value()), kv),
+ Vacant(_) => assert_eq!(v, None),
+ }
+ }
+ }
+
+}
diff --git a/src/libstd/collections/hash/mod.rs b/src/libstd/collections/hash/mod.rs
new file mode 100644
index 0000000..0d1bbb5
--- /dev/null
+++ b/src/libstd/collections/hash/mod.rs
@@ -0,0 +1,14 @@
+//! Unordered containers, implemented as hash-tables
+
+mod bench;
+mod table;
+pub mod map;
+pub mod set;
+
+trait Recover<Q: ?Sized> {
+ type Key;
+
+ fn get(&self, key: &Q) -> Option<&Self::Key>;
+ fn take(&mut self, key: &Q) -> Option<Self::Key>;
+ fn replace(&mut self, key: Self::Key) -> Option<Self::Key>;
+}
diff --git a/src/libstd/collections/hash/set.rs b/src/libstd/collections/hash/set.rs
new file mode 100644
index 0000000..b9fcc23
--- /dev/null
+++ b/src/libstd/collections/hash/set.rs
@@ -0,0 +1,1826 @@
+use crate::borrow::Borrow;
+use crate::fmt;
+use crate::hash::{Hash, BuildHasher};
+use crate::iter::{Chain, FromIterator, FusedIterator};
+use crate::ops::{BitOr, BitAnd, BitXor, Sub};
+
+use super::Recover;
+use super::map::{self, HashMap, Keys, RandomState};
+
+// Future Optimization (FIXME!)
+// ============================
+//
+// Iteration over zero sized values is a noop. There is no need
+// for `bucket.val` in the case of HashSet. I suppose we would need HKT
+// to get rid of it properly.
+
+/// A hash set implemented as a `HashMap` where the value is `()`.
+///
+/// As with the [`HashMap`] type, a `HashSet` requires that the elements
+/// implement the [`Eq`] and [`Hash`] traits. This can frequently be achieved by
+/// using `#[derive(PartialEq, Eq, Hash)]`. If you implement these yourself,
+/// it is important that the following property holds:
+///
+/// ```text
+/// k1 == k2 -> hash(k1) == hash(k2)
+/// ```
+///
+/// In other words, if two keys are equal, their hashes must be equal.
+///
+///
+/// It is a logic error for an item to be modified in such a way that the
+/// item's hash, as determined by the [`Hash`] trait, or its equality, as
+/// determined by the [`Eq`] trait, changes while it is in the set. This is
+/// normally only possible through [`Cell`], [`RefCell`], global state, I/O, or
+/// unsafe code.
+///
+/// # Examples
+///
+/// ```
+/// use std::collections::HashSet;
+/// // Type inference lets us omit an explicit type signature (which
+/// // would be `HashSet<String>` in this example).
+/// let mut books = HashSet::new();
+///
+/// // Add some books.
+/// books.insert("A Dance With Dragons".to_string());
+/// books.insert("To Kill a Mockingbird".to_string());
+/// books.insert("The Odyssey".to_string());
+/// books.insert("The Great Gatsby".to_string());
+///
+/// // Check for a specific one.
+/// if !books.contains("The Winds of Winter") {
+/// println!("We have {} books, but The Winds of Winter ain't one.",
+/// books.len());
+/// }
+///
+/// // Remove a book.
+/// books.remove("The Odyssey");
+///
+/// // Iterate over everything.
+/// for book in &books {
+/// println!("{}", book);
+/// }
+/// ```
+///
+/// The easiest way to use `HashSet` with a custom type is to derive
+/// [`Eq`] and [`Hash`]. We must also derive [`PartialEq`], this will in the
+/// future be implied by [`Eq`].
+///
+/// ```
+/// use std::collections::HashSet;
+/// #[derive(Hash, Eq, PartialEq, Debug)]
+/// struct Viking {
+/// name: String,
+/// power: usize,
+/// }
+///
+/// let mut vikings = HashSet::new();
+///
+/// vikings.insert(Viking { name: "Einar".to_string(), power: 9 });
+/// vikings.insert(Viking { name: "Einar".to_string(), power: 9 });
+/// vikings.insert(Viking { name: "Olaf".to_string(), power: 4 });
+/// vikings.insert(Viking { name: "Harald".to_string(), power: 8 });
+///
+/// // Use derived implementation to print the vikings.
+/// for x in &vikings {
+/// println!("{:?}", x);
+/// }
+/// ```
+///
+/// A `HashSet` with fixed list of elements can be initialized from an array:
+///
+/// ```
+/// use std::collections::HashSet;
+///
+/// fn main() {
+/// let viking_names: HashSet<&'static str> =
+/// [ "Einar", "Olaf", "Harald" ].iter().cloned().collect();
+/// // use the values stored in the set
+/// }
+/// ```
+///
+/// [`Cell`]: ../../std/cell/struct.Cell.html
+/// [`Eq`]: ../../std/cmp/trait.Eq.html
+/// [`Hash`]: ../../std/hash/trait.Hash.html
+/// [`HashMap`]: struct.HashMap.html
+/// [`PartialEq`]: ../../std/cmp/trait.PartialEq.html
+/// [`RefCell`]: ../../std/cell/struct.RefCell.html
+#[derive(Clone)]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct HashSet<T, S = RandomState> {
+ map: HashMap<T, (), S>,
+}
+
+impl<T: Hash + Eq> HashSet<T, RandomState> {
+ /// Creates an empty `HashSet`.
+ ///
+ /// The hash set is initially created with a capacity of 0, so it will not allocate until it
+ /// is first inserted into.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::HashSet;
+ /// let set: HashSet<i32> = HashSet::new();
+ /// ```
+ #[inline]
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn new() -> HashSet<T, RandomState> {
+ HashSet { map: HashMap::new() }
+ }
+
+ /// Creates an empty `HashSet` with the specified capacity.
+ ///
+ /// The hash set will be able to hold at least `capacity` elements without
+ /// reallocating. If `capacity` is 0, the hash set will not allocate.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::HashSet;
+ /// let set: HashSet<i32> = HashSet::with_capacity(10);
+ /// assert!(set.capacity() >= 10);
+ /// ```
+ #[inline]
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn with_capacity(capacity: usize) -> HashSet<T, RandomState> {
+ HashSet { map: HashMap::with_capacity(capacity) }
+ }
+}
+
+impl<T, S> HashSet<T, S> {
+ /// Returns the number of elements the set can hold without reallocating.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::HashSet;
+ /// let set: HashSet<i32> = HashSet::with_capacity(100);
+ /// assert!(set.capacity() >= 100);
+ /// ```
+ #[inline]
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn capacity(&self) -> usize {
+ self.map.capacity()
+ }
+
+ /// An iterator visiting all elements in arbitrary order.
+ /// The iterator element type is `&'a T`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::HashSet;
+ /// let mut set = HashSet::new();
+ /// set.insert("a");
+ /// set.insert("b");
+ ///
+ /// // Will print in an arbitrary order.
+ /// for x in set.iter() {
+ /// println!("{}", x);
+ /// }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn iter(&self) -> Iter<'_, T> {
+ Iter { iter: self.map.keys() }
+ }
+
+ /// Returns the number of elements in the set.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::HashSet;
+ ///
+ /// let mut v = HashSet::new();
+ /// assert_eq!(v.len(), 0);
+ /// v.insert(1);
+ /// assert_eq!(v.len(), 1);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn len(&self) -> usize {
+ self.map.len()
+ }
+
+ /// Returns `true` if the set contains no elements.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::HashSet;
+ ///
+ /// let mut v = HashSet::new();
+ /// assert!(v.is_empty());
+ /// v.insert(1);
+ /// assert!(!v.is_empty());
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn is_empty(&self) -> bool {
+ self.map.is_empty()
+ }
+
+ /// Clears the set, returning all elements in an iterator.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::HashSet;
+ ///
+ /// let mut set: HashSet<_> = [1, 2, 3].iter().cloned().collect();
+ /// assert!(!set.is_empty());
+ ///
+ /// // print 1, 2, 3 in an arbitrary order
+ /// for i in set.drain() {
+ /// println!("{}", i);
+ /// }
+ ///
+ /// assert!(set.is_empty());
+ /// ```
+ #[inline]
+ #[stable(feature = "drain", since = "1.6.0")]
+ pub fn drain(&mut self) -> Drain<'_, T> {
+ Drain { iter: self.map.drain() }
+ }
+
+ /// Clears the set, removing all values.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::HashSet;
+ ///
+ /// let mut v = HashSet::new();
+ /// v.insert(1);
+ /// v.clear();
+ /// assert!(v.is_empty());
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn clear(&mut self) {
+ self.map.clear()
+ }
+}
+
+impl<T, S> HashSet<T, S>
+ where T: Eq + Hash,
+ S: BuildHasher
+{
+ /// Creates a new empty hash set which will use the given hasher to hash
+ /// keys.
+ ///
+ /// The hash set is also created with the default initial capacity.
+ ///
+ /// Warning: `hasher` is normally randomly generated, and
+ /// is designed to allow `HashSet`s to be resistant to attacks that
+ /// cause many collisions and very poor performance. Setting it
+ /// manually using this function can expose a DoS attack vector.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::HashSet;
+ /// use std::collections::hash_map::RandomState;
+ ///
+ /// let s = RandomState::new();
+ /// let mut set = HashSet::with_hasher(s);
+ /// set.insert(2);
+ /// ```
+ #[inline]
+ #[stable(feature = "hashmap_build_hasher", since = "1.7.0")]
+ pub fn with_hasher(hasher: S) -> HashSet<T, S> {
+ HashSet { map: HashMap::with_hasher(hasher) }
+ }
+
+ /// Creates an empty `HashSet` with the specified capacity, using
+ /// `hasher` to hash the keys.
+ ///
+ /// The hash set will be able to hold at least `capacity` elements without
+ /// reallocating. If `capacity` is 0, the hash set will not allocate.
+ ///
+ /// Warning: `hasher` is normally randomly generated, and
+ /// is designed to allow `HashSet`s to be resistant to attacks that
+ /// cause many collisions and very poor performance. Setting it
+ /// manually using this function can expose a DoS attack vector.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::HashSet;
+ /// use std::collections::hash_map::RandomState;
+ ///
+ /// let s = RandomState::new();
+ /// let mut set = HashSet::with_capacity_and_hasher(10, s);
+ /// set.insert(1);
+ /// ```
+ #[inline]
+ #[stable(feature = "hashmap_build_hasher", since = "1.7.0")]
+ pub fn with_capacity_and_hasher(capacity: usize, hasher: S) -> HashSet<T, S> {
+ HashSet { map: HashMap::with_capacity_and_hasher(capacity, hasher) }
+ }
+
+ /// Returns a reference to the set's [`BuildHasher`].
+ ///
+ /// [`BuildHasher`]: ../../std/hash/trait.BuildHasher.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::HashSet;
+ /// use std::collections::hash_map::RandomState;
+ ///
+ /// let hasher = RandomState::new();
+ /// let set: HashSet<i32> = HashSet::with_hasher(hasher);
+ /// let hasher: &RandomState = set.hasher();
+ /// ```
+ #[stable(feature = "hashmap_public_hasher", since = "1.9.0")]
+ pub fn hasher(&self) -> &S {
+ self.map.hasher()
+ }
+
+ /// Reserves capacity for at least `additional` more elements to be inserted
+ /// in the `HashSet`. The collection may reserve more space to avoid
+ /// frequent reallocations.
+ ///
+ /// # Panics
+ ///
+ /// Panics if the new allocation size overflows `usize`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::HashSet;
+ /// let mut set: HashSet<i32> = HashSet::new();
+ /// set.reserve(10);
+ /// assert!(set.capacity() >= 10);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn reserve(&mut self, additional: usize) {
+ self.map.reserve(additional)
+ }
+
+ /// Shrinks the capacity of the set as much as possible. It will drop
+ /// down as much as possible while maintaining the internal rules
+ /// and possibly leaving some space in accordance with the resize policy.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::HashSet;
+ ///
+ /// let mut set = HashSet::with_capacity(100);
+ /// set.insert(1);
+ /// set.insert(2);
+ /// assert!(set.capacity() >= 100);
+ /// set.shrink_to_fit();
+ /// assert!(set.capacity() >= 2);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn shrink_to_fit(&mut self) {
+ self.map.shrink_to_fit()
+ }
+
+ /// Shrinks the capacity of the set with a lower limit. It will drop
+ /// down no lower than the supplied limit while maintaining the internal rules
+ /// and possibly leaving some space in accordance with the resize policy.
+ ///
+ /// Panics if the current capacity is smaller than the supplied
+ /// minimum capacity.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(shrink_to)]
+ /// use std::collections::HashSet;
+ ///
+ /// let mut set = HashSet::with_capacity(100);
+ /// set.insert(1);
+ /// set.insert(2);
+ /// assert!(set.capacity() >= 100);
+ /// set.shrink_to(10);
+ /// assert!(set.capacity() >= 10);
+ /// set.shrink_to(0);
+ /// assert!(set.capacity() >= 2);
+ /// ```
+ #[inline]
+ #[unstable(feature = "shrink_to", reason = "new API", issue="56431")]
+ pub fn shrink_to(&mut self, min_capacity: usize) {
+ self.map.shrink_to(min_capacity)
+ }
+
+ /// Visits the values representing the difference,
+ /// i.e., the values that are in `self` but not in `other`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::HashSet;
+ /// let a: HashSet<_> = [1, 2, 3].iter().cloned().collect();
+ /// let b: HashSet<_> = [4, 2, 3, 4].iter().cloned().collect();
+ ///
+ /// // Can be seen as `a - b`.
+ /// for x in a.difference(&b) {
+ /// println!("{}", x); // Print 1
+ /// }
+ ///
+ /// let diff: HashSet<_> = a.difference(&b).collect();
+ /// assert_eq!(diff, [1].iter().collect());
+ ///
+ /// // Note that difference is not symmetric,
+ /// // and `b - a` means something else:
+ /// let diff: HashSet<_> = b.difference(&a).collect();
+ /// assert_eq!(diff, [4].iter().collect());
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn difference<'a>(&'a self, other: &'a HashSet<T, S>) -> Difference<'a, T, S> {
+ Difference {
+ iter: self.iter(),
+ other,
+ }
+ }
+
+ /// Visits the values representing the symmetric difference,
+ /// i.e., the values that are in `self` or in `other` but not in both.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::HashSet;
+ /// let a: HashSet<_> = [1, 2, 3].iter().cloned().collect();
+ /// let b: HashSet<_> = [4, 2, 3, 4].iter().cloned().collect();
+ ///
+ /// // Print 1, 4 in arbitrary order.
+ /// for x in a.symmetric_difference(&b) {
+ /// println!("{}", x);
+ /// }
+ ///
+ /// let diff1: HashSet<_> = a.symmetric_difference(&b).collect();
+ /// let diff2: HashSet<_> = b.symmetric_difference(&a).collect();
+ ///
+ /// assert_eq!(diff1, diff2);
+ /// assert_eq!(diff1, [1, 4].iter().collect());
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn symmetric_difference<'a>(&'a self,
+ other: &'a HashSet<T, S>)
+ -> SymmetricDifference<'a, T, S> {
+ SymmetricDifference { iter: self.difference(other).chain(other.difference(self)) }
+ }
+
+ /// Visits the values representing the intersection,
+ /// i.e., the values that are both in `self` and `other`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::HashSet;
+ /// let a: HashSet<_> = [1, 2, 3].iter().cloned().collect();
+ /// let b: HashSet<_> = [4, 2, 3, 4].iter().cloned().collect();
+ ///
+ /// // Print 2, 3 in arbitrary order.
+ /// for x in a.intersection(&b) {
+ /// println!("{}", x);
+ /// }
+ ///
+ /// let intersection: HashSet<_> = a.intersection(&b).collect();
+ /// assert_eq!(intersection, [2, 3].iter().collect());
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn intersection<'a>(&'a self, other: &'a HashSet<T, S>) -> Intersection<'a, T, S> {
+ if self.len() <= other.len() {
+ Intersection {
+ iter: self.iter(),
+ other,
+ }
+ } else {
+ Intersection {
+ iter: other.iter(),
+ other: self,
+ }
+ }
+ }
+
+ /// Visits the values representing the union,
+ /// i.e., all the values in `self` or `other`, without duplicates.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::HashSet;
+ /// let a: HashSet<_> = [1, 2, 3].iter().cloned().collect();
+ /// let b: HashSet<_> = [4, 2, 3, 4].iter().cloned().collect();
+ ///
+ /// // Print 1, 2, 3, 4 in arbitrary order.
+ /// for x in a.union(&b) {
+ /// println!("{}", x);
+ /// }
+ ///
+ /// let union: HashSet<_> = a.union(&b).collect();
+ /// assert_eq!(union, [1, 2, 3, 4].iter().collect());
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn union<'a>(&'a self, other: &'a HashSet<T, S>) -> Union<'a, T, S> {
+ if self.len() <= other.len() {
+ Union {
+ iter: self.iter().chain(other.difference(self)),
+ }
+ } else {
+ Union {
+ iter: other.iter().chain(self.difference(other)),
+ }
+ }
+ }
+
+ /// Returns `true` if the set contains a value.
+ ///
+ /// The value may be any borrowed form of the set's value type, but
+ /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for
+ /// the value type.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::HashSet;
+ ///
+ /// let set: HashSet<_> = [1, 2, 3].iter().cloned().collect();
+ /// assert_eq!(set.contains(&1), true);
+ /// assert_eq!(set.contains(&4), false);
+ /// ```
+ ///
+ /// [`Eq`]: ../../std/cmp/trait.Eq.html
+ /// [`Hash`]: ../../std/hash/trait.Hash.html
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn contains<Q: ?Sized>(&self, value: &Q) -> bool
+ where T: Borrow<Q>,
+ Q: Hash + Eq
+ {
+ self.map.contains_key(value)
+ }
+
+ /// Returns a reference to the value in the set, if any, that is equal to the given value.
+ ///
+ /// The value may be any borrowed form of the set's value type, but
+ /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for
+ /// the value type.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::HashSet;
+ ///
+ /// let set: HashSet<_> = [1, 2, 3].iter().cloned().collect();
+ /// assert_eq!(set.get(&2), Some(&2));
+ /// assert_eq!(set.get(&4), None);
+ /// ```
+ ///
+ /// [`Eq`]: ../../std/cmp/trait.Eq.html
+ /// [`Hash`]: ../../std/hash/trait.Hash.html
+ #[stable(feature = "set_recovery", since = "1.9.0")]
+ pub fn get<Q: ?Sized>(&self, value: &Q) -> Option<&T>
+ where T: Borrow<Q>,
+ Q: Hash + Eq
+ {
+ Recover::get(&self.map, value)
+ }
+
+ /// Returns `true` if `self` has no elements in common with `other`.
+ /// This is equivalent to checking for an empty intersection.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::HashSet;
+ ///
+ /// let a: HashSet<_> = [1, 2, 3].iter().cloned().collect();
+ /// let mut b = HashSet::new();
+ ///
+ /// assert_eq!(a.is_disjoint(&b), true);
+ /// b.insert(4);
+ /// assert_eq!(a.is_disjoint(&b), true);
+ /// b.insert(1);
+ /// assert_eq!(a.is_disjoint(&b), false);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn is_disjoint(&self, other: &HashSet<T, S>) -> bool {
+ if self.len() <= other.len() {
+ self.iter().all(|v| !other.contains(v))
+ } else {
+ other.iter().all(|v| !self.contains(v))
+ }
+ }
+
+ /// Returns `true` if the set is a subset of another,
+ /// i.e., `other` contains at least all the values in `self`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::HashSet;
+ ///
+ /// let sup: HashSet<_> = [1, 2, 3].iter().cloned().collect();
+ /// let mut set = HashSet::new();
+ ///
+ /// assert_eq!(set.is_subset(&sup), true);
+ /// set.insert(2);
+ /// assert_eq!(set.is_subset(&sup), true);
+ /// set.insert(4);
+ /// assert_eq!(set.is_subset(&sup), false);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn is_subset(&self, other: &HashSet<T, S>) -> bool {
+ if self.len() <= other.len() {
+ self.iter().all(|v| other.contains(v))
+ } else {
+ false
+ }
+ }
+
+ /// Returns `true` if the set is a superset of another,
+ /// i.e., `self` contains at least all the values in `other`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::HashSet;
+ ///
+ /// let sub: HashSet<_> = [1, 2].iter().cloned().collect();
+ /// let mut set = HashSet::new();
+ ///
+ /// assert_eq!(set.is_superset(&sub), false);
+ ///
+ /// set.insert(0);
+ /// set.insert(1);
+ /// assert_eq!(set.is_superset(&sub), false);
+ ///
+ /// set.insert(2);
+ /// assert_eq!(set.is_superset(&sub), true);
+ /// ```
+ #[inline]
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn is_superset(&self, other: &HashSet<T, S>) -> bool {
+ other.is_subset(self)
+ }
+
+ /// Adds a value to the set.
+ ///
+ /// If the set did not have this value present, `true` is returned.
+ ///
+ /// If the set did have this value present, `false` is returned.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::HashSet;
+ ///
+ /// let mut set = HashSet::new();
+ ///
+ /// assert_eq!(set.insert(2), true);
+ /// assert_eq!(set.insert(2), false);
+ /// assert_eq!(set.len(), 1);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn insert(&mut self, value: T) -> bool {
+ self.map.insert(value, ()).is_none()
+ }
+
+ /// Adds a value to the set, replacing the existing value, if any, that is equal to the given
+ /// one. Returns the replaced value.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::HashSet;
+ ///
+ /// let mut set = HashSet::new();
+ /// set.insert(Vec::<i32>::new());
+ ///
+ /// assert_eq!(set.get(&[][..]).unwrap().capacity(), 0);
+ /// set.replace(Vec::with_capacity(10));
+ /// assert_eq!(set.get(&[][..]).unwrap().capacity(), 10);
+ /// ```
+ #[stable(feature = "set_recovery", since = "1.9.0")]
+ pub fn replace(&mut self, value: T) -> Option<T> {
+ Recover::replace(&mut self.map, value)
+ }
+
+ /// Removes a value from the set. Returns whether the value was
+ /// present in the set.
+ ///
+ /// The value may be any borrowed form of the set's value type, but
+ /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for
+ /// the value type.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::HashSet;
+ ///
+ /// let mut set = HashSet::new();
+ ///
+ /// set.insert(2);
+ /// assert_eq!(set.remove(&2), true);
+ /// assert_eq!(set.remove(&2), false);
+ /// ```
+ ///
+ /// [`Eq`]: ../../std/cmp/trait.Eq.html
+ /// [`Hash`]: ../../std/hash/trait.Hash.html
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn remove<Q: ?Sized>(&mut self, value: &Q) -> bool
+ where T: Borrow<Q>,
+ Q: Hash + Eq
+ {
+ self.map.remove(value).is_some()
+ }
+
+ /// Removes and returns the value in the set, if any, that is equal to the given one.
+ ///
+ /// The value may be any borrowed form of the set's value type, but
+ /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for
+ /// the value type.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::HashSet;
+ ///
+ /// let mut set: HashSet<_> = [1, 2, 3].iter().cloned().collect();
+ /// assert_eq!(set.take(&2), Some(2));
+ /// assert_eq!(set.take(&2), None);
+ /// ```
+ ///
+ /// [`Eq`]: ../../std/cmp/trait.Eq.html
+ /// [`Hash`]: ../../std/hash/trait.Hash.html
+ #[stable(feature = "set_recovery", since = "1.9.0")]
+ pub fn take<Q: ?Sized>(&mut self, value: &Q) -> Option<T>
+ where T: Borrow<Q>,
+ Q: Hash + Eq
+ {
+ Recover::take(&mut self.map, value)
+ }
+
+ /// Retains only the elements specified by the predicate.
+ ///
+ /// In other words, remove all elements `e` such that `f(&e)` returns `false`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::HashSet;
+ ///
+ /// let xs = [1,2,3,4,5,6];
+ /// let mut set: HashSet<i32> = xs.iter().cloned().collect();
+ /// set.retain(|&k| k % 2 == 0);
+ /// assert_eq!(set.len(), 3);
+ /// ```
+ #[stable(feature = "retain_hash_collection", since = "1.18.0")]
+ pub fn retain<F>(&mut self, mut f: F)
+ where F: FnMut(&T) -> bool
+ {
+ self.map.retain(|k, _| f(k));
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T, S> PartialEq for HashSet<T, S>
+ where T: Eq + Hash,
+ S: BuildHasher
+{
+ fn eq(&self, other: &HashSet<T, S>) -> bool {
+ if self.len() != other.len() {
+ return false;
+ }
+
+ self.iter().all(|key| other.contains(key))
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T, S> Eq for HashSet<T, S>
+ where T: Eq + Hash,
+ S: BuildHasher
+{
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T, S> fmt::Debug for HashSet<T, S>
+ where T: Eq + Hash + fmt::Debug,
+ S: BuildHasher
+{
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_set().entries(self.iter()).finish()
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T, S> FromIterator<T> for HashSet<T, S>
+ where T: Eq + Hash,
+ S: BuildHasher + Default
+{
+ fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> HashSet<T, S> {
+ let mut set = HashSet::with_hasher(Default::default());
+ set.extend(iter);
+ set
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T, S> Extend<T> for HashSet<T, S>
+ where T: Eq + Hash,
+ S: BuildHasher
+{
+ fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
+ self.map.extend(iter.into_iter().map(|k| (k, ())));
+ }
+}
+
+#[stable(feature = "hash_extend_copy", since = "1.4.0")]
+impl<'a, T, S> Extend<&'a T> for HashSet<T, S>
+ where T: 'a + Eq + Hash + Copy,
+ S: BuildHasher
+{
+ fn extend<I: IntoIterator<Item = &'a T>>(&mut self, iter: I) {
+ self.extend(iter.into_iter().cloned());
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T, S> Default for HashSet<T, S>
+ where T: Eq + Hash,
+ S: BuildHasher + Default
+{
+ /// Creates an empty `HashSet<T, S>` with the `Default` value for the hasher.
+ fn default() -> HashSet<T, S> {
+ HashSet { map: HashMap::default() }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T, S> BitOr<&HashSet<T, S>> for &HashSet<T, S>
+ where T: Eq + Hash + Clone,
+ S: BuildHasher + Default
+{
+ type Output = HashSet<T, S>;
+
+ /// Returns the union of `self` and `rhs` as a new `HashSet<T, S>`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::HashSet;
+ ///
+ /// let a: HashSet<_> = vec![1, 2, 3].into_iter().collect();
+ /// let b: HashSet<_> = vec![3, 4, 5].into_iter().collect();
+ ///
+ /// let set = &a | &b;
+ ///
+ /// let mut i = 0;
+ /// let expected = [1, 2, 3, 4, 5];
+ /// for x in &set {
+ /// assert!(expected.contains(x));
+ /// i += 1;
+ /// }
+ /// assert_eq!(i, expected.len());
+ /// ```
+ fn bitor(self, rhs: &HashSet<T, S>) -> HashSet<T, S> {
+ self.union(rhs).cloned().collect()
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T, S> BitAnd<&HashSet<T, S>> for &HashSet<T, S>
+ where T: Eq + Hash + Clone,
+ S: BuildHasher + Default
+{
+ type Output = HashSet<T, S>;
+
+ /// Returns the intersection of `self` and `rhs` as a new `HashSet<T, S>`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::HashSet;
+ ///
+ /// let a: HashSet<_> = vec![1, 2, 3].into_iter().collect();
+ /// let b: HashSet<_> = vec![2, 3, 4].into_iter().collect();
+ ///
+ /// let set = &a & &b;
+ ///
+ /// let mut i = 0;
+ /// let expected = [2, 3];
+ /// for x in &set {
+ /// assert!(expected.contains(x));
+ /// i += 1;
+ /// }
+ /// assert_eq!(i, expected.len());
+ /// ```
+ fn bitand(self, rhs: &HashSet<T, S>) -> HashSet<T, S> {
+ self.intersection(rhs).cloned().collect()
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T, S> BitXor<&HashSet<T, S>> for &HashSet<T, S>
+ where T: Eq + Hash + Clone,
+ S: BuildHasher + Default
+{
+ type Output = HashSet<T, S>;
+
+ /// Returns the symmetric difference of `self` and `rhs` as a new `HashSet<T, S>`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::HashSet;
+ ///
+ /// let a: HashSet<_> = vec![1, 2, 3].into_iter().collect();
+ /// let b: HashSet<_> = vec![3, 4, 5].into_iter().collect();
+ ///
+ /// let set = &a ^ &b;
+ ///
+ /// let mut i = 0;
+ /// let expected = [1, 2, 4, 5];
+ /// for x in &set {
+ /// assert!(expected.contains(x));
+ /// i += 1;
+ /// }
+ /// assert_eq!(i, expected.len());
+ /// ```
+ fn bitxor(self, rhs: &HashSet<T, S>) -> HashSet<T, S> {
+ self.symmetric_difference(rhs).cloned().collect()
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T, S> Sub<&HashSet<T, S>> for &HashSet<T, S>
+ where T: Eq + Hash + Clone,
+ S: BuildHasher + Default
+{
+ type Output = HashSet<T, S>;
+
+ /// Returns the difference of `self` and `rhs` as a new `HashSet<T, S>`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::HashSet;
+ ///
+ /// let a: HashSet<_> = vec![1, 2, 3].into_iter().collect();
+ /// let b: HashSet<_> = vec![3, 4, 5].into_iter().collect();
+ ///
+ /// let set = &a - &b;
+ ///
+ /// let mut i = 0;
+ /// let expected = [1, 2];
+ /// for x in &set {
+ /// assert!(expected.contains(x));
+ /// i += 1;
+ /// }
+ /// assert_eq!(i, expected.len());
+ /// ```
+ fn sub(self, rhs: &HashSet<T, S>) -> HashSet<T, S> {
+ self.difference(rhs).cloned().collect()
+ }
+}
+
+/// An iterator over the items of a `HashSet`.
+///
+/// This `struct` is created by the [`iter`] method on [`HashSet`].
+/// See its documentation for more.
+///
+/// [`HashSet`]: struct.HashSet.html
+/// [`iter`]: struct.HashSet.html#method.iter
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct Iter<'a, K: 'a> {
+ iter: Keys<'a, K, ()>,
+}
+
+/// An owning iterator over the items of a `HashSet`.
+///
+/// This `struct` is created by the [`into_iter`] method on [`HashSet`][`HashSet`]
+/// (provided by the `IntoIterator` trait). See its documentation for more.
+///
+/// [`HashSet`]: struct.HashSet.html
+/// [`into_iter`]: struct.HashSet.html#method.into_iter
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct IntoIter<K> {
+ iter: map::IntoIter<K, ()>,
+}
+
+/// A draining iterator over the items of a `HashSet`.
+///
+/// This `struct` is created by the [`drain`] method on [`HashSet`].
+/// See its documentation for more.
+///
+/// [`HashSet`]: struct.HashSet.html
+/// [`drain`]: struct.HashSet.html#method.drain
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct Drain<'a, K: 'a> {
+ iter: map::Drain<'a, K, ()>,
+}
+
+/// A lazy iterator producing elements in the intersection of `HashSet`s.
+///
+/// This `struct` is created by the [`intersection`] method on [`HashSet`].
+/// See its documentation for more.
+///
+/// [`HashSet`]: struct.HashSet.html
+/// [`intersection`]: struct.HashSet.html#method.intersection
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct Intersection<'a, T: 'a, S: 'a> {
+ // iterator of the first set
+ iter: Iter<'a, T>,
+ // the second set
+ other: &'a HashSet<T, S>,
+}
+
+/// A lazy iterator producing elements in the difference of `HashSet`s.
+///
+/// This `struct` is created by the [`difference`] method on [`HashSet`].
+/// See its documentation for more.
+///
+/// [`HashSet`]: struct.HashSet.html
+/// [`difference`]: struct.HashSet.html#method.difference
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct Difference<'a, T: 'a, S: 'a> {
+ // iterator of the first set
+ iter: Iter<'a, T>,
+ // the second set
+ other: &'a HashSet<T, S>,
+}
+
+/// A lazy iterator producing elements in the symmetric difference of `HashSet`s.
+///
+/// This `struct` is created by the [`symmetric_difference`] method on
+/// [`HashSet`]. See its documentation for more.
+///
+/// [`HashSet`]: struct.HashSet.html
+/// [`symmetric_difference`]: struct.HashSet.html#method.symmetric_difference
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct SymmetricDifference<'a, T: 'a, S: 'a> {
+ iter: Chain<Difference<'a, T, S>, Difference<'a, T, S>>,
+}
+
+/// A lazy iterator producing elements in the union of `HashSet`s.
+///
+/// This `struct` is created by the [`union`] method on [`HashSet`].
+/// See its documentation for more.
+///
+/// [`HashSet`]: struct.HashSet.html
+/// [`union`]: struct.HashSet.html#method.union
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct Union<'a, T: 'a, S: 'a> {
+ iter: Chain<Iter<'a, T>, Difference<'a, T, S>>,
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a, T, S> IntoIterator for &'a HashSet<T, S> {
+ type Item = &'a T;
+ type IntoIter = Iter<'a, T>;
+
+ fn into_iter(self) -> Iter<'a, T> {
+ self.iter()
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T, S> IntoIterator for HashSet<T, S> {
+ type Item = T;
+ type IntoIter = IntoIter<T>;
+
+ /// Creates a consuming iterator, that is, one that moves each value out
+ /// of the set in arbitrary order. The set cannot be used after calling
+ /// this.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::HashSet;
+ /// let mut set = HashSet::new();
+ /// set.insert("a".to_string());
+ /// set.insert("b".to_string());
+ ///
+ /// // Not possible to collect to a Vec<String> with a regular `.iter()`.
+ /// let v: Vec<String> = set.into_iter().collect();
+ ///
+ /// // Will print in an arbitrary order.
+ /// for x in &v {
+ /// println!("{}", x);
+ /// }
+ /// ```
+ fn into_iter(self) -> IntoIter<T> {
+ IntoIter { iter: self.map.into_iter() }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<K> Clone for Iter<'_, K> {
+ fn clone(&self) -> Self {
+ Iter { iter: self.iter.clone() }
+ }
+}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a, K> Iterator for Iter<'a, K> {
+ type Item = &'a K;
+
+ fn next(&mut self) -> Option<&'a K> {
+ self.iter.next()
+ }
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ self.iter.size_hint()
+ }
+}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<K> ExactSizeIterator for Iter<'_, K> {
+ fn len(&self) -> usize {
+ self.iter.len()
+ }
+}
+#[stable(feature = "fused", since = "1.26.0")]
+impl<K> FusedIterator for Iter<'_, K> {}
+
+#[stable(feature = "std_debug", since = "1.16.0")]
+impl<K: fmt::Debug> fmt::Debug for Iter<'_, K> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_list().entries(self.clone()).finish()
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<K> Iterator for IntoIter<K> {
+ type Item = K;
+
+ fn next(&mut self) -> Option<K> {
+ self.iter.next().map(|(k, _)| k)
+ }
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ self.iter.size_hint()
+ }
+}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<K> ExactSizeIterator for IntoIter<K> {
+ fn len(&self) -> usize {
+ self.iter.len()
+ }
+}
+#[stable(feature = "fused", since = "1.26.0")]
+impl<K> FusedIterator for IntoIter<K> {}
+
+#[stable(feature = "std_debug", since = "1.16.0")]
+impl<K: fmt::Debug> fmt::Debug for IntoIter<K> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ let entries_iter = self.iter
+ .inner
+ .iter()
+ .map(|(k, _)| k);
+ f.debug_list().entries(entries_iter).finish()
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a, K> Iterator for Drain<'a, K> {
+ type Item = K;
+
+ fn next(&mut self) -> Option<K> {
+ self.iter.next().map(|(k, _)| k)
+ }
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ self.iter.size_hint()
+ }
+}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<K> ExactSizeIterator for Drain<'_, K> {
+ fn len(&self) -> usize {
+ self.iter.len()
+ }
+}
+#[stable(feature = "fused", since = "1.26.0")]
+impl<K> FusedIterator for Drain<'_, K> {}
+
+#[stable(feature = "std_debug", since = "1.16.0")]
+impl<K: fmt::Debug> fmt::Debug for Drain<'_, K> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ let entries_iter = self.iter
+ .inner
+ .iter()
+ .map(|(k, _)| k);
+ f.debug_list().entries(entries_iter).finish()
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T, S> Clone for Intersection<'_, T, S> {
+ fn clone(&self) -> Self {
+ Intersection { iter: self.iter.clone(), ..*self }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a, T, S> Iterator for Intersection<'a, T, S>
+ where T: Eq + Hash,
+ S: BuildHasher
+{
+ type Item = &'a T;
+
+ fn next(&mut self) -> Option<&'a T> {
+ loop {
+ let elt = self.iter.next()?;
+ if self.other.contains(elt) {
+ return Some(elt);
+ }
+ }
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ let (_, upper) = self.iter.size_hint();
+ (0, upper)
+ }
+}
+
+#[stable(feature = "std_debug", since = "1.16.0")]
+impl<T, S> fmt::Debug for Intersection<'_, T, S>
+ where T: fmt::Debug + Eq + Hash,
+ S: BuildHasher
+{
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_list().entries(self.clone()).finish()
+ }
+}
+
+#[stable(feature = "fused", since = "1.26.0")]
+impl<T, S> FusedIterator for Intersection<'_, T, S>
+ where T: Eq + Hash,
+ S: BuildHasher
+{
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T, S> Clone for Difference<'_, T, S> {
+ fn clone(&self) -> Self {
+ Difference { iter: self.iter.clone(), ..*self }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a, T, S> Iterator for Difference<'a, T, S>
+ where T: Eq + Hash,
+ S: BuildHasher
+{
+ type Item = &'a T;
+
+ fn next(&mut self) -> Option<&'a T> {
+ loop {
+ let elt = self.iter.next()?;
+ if !self.other.contains(elt) {
+ return Some(elt);
+ }
+ }
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ let (_, upper) = self.iter.size_hint();
+ (0, upper)
+ }
+}
+
+#[stable(feature = "fused", since = "1.26.0")]
+impl<T, S> FusedIterator for Difference<'_, T, S>
+ where T: Eq + Hash,
+ S: BuildHasher
+{
+}
+
+#[stable(feature = "std_debug", since = "1.16.0")]
+impl<T, S> fmt::Debug for Difference<'_, T, S>
+ where T: fmt::Debug + Eq + Hash,
+ S: BuildHasher
+{
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_list().entries(self.clone()).finish()
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T, S> Clone for SymmetricDifference<'_, T, S> {
+ fn clone(&self) -> Self {
+ SymmetricDifference { iter: self.iter.clone() }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a, T, S> Iterator for SymmetricDifference<'a, T, S>
+ where T: Eq + Hash,
+ S: BuildHasher
+{
+ type Item = &'a T;
+
+ fn next(&mut self) -> Option<&'a T> {
+ self.iter.next()
+ }
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ self.iter.size_hint()
+ }
+}
+
+#[stable(feature = "fused", since = "1.26.0")]
+impl<T, S> FusedIterator for SymmetricDifference<'_, T, S>
+ where T: Eq + Hash,
+ S: BuildHasher
+{
+}
+
+#[stable(feature = "std_debug", since = "1.16.0")]
+impl<T, S> fmt::Debug for SymmetricDifference<'_, T, S>
+ where T: fmt::Debug + Eq + Hash,
+ S: BuildHasher
+{
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_list().entries(self.clone()).finish()
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T, S> Clone for Union<'_, T, S> {
+ fn clone(&self) -> Self {
+ Union { iter: self.iter.clone() }
+ }
+}
+
+#[stable(feature = "fused", since = "1.26.0")]
+impl<T, S> FusedIterator for Union<'_, T, S>
+ where T: Eq + Hash,
+ S: BuildHasher
+{
+}
+
+#[stable(feature = "std_debug", since = "1.16.0")]
+impl<T, S> fmt::Debug for Union<'_, T, S>
+ where T: fmt::Debug + Eq + Hash,
+ S: BuildHasher
+{
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_list().entries(self.clone()).finish()
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a, T, S> Iterator for Union<'a, T, S>
+ where T: Eq + Hash,
+ S: BuildHasher
+{
+ type Item = &'a T;
+
+ fn next(&mut self) -> Option<&'a T> {
+ self.iter.next()
+ }
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ self.iter.size_hint()
+ }
+}
+
+#[allow(dead_code)]
+fn assert_covariance() {
+ fn set<'new>(v: HashSet<&'static str>) -> HashSet<&'new str> {
+ v
+ }
+ fn iter<'a, 'new>(v: Iter<'a, &'static str>) -> Iter<'a, &'new str> {
+ v
+ }
+ fn into_iter<'new>(v: IntoIter<&'static str>) -> IntoIter<&'new str> {
+ v
+ }
+ fn difference<'a, 'new>(v: Difference<'a, &'static str, RandomState>)
+ -> Difference<'a, &'new str, RandomState> {
+ v
+ }
+ fn symmetric_difference<'a, 'new>(v: SymmetricDifference<'a, &'static str, RandomState>)
+ -> SymmetricDifference<'a, &'new str, RandomState> {
+ v
+ }
+ fn intersection<'a, 'new>(v: Intersection<'a, &'static str, RandomState>)
+ -> Intersection<'a, &'new str, RandomState> {
+ v
+ }
+ fn union<'a, 'new>(v: Union<'a, &'static str, RandomState>)
+ -> Union<'a, &'new str, RandomState> {
+ v
+ }
+ fn drain<'new>(d: Drain<'static, &'static str>) -> Drain<'new, &'new str> {
+ d
+ }
+}
+
+#[cfg(test)]
+mod test_set {
+ use super::HashSet;
+ use super::super::map::RandomState;
+
+ #[test]
+ fn test_zero_capacities() {
+ type HS = HashSet<i32>;
+
+ let s = HS::new();
+ assert_eq!(s.capacity(), 0);
+
+ let s = HS::default();
+ assert_eq!(s.capacity(), 0);
+
+ let s = HS::with_hasher(RandomState::new());
+ assert_eq!(s.capacity(), 0);
+
+ let s = HS::with_capacity(0);
+ assert_eq!(s.capacity(), 0);
+
+ let s = HS::with_capacity_and_hasher(0, RandomState::new());
+ assert_eq!(s.capacity(), 0);
+
+ let mut s = HS::new();
+ s.insert(1);
+ s.insert(2);
+ s.remove(&1);
+ s.remove(&2);
+ s.shrink_to_fit();
+ assert_eq!(s.capacity(), 0);
+
+ let mut s = HS::new();
+ s.reserve(0);
+ assert_eq!(s.capacity(), 0);
+ }
+
+ #[test]
+ fn test_disjoint() {
+ let mut xs = HashSet::new();
+ let mut ys = HashSet::new();
+ assert!(xs.is_disjoint(&ys));
+ assert!(ys.is_disjoint(&xs));
+ assert!(xs.insert(5));
+ assert!(ys.insert(11));
+ assert!(xs.is_disjoint(&ys));
+ assert!(ys.is_disjoint(&xs));
+ assert!(xs.insert(7));
+ assert!(xs.insert(19));
+ assert!(xs.insert(4));
+ assert!(ys.insert(2));
+ assert!(ys.insert(-11));
+ assert!(xs.is_disjoint(&ys));
+ assert!(ys.is_disjoint(&xs));
+ assert!(ys.insert(7));
+ assert!(!xs.is_disjoint(&ys));
+ assert!(!ys.is_disjoint(&xs));
+ }
+
+ #[test]
+ fn test_subset_and_superset() {
+ let mut a = HashSet::new();
+ assert!(a.insert(0));
+ assert!(a.insert(5));
+ assert!(a.insert(11));
+ assert!(a.insert(7));
+
+ let mut b = HashSet::new();
+ assert!(b.insert(0));
+ assert!(b.insert(7));
+ assert!(b.insert(19));
+ assert!(b.insert(250));
+ assert!(b.insert(11));
+ assert!(b.insert(200));
+
+ assert!(!a.is_subset(&b));
+ assert!(!a.is_superset(&b));
+ assert!(!b.is_subset(&a));
+ assert!(!b.is_superset(&a));
+
+ assert!(b.insert(5));
+
+ assert!(a.is_subset(&b));
+ assert!(!a.is_superset(&b));
+ assert!(!b.is_subset(&a));
+ assert!(b.is_superset(&a));
+ }
+
+ #[test]
+ fn test_iterate() {
+ let mut a = HashSet::new();
+ for i in 0..32 {
+ assert!(a.insert(i));
+ }
+ let mut observed: u32 = 0;
+ for k in &a {
+ observed |= 1 << *k;
+ }
+ assert_eq!(observed, 0xFFFF_FFFF);
+ }
+
+ #[test]
+ fn test_intersection() {
+ let mut a = HashSet::new();
+ let mut b = HashSet::new();
+ assert!(a.intersection(&b).next().is_none());
+
+ assert!(a.insert(11));
+ assert!(a.insert(1));
+ assert!(a.insert(3));
+ assert!(a.insert(77));
+ assert!(a.insert(103));
+ assert!(a.insert(5));
+ assert!(a.insert(-5));
+
+ assert!(b.insert(2));
+ assert!(b.insert(11));
+ assert!(b.insert(77));
+ assert!(b.insert(-9));
+ assert!(b.insert(-42));
+ assert!(b.insert(5));
+ assert!(b.insert(3));
+
+ let mut i = 0;
+ let expected = [3, 5, 11, 77];
+ for x in a.intersection(&b) {
+ assert!(expected.contains(x));
+ i += 1
+ }
+ assert_eq!(i, expected.len());
+
+ assert!(a.insert(9)); // make a bigger than b
+
+ i = 0;
+ for x in a.intersection(&b) {
+ assert!(expected.contains(x));
+ i += 1
+ }
+ assert_eq!(i, expected.len());
+
+ i = 0;
+ for x in b.intersection(&a) {
+ assert!(expected.contains(x));
+ i += 1
+ }
+ assert_eq!(i, expected.len());
+ }
+
+ #[test]
+ fn test_difference() {
+ let mut a = HashSet::new();
+ let mut b = HashSet::new();
+
+ assert!(a.insert(1));
+ assert!(a.insert(3));
+ assert!(a.insert(5));
+ assert!(a.insert(9));
+ assert!(a.insert(11));
+
+ assert!(b.insert(3));
+ assert!(b.insert(9));
+
+ let mut i = 0;
+ let expected = [1, 5, 11];
+ for x in a.difference(&b) {
+ assert!(expected.contains(x));
+ i += 1
+ }
+ assert_eq!(i, expected.len());
+ }
+
+ #[test]
+ fn test_symmetric_difference() {
+ let mut a = HashSet::new();
+ let mut b = HashSet::new();
+
+ assert!(a.insert(1));
+ assert!(a.insert(3));
+ assert!(a.insert(5));
+ assert!(a.insert(9));
+ assert!(a.insert(11));
+
+ assert!(b.insert(-2));
+ assert!(b.insert(3));
+ assert!(b.insert(9));
+ assert!(b.insert(14));
+ assert!(b.insert(22));
+
+ let mut i = 0;
+ let expected = [-2, 1, 5, 11, 14, 22];
+ for x in a.symmetric_difference(&b) {
+ assert!(expected.contains(x));
+ i += 1
+ }
+ assert_eq!(i, expected.len());
+ }
+
+ #[test]
+ fn test_union() {
+ let mut a = HashSet::new();
+ let mut b = HashSet::new();
+ assert!(a.union(&b).next().is_none());
+ assert!(b.union(&a).next().is_none());
+
+ assert!(a.insert(1));
+ assert!(a.insert(3));
+ assert!(a.insert(11));
+ assert!(a.insert(16));
+ assert!(a.insert(19));
+ assert!(a.insert(24));
+
+ assert!(b.insert(-2));
+ assert!(b.insert(1));
+ assert!(b.insert(5));
+ assert!(b.insert(9));
+ assert!(b.insert(13));
+ assert!(b.insert(19));
+
+ let mut i = 0;
+ let expected = [-2, 1, 3, 5, 9, 11, 13, 16, 19, 24];
+ for x in a.union(&b) {
+ assert!(expected.contains(x));
+ i += 1
+ }
+ assert_eq!(i, expected.len());
+
+ assert!(a.insert(9)); // make a bigger than b
+ assert!(a.insert(5));
+
+ i = 0;
+ for x in a.union(&b) {
+ assert!(expected.contains(x));
+ i += 1
+ }
+ assert_eq!(i, expected.len());
+
+ i = 0;
+ for x in b.union(&a) {
+ assert!(expected.contains(x));
+ i += 1
+ }
+ assert_eq!(i, expected.len());
+ }
+
+ #[test]
+ fn test_from_iter() {
+ let xs = [1, 2, 3, 4, 5, 6, 7, 8, 9];
+
+ let set: HashSet<_> = xs.iter().cloned().collect();
+
+ for x in &xs {
+ assert!(set.contains(x));
+ }
+ }
+
+ #[test]
+ fn test_move_iter() {
+ let hs = {
+ let mut hs = HashSet::new();
+
+ hs.insert('a');
+ hs.insert('b');
+
+ hs
+ };
+
+ let v = hs.into_iter().collect::<Vec<char>>();
+ assert!(v == ['a', 'b'] || v == ['b', 'a']);
+ }
+
+ #[test]
+ fn test_eq() {
+ // These constants once happened to expose a bug in insert().
+ // I'm keeping them around to prevent a regression.
+ let mut s1 = HashSet::new();
+
+ s1.insert(1);
+ s1.insert(2);
+ s1.insert(3);
+
+ let mut s2 = HashSet::new();
+
+ s2.insert(1);
+ s2.insert(2);
+
+ assert!(s1 != s2);
+
+ s2.insert(3);
+
+ assert_eq!(s1, s2);
+ }
+
+ #[test]
+ fn test_show() {
+ let mut set = HashSet::new();
+ let empty = HashSet::<i32>::new();
+
+ set.insert(1);
+ set.insert(2);
+
+ let set_str = format!("{:?}", set);
+
+ assert!(set_str == "{1, 2}" || set_str == "{2, 1}");
+ assert_eq!(format!("{:?}", empty), "{}");
+ }
+
+ #[test]
+ fn test_trivial_drain() {
+ let mut s = HashSet::<i32>::new();
+ for _ in s.drain() {}
+ assert!(s.is_empty());
+ drop(s);
+
+ let mut s = HashSet::<i32>::new();
+ drop(s.drain());
+ assert!(s.is_empty());
+ }
+
+ #[test]
+ fn test_drain() {
+ let mut s: HashSet<_> = (1..100).collect();
+
+ // try this a bunch of times to make sure we don't screw up internal state.
+ for _ in 0..20 {
+ assert_eq!(s.len(), 99);
+
+ {
+ let mut last_i = 0;
+ let mut d = s.drain();
+ for (i, x) in d.by_ref().take(50).enumerate() {
+ last_i = i;
+ assert!(x != 0);
+ }
+ assert_eq!(last_i, 49);
+ }
+
+ for _ in &s {
+ panic!("s should be empty!");
+ }
+
+ // reset to try again.
+ s.extend(1..100);
+ }
+ }
+
+ #[test]
+ fn test_replace() {
+ use crate::hash;
+
+ #[derive(Debug)]
+ struct Foo(&'static str, i32);
+
+ impl PartialEq for Foo {
+ fn eq(&self, other: &Self) -> bool {
+ self.0 == other.0
+ }
+ }
+
+ impl Eq for Foo {}
+
+ impl hash::Hash for Foo {
+ fn hash<H: hash::Hasher>(&self, h: &mut H) {
+ self.0.hash(h);
+ }
+ }
+
+ let mut s = HashSet::new();
+ assert_eq!(s.replace(Foo("a", 1)), None);
+ assert_eq!(s.len(), 1);
+ assert_eq!(s.replace(Foo("a", 2)), Some(Foo("a", 1)));
+ assert_eq!(s.len(), 1);
+
+ let mut it = s.iter();
+ assert_eq!(it.next(), Some(&Foo("a", 2)));
+ assert_eq!(it.next(), None);
+ }
+
+ #[test]
+ fn test_extend_ref() {
+ let mut a = HashSet::new();
+ a.insert(1);
+
+ a.extend(&[2, 3, 4]);
+
+ assert_eq!(a.len(), 4);
+ assert!(a.contains(&1));
+ assert!(a.contains(&2));
+ assert!(a.contains(&3));
+ assert!(a.contains(&4));
+
+ let mut b = HashSet::new();
+ b.insert(5);
+ b.insert(6);
+
+ a.extend(&b);
+
+ assert_eq!(a.len(), 6);
+ assert!(a.contains(&1));
+ assert!(a.contains(&2));
+ assert!(a.contains(&3));
+ assert!(a.contains(&4));
+ assert!(a.contains(&5));
+ assert!(a.contains(&6));
+ }
+
+ #[test]
+ fn test_retain() {
+ let xs = [1, 2, 3, 4, 5, 6];
+ let mut set: HashSet<i32> = xs.iter().cloned().collect();
+ set.retain(|&k| k % 2 == 0);
+ assert_eq!(set.len(), 3);
+ assert!(set.contains(&2));
+ assert!(set.contains(&4));
+ assert!(set.contains(&6));
+ }
+}
diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs
new file mode 100644
index 0000000..2113b44
--- /dev/null
+++ b/src/libstd/collections/hash/table.rs
@@ -0,0 +1,1131 @@
+use crate::alloc::{Global, Alloc, Layout, LayoutErr, handle_alloc_error};
+use crate::collections::CollectionAllocErr;
+use crate::hash::{BuildHasher, Hash, Hasher};
+use crate::marker;
+use crate::mem::{self, size_of, needs_drop};
+use crate::ops::{Deref, DerefMut};
+use crate::ptr::{self, Unique, NonNull};
+use crate::hint;
+
+use self::BucketState::*;
+
+/// Integer type used for stored hash values.
+///
+/// No more than bit_width(usize) bits are needed to select a bucket.
+///
+/// The most significant bit is ours to use for tagging `SafeHash`.
+///
+/// (Even if we could have usize::MAX bytes allocated for buckets,
+/// each bucket stores at least a `HashUint`, so there can be no more than
+/// usize::MAX / size_of(usize) buckets.)
+type HashUint = usize;
+
+const EMPTY_BUCKET: HashUint = 0;
+const EMPTY: usize = 1;
+
+/// Special `Unique<HashUint>` that uses the lower bit of the pointer
+/// to expose a boolean tag.
+/// Note: when the pointer is initialized to EMPTY `.ptr()` will return
+/// null and the tag functions shouldn't be used.
+struct TaggedHashUintPtr(Unique<HashUint>);
+
+impl TaggedHashUintPtr {
+ #[inline]
+ unsafe fn new(ptr: *mut HashUint) -> Self {
+ debug_assert!(ptr as usize & 1 == 0 || ptr as usize == EMPTY as usize);
+ TaggedHashUintPtr(Unique::new_unchecked(ptr))
+ }
+
+ #[inline]
+ fn set_tag(&mut self, value: bool) {
+ let mut usize_ptr = self.0.as_ptr() as usize;
+ unsafe {
+ if value {
+ usize_ptr |= 1;
+ } else {
+ usize_ptr &= !1;
+ }
+ self.0 = Unique::new_unchecked(usize_ptr as *mut HashUint)
+ }
+ }
+
+ #[inline]
+ fn tag(&self) -> bool {
+ (self.0.as_ptr() as usize) & 1 == 1
+ }
+
+ #[inline]
+ fn ptr(&self) -> *mut HashUint {
+ (self.0.as_ptr() as usize & !1) as *mut HashUint
+ }
+}
+
+/// The raw hashtable, providing safe-ish access to the unzipped and highly
+/// optimized arrays of hashes, and key-value pairs.
+///
+/// This design is a lot faster than the naive
+/// `Vec<Option<(u64, K, V)>>`, because we don't pay for the overhead of an
+/// option on every element, and we get a generally more cache-aware design.
+///
+/// Essential invariants of this structure:
+///
+/// - if `t.hashes[i] == EMPTY_BUCKET`, then `Bucket::at_index(&t, i).raw`
+/// points to 'undefined' contents. Don't read from it. This invariant is
+/// enforced outside this module with the `EmptyBucket`, `FullBucket`,
+/// and `SafeHash` types.
+///
+/// - An `EmptyBucket` is only constructed at an index with
+/// a hash of EMPTY_BUCKET.
+///
+/// - A `FullBucket` is only constructed at an index with a
+/// non-EMPTY_BUCKET hash.
+///
+/// - A `SafeHash` is only constructed for non-`EMPTY_BUCKET` hash. We get
+/// around hashes of zero by changing them to 0x8000_0000_0000_0000,
+/// which will likely map to the same bucket, while not being confused
+/// with "empty".
+///
+/// - Both "arrays represented by pointers" are the same length:
+/// `capacity`. This is set at creation and never changes. The arrays
+/// are unzipped and are more cache aware (scanning through 8 hashes
+/// brings in at most 2 cache lines, since they're all right beside each
+/// other). This layout may waste space in padding such as in a map from
+/// u64 to u8, but is a more cache conscious layout as the key-value pairs
+/// are only very shortly probed and the desired value will be in the same
+/// or next cache line.
+///
+/// You can kind of think of this module/data structure as a safe wrapper
+/// around just the "table" part of the hashtable. It enforces some
+/// invariants at the type level and employs some performance trickery,
+/// but in general is just a tricked out `Vec<Option<(u64, K, V)>>`.
+///
+/// The hashtable also exposes a special boolean tag. The tag defaults to false
+/// when the RawTable is created and is accessible with the `tag` and `set_tag`
+/// functions.
+pub struct RawTable<K, V> {
+ capacity_mask: usize,
+ size: usize,
+ hashes: TaggedHashUintPtr,
+
+ // Because K/V do not appear directly in any of the types in the struct,
+ // inform rustc that in fact instances of K and V are reachable from here.
+ marker: marker::PhantomData<(K, V)>,
+}
+
+// An unsafe view of a RawTable bucket
+// Valid indexes are within [0..table_capacity)
+pub struct RawBucket<K, V> {
+ hash_start: *mut HashUint,
+ // We use *const to ensure covariance with respect to K and V
+ pair_start: *const (K, V),
+ idx: usize,
+ _marker: marker::PhantomData<(K, V)>,
+}
+
+impl<K, V> Copy for RawBucket<K, V> {}
+impl<K, V> Clone for RawBucket<K, V> {
+ fn clone(&self) -> RawBucket<K, V> {
+ *self
+ }
+}
+
+pub struct Bucket<K, V, M> {
+ raw: RawBucket<K, V>,
+ table: M,
+}
+
+impl<K, V, M: Copy> Copy for Bucket<K, V, M> {}
+impl<K, V, M: Copy> Clone for Bucket<K, V, M> {
+ fn clone(&self) -> Bucket<K, V, M> {
+ *self
+ }
+}
+
+pub struct EmptyBucket<K, V, M> {
+ raw: RawBucket<K, V>,
+ table: M,
+}
+
+pub struct FullBucket<K, V, M> {
+ raw: RawBucket<K, V>,
+ table: M,
+}
+
+pub type FullBucketMut<'table, K, V> = FullBucket<K, V, &'table mut RawTable<K, V>>;
+
+pub enum BucketState<K, V, M> {
+ Empty(EmptyBucket<K, V, M>),
+ Full(FullBucket<K, V, M>),
+}
+
+// A GapThenFull encapsulates the state of two consecutive buckets at once.
+// The first bucket, called the gap, is known to be empty.
+// The second bucket is full.
+pub struct GapThenFull<K, V, M> {
+ gap: EmptyBucket<K, V, ()>,
+ full: FullBucket<K, V, M>,
+}
+
+/// A hash that is not zero, since we use a hash of zero to represent empty
+/// buckets.
+#[derive(PartialEq, Copy, Clone)]
+pub struct SafeHash {
+ hash: HashUint,
+}
+
+impl SafeHash {
+ /// Peek at the hash value, which is guaranteed to be non-zero.
+ #[inline(always)]
+ pub fn inspect(&self) -> HashUint {
+ self.hash
+ }
+
+ #[inline(always)]
+ pub fn new(hash: u64) -> Self {
+ // We need to avoid 0 in order to prevent collisions with
+ // EMPTY_HASH. We can maintain our precious uniform distribution
+ // of initial indexes by unconditionally setting the MSB,
+ // effectively reducing the hashes by one bit.
+ //
+ // Truncate hash to fit in `HashUint`.
+ let hash_bits = size_of::<HashUint>() * 8;
+ SafeHash { hash: (1 << (hash_bits - 1)) | (hash as HashUint) }
+ }
+}
+
+/// We need to remove hashes of 0. That's reserved for empty buckets.
+/// This function wraps up `hash_keyed` to be the only way outside this
+/// module to generate a SafeHash.
+pub fn make_hash<T: ?Sized, S>(hash_state: &S, t: &T) -> SafeHash
+ where T: Hash,
+ S: BuildHasher
+{
+ let mut state = hash_state.build_hasher();
+ t.hash(&mut state);
+ SafeHash::new(state.finish())
+}
+
+// `replace` casts a `*HashUint` to a `*SafeHash`. Since we statically
+// ensure that a `FullBucket` points to an index with a non-zero hash,
+// and a `SafeHash` is just a `HashUint` with a different name, this is
+// safe.
+//
+// This test ensures that a `SafeHash` really IS the same size as a
+// `HashUint`. If you need to change the size of `SafeHash` (and
+// consequently made this test fail), `replace` needs to be
+// modified to no longer assume this.
+#[test]
+fn can_alias_safehash_as_hash() {
+ assert_eq!(size_of::<SafeHash>(), size_of::<HashUint>())
+}
+
+// RawBucket methods are unsafe as it's possible to
+// make a RawBucket point to invalid memory using safe code.
+impl<K, V> RawBucket<K, V> {
+ unsafe fn hash(&self) -> *mut HashUint {
+ self.hash_start.add(self.idx)
+ }
+ unsafe fn pair(&self) -> *mut (K, V) {
+ self.pair_start.add(self.idx) as *mut (K, V)
+ }
+ unsafe fn hash_pair(&self) -> (*mut HashUint, *mut (K, V)) {
+ (self.hash(), self.pair())
+ }
+}
+
+// Buckets hold references to the table.
+impl<K, V, M> FullBucket<K, V, M> {
+ /// Borrow a reference to the table.
+ pub fn table(&self) -> &M {
+ &self.table
+ }
+ /// Borrow a mutable reference to the table.
+ pub fn table_mut(&mut self) -> &mut M {
+ &mut self.table
+ }
+ /// Move out the reference to the table.
+ pub fn into_table(self) -> M {
+ self.table
+ }
+ /// Gets the raw index.
+ pub fn index(&self) -> usize {
+ self.raw.idx
+ }
+ /// Gets the raw bucket.
+ pub fn raw(&self) -> RawBucket<K, V> {
+ self.raw
+ }
+}
+
+impl<K, V, M> EmptyBucket<K, V, M> {
+ /// Borrow a reference to the table.
+ pub fn table(&self) -> &M {
+ &self.table
+ }
+ /// Borrow a mutable reference to the table.
+ pub fn table_mut(&mut self) -> &mut M {
+ &mut self.table
+ }
+}
+
+impl<K, V, M> Bucket<K, V, M> {
+ /// Gets the raw index.
+ pub fn index(&self) -> usize {
+ self.raw.idx
+ }
+ /// get the table.
+ pub fn into_table(self) -> M {
+ self.table
+ }
+}
+
+impl<K, V, M> Deref for FullBucket<K, V, M>
+ where M: Deref<Target = RawTable<K, V>>
+{
+ type Target = RawTable<K, V>;
+ fn deref(&self) -> &RawTable<K, V> {
+ &self.table
+ }
+}
+
+/// `Put` is implemented for types which provide access to a table and cannot be invalidated
+/// by filling a bucket. A similar implementation for `Take` is possible.
+pub trait Put<K, V> {
+ unsafe fn borrow_table_mut(&mut self) -> &mut RawTable<K, V>;
+}
+
+
+impl<K, V> Put<K, V> for &mut RawTable<K, V> {
+ unsafe fn borrow_table_mut(&mut self) -> &mut RawTable<K, V> {
+ *self
+ }
+}
+
+impl<K, V, M> Put<K, V> for Bucket<K, V, M>
+ where M: Put<K, V>
+{
+ unsafe fn borrow_table_mut(&mut self) -> &mut RawTable<K, V> {
+ self.table.borrow_table_mut()
+ }
+}
+
+impl<K, V, M> Put<K, V> for FullBucket<K, V, M>
+ where M: Put<K, V>
+{
+ unsafe fn borrow_table_mut(&mut self) -> &mut RawTable<K, V> {
+ self.table.borrow_table_mut()
+ }
+}
+
+impl<K, V, M: Deref<Target = RawTable<K, V>>> Bucket<K, V, M> {
+ #[inline]
+ pub fn new(table: M, hash: SafeHash) -> Bucket<K, V, M> {
+ Bucket::at_index(table, hash.inspect() as usize)
+ }
+
+ pub fn new_from(r: RawBucket<K, V>, t: M)
+ -> Bucket<K, V, M>
+ {
+ Bucket {
+ raw: r,
+ table: t,
+ }
+ }
+
+ #[inline]
+ pub fn at_index(table: M, ib_index: usize) -> Bucket<K, V, M> {
+ // if capacity is 0, then the RawBucket will be populated with bogus pointers.
+ // This is an uncommon case though, so avoid it in release builds.
+ debug_assert!(table.capacity() > 0,
+ "Table should have capacity at this point");
+ let ib_index = ib_index & table.capacity_mask;
+ Bucket {
+ raw: table.raw_bucket_at(ib_index),
+ table,
+ }
+ }
+
+ pub fn first(table: M) -> Bucket<K, V, M> {
+ Bucket {
+ raw: table.raw_bucket_at(0),
+ table,
+ }
+ }
+
+ // "So a few of the first shall be last: for many be called,
+ // but few chosen."
+ //
+ // We'll most likely encounter a few buckets at the beginning that
+ // have their initial buckets near the end of the table. They were
+ // placed at the beginning as the probe wrapped around the table
+ // during insertion. We must skip forward to a bucket that won't
+ // get reinserted too early and won't unfairly steal others spot.
+ // This eliminates the need for robin hood.
+ pub fn head_bucket(table: M) -> Bucket<K, V, M> {
+ let mut bucket = Bucket::first(table);
+
+ loop {
+ bucket = match bucket.peek() {
+ Full(full) => {
+ if full.displacement() == 0 {
+ // This bucket occupies its ideal spot.
+ // It indicates the start of another "cluster".
+ bucket = full.into_bucket();
+ break;
+ }
+ // Leaving this bucket in the last cluster for later.
+ full.into_bucket()
+ }
+ Empty(b) => {
+ // Encountered a hole between clusters.
+ b.into_bucket()
+ }
+ };
+ bucket.next();
+ }
+ bucket
+ }
+
+ /// Reads a bucket at a given index, returning an enum indicating whether
+ /// it's initialized or not. You need to match on this enum to get
+ /// the appropriate types to call most of the other functions in
+ /// this module.
+ pub fn peek(self) -> BucketState<K, V, M> {
+ match unsafe { *self.raw.hash() } {
+ EMPTY_BUCKET => {
+ Empty(EmptyBucket {
+ raw: self.raw,
+ table: self.table,
+ })
+ }
+ _ => {
+ Full(FullBucket {
+ raw: self.raw,
+ table: self.table,
+ })
+ }
+ }
+ }
+
+ /// Modifies the bucket in place to make it point to the next slot.
+ pub fn next(&mut self) {
+ self.raw.idx = self.raw.idx.wrapping_add(1) & self.table.capacity_mask;
+ }
+
+ /// Modifies the bucket in place to make it point to the previous slot.
+ pub fn prev(&mut self) {
+ self.raw.idx = self.raw.idx.wrapping_sub(1) & self.table.capacity_mask;
+ }
+}
+
+impl<K, V, M: Deref<Target = RawTable<K, V>>> EmptyBucket<K, V, M> {
+ #[inline]
+ pub fn next(self) -> Bucket<K, V, M> {
+ let mut bucket = self.into_bucket();
+ bucket.next();
+ bucket
+ }
+
+ #[inline]
+ pub fn into_bucket(self) -> Bucket<K, V, M> {
+ Bucket {
+ raw: self.raw,
+ table: self.table,
+ }
+ }
+
+ pub fn gap_peek(self) -> Result<GapThenFull<K, V, M>, Bucket<K, V, M>> {
+ let gap = EmptyBucket {
+ raw: self.raw,
+ table: (),
+ };
+
+ match self.next().peek() {
+ Full(bucket) => {
+ Ok(GapThenFull {
+ gap,
+ full: bucket,
+ })
+ }
+ Empty(e) => Err(e.into_bucket()),
+ }
+ }
+}
+
+impl<K, V, M> EmptyBucket<K, V, M>
+ where M: Put<K, V>
+{
+ /// Puts given key and value pair, along with the key's hash,
+ /// into this bucket in the hashtable. Note how `self` is 'moved' into
+ /// this function, because this slot will no longer be empty when
+ /// we return! A `FullBucket` is returned for later use, pointing to
+ /// the newly-filled slot in the hashtable.
+ ///
+ /// Use `make_hash` to construct a `SafeHash` to pass to this function.
+ pub fn put(mut self, hash: SafeHash, key: K, value: V) -> FullBucket<K, V, M> {
+ unsafe {
+ *self.raw.hash() = hash.inspect();
+ ptr::write(self.raw.pair(), (key, value));
+
+ self.table.borrow_table_mut().size += 1;
+ }
+
+ FullBucket {
+ raw: self.raw,
+ table: self.table,
+ }
+ }
+}
+
+impl<K, V, M: Deref<Target = RawTable<K, V>>> FullBucket<K, V, M> {
+ #[inline]
+ pub fn next(self) -> Bucket<K, V, M> {
+ let mut bucket = self.into_bucket();
+ bucket.next();
+ bucket
+ }
+
+ #[inline]
+ pub fn into_bucket(self) -> Bucket<K, V, M> {
+ Bucket {
+ raw: self.raw,
+ table: self.table,
+ }
+ }
+
+ /// Duplicates the current position. This can be useful for operations
+ /// on two or more buckets.
+ pub fn stash(self) -> FullBucket<K, V, Self> {
+ FullBucket {
+ raw: self.raw,
+ table: self,
+ }
+ }
+
+ /// Gets the distance between this bucket and the 'ideal' location
+ /// as determined by the key's hash stored in it.
+ ///
+ /// In the cited blog posts above, this is called the "distance to
+ /// initial bucket", or DIB. Also known as "probe count".
+ pub fn displacement(&self) -> usize {
+ // Calculates the distance one has to travel when going from
+ // `hash mod capacity` onwards to `idx mod capacity`, wrapping around
+ // if the destination is not reached before the end of the table.
+ (self.raw.idx.wrapping_sub(self.hash().inspect() as usize)) & self.table.capacity_mask
+ }
+
+ #[inline]
+ pub fn hash(&self) -> SafeHash {
+ unsafe { SafeHash { hash: *self.raw.hash() } }
+ }
+
+ /// Gets references to the key and value at a given index.
+ pub fn read(&self) -> (&K, &V) {
+ unsafe {
+ let pair_ptr = self.raw.pair();
+ (&(*pair_ptr).0, &(*pair_ptr).1)
+ }
+ }
+}
+
+// We take a mutable reference to the table instead of accepting anything that
+// implements `DerefMut` to prevent fn `take` from being called on `stash`ed
+// buckets.
+impl<'t, K, V> FullBucket<K, V, &'t mut RawTable<K, V>> {
+ /// Removes this bucket's key and value from the hashtable.
+ ///
+ /// This works similarly to `put`, building an `EmptyBucket` out of the
+ /// taken bucket.
+ pub fn take(self) -> (EmptyBucket<K, V, &'t mut RawTable<K, V>>, K, V) {
+ self.table.size -= 1;
+
+ unsafe {
+ *self.raw.hash() = EMPTY_BUCKET;
+ let (k, v) = ptr::read(self.raw.pair());
+ (EmptyBucket {
+ raw: self.raw,
+ table: self.table,
+ },
+ k,
+ v)
+ }
+ }
+}
+
+// This use of `Put` is misleading and restrictive, but safe and sufficient for our use cases
+// where `M` is a full bucket or table reference type with mutable access to the table.
+impl<K, V, M> FullBucket<K, V, M>
+ where M: Put<K, V>
+{
+ pub fn replace(&mut self, h: SafeHash, k: K, v: V) -> (SafeHash, K, V) {
+ unsafe {
+ let old_hash = ptr::replace(self.raw.hash() as *mut SafeHash, h);
+ let (old_key, old_val) = ptr::replace(self.raw.pair(), (k, v));
+
+ (old_hash, old_key, old_val)
+ }
+ }
+}
+
+impl<K, V, M> FullBucket<K, V, M>
+ where M: Deref<Target = RawTable<K, V>> + DerefMut
+{
+ /// Gets mutable references to the key and value at a given index.
+ pub fn read_mut(&mut self) -> (&mut K, &mut V) {
+ unsafe {
+ let pair_ptr = self.raw.pair();
+ (&mut (*pair_ptr).0, &mut (*pair_ptr).1)
+ }
+ }
+}
+
+impl<'t, K, V, M> FullBucket<K, V, M>
+ where M: Deref<Target = RawTable<K, V>> + 't
+{
+ /// Exchange a bucket state for immutable references into the table.
+ /// Because the underlying reference to the table is also consumed,
+ /// no further changes to the structure of the table are possible;
+ /// in exchange for this, the returned references have a longer lifetime
+ /// than the references returned by `read()`.
+ pub fn into_refs(self) -> (&'t K, &'t V) {
+ unsafe {
+ let pair_ptr = self.raw.pair();
+ (&(*pair_ptr).0, &(*pair_ptr).1)
+ }
+ }
+}
+
+impl<'t, K, V, M> FullBucket<K, V, M>
+ where M: Deref<Target = RawTable<K, V>> + DerefMut + 't
+{
+ /// This works similarly to `into_refs`, exchanging a bucket state
+ /// for mutable references into the table.
+ pub fn into_mut_refs(self) -> (&'t mut K, &'t mut V) {
+ unsafe {
+ let pair_ptr = self.raw.pair();
+ (&mut (*pair_ptr).0, &mut (*pair_ptr).1)
+ }
+ }
+}
+
+impl<K, V, M> GapThenFull<K, V, M>
+ where M: Deref<Target = RawTable<K, V>>
+{
+ #[inline]
+ pub fn full(&self) -> &FullBucket<K, V, M> {
+ &self.full
+ }
+
+ pub fn into_table(self) -> M {
+ self.full.into_table()
+ }
+
+ pub fn shift(mut self) -> Result<GapThenFull<K, V, M>, Bucket<K, V, M>> {
+ unsafe {
+ let (gap_hash, gap_pair) = self.gap.raw.hash_pair();
+ let (full_hash, full_pair) = self.full.raw.hash_pair();
+ *gap_hash = mem::replace(&mut *full_hash, EMPTY_BUCKET);
+ ptr::copy_nonoverlapping(full_pair, gap_pair, 1);
+ }
+
+ let FullBucket { raw: prev_raw, .. } = self.full;
+
+ match self.full.next().peek() {
+ Full(bucket) => {
+ self.gap.raw = prev_raw;
+
+ self.full = bucket;
+
+ Ok(self)
+ }
+ Empty(b) => Err(b.into_bucket()),
+ }
+ }
+}
+
+// Returns a Layout which describes the allocation required for a hash table,
+// and the offset of the array of (key, value) pairs in the allocation.
+#[inline(always)]
+fn calculate_layout<K, V>(capacity: usize) -> Result<(Layout, usize), LayoutErr> {
+ let hashes = Layout::array::<HashUint>(capacity)?;
+ let pairs = Layout::array::<(K, V)>(capacity)?;
+ hashes.extend(pairs).map(|(layout, _)| {
+ // LLVM seems to have trouble properly const-propagating pairs.align(),
+ // possibly due to the use of NonZeroUsize. This little hack allows it
+ // to generate optimal code.
+ //
+ // See https://github.com/rust-lang/rust/issues/51346 for more details.
+ (
+ layout,
+ hashes.size() + hashes.padding_needed_for(mem::align_of::<(K, V)>()),
+ )
+ })
+}
+
+pub(crate) enum Fallibility {
+ Fallible,
+ Infallible,
+}
+
+use self::Fallibility::*;
+
+impl<K, V> RawTable<K, V> {
+ /// Does not initialize the buckets. The caller should ensure they,
+ /// at the very least, set every hash to EMPTY_BUCKET.
+ /// Returns an error if it cannot allocate or capacity overflows.
+ unsafe fn new_uninitialized_internal(
+ capacity: usize,
+ fallibility: Fallibility,
+ ) -> Result<RawTable<K, V>, CollectionAllocErr> {
+ if capacity == 0 {
+ return Ok(RawTable {
+ size: 0,
+ capacity_mask: capacity.wrapping_sub(1),
+ hashes: TaggedHashUintPtr::new(EMPTY as *mut HashUint),
+ marker: marker::PhantomData,
+ });
+ }
+
+ // Allocating hashmaps is a little tricky. We need to allocate two
+ // arrays, but since we know their sizes and alignments up front,
+ // we just allocate a single array, and then have the subarrays
+ // point into it.
+ let (layout, _) = calculate_layout::<K, V>(capacity)?;
+ let buffer = Global.alloc(layout).map_err(|e| match fallibility {
+ Infallible => handle_alloc_error(layout),
+ Fallible => e,
+ })?;
+
+ Ok(RawTable {
+ capacity_mask: capacity.wrapping_sub(1),
+ size: 0,
+ hashes: TaggedHashUintPtr::new(buffer.cast().as_ptr()),
+ marker: marker::PhantomData,
+ })
+ }
+
+ /// Does not initialize the buckets. The caller should ensure they,
+ /// at the very least, set every hash to EMPTY_BUCKET.
+ unsafe fn new_uninitialized(capacity: usize) -> RawTable<K, V> {
+ match Self::new_uninitialized_internal(capacity, Infallible) {
+ Err(CollectionAllocErr::CapacityOverflow) => panic!("capacity overflow"),
+ Err(CollectionAllocErr::AllocErr) => unreachable!(),
+ Ok(table) => { table }
+ }
+ }
+
+ #[inline(always)]
+ fn raw_bucket_at(&self, index: usize) -> RawBucket<K, V> {
+ let (_, pairs_offset) = calculate_layout::<K, V>(self.capacity())
+ .unwrap_or_else(|_| unsafe { hint::unreachable_unchecked() });
+ let buffer = self.hashes.ptr() as *mut u8;
+ unsafe {
+ RawBucket {
+ hash_start: buffer as *mut HashUint,
+ pair_start: buffer.add(pairs_offset) as *const (K, V),
+ idx: index,
+ _marker: marker::PhantomData,
+ }
+ }
+ }
+
+ #[inline]
+ fn new_internal(
+ capacity: usize,
+ fallibility: Fallibility,
+ ) -> Result<RawTable<K, V>, CollectionAllocErr> {
+ unsafe {
+ let ret = RawTable::new_uninitialized_internal(capacity, fallibility)?;
+ if capacity > 0 {
+ ptr::write_bytes(ret.hashes.ptr(), 0, capacity);
+ }
+ Ok(ret)
+ }
+ }
+
+ /// Tries to create a new raw table from a given capacity. If it cannot allocate,
+ /// it returns with AllocErr.
+ #[inline]
+ pub fn try_new(capacity: usize) -> Result<RawTable<K, V>, CollectionAllocErr> {
+ Self::new_internal(capacity, Fallible)
+ }
+
+ /// Creates a new raw table from a given capacity. All buckets are
+ /// initially empty.
+ #[inline]
+ pub fn new(capacity: usize) -> RawTable<K, V> {
+ match Self::new_internal(capacity, Infallible) {
+ Err(CollectionAllocErr::CapacityOverflow) => panic!("capacity overflow"),
+ Err(CollectionAllocErr::AllocErr) => unreachable!(),
+ Ok(table) => { table }
+ }
+ }
+
+ /// The hashtable's capacity, similar to a vector's.
+ pub fn capacity(&self) -> usize {
+ self.capacity_mask.wrapping_add(1)
+ }
+
+ /// The number of elements ever `put` in the hashtable, minus the number
+ /// of elements ever `take`n.
+ pub fn size(&self) -> usize {
+ self.size
+ }
+
+ fn raw_buckets(&self) -> RawBuckets<'_, K, V> {
+ RawBuckets {
+ raw: self.raw_bucket_at(0),
+ elems_left: self.size,
+ marker: marker::PhantomData,
+ }
+ }
+
+ pub fn iter(&self) -> Iter<'_, K, V> {
+ Iter {
+ iter: self.raw_buckets(),
+ }
+ }
+
+ pub fn iter_mut(&mut self) -> IterMut<'_, K, V> {
+ IterMut {
+ iter: self.raw_buckets(),
+ _marker: marker::PhantomData,
+ }
+ }
+
+ pub fn into_iter(self) -> IntoIter<K, V> {
+ let RawBuckets { raw, elems_left, .. } = self.raw_buckets();
+ // Replace the marker regardless of lifetime bounds on parameters.
+ IntoIter {
+ iter: RawBuckets {
+ raw,
+ elems_left,
+ marker: marker::PhantomData,
+ },
+ table: self,
+ }
+ }
+
+ pub fn drain(&mut self) -> Drain<'_, K, V> {
+ let RawBuckets { raw, elems_left, .. } = self.raw_buckets();
+ // Replace the marker regardless of lifetime bounds on parameters.
+ Drain {
+ iter: RawBuckets {
+ raw,
+ elems_left,
+ marker: marker::PhantomData,
+ },
+ table: NonNull::from(self),
+ marker: marker::PhantomData,
+ }
+ }
+
+ /// Drops buckets in reverse order. It leaves the table in an inconsistent
+ /// state and should only be used for dropping the table's remaining
+ /// entries. It's used in the implementation of Drop.
+ unsafe fn rev_drop_buckets(&mut self) {
+ // initialize the raw bucket past the end of the table
+ let mut raw = self.raw_bucket_at(self.capacity());
+ let mut elems_left = self.size;
+
+ while elems_left != 0 {
+ raw.idx -= 1;
+
+ if *raw.hash() != EMPTY_BUCKET {
+ elems_left -= 1;
+ ptr::drop_in_place(raw.pair());
+ }
+ }
+ }
+
+ /// Sets the table tag.
+ pub fn set_tag(&mut self, value: bool) {
+ self.hashes.set_tag(value)
+ }
+
+ /// Gets the table tag.
+ pub fn tag(&self) -> bool {
+ self.hashes.tag()
+ }
+}
+
+/// A raw iterator. The basis for some other iterators in this module. Although
+/// this interface is safe, it's not used outside this module.
+struct RawBuckets<'a, K, V> {
+ raw: RawBucket<K, V>,
+ elems_left: usize,
+
+ // Strictly speaking, this should be &'a (K,V), but that would
+ // require that K:'a, and we often use RawBuckets<'static...> for
+ // move iterations, so that messes up a lot of other things. So
+ // just use `&'a (K,V)` as this is not a publicly exposed type
+ // anyway.
+ marker: marker::PhantomData<&'a ()>,
+}
+
+// FIXME(#26925) Remove in favor of `#[derive(Clone)]`
+impl<K, V> Clone for RawBuckets<'_, K, V> {
+ fn clone(&self) -> Self {
+ RawBuckets {
+ raw: self.raw,
+ elems_left: self.elems_left,
+ marker: marker::PhantomData,
+ }
+ }
+}
+
+
+impl<'a, K, V> Iterator for RawBuckets<'a, K, V> {
+ type Item = RawBucket<K, V>;
+
+ fn next(&mut self) -> Option<RawBucket<K, V>> {
+ if self.elems_left == 0 {
+ return None;
+ }
+
+ loop {
+ unsafe {
+ let item = self.raw;
+ self.raw.idx += 1;
+ if *item.hash() != EMPTY_BUCKET {
+ self.elems_left -= 1;
+ return Some(item);
+ }
+ }
+ }
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ (self.elems_left, Some(self.elems_left))
+ }
+}
+
+impl<K, V> ExactSizeIterator for RawBuckets<'_, K, V> {
+ fn len(&self) -> usize {
+ self.elems_left
+ }
+}
+
+/// Iterator over shared references to entries in a table.
+pub struct Iter<'a, K: 'a, V: 'a> {
+ iter: RawBuckets<'a, K, V>,
+}
+
+unsafe impl<K: Sync, V: Sync> Sync for Iter<'_, K, V> {}
+unsafe impl<K: Sync, V: Sync> Send for Iter<'_, K, V> {}
+
+// FIXME(#26925) Remove in favor of `#[derive(Clone)]`
+impl<K, V> Clone for Iter<'_, K, V> {
+ fn clone(&self) -> Self {
+ Iter {
+ iter: self.iter.clone(),
+ }
+ }
+}
+
+/// Iterator over mutable references to entries in a table.
+pub struct IterMut<'a, K: 'a, V: 'a> {
+ iter: RawBuckets<'a, K, V>,
+ // To ensure invariance with respect to V
+ _marker: marker::PhantomData<&'a mut V>,
+}
+
+unsafe impl<K: Sync, V: Sync> Sync for IterMut<'_, K, V> {}
+// Both K: Sync and K: Send are correct for IterMut's Send impl,
+// but Send is the more useful bound
+unsafe impl<K: Send, V: Send> Send for IterMut<'_, K, V> {}
+
+impl<'a, K: 'a, V: 'a> IterMut<'a, K, V> {
+ pub fn iter(&self) -> Iter<'_, K, V> {
+ Iter {
+ iter: self.iter.clone(),
+ }
+ }
+}
+
+/// Iterator over the entries in a table, consuming the table.
+pub struct IntoIter<K, V> {
+ table: RawTable<K, V>,
+ iter: RawBuckets<'static, K, V>,
+}
+
+unsafe impl<K: Sync, V: Sync> Sync for IntoIter<K, V> {}
+unsafe impl<K: Send, V: Send> Send for IntoIter<K, V> {}
+
+impl<K, V> IntoIter<K, V> {
+ pub fn iter(&self) -> Iter<'_, K, V> {
+ Iter {
+ iter: self.iter.clone(),
+ }
+ }
+}
+
+/// Iterator over the entries in a table, clearing the table.
+pub struct Drain<'a, K: 'a, V: 'a> {
+ table: NonNull<RawTable<K, V>>,
+ iter: RawBuckets<'static, K, V>,
+ marker: marker::PhantomData<&'a RawTable<K, V>>,
+}
+
+unsafe impl<K: Sync, V: Sync> Sync for Drain<'_, K, V> {}
+unsafe impl<K: Send, V: Send> Send for Drain<'_, K, V> {}
+
+impl<'a, K, V> Drain<'a, K, V> {
+ pub fn iter(&self) -> Iter<'_, K, V> {
+ Iter {
+ iter: self.iter.clone(),
+ }
+ }
+}
+
+impl<'a, K, V> Iterator for Iter<'a, K, V> {
+ type Item = (&'a K, &'a V);
+
+ fn next(&mut self) -> Option<(&'a K, &'a V)> {
+ self.iter.next().map(|raw| unsafe {
+ let pair_ptr = raw.pair();
+ (&(*pair_ptr).0, &(*pair_ptr).1)
+ })
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ self.iter.size_hint()
+ }
+}
+
+impl<K, V> ExactSizeIterator for Iter<'_, K, V> {
+ fn len(&self) -> usize {
+ self.iter.len()
+ }
+}
+
+impl<'a, K, V> Iterator for IterMut<'a, K, V> {
+ type Item = (&'a K, &'a mut V);
+
+ fn next(&mut self) -> Option<(&'a K, &'a mut V)> {
+ self.iter.next().map(|raw| unsafe {
+ let pair_ptr = raw.pair();
+ (&(*pair_ptr).0, &mut (*pair_ptr).1)
+ })
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ self.iter.size_hint()
+ }
+}
+
+impl<K, V> ExactSizeIterator for IterMut<'_, K, V> {
+ fn len(&self) -> usize {
+ self.iter.len()
+ }
+}
+
+impl<K, V> Iterator for IntoIter<K, V> {
+ type Item = (SafeHash, K, V);
+
+ fn next(&mut self) -> Option<(SafeHash, K, V)> {
+ self.iter.next().map(|raw| {
+ self.table.size -= 1;
+ unsafe {
+ let (k, v) = ptr::read(raw.pair());
+ (SafeHash { hash: *raw.hash() }, k, v)
+ }
+ })
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ self.iter.size_hint()
+ }
+}
+
+impl<K, V> ExactSizeIterator for IntoIter<K, V> {
+ fn len(&self) -> usize {
+ self.iter().len()
+ }
+}
+
+impl<'a, K, V> Iterator for Drain<'a, K, V> {
+ type Item = (SafeHash, K, V);
+
+ #[inline]
+ fn next(&mut self) -> Option<(SafeHash, K, V)> {
+ self.iter.next().map(|raw| {
+ unsafe {
+ self.table.as_mut().size -= 1;
+ let (k, v) = ptr::read(raw.pair());
+ (SafeHash { hash: ptr::replace(&mut *raw.hash(), EMPTY_BUCKET) }, k, v)
+ }
+ })
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ self.iter.size_hint()
+ }
+}
+
+impl<K, V> ExactSizeIterator for Drain<'_, K, V> {
+ fn len(&self) -> usize {
+ self.iter.len()
+ }
+}
+
+impl<K, V> Drop for Drain<'_, K, V> {
+ fn drop(&mut self) {
+ self.for_each(drop);
+ }
+}
+
+impl<K: Clone, V: Clone> Clone for RawTable<K, V> {
+ fn clone(&self) -> RawTable<K, V> {
+ unsafe {
+ let cap = self.capacity();
+ let mut new_ht = RawTable::new_uninitialized(cap);
+
+ let mut new_buckets = new_ht.raw_bucket_at(0);
+ let mut buckets = self.raw_bucket_at(0);
+ while buckets.idx < cap {
+ *new_buckets.hash() = *buckets.hash();
+ if *new_buckets.hash() != EMPTY_BUCKET {
+ let pair_ptr = buckets.pair();
+ let kv = ((*pair_ptr).0.clone(), (*pair_ptr).1.clone());
+ ptr::write(new_buckets.pair(), kv);
+ }
+ buckets.idx += 1;
+ new_buckets.idx += 1;
+ }
+
+ new_ht.size = self.size();
+ new_ht.set_tag(self.tag());
+
+ new_ht
+ }
+ }
+}
+
+unsafe impl<#[may_dangle] K, #[may_dangle] V> Drop for RawTable<K, V> {
+ fn drop(&mut self) {
+ if self.capacity() == 0 {
+ return;
+ }
+
+ // This is done in reverse because we've likely partially taken
+ // some elements out with `.into_iter()` from the front.
+ // Check if the size is 0, so we don't do a useless scan when
+ // dropping empty tables such as on resize.
+ // Also avoid double drop of elements that have been already moved out.
+ unsafe {
+ if needs_drop::<(K, V)>() {
+ // avoid linear runtime for types that don't need drop
+ self.rev_drop_buckets();
+ }
+ }
+
+ let (layout, _) = calculate_layout::<K, V>(self.capacity())
+ .unwrap_or_else(|_| unsafe { hint::unreachable_unchecked() });
+ unsafe {
+ Global.dealloc(NonNull::new_unchecked(self.hashes.ptr()).cast(), layout);
+ // Remember how everything was allocated out of one buffer
+ // during initialization? We only need one call to free here.
+ }
+ }
+}
diff --git a/src/libstd/collections/mod.rs b/src/libstd/collections/mod.rs
new file mode 100644
index 0000000..286ce2d
--- /dev/null
+++ b/src/libstd/collections/mod.rs
@@ -0,0 +1,447 @@
+//! Collection types.
+//!
+//! Rust's standard collection library provides efficient implementations of the
+//! most common general purpose programming data structures. By using the
+//! standard implementations, it should be possible for two libraries to
+//! communicate without significant data conversion.
+//!
+//! To get this out of the way: you should probably just use [`Vec`] or [`HashMap`].
+//! These two collections cover most use cases for generic data storage and
+//! processing. They are exceptionally good at doing what they do. All the other
+//! collections in the standard library have specific use cases where they are
+//! the optimal choice, but these cases are borderline *niche* in comparison.
+//! Even when `Vec` and `HashMap` are technically suboptimal, they're probably a
+//! good enough choice to get started.
+//!
+//! Rust's collections can be grouped into four major categories:
+//!
+//! * Sequences: [`Vec`], [`VecDeque`], [`LinkedList`]
+//! * Maps: [`HashMap`], [`BTreeMap`]
+//! * Sets: [`HashSet`], [`BTreeSet`]
+//! * Misc: [`BinaryHeap`]
+//!
+//! # When Should You Use Which Collection?
+//!
+//! These are fairly high-level and quick break-downs of when each collection
+//! should be considered. Detailed discussions of strengths and weaknesses of
+//! individual collections can be found on their own documentation pages.
+//!
+//! ### Use a `Vec` when:
+//! * You want to collect items up to be processed or sent elsewhere later, and
+//! don't care about any properties of the actual values being stored.
+//! * You want a sequence of elements in a particular order, and will only be
+//! appending to (or near) the end.
+//! * You want a stack.
+//! * You want a resizable array.
+//! * You want a heap-allocated array.
+//!
+//! ### Use a `VecDeque` when:
+//! * You want a [`Vec`] that supports efficient insertion at both ends of the
+//! sequence.
+//! * You want a queue.
+//! * You want a double-ended queue (deque).
+//!
+//! ### Use a `LinkedList` when:
+//! * You want a [`Vec`] or [`VecDeque`] of unknown size, and can't tolerate
+//! amortization.
+//! * You want to efficiently split and append lists.
+//! * You are *absolutely* certain you *really*, *truly*, want a doubly linked
+//! list.
+//!
+//! ### Use a `HashMap` when:
+//! * You want to associate arbitrary keys with an arbitrary value.
+//! * You want a cache.
+//! * You want a map, with no extra functionality.
+//!
+//! ### Use a `BTreeMap` when:
+//! * You want a map sorted by its keys.
+//! * You want to be able to get a range of entries on-demand.
+//! * You're interested in what the smallest or largest key-value pair is.
+//! * You want to find the largest or smallest key that is smaller or larger
+//! than something.
+//!
+//! ### Use the `Set` variant of any of these `Map`s when:
+//! * You just want to remember which keys you've seen.
+//! * There is no meaningful value to associate with your keys.
+//! * You just want a set.
+//!
+//! ### Use a `BinaryHeap` when:
+//!
+//! * You want to store a bunch of elements, but only ever want to process the
+//! "biggest" or "most important" one at any given time.
+//! * You want a priority queue.
+//!
+//! # Performance
+//!
+//! Choosing the right collection for the job requires an understanding of what
+//! each collection is good at. Here we briefly summarize the performance of
+//! different collections for certain important operations. For further details,
+//! see each type's documentation, and note that the names of actual methods may
+//! differ from the tables below on certain collections.
+//!
+//! Throughout the documentation, we will follow a few conventions. For all
+//! operations, the collection's size is denoted by n. If another collection is
+//! involved in the operation, it contains m elements. Operations which have an
+//! *amortized* cost are suffixed with a `*`. Operations with an *expected*
+//! cost are suffixed with a `~`.
+//!
+//! All amortized costs are for the potential need to resize when capacity is
+//! exhausted. If a resize occurs it will take O(n) time. Our collections never
+//! automatically shrink, so removal operations aren't amortized. Over a
+//! sufficiently large series of operations, the average cost per operation will
+//! deterministically equal the given cost.
+//!
+//! Only [`HashMap`] has expected costs, due to the probabilistic nature of hashing.
+//! It is theoretically possible, though very unlikely, for [`HashMap`] to
+//! experience worse performance.
+//!
+//! ## Sequences
+//!
+//! | | get(i) | insert(i) | remove(i) | append | split_off(i) |
+//! |----------------|----------------|-----------------|----------------|--------|----------------|
+//! | [`Vec`] | O(1) | O(n-i)* | O(n-i) | O(m)* | O(n-i) |
+//! | [`VecDeque`] | O(1) | O(min(i, n-i))* | O(min(i, n-i)) | O(m)* | O(min(i, n-i)) |
+//! | [`LinkedList`] | O(min(i, n-i)) | O(min(i, n-i)) | O(min(i, n-i)) | O(1) | O(min(i, n-i)) |
+//!
+//! Note that where ties occur, [`Vec`] is generally going to be faster than [`VecDeque`], and
+//! [`VecDeque`] is generally going to be faster than [`LinkedList`].
+//!
+//! ## Maps
+//!
+//! For Sets, all operations have the cost of the equivalent Map operation.
+//!
+//! | | get | insert | remove | predecessor | append |
+//! |--------------|-----------|----------|----------|-------------|--------|
+//! | [`HashMap`] | O(1)~ | O(1)~* | O(1)~ | N/A | N/A |
+//! | [`BTreeMap`] | O(log n) | O(log n) | O(log n) | O(log n) | O(n+m) |
+//!
+//! # Correct and Efficient Usage of Collections
+//!
+//! Of course, knowing which collection is the right one for the job doesn't
+//! instantly permit you to use it correctly. Here are some quick tips for
+//! efficient and correct usage of the standard collections in general. If
+//! you're interested in how to use a specific collection in particular, consult
+//! its documentation for detailed discussion and code examples.
+//!
+//! ## Capacity Management
+//!
+//! Many collections provide several constructors and methods that refer to
+//! "capacity". These collections are generally built on top of an array.
+//! Optimally, this array would be exactly the right size to fit only the
+//! elements stored in the collection, but for the collection to do this would
+//! be very inefficient. If the backing array was exactly the right size at all
+//! times, then every time an element is inserted, the collection would have to
+//! grow the array to fit it. Due to the way memory is allocated and managed on
+//! most computers, this would almost surely require allocating an entirely new
+//! array and copying every single element from the old one into the new one.
+//! Hopefully you can see that this wouldn't be very efficient to do on every
+//! operation.
+//!
+//! Most collections therefore use an *amortized* allocation strategy. They
+//! generally let themselves have a fair amount of unoccupied space so that they
+//! only have to grow on occasion. When they do grow, they allocate a
+//! substantially larger array to move the elements into so that it will take a
+//! while for another grow to be required. While this strategy is great in
+//! general, it would be even better if the collection *never* had to resize its
+//! backing array. Unfortunately, the collection itself doesn't have enough
+//! information to do this itself. Therefore, it is up to us programmers to give
+//! it hints.
+//!
+//! Any `with_capacity` constructor will instruct the collection to allocate
+//! enough space for the specified number of elements. Ideally this will be for
+//! exactly that many elements, but some implementation details may prevent
+//! this. [`Vec`] and [`VecDeque`] can be relied on to allocate exactly the
+//! requested amount, though. Use `with_capacity` when you know exactly how many
+//! elements will be inserted, or at least have a reasonable upper-bound on that
+//! number.
+//!
+//! When anticipating a large influx of elements, the `reserve` family of
+//! methods can be used to hint to the collection how much room it should make
+//! for the coming items. As with `with_capacity`, the precise behavior of
+//! these methods will be specific to the collection of interest.
+//!
+//! For optimal performance, collections will generally avoid shrinking
+//! themselves. If you believe that a collection will not soon contain any more
+//! elements, or just really need the memory, the `shrink_to_fit` method prompts
+//! the collection to shrink the backing array to the minimum size capable of
+//! holding its elements.
+//!
+//! Finally, if ever you're interested in what the actual capacity of the
+//! collection is, most collections provide a `capacity` method to query this
+//! information on demand. This can be useful for debugging purposes, or for
+//! use with the `reserve` methods.
+//!
+//! ## Iterators
+//!
+//! Iterators are a powerful and robust mechanism used throughout Rust's
+//! standard libraries. Iterators provide a sequence of values in a generic,
+//! safe, efficient and convenient way. The contents of an iterator are usually
+//! *lazily* evaluated, so that only the values that are actually needed are
+//! ever actually produced, and no allocation need be done to temporarily store
+//! them. Iterators are primarily consumed using a `for` loop, although many
+//! functions also take iterators where a collection or sequence of values is
+//! desired.
+//!
+//! All of the standard collections provide several iterators for performing
+//! bulk manipulation of their contents. The three primary iterators almost
+//! every collection should provide are `iter`, `iter_mut`, and `into_iter`.
+//! Some of these are not provided on collections where it would be unsound or
+//! unreasonable to provide them.
+//!
+//! `iter` provides an iterator of immutable references to all the contents of a
+//! collection in the most "natural" order. For sequence collections like [`Vec`],
+//! this means the items will be yielded in increasing order of index starting
+//! at 0. For ordered collections like [`BTreeMap`], this means that the items
+//! will be yielded in sorted order. For unordered collections like [`HashMap`],
+//! the items will be yielded in whatever order the internal representation made
+//! most convenient. This is great for reading through all the contents of the
+//! collection.
+//!
+//! ```
+//! let vec = vec![1, 2, 3, 4];
+//! for x in vec.iter() {
+//! println!("vec contained {}", x);
+//! }
+//! ```
+//!
+//! `iter_mut` provides an iterator of *mutable* references in the same order as
+//! `iter`. This is great for mutating all the contents of the collection.
+//!
+//! ```
+//! let mut vec = vec![1, 2, 3, 4];
+//! for x in vec.iter_mut() {
+//! *x += 1;
+//! }
+//! ```
+//!
+//! `into_iter` transforms the actual collection into an iterator over its
+//! contents by-value. This is great when the collection itself is no longer
+//! needed, and the values are needed elsewhere. Using `extend` with `into_iter`
+//! is the main way that contents of one collection are moved into another.
+//! `extend` automatically calls `into_iter`, and takes any `T: `[`IntoIterator`].
+//! Calling `collect` on an iterator itself is also a great way to convert one
+//! collection into another. Both of these methods should internally use the
+//! capacity management tools discussed in the previous section to do this as
+//! efficiently as possible.
+//!
+//! ```
+//! let mut vec1 = vec![1, 2, 3, 4];
+//! let vec2 = vec![10, 20, 30, 40];
+//! vec1.extend(vec2);
+//! ```
+//!
+//! ```
+//! use std::collections::VecDeque;
+//!
+//! let vec = vec![1, 2, 3, 4];
+//! let buf: VecDeque<_> = vec.into_iter().collect();
+//! ```
+//!
+//! Iterators also provide a series of *adapter* methods for performing common
+//! threads to sequences. Among the adapters are functional favorites like `map`,
+//! `fold`, `skip` and `take`. Of particular interest to collections is the
+//! `rev` adapter, that reverses any iterator that supports this operation. Most
+//! collections provide reversible iterators as the way to iterate over them in
+//! reverse order.
+//!
+//! ```
+//! let vec = vec![1, 2, 3, 4];
+//! for x in vec.iter().rev() {
+//! println!("vec contained {}", x);
+//! }
+//! ```
+//!
+//! Several other collection methods also return iterators to yield a sequence
+//! of results but avoid allocating an entire collection to store the result in.
+//! This provides maximum flexibility as `collect` or `extend` can be called to
+//! "pipe" the sequence into any collection if desired. Otherwise, the sequence
+//! can be looped over with a `for` loop. The iterator can also be discarded
+//! after partial use, preventing the computation of the unused items.
+//!
+//! ## Entries
+//!
+//! The `entry` API is intended to provide an efficient mechanism for
+//! manipulating the contents of a map conditionally on the presence of a key or
+//! not. The primary motivating use case for this is to provide efficient
+//! accumulator maps. For instance, if one wishes to maintain a count of the
+//! number of times each key has been seen, they will have to perform some
+//! conditional logic on whether this is the first time the key has been seen or
+//! not. Normally, this would require a `find` followed by an `insert`,
+//! effectively duplicating the search effort on each insertion.
+//!
+//! When a user calls `map.entry(&key)`, the map will search for the key and
+//! then yield a variant of the `Entry` enum.
+//!
+//! If a `Vacant(entry)` is yielded, then the key *was not* found. In this case
+//! the only valid operation is to `insert` a value into the entry. When this is
+//! done, the vacant entry is consumed and converted into a mutable reference to
+//! the value that was inserted. This allows for further manipulation of the
+//! value beyond the lifetime of the search itself. This is useful if complex
+//! logic needs to be performed on the value regardless of whether the value was
+//! just inserted.
+//!
+//! If an `Occupied(entry)` is yielded, then the key *was* found. In this case,
+//! the user has several options: they can `get`, `insert` or `remove` the
+//! value of the occupied entry. Additionally, they can convert the occupied
+//! entry into a mutable reference to its value, providing symmetry to the
+//! vacant `insert` case.
+//!
+//! ### Examples
+//!
+//! Here are the two primary ways in which `entry` is used. First, a simple
+//! example where the logic performed on the values is trivial.
+//!
+//! #### Counting the number of times each character in a string occurs
+//!
+//! ```
+//! use std::collections::btree_map::BTreeMap;
+//!
+//! let mut count = BTreeMap::new();
+//! let message = "she sells sea shells by the sea shore";
+//!
+//! for c in message.chars() {
+//! *count.entry(c).or_insert(0) += 1;
+//! }
+//!
+//! assert_eq!(count.get(&'s'), Some(&8));
+//!
+//! println!("Number of occurrences of each character");
+//! for (char, count) in &count {
+//! println!("{}: {}", char, count);
+//! }
+//! ```
+//!
+//! When the logic to be performed on the value is more complex, we may simply
+//! use the `entry` API to ensure that the value is initialized and perform the
+//! logic afterwards.
+//!
+//! #### Tracking the inebriation of customers at a bar
+//!
+//! ```
+//! use std::collections::btree_map::BTreeMap;
+//!
+//! // A client of the bar. They have a blood alcohol level.
+//! struct Person { blood_alcohol: f32 }
+//!
+//! // All the orders made to the bar, by client ID.
+//! let orders = vec![1, 2, 1, 2, 3, 4, 1, 2, 2, 3, 4, 1, 1, 1];
+//!
+//! // Our clients.
+//! let mut blood_alcohol = BTreeMap::new();
+//!
+//! for id in orders {
+//! // If this is the first time we've seen this customer, initialize them
+//! // with no blood alcohol. Otherwise, just retrieve them.
+//! let person = blood_alcohol.entry(id).or_insert(Person { blood_alcohol: 0.0 });
+//!
+//! // Reduce their blood alcohol level. It takes time to order and drink a beer!
+//! person.blood_alcohol *= 0.9;
+//!
+//! // Check if they're sober enough to have another beer.
+//! if person.blood_alcohol > 0.3 {
+//! // Too drunk... for now.
+//! println!("Sorry {}, I have to cut you off", id);
+//! } else {
+//! // Have another!
+//! person.blood_alcohol += 0.1;
+//! }
+//! }
+//! ```
+//!
+//! # Insert and complex keys
+//!
+//! If we have a more complex key, calls to `insert` will
+//! not update the value of the key. For example:
+//!
+//! ```
+//! use std::cmp::Ordering;
+//! use std::collections::BTreeMap;
+//! use std::hash::{Hash, Hasher};
+//!
+//! #[derive(Debug)]
+//! struct Foo {
+//! a: u32,
+//! b: &'static str,
+//! }
+//!
+//! // we will compare `Foo`s by their `a` value only.
+//! impl PartialEq for Foo {
+//! fn eq(&self, other: &Self) -> bool { self.a == other.a }
+//! }
+//!
+//! impl Eq for Foo {}
+//!
+//! // we will hash `Foo`s by their `a` value only.
+//! impl Hash for Foo {
+//! fn hash<H: Hasher>(&self, h: &mut H) { self.a.hash(h); }
+//! }
+//!
+//! impl PartialOrd for Foo {
+//! fn partial_cmp(&self, other: &Self) -> Option<Ordering> { self.a.partial_cmp(&other.a) }
+//! }
+//!
+//! impl Ord for Foo {
+//! fn cmp(&self, other: &Self) -> Ordering { self.a.cmp(&other.a) }
+//! }
+//!
+//! let mut map = BTreeMap::new();
+//! map.insert(Foo { a: 1, b: "baz" }, 99);
+//!
+//! // We already have a Foo with an a of 1, so this will be updating the value.
+//! map.insert(Foo { a: 1, b: "xyz" }, 100);
+//!
+//! // The value has been updated...
+//! assert_eq!(map.values().next().unwrap(), &100);
+//!
+//! // ...but the key hasn't changed. b is still "baz", not "xyz".
+//! assert_eq!(map.keys().next().unwrap().b, "baz");
+//! ```
+//!
+//! [`Vec`]: ../../std/vec/struct.Vec.html
+//! [`HashMap`]: ../../std/collections/struct.HashMap.html
+//! [`VecDeque`]: ../../std/collections/struct.VecDeque.html
+//! [`LinkedList`]: ../../std/collections/struct.LinkedList.html
+//! [`BTreeMap`]: ../../std/collections/struct.BTreeMap.html
+//! [`HashSet`]: ../../std/collections/struct.HashSet.html
+//! [`BTreeSet`]: ../../std/collections/struct.BTreeSet.html
+//! [`BinaryHeap`]: ../../std/collections/struct.BinaryHeap.html
+//! [`IntoIterator`]: ../../std/iter/trait.IntoIterator.html
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_deprecated(reason = "moved to `std::ops::Bound`", since = "1.26.0")]
+#[doc(hidden)]
+pub use crate::ops::Bound;
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use alloc_crate::collections::{BinaryHeap, BTreeMap, BTreeSet};
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use alloc_crate::collections::{LinkedList, VecDeque};
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use alloc_crate::collections::{binary_heap, btree_map, btree_set};
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use alloc_crate::collections::{linked_list, vec_deque};
+
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use self::hash_map::HashMap;
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use self::hash_set::HashSet;
+
+#[unstable(feature = "try_reserve", reason = "new API", issue="48043")]
+pub use alloc_crate::collections::CollectionAllocErr;
+
+mod hash;
+
+#[stable(feature = "rust1", since = "1.0.0")]
+pub mod hash_map {
+ //! A hash map implemented with linear probing and Robin Hood bucket stealing.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub use super::hash::map::*;
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+pub mod hash_set {
+ //! A hash set implemented as a `HashMap` where the value is `()`.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub use super::hash::set::*;
+}
diff --git a/src/libstd/env.rs b/src/libstd/env.rs
new file mode 100644
index 0000000..01b301c
--- /dev/null
+++ b/src/libstd/env.rs
@@ -0,0 +1,1082 @@
+//! Inspection and manipulation of the process's environment.
+//!
+//! This module contains functions to inspect various aspects such as
+//! environment variables, process arguments, the current directory, and various
+//! other important directories.
+//!
+//! There are several functions and structs in this module that have a
+//! counterpart ending in `os`. Those ending in `os` will return an [`OsString`]
+//! and those without will be returning a [`String`].
+//!
+//! [`OsString`]: ../../std/ffi/struct.OsString.html
+//! [`String`]: ../string/struct.String.html
+
+#![stable(feature = "env", since = "1.0.0")]
+
+use crate::error::Error;
+use crate::ffi::{OsStr, OsString};
+use crate::fmt;
+use crate::io;
+use crate::path::{Path, PathBuf};
+use crate::sys;
+use crate::sys::os as os_imp;
+
+/// Returns the current working directory as a [`PathBuf`].
+///
+/// # Errors
+///
+/// Returns an [`Err`] if the current working directory value is invalid.
+/// Possible cases:
+///
+/// * Current directory does not exist.
+/// * There are insufficient permissions to access the current directory.
+///
+/// [`PathBuf`]: ../../std/path/struct.PathBuf.html
+/// [`Err`]: ../../std/result/enum.Result.html#method.err
+///
+/// # Examples
+///
+/// ```
+/// use std::env;
+///
+/// fn main() -> std::io::Result<()> {
+/// let path = env::current_dir()?;
+/// println!("The current directory is {}", path.display());
+/// Ok(())
+/// }
+/// ```
+#[stable(feature = "env", since = "1.0.0")]
+pub fn current_dir() -> io::Result<PathBuf> {
+ os_imp::getcwd()
+}
+
+/// Changes the current working directory to the specified path.
+///
+/// Returns an [`Err`] if the operation fails.
+///
+/// [`Err`]: ../../std/result/enum.Result.html#method.err
+///
+/// # Examples
+///
+/// ```
+/// use std::env;
+/// use std::path::Path;
+///
+/// let root = Path::new("/");
+/// assert!(env::set_current_dir(&root).is_ok());
+/// println!("Successfully changed working directory to {}!", root.display());
+/// ```
+#[stable(feature = "env", since = "1.0.0")]
+pub fn set_current_dir<P: AsRef<Path>>(path: P) -> io::Result<()> {
+ os_imp::chdir(path.as_ref())
+}
+
+/// An iterator over a snapshot of the environment variables of this process.
+///
+/// This structure is created by the [`std::env::vars`] function. See its
+/// documentation for more.
+///
+/// [`std::env::vars`]: fn.vars.html
+#[stable(feature = "env", since = "1.0.0")]
+pub struct Vars { inner: VarsOs }
+
+/// An iterator over a snapshot of the environment variables of this process.
+///
+/// This structure is created by the [`std::env::vars_os`] function. See
+/// its documentation for more.
+///
+/// [`std::env::vars_os`]: fn.vars_os.html
+#[stable(feature = "env", since = "1.0.0")]
+pub struct VarsOs { inner: os_imp::Env }
+
+/// Returns an iterator of (variable, value) pairs of strings, for all the
+/// environment variables of the current process.
+///
+/// The returned iterator contains a snapshot of the process's environment
+/// variables at the time of this invocation. Modifications to environment
+/// variables afterwards will not be reflected in the returned iterator.
+///
+/// # Panics
+///
+/// While iterating, the returned iterator will panic if any key or value in the
+/// environment is not valid unicode. If this is not desired, consider using the
+/// [`env::vars_os`] function.
+///
+/// [`env::vars_os`]: fn.vars_os.html
+///
+/// # Examples
+///
+/// ```
+/// use std::env;
+///
+/// // We will iterate through the references to the element returned by
+/// // env::vars();
+/// for (key, value) in env::vars() {
+/// println!("{}: {}", key, value);
+/// }
+/// ```
+#[stable(feature = "env", since = "1.0.0")]
+pub fn vars() -> Vars {
+ Vars { inner: vars_os() }
+}
+
+/// Returns an iterator of (variable, value) pairs of OS strings, for all the
+/// environment variables of the current process.
+///
+/// The returned iterator contains a snapshot of the process's environment
+/// variables at the time of this invocation. Modifications to environment
+/// variables afterwards will not be reflected in the returned iterator.
+///
+/// # Examples
+///
+/// ```
+/// use std::env;
+///
+/// // We will iterate through the references to the element returned by
+/// // env::vars_os();
+/// for (key, value) in env::vars_os() {
+/// println!("{:?}: {:?}", key, value);
+/// }
+/// ```
+#[stable(feature = "env", since = "1.0.0")]
+pub fn vars_os() -> VarsOs {
+ VarsOs { inner: os_imp::env() }
+}
+
+#[stable(feature = "env", since = "1.0.0")]
+impl Iterator for Vars {
+ type Item = (String, String);
+ fn next(&mut self) -> Option<(String, String)> {
+ self.inner.next().map(|(a, b)| {
+ (a.into_string().unwrap(), b.into_string().unwrap())
+ })
+ }
+ fn size_hint(&self) -> (usize, Option<usize>) { self.inner.size_hint() }
+}
+
+#[stable(feature = "std_debug", since = "1.16.0")]
+impl fmt::Debug for Vars {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.pad("Vars { .. }")
+ }
+}
+
+#[stable(feature = "env", since = "1.0.0")]
+impl Iterator for VarsOs {
+ type Item = (OsString, OsString);
+ fn next(&mut self) -> Option<(OsString, OsString)> { self.inner.next() }
+ fn size_hint(&self) -> (usize, Option<usize>) { self.inner.size_hint() }
+}
+
+#[stable(feature = "std_debug", since = "1.16.0")]
+impl fmt::Debug for VarsOs {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.pad("VarsOs { .. }")
+ }
+}
+
+/// Fetches the environment variable `key` from the current process.
+///
+/// # Errors
+///
+/// * Environment variable is not present
+/// * Environment variable is not valid unicode
+///
+/// # Examples
+///
+/// ```
+/// use std::env;
+///
+/// let key = "HOME";
+/// match env::var(key) {
+/// Ok(val) => println!("{}: {:?}", key, val),
+/// Err(e) => println!("couldn't interpret {}: {}", key, e),
+/// }
+/// ```
+#[stable(feature = "env", since = "1.0.0")]
+pub fn var<K: AsRef<OsStr>>(key: K) -> Result<String, VarError> {
+ _var(key.as_ref())
+}
+
+fn _var(key: &OsStr) -> Result<String, VarError> {
+ match var_os(key) {
+ Some(s) => s.into_string().map_err(VarError::NotUnicode),
+ None => Err(VarError::NotPresent),
+ }
+}
+
+/// Fetches the environment variable `key` from the current process, returning
+/// [`None`] if the variable isn't set.
+///
+/// [`None`]: ../option/enum.Option.html#variant.None
+///
+/// # Examples
+///
+/// ```
+/// use std::env;
+///
+/// let key = "HOME";
+/// match env::var_os(key) {
+/// Some(val) => println!("{}: {:?}", key, val),
+/// None => println!("{} is not defined in the environment.", key)
+/// }
+/// ```
+#[stable(feature = "env", since = "1.0.0")]
+pub fn var_os<K: AsRef<OsStr>>(key: K) -> Option<OsString> {
+ _var_os(key.as_ref())
+}
+
+fn _var_os(key: &OsStr) -> Option<OsString> {
+ os_imp::getenv(key).unwrap_or_else(|e| {
+ panic!("failed to get environment variable `{:?}`: {}", key, e)
+ })
+}
+
+/// The error type for operations interacting with environment variables.
+/// Possibly returned from the [`env::var`] function.
+///
+/// [`env::var`]: fn.var.html
+#[derive(Debug, PartialEq, Eq, Clone)]
+#[stable(feature = "env", since = "1.0.0")]
+pub enum VarError {
+ /// The specified environment variable was not present in the current
+ /// process's environment.
+ #[stable(feature = "env", since = "1.0.0")]
+ NotPresent,
+
+ /// The specified environment variable was found, but it did not contain
+ /// valid unicode data. The found data is returned as a payload of this
+ /// variant.
+ #[stable(feature = "env", since = "1.0.0")]
+ NotUnicode(#[stable(feature = "env", since = "1.0.0")] OsString),
+}
+
+#[stable(feature = "env", since = "1.0.0")]
+impl fmt::Display for VarError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match *self {
+ VarError::NotPresent => write!(f, "environment variable not found"),
+ VarError::NotUnicode(ref s) => {
+ write!(f, "environment variable was not valid unicode: {:?}", s)
+ }
+ }
+ }
+}
+
+#[stable(feature = "env", since = "1.0.0")]
+impl Error for VarError {
+ fn description(&self) -> &str {
+ match *self {
+ VarError::NotPresent => "environment variable not found",
+ VarError::NotUnicode(..) => "environment variable was not valid unicode",
+ }
+ }
+}
+
+/// Sets the environment variable `k` to the value `v` for the currently running
+/// process.
+///
+/// Note that while concurrent access to environment variables is safe in Rust,
+/// some platforms only expose inherently unsafe non-threadsafe APIs for
+/// inspecting the environment. As a result extra care needs to be taken when
+/// auditing calls to unsafe external FFI functions to ensure that any external
+/// environment accesses are properly synchronized with accesses in Rust.
+///
+/// Discussion of this unsafety on Unix may be found in:
+///
+/// - [Austin Group Bugzilla](http://austingroupbugs.net/view.php?id=188)
+/// - [GNU C library Bugzilla](https://sourceware.org/bugzilla/show_bug.cgi?id=15607#c2)
+///
+/// # Panics
+///
+/// This function may panic if `key` is empty, contains an ASCII equals sign
+/// `'='` or the NUL character `'\0'`, or when the value contains the NUL
+/// character.
+///
+/// # Examples
+///
+/// ```
+/// use std::env;
+///
+/// let key = "KEY";
+/// env::set_var(key, "VALUE");
+/// assert_eq!(env::var(key), Ok("VALUE".to_string()));
+/// ```
+#[stable(feature = "env", since = "1.0.0")]
+pub fn set_var<K: AsRef<OsStr>, V: AsRef<OsStr>>(k: K, v: V) {
+ _set_var(k.as_ref(), v.as_ref())
+}
+
+fn _set_var(k: &OsStr, v: &OsStr) {
+ os_imp::setenv(k, v).unwrap_or_else(|e| {
+ panic!("failed to set environment variable `{:?}` to `{:?}`: {}",
+ k, v, e)
+ })
+}
+
+/// Removes an environment variable from the environment of the currently running process.
+///
+/// Note that while concurrent access to environment variables is safe in Rust,
+/// some platforms only expose inherently unsafe non-threadsafe APIs for
+/// inspecting the environment. As a result extra care needs to be taken when
+/// auditing calls to unsafe external FFI functions to ensure that any external
+/// environment accesses are properly synchronized with accesses in Rust.
+///
+/// Discussion of this unsafety on Unix may be found in:
+///
+/// - [Austin Group Bugzilla](http://austingroupbugs.net/view.php?id=188)
+/// - [GNU C library Bugzilla](https://sourceware.org/bugzilla/show_bug.cgi?id=15607#c2)
+///
+/// # Panics
+///
+/// This function may panic if `key` is empty, contains an ASCII equals sign
+/// `'='` or the NUL character `'\0'`, or when the value contains the NUL
+/// character.
+///
+/// # Examples
+///
+/// ```
+/// use std::env;
+///
+/// let key = "KEY";
+/// env::set_var(key, "VALUE");
+/// assert_eq!(env::var(key), Ok("VALUE".to_string()));
+///
+/// env::remove_var(key);
+/// assert!(env::var(key).is_err());
+/// ```
+#[stable(feature = "env", since = "1.0.0")]
+pub fn remove_var<K: AsRef<OsStr>>(k: K) {
+ _remove_var(k.as_ref())
+}
+
+fn _remove_var(k: &OsStr) {
+ os_imp::unsetenv(k).unwrap_or_else(|e| {
+ panic!("failed to remove environment variable `{:?}`: {}", k, e)
+ })
+}
+
+/// An iterator that splits an environment variable into paths according to
+/// platform-specific conventions.
+///
+/// This structure is created by the [`std::env::split_paths`] function. See its
+/// documentation for more.
+///
+/// [`std::env::split_paths`]: fn.split_paths.html
+#[stable(feature = "env", since = "1.0.0")]
+pub struct SplitPaths<'a> { inner: os_imp::SplitPaths<'a> }
+
+/// Parses input according to platform conventions for the `PATH`
+/// environment variable.
+///
+/// Returns an iterator over the paths contained in `unparsed`.
+///
+/// # Examples
+///
+/// ```
+/// use std::env;
+///
+/// let key = "PATH";
+/// match env::var_os(key) {
+/// Some(paths) => {
+/// for path in env::split_paths(&paths) {
+/// println!("'{}'", path.display());
+/// }
+/// }
+/// None => println!("{} is not defined in the environment.", key)
+/// }
+/// ```
+#[stable(feature = "env", since = "1.0.0")]
+pub fn split_paths<T: AsRef<OsStr> + ?Sized>(unparsed: &T) -> SplitPaths<'_> {
+ SplitPaths { inner: os_imp::split_paths(unparsed.as_ref()) }
+}
+
+#[stable(feature = "env", since = "1.0.0")]
+impl<'a> Iterator for SplitPaths<'a> {
+ type Item = PathBuf;
+ fn next(&mut self) -> Option<PathBuf> { self.inner.next() }
+ fn size_hint(&self) -> (usize, Option<usize>) { self.inner.size_hint() }
+}
+
+#[stable(feature = "std_debug", since = "1.16.0")]
+impl fmt::Debug for SplitPaths<'_> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.pad("SplitPaths { .. }")
+ }
+}
+
+/// The error type for operations on the `PATH` variable. Possibly returned from
+/// the [`env::join_paths`] function.
+///
+/// [`env::join_paths`]: fn.join_paths.html
+#[derive(Debug)]
+#[stable(feature = "env", since = "1.0.0")]
+pub struct JoinPathsError {
+ inner: os_imp::JoinPathsError
+}
+
+/// Joins a collection of [`Path`]s appropriately for the `PATH`
+/// environment variable.
+///
+/// # Errors
+///
+/// Returns an [`Err`][err] (containing an error message) if one of the input
+/// [`Path`]s contains an invalid character for constructing the `PATH`
+/// variable (a double quote on Windows or a colon on Unix).
+///
+/// [`Path`]: ../../std/path/struct.Path.html
+/// [`OsString`]: ../../std/ffi/struct.OsString.html
+/// [err]: ../../std/result/enum.Result.html#variant.Err
+///
+/// # Examples
+///
+/// Joining paths on a Unix-like platform:
+///
+/// ```
+/// use std::env;
+/// use std::ffi::OsString;
+/// use std::path::Path;
+///
+/// fn main() -> Result<(), env::JoinPathsError> {
+/// # if cfg!(unix) {
+/// let paths = [Path::new("/bin"), Path::new("/usr/bin")];
+/// let path_os_string = env::join_paths(paths.iter())?;
+/// assert_eq!(path_os_string, OsString::from("/bin:/usr/bin"));
+/// # }
+/// Ok(())
+/// }
+/// ```
+///
+/// Joining a path containing a colon on a Unix-like platform results in an error:
+///
+/// ```
+/// # if cfg!(unix) {
+/// use std::env;
+/// use std::path::Path;
+///
+/// let paths = [Path::new("/bin"), Path::new("/usr/bi:n")];
+/// assert!(env::join_paths(paths.iter()).is_err());
+/// # }
+/// ```
+///
+/// Using `env::join_paths` with `env::spit_paths` to append an item to the `PATH` environment
+/// variable:
+///
+/// ```
+/// use std::env;
+/// use std::path::PathBuf;
+///
+/// fn main() -> Result<(), env::JoinPathsError> {
+/// if let Some(path) = env::var_os("PATH") {
+/// let mut paths = env::split_paths(&path).collect::<Vec<_>>();
+/// paths.push(PathBuf::from("/home/xyz/bin"));
+/// let new_path = env::join_paths(paths)?;
+/// env::set_var("PATH", &new_path);
+/// }
+///
+/// Ok(())
+/// }
+/// ```
+#[stable(feature = "env", since = "1.0.0")]
+pub fn join_paths<I, T>(paths: I) -> Result<OsString, JoinPathsError>
+ where I: IntoIterator<Item=T>, T: AsRef<OsStr>
+{
+ os_imp::join_paths(paths.into_iter()).map_err(|e| {
+ JoinPathsError { inner: e }
+ })
+}
+
+#[stable(feature = "env", since = "1.0.0")]
+impl fmt::Display for JoinPathsError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ self.inner.fmt(f)
+ }
+}
+
+#[stable(feature = "env", since = "1.0.0")]
+impl Error for JoinPathsError {
+ fn description(&self) -> &str { self.inner.description() }
+}
+
+/// Returns the path of the current user's home directory if known.
+///
+/// # Unix
+///
+/// - Returns the value of the 'HOME' environment variable if it is set
+/// (including to an empty string).
+/// - Otherwise, it tries to determine the home directory by invoking the `getpwuid_r` function
+/// using the UID of the current user. An empty home directory field returned from the
+/// `getpwuid_r` function is considered to be a valid value.
+/// - Returns `None` if the current user has no entry in the /etc/passwd file.
+///
+/// # Windows
+///
+/// - Returns the value of the 'HOME' environment variable if it is set
+/// (including to an empty string).
+/// - Otherwise, returns the value of the 'USERPROFILE' environment variable if it is set
+/// (including to an empty string).
+/// - If both do not exist, [`GetUserProfileDirectory`][msdn] is used to return the path.
+///
+/// [msdn]: https://msdn.microsoft.com/en-us/library/windows/desktop/bb762280(v=vs.85).aspx
+///
+/// # Examples
+///
+/// ```
+/// use std::env;
+///
+/// match env::home_dir() {
+/// Some(path) => println!("Your home directory, probably: {}", path.display()),
+/// None => println!("Impossible to get your home dir!"),
+/// }
+/// ```
+#[rustc_deprecated(since = "1.29.0",
+ reason = "This function's behavior is unexpected and probably not what you want. \
+ Consider using the home_dir function from https://crates.io/crates/dirs instead.")]
+#[stable(feature = "env", since = "1.0.0")]
+pub fn home_dir() -> Option<PathBuf> {
+ os_imp::home_dir()
+}
+
+/// Returns the path of a temporary directory.
+///
+/// # Unix
+///
+/// Returns the value of the `TMPDIR` environment variable if it is
+/// set, otherwise for non-Android it returns `/tmp`. If Android, since there
+/// is no global temporary folder (it is usually allocated per-app), it returns
+/// `/data/local/tmp`.
+///
+/// # Windows
+///
+/// Returns the value of, in order, the `TMP`, `TEMP`,
+/// `USERPROFILE` environment variable if any are set and not the empty
+/// string. Otherwise, `temp_dir` returns the path of the Windows directory.
+/// This behavior is identical to that of [`GetTempPath`][msdn], which this
+/// function uses internally.
+///
+/// [msdn]: https://msdn.microsoft.com/en-us/library/windows/desktop/aa364992(v=vs.85).aspx
+///
+/// ```no_run
+/// use std::env;
+/// use std::fs::File;
+///
+/// fn main() -> std::io::Result<()> {
+/// let mut dir = env::temp_dir();
+/// dir.push("foo.txt");
+///
+/// let f = File::create(dir)?;
+/// Ok(())
+/// }
+/// ```
+#[stable(feature = "env", since = "1.0.0")]
+pub fn temp_dir() -> PathBuf {
+ os_imp::temp_dir()
+}
+
+/// Returns the full filesystem path of the current running executable.
+///
+/// # Platform-specific behavior
+///
+/// If the executable was invoked through a symbolic link, some platforms will
+/// return the path of the symbolic link and other platforms will return the
+/// path of the symbolic link’s target.
+///
+/// # Errors
+///
+/// Acquiring the path of the current executable is a platform-specific operation
+/// that can fail for a good number of reasons. Some errors can include, but not
+/// be limited to, filesystem operations failing or general syscall failures.
+///
+/// # Security
+///
+/// The output of this function should not be used in anything that might have
+/// security implications. For example:
+///
+/// ```
+/// fn main() {
+/// println!("{:?}", std::env::current_exe());
+/// }
+/// ```
+///
+/// On Linux systems, if this is compiled as `foo`:
+///
+/// ```bash
+/// $ rustc foo.rs
+/// $ ./foo
+/// Ok("/home/alex/foo")
+/// ```
+///
+/// And you make a hard link of the program:
+///
+/// ```bash
+/// $ ln foo bar
+/// ```
+///
+/// When you run it, you won’t get the path of the original executable, you’ll
+/// get the path of the hard link:
+///
+/// ```bash
+/// $ ./bar
+/// Ok("/home/alex/bar")
+/// ```
+///
+/// This sort of behavior has been known to [lead to privilege escalation] when
+/// used incorrectly.
+///
+/// [lead to privilege escalation]: https://securityvulns.com/Wdocument183.html
+///
+/// # Examples
+///
+/// ```
+/// use std::env;
+///
+/// match env::current_exe() {
+/// Ok(exe_path) => println!("Path of this executable is: {}",
+/// exe_path.display()),
+/// Err(e) => println!("failed to get current exe path: {}", e),
+/// };
+/// ```
+#[stable(feature = "env", since = "1.0.0")]
+pub fn current_exe() -> io::Result<PathBuf> {
+ os_imp::current_exe()
+}
+
+/// An iterator over the arguments of a process, yielding a [`String`] value for
+/// each argument.
+///
+/// This struct is created by the [`std::env::args`] function. See its
+/// documentation for more.
+///
+/// The first element is traditionally the path of the executable, but it can be
+/// set to arbitrary text, and may not even exist. This means this property
+/// should not be relied upon for security purposes.
+///
+/// [`String`]: ../string/struct.String.html
+/// [`std::env::args`]: ./fn.args.html
+#[stable(feature = "env", since = "1.0.0")]
+pub struct Args { inner: ArgsOs }
+
+/// An iterator over the arguments of a process, yielding an [`OsString`] value
+/// for each argument.
+///
+/// This struct is created by the [`std::env::args_os`] function. See its
+/// documentation for more.
+///
+/// The first element is traditionally the path of the executable, but it can be
+/// set to arbitrary text, and may not even exist. This means this property
+/// should not be relied upon for security purposes.
+///
+/// [`OsString`]: ../ffi/struct.OsString.html
+/// [`std::env::args_os`]: ./fn.args_os.html
+#[stable(feature = "env", since = "1.0.0")]
+pub struct ArgsOs { inner: sys::args::Args }
+
+/// Returns the arguments which this program was started with (normally passed
+/// via the command line).
+///
+/// The first element is traditionally the path of the executable, but it can be
+/// set to arbitrary text, and may not even exist. This means this property should
+/// not be relied upon for security purposes.
+///
+/// On Unix systems shell usually expands unquoted arguments with glob patterns
+/// (such as `*` and `?`). On Windows this is not done, and such arguments are
+/// passed as-is.
+///
+/// # Panics
+///
+/// The returned iterator will panic during iteration if any argument to the
+/// process is not valid unicode. If this is not desired,
+/// use the [`args_os`] function instead.
+///
+/// # Examples
+///
+/// ```
+/// use std::env;
+///
+/// // Prints each argument on a separate line
+/// for argument in env::args() {
+/// println!("{}", argument);
+/// }
+/// ```
+///
+/// [`args_os`]: ./fn.args_os.html
+#[stable(feature = "env", since = "1.0.0")]
+pub fn args() -> Args {
+ Args { inner: args_os() }
+}
+
+/// Returns the arguments which this program was started with (normally passed
+/// via the command line).
+///
+/// The first element is traditionally the path of the executable, but it can be
+/// set to arbitrary text, and it may not even exist, so this property should
+/// not be relied upon for security purposes.
+///
+/// # Examples
+///
+/// ```
+/// use std::env;
+///
+/// // Prints each argument on a separate line
+/// for argument in env::args_os() {
+/// println!("{:?}", argument);
+/// }
+/// ```
+#[stable(feature = "env", since = "1.0.0")]
+pub fn args_os() -> ArgsOs {
+ ArgsOs { inner: sys::args::args() }
+}
+
+#[stable(feature = "env_unimpl_send_sync", since = "1.26.0")]
+impl !Send for Args {}
+
+#[stable(feature = "env_unimpl_send_sync", since = "1.26.0")]
+impl !Sync for Args {}
+
+#[stable(feature = "env", since = "1.0.0")]
+impl Iterator for Args {
+ type Item = String;
+ fn next(&mut self) -> Option<String> {
+ self.inner.next().map(|s| s.into_string().unwrap())
+ }
+ fn size_hint(&self) -> (usize, Option<usize>) { self.inner.size_hint() }
+}
+
+#[stable(feature = "env", since = "1.0.0")]
+impl ExactSizeIterator for Args {
+ fn len(&self) -> usize { self.inner.len() }
+ fn is_empty(&self) -> bool { self.inner.is_empty() }
+}
+
+#[stable(feature = "env_iterators", since = "1.12.0")]
+impl DoubleEndedIterator for Args {
+ fn next_back(&mut self) -> Option<String> {
+ self.inner.next_back().map(|s| s.into_string().unwrap())
+ }
+}
+
+#[stable(feature = "std_debug", since = "1.16.0")]
+impl fmt::Debug for Args {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("Args")
+ .field("inner", &self.inner.inner.inner_debug())
+ .finish()
+ }
+}
+
+#[stable(feature = "env_unimpl_send_sync", since = "1.26.0")]
+impl !Send for ArgsOs {}
+
+#[stable(feature = "env_unimpl_send_sync", since = "1.26.0")]
+impl !Sync for ArgsOs {}
+
+#[stable(feature = "env", since = "1.0.0")]
+impl Iterator for ArgsOs {
+ type Item = OsString;
+ fn next(&mut self) -> Option<OsString> { self.inner.next() }
+ fn size_hint(&self) -> (usize, Option<usize>) { self.inner.size_hint() }
+}
+
+#[stable(feature = "env", since = "1.0.0")]
+impl ExactSizeIterator for ArgsOs {
+ fn len(&self) -> usize { self.inner.len() }
+ fn is_empty(&self) -> bool { self.inner.is_empty() }
+}
+
+#[stable(feature = "env_iterators", since = "1.12.0")]
+impl DoubleEndedIterator for ArgsOs {
+ fn next_back(&mut self) -> Option<OsString> { self.inner.next_back() }
+}
+
+#[stable(feature = "std_debug", since = "1.16.0")]
+impl fmt::Debug for ArgsOs {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("ArgsOs")
+ .field("inner", &self.inner.inner_debug())
+ .finish()
+ }
+}
+
+/// Constants associated with the current target
+#[stable(feature = "env", since = "1.0.0")]
+pub mod consts {
+ use crate::sys::env::os;
+
+ /// A string describing the architecture of the CPU that is currently
+ /// in use.
+ ///
+ /// Some possible values:
+ ///
+ /// - x86
+ /// - x86_64
+ /// - arm
+ /// - aarch64
+ /// - mips
+ /// - mips64
+ /// - powerpc
+ /// - powerpc64
+ /// - s390x
+ /// - sparc64
+ #[stable(feature = "env", since = "1.0.0")]
+ pub const ARCH: &str = super::arch::ARCH;
+
+ /// The family of the operating system. Example value is `unix`.
+ ///
+ /// Some possible values:
+ ///
+ /// - unix
+ /// - windows
+ #[stable(feature = "env", since = "1.0.0")]
+ pub const FAMILY: &str = os::FAMILY;
+
+ /// A string describing the specific operating system in use.
+ /// Example value is `linux`.
+ ///
+ /// Some possible values:
+ ///
+ /// - linux
+ /// - macos
+ /// - ios
+ /// - freebsd
+ /// - dragonfly
+ /// - bitrig
+ /// - netbsd
+ /// - openbsd
+ /// - solaris
+ /// - android
+ /// - windows
+ #[stable(feature = "env", since = "1.0.0")]
+ pub const OS: &str = os::OS;
+
+ /// Specifies the filename prefix used for shared libraries on this
+ /// platform. Example value is `lib`.
+ ///
+ /// Some possible values:
+ ///
+ /// - lib
+ /// - `""` (an empty string)
+ #[stable(feature = "env", since = "1.0.0")]
+ pub const DLL_PREFIX: &str = os::DLL_PREFIX;
+
+ /// Specifies the filename suffix used for shared libraries on this
+ /// platform. Example value is `.so`.
+ ///
+ /// Some possible values:
+ ///
+ /// - .so
+ /// - .dylib
+ /// - .dll
+ #[stable(feature = "env", since = "1.0.0")]
+ pub const DLL_SUFFIX: &str = os::DLL_SUFFIX;
+
+ /// Specifies the file extension used for shared libraries on this
+ /// platform that goes after the dot. Example value is `so`.
+ ///
+ /// Some possible values:
+ ///
+ /// - so
+ /// - dylib
+ /// - dll
+ #[stable(feature = "env", since = "1.0.0")]
+ pub const DLL_EXTENSION: &str = os::DLL_EXTENSION;
+
+ /// Specifies the filename suffix used for executable binaries on this
+ /// platform. Example value is `.exe`.
+ ///
+ /// Some possible values:
+ ///
+ /// - .exe
+ /// - .nexe
+ /// - .pexe
+ /// - `""` (an empty string)
+ #[stable(feature = "env", since = "1.0.0")]
+ pub const EXE_SUFFIX: &str = os::EXE_SUFFIX;
+
+ /// Specifies the file extension, if any, used for executable binaries
+ /// on this platform. Example value is `exe`.
+ ///
+ /// Some possible values:
+ ///
+ /// - exe
+ /// - `""` (an empty string)
+ #[stable(feature = "env", since = "1.0.0")]
+ pub const EXE_EXTENSION: &str = os::EXE_EXTENSION;
+}
+
+#[cfg(target_arch = "x86")]
+mod arch {
+ pub const ARCH: &str = "x86";
+}
+
+#[cfg(target_arch = "x86_64")]
+mod arch {
+ pub const ARCH: &str = "x86_64";
+}
+
+#[cfg(target_arch = "arm")]
+mod arch {
+ pub const ARCH: &str = "arm";
+}
+
+#[cfg(target_arch = "aarch64")]
+mod arch {
+ pub const ARCH: &str = "aarch64";
+}
+
+#[cfg(target_arch = "mips")]
+mod arch {
+ pub const ARCH: &str = "mips";
+}
+
+#[cfg(target_arch = "mips64")]
+mod arch {
+ pub const ARCH: &str = "mips64";
+}
+
+#[cfg(target_arch = "powerpc")]
+mod arch {
+ pub const ARCH: &str = "powerpc";
+}
+
+#[cfg(target_arch = "powerpc64")]
+mod arch {
+ pub const ARCH: &str = "powerpc64";
+}
+
+#[cfg(target_arch = "s390x")]
+mod arch {
+ pub const ARCH: &str = "s390x";
+}
+
+#[cfg(target_arch = "sparc64")]
+mod arch {
+ pub const ARCH: &str = "sparc64";
+}
+
+#[cfg(target_arch = "le32")]
+mod arch {
+ pub const ARCH: &str = "le32";
+}
+
+#[cfg(target_arch = "asmjs")]
+mod arch {
+ pub const ARCH: &str = "asmjs";
+}
+
+#[cfg(target_arch = "wasm32")]
+mod arch {
+ pub const ARCH: &str = "wasm32";
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ use crate::path::Path;
+
+ #[test]
+ #[cfg_attr(any(target_os = "emscripten", target_env = "sgx"), ignore)]
+ fn test_self_exe_path() {
+ let path = current_exe();
+ assert!(path.is_ok());
+ let path = path.unwrap();
+
+ // Hard to test this function
+ assert!(path.is_absolute());
+ }
+
+ #[test]
+ fn test() {
+ assert!((!Path::new("test-path").is_absolute()));
+
+ #[cfg(not(target_env = "sgx"))]
+ current_dir().unwrap();
+ }
+
+ #[test]
+ #[cfg(windows)]
+ fn split_paths_windows() {
+ use crate::path::PathBuf;
+
+ fn check_parse(unparsed: &str, parsed: &[&str]) -> bool {
+ split_paths(unparsed).collect::<Vec<_>>() ==
+ parsed.iter().map(|s| PathBuf::from(*s)).collect::<Vec<_>>()
+ }
+
+ assert!(check_parse("", &mut [""]));
+ assert!(check_parse(r#""""#, &mut [""]));
+ assert!(check_parse(";;", &mut ["", "", ""]));
+ assert!(check_parse(r"c:\", &mut [r"c:\"]));
+ assert!(check_parse(r"c:\;", &mut [r"c:\", ""]));
+ assert!(check_parse(r"c:\;c:\Program Files\",
+ &mut [r"c:\", r"c:\Program Files\"]));
+ assert!(check_parse(r#"c:\;c:\"foo"\"#, &mut [r"c:\", r"c:\foo\"]));
+ assert!(check_parse(r#"c:\;c:\"foo;bar"\;c:\baz"#,
+ &mut [r"c:\", r"c:\foo;bar\", r"c:\baz"]));
+ }
+
+ #[test]
+ #[cfg(unix)]
+ fn split_paths_unix() {
+ use crate::path::PathBuf;
+
+ fn check_parse(unparsed: &str, parsed: &[&str]) -> bool {
+ split_paths(unparsed).collect::<Vec<_>>() ==
+ parsed.iter().map(|s| PathBuf::from(*s)).collect::<Vec<_>>()
+ }
+
+ assert!(check_parse("", &mut [""]));
+ assert!(check_parse("::", &mut ["", "", ""]));
+ assert!(check_parse("/", &mut ["/"]));
+ assert!(check_parse("/:", &mut ["/", ""]));
+ assert!(check_parse("/:/usr/local", &mut ["/", "/usr/local"]));
+ }
+
+ #[test]
+ #[cfg(unix)]
+ fn join_paths_unix() {
+ use crate::ffi::OsStr;
+
+ fn test_eq(input: &[&str], output: &str) -> bool {
+ &*join_paths(input.iter().cloned()).unwrap() ==
+ OsStr::new(output)
+ }
+
+ assert!(test_eq(&[], ""));
+ assert!(test_eq(&["/bin", "/usr/bin", "/usr/local/bin"],
+ "/bin:/usr/bin:/usr/local/bin"));
+ assert!(test_eq(&["", "/bin", "", "", "/usr/bin", ""],
+ ":/bin:::/usr/bin:"));
+ assert!(join_paths(["/te:st"].iter().cloned()).is_err());
+ }
+
+ #[test]
+ #[cfg(windows)]
+ fn join_paths_windows() {
+ use crate::ffi::OsStr;
+
+ fn test_eq(input: &[&str], output: &str) -> bool {
+ &*join_paths(input.iter().cloned()).unwrap() ==
+ OsStr::new(output)
+ }
+
+ assert!(test_eq(&[], ""));
+ assert!(test_eq(&[r"c:\windows", r"c:\"],
+ r"c:\windows;c:\"));
+ assert!(test_eq(&["", r"c:\windows", "", "", r"c:\", ""],
+ r";c:\windows;;;c:\;"));
+ assert!(test_eq(&[r"c:\te;st", r"c:\"],
+ r#""c:\te;st";c:\"#));
+ assert!(join_paths([r#"c:\te"st"#].iter().cloned()).is_err());
+ }
+
+ #[test]
+ fn args_debug() {
+ assert_eq!(
+ format!("Args {{ inner: {:?} }}", args().collect::<Vec<_>>()),
+ format!("{:?}", args()));
+ assert_eq!(
+ format!("ArgsOs {{ inner: {:?} }}", args_os().collect::<Vec<_>>()),
+ format!("{:?}", args_os()));
+ }
+}
diff --git a/src/libstd/error.rs b/src/libstd/error.rs
new file mode 100644
index 0000000..7cb830e
--- /dev/null
+++ b/src/libstd/error.rs
@@ -0,0 +1,898 @@
+//! Traits for working with Errors.
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+// A note about crates and the facade:
+//
+// Originally, the `Error` trait was defined in libcore, and the impls
+// were scattered about. However, coherence objected to this
+// arrangement, because to create the blanket impls for `Box` required
+// knowing that `&str: !Error`, and we have no means to deal with that
+// sort of conflict just now. Therefore, for the time being, we have
+// moved the `Error` trait into libstd. As we evolve a sol'n to the
+// coherence challenge (e.g., specialization, neg impls, etc) we can
+// reconsider what crate these items belong in.
+
+use core::array;
+
+use crate::alloc::{AllocErr, LayoutErr, CannotReallocInPlace};
+use crate::any::TypeId;
+use crate::borrow::Cow;
+use crate::cell;
+use crate::char;
+use crate::fmt::{self, Debug, Display};
+use crate::mem::transmute;
+use crate::num;
+use crate::str;
+use crate::string;
+
+/// `Error` is a trait representing the basic expectations for error values,
+/// i.e., values of type `E` in [`Result<T, E>`]. Errors must describe
+/// themselves through the [`Display`] and [`Debug`] traits, and may provide
+/// cause chain information:
+///
+/// The [`source`] method is generally used when errors cross "abstraction
+/// boundaries". If one module must report an error that is caused by an error
+/// from a lower-level module, it can allow access to that error via the
+/// [`source`] method. This makes it possible for the high-level module to
+/// provide its own errors while also revealing some of the implementation for
+/// debugging via [`source`] chains.
+///
+/// [`Result<T, E>`]: ../result/enum.Result.html
+/// [`Display`]: ../fmt/trait.Display.html
+/// [`Debug`]: ../fmt/trait.Debug.html
+/// [`source`]: trait.Error.html#method.source
+#[stable(feature = "rust1", since = "1.0.0")]
+pub trait Error: Debug + Display {
+ /// **This method is soft-deprecated.**
+ ///
+ /// Although using it won’t cause compilation warning,
+ /// new code should use [`Display`] instead
+ /// and new `impl`s can omit it.
+ ///
+ /// To obtain error description as a string, use `to_string()`.
+ ///
+ /// [`Display`]: ../fmt/trait.Display.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// match "xc".parse::<u32>() {
+ /// Err(e) => {
+ /// // Print `e` itself, not `e.description()`.
+ /// println!("Error: {}", e);
+ /// }
+ /// _ => println!("No error"),
+ /// }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ fn description(&self) -> &str {
+ "description() is deprecated; use Display"
+ }
+
+ /// The lower-level cause of this error, if any.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::error::Error;
+ /// use std::fmt;
+ ///
+ /// #[derive(Debug)]
+ /// struct SuperError {
+ /// side: SuperErrorSideKick,
+ /// }
+ ///
+ /// impl fmt::Display for SuperError {
+ /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ /// write!(f, "SuperError is here!")
+ /// }
+ /// }
+ ///
+ /// impl Error for SuperError {
+ /// fn description(&self) -> &str {
+ /// "I'm the superhero of errors"
+ /// }
+ ///
+ /// fn cause(&self) -> Option<&Error> {
+ /// Some(&self.side)
+ /// }
+ /// }
+ ///
+ /// #[derive(Debug)]
+ /// struct SuperErrorSideKick;
+ ///
+ /// impl fmt::Display for SuperErrorSideKick {
+ /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ /// write!(f, "SuperErrorSideKick is here!")
+ /// }
+ /// }
+ ///
+ /// impl Error for SuperErrorSideKick {
+ /// fn description(&self) -> &str {
+ /// "I'm SuperError side kick"
+ /// }
+ /// }
+ ///
+ /// fn get_super_error() -> Result<(), SuperError> {
+ /// Err(SuperError { side: SuperErrorSideKick })
+ /// }
+ ///
+ /// fn main() {
+ /// match get_super_error() {
+ /// Err(e) => {
+ /// println!("Error: {}", e.description());
+ /// println!("Caused by: {}", e.cause().unwrap());
+ /// }
+ /// _ => println!("No error"),
+ /// }
+ /// }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_deprecated(since = "1.33.0", reason = "replaced by Error::source, which can support \
+ downcasting")]
+ fn cause(&self) -> Option<&dyn Error> {
+ self.source()
+ }
+
+ /// The lower-level source of this error, if any.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::error::Error;
+ /// use std::fmt;
+ ///
+ /// #[derive(Debug)]
+ /// struct SuperError {
+ /// side: SuperErrorSideKick,
+ /// }
+ ///
+ /// impl fmt::Display for SuperError {
+ /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ /// write!(f, "SuperError is here!")
+ /// }
+ /// }
+ ///
+ /// impl Error for SuperError {
+ /// fn description(&self) -> &str {
+ /// "I'm the superhero of errors"
+ /// }
+ ///
+ /// fn source(&self) -> Option<&(dyn Error + 'static)> {
+ /// Some(&self.side)
+ /// }
+ /// }
+ ///
+ /// #[derive(Debug)]
+ /// struct SuperErrorSideKick;
+ ///
+ /// impl fmt::Display for SuperErrorSideKick {
+ /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ /// write!(f, "SuperErrorSideKick is here!")
+ /// }
+ /// }
+ ///
+ /// impl Error for SuperErrorSideKick {
+ /// fn description(&self) -> &str {
+ /// "I'm SuperError side kick"
+ /// }
+ /// }
+ ///
+ /// fn get_super_error() -> Result<(), SuperError> {
+ /// Err(SuperError { side: SuperErrorSideKick })
+ /// }
+ ///
+ /// fn main() {
+ /// match get_super_error() {
+ /// Err(e) => {
+ /// println!("Error: {}", e.description());
+ /// println!("Caused by: {}", e.source().unwrap());
+ /// }
+ /// _ => println!("No error"),
+ /// }
+ /// }
+ /// ```
+ #[stable(feature = "error_source", since = "1.30.0")]
+ fn source(&self) -> Option<&(dyn Error + 'static)> { None }
+
+ /// Gets the `TypeId` of `self`
+ #[doc(hidden)]
+ #[unstable(feature = "error_type_id",
+ reason = "this is memory unsafe to override in user code",
+ issue = "60784")]
+ fn type_id(&self) -> TypeId where Self: 'static {
+ TypeId::of::<Self>()
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a, E: Error + 'a> From<E> for Box<dyn Error + 'a> {
+ /// Converts a type of [`Error`] into a box of dyn [`Error`].
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::error::Error;
+ /// use std::fmt;
+ /// use std::mem;
+ ///
+ /// #[derive(Debug)]
+ /// struct AnError;
+ ///
+ /// impl fmt::Display for AnError {
+ /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ /// write!(f , "An error")
+ /// }
+ /// }
+ ///
+ /// impl Error for AnError {
+ /// fn description(&self) -> &str {
+ /// "Description of an error"
+ /// }
+ /// }
+ ///
+ /// let an_error = AnError;
+ /// assert!(0 == mem::size_of_val(&an_error));
+ /// let a_boxed_error = Box::<Error>::from(an_error);
+ /// assert!(mem::size_of::<Box<dyn Error>>() == mem::size_of_val(&a_boxed_error))
+ /// ```
+ fn from(err: E) -> Box<dyn Error + 'a> {
+ Box::new(err)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a, E: Error + Send + Sync + 'a> From<E> for Box<dyn Error + Send + Sync + 'a> {
+ /// Converts a type of [`Error`] + [`Send`] + [`Sync`] into a box of dyn [`Error`] +
+ /// [`Send`] + [`Sync`].
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::error::Error;
+ /// use std::fmt;
+ /// use std::mem;
+ ///
+ /// #[derive(Debug)]
+ /// struct AnError;
+ ///
+ /// impl fmt::Display for AnError {
+ /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ /// write!(f , "An error")
+ /// }
+ /// }
+ ///
+ /// impl Error for AnError {
+ /// fn description(&self) -> &str {
+ /// "Description of an error"
+ /// }
+ /// }
+ ///
+ /// unsafe impl Send for AnError {}
+ ///
+ /// unsafe impl Sync for AnError {}
+ ///
+ /// let an_error = AnError;
+ /// assert!(0 == mem::size_of_val(&an_error));
+ /// let a_boxed_error = Box::<Error + Send + Sync>::from(an_error);
+ /// assert!(
+ /// mem::size_of::<Box<dyn Error + Send + Sync>>() == mem::size_of_val(&a_boxed_error))
+ /// ```
+ fn from(err: E) -> Box<dyn Error + Send + Sync + 'a> {
+ Box::new(err)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl From<String> for Box<dyn Error + Send + Sync> {
+ /// Converts a [`String`] into a box of dyn [`Error`] + [`Send`] + [`Sync`].
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::error::Error;
+ /// use std::mem;
+ ///
+ /// let a_string_error = "a string error".to_string();
+ /// let a_boxed_error = Box::<Error + Send + Sync>::from(a_string_error);
+ /// assert!(
+ /// mem::size_of::<Box<dyn Error + Send + Sync>>() == mem::size_of_val(&a_boxed_error))
+ /// ```
+ fn from(err: String) -> Box<dyn Error + Send + Sync> {
+ #[derive(Debug)]
+ struct StringError(String);
+
+ impl Error for StringError {
+ fn description(&self) -> &str { &self.0 }
+ }
+
+ impl Display for StringError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ Display::fmt(&self.0, f)
+ }
+ }
+
+ Box::new(StringError(err))
+ }
+}
+
+#[stable(feature = "string_box_error", since = "1.6.0")]
+impl From<String> for Box<dyn Error> {
+ /// Converts a [`String`] into a box of dyn [`Error`].
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::error::Error;
+ /// use std::mem;
+ ///
+ /// let a_string_error = "a string error".to_string();
+ /// let a_boxed_error = Box::<Error>::from(a_string_error);
+ /// assert!(mem::size_of::<Box<dyn Error>>() == mem::size_of_val(&a_boxed_error))
+ /// ```
+ fn from(str_err: String) -> Box<dyn Error> {
+ let err1: Box<dyn Error + Send + Sync> = From::from(str_err);
+ let err2: Box<dyn Error> = err1;
+ err2
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a> From<&str> for Box<dyn Error + Send + Sync + 'a> {
+ /// Converts a [`str`] into a box of dyn [`Error`] + [`Send`] + [`Sync`].
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::error::Error;
+ /// use std::mem;
+ ///
+ /// let a_str_error = "a str error";
+ /// let a_boxed_error = Box::<Error + Send + Sync>::from(a_str_error);
+ /// assert!(
+ /// mem::size_of::<Box<dyn Error + Send + Sync>>() == mem::size_of_val(&a_boxed_error))
+ /// ```
+ fn from(err: &str) -> Box<dyn Error + Send + Sync + 'a> {
+ From::from(String::from(err))
+ }
+}
+
+#[stable(feature = "string_box_error", since = "1.6.0")]
+impl From<&str> for Box<dyn Error> {
+ /// Converts a [`str`] into a box of dyn [`Error`].
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::error::Error;
+ /// use std::mem;
+ ///
+ /// let a_str_error = "a str error";
+ /// let a_boxed_error = Box::<Error>::from(a_str_error);
+ /// assert!(mem::size_of::<Box<dyn Error>>() == mem::size_of_val(&a_boxed_error))
+ /// ```
+ fn from(err: &str) -> Box<dyn Error> {
+ From::from(String::from(err))
+ }
+}
+
+#[stable(feature = "cow_box_error", since = "1.22.0")]
+impl<'a, 'b> From<Cow<'b, str>> for Box<dyn Error + Send + Sync + 'a> {
+ /// Converts a [`Cow`] into a box of dyn [`Error`] + [`Send`] + [`Sync`].
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::error::Error;
+ /// use std::mem;
+ /// use std::borrow::Cow;
+ ///
+ /// let a_cow_str_error = Cow::from("a str error");
+ /// let a_boxed_error = Box::<Error + Send + Sync>::from(a_cow_str_error);
+ /// assert!(
+ /// mem::size_of::<Box<dyn Error + Send + Sync>>() == mem::size_of_val(&a_boxed_error))
+ /// ```
+ fn from(err: Cow<'b, str>) -> Box<dyn Error + Send + Sync + 'a> {
+ From::from(String::from(err))
+ }
+}
+
+#[stable(feature = "cow_box_error", since = "1.22.0")]
+impl<'a> From<Cow<'a, str>> for Box<dyn Error> {
+ /// Converts a [`Cow`] into a box of dyn [`Error`].
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::error::Error;
+ /// use std::mem;
+ /// use std::borrow::Cow;
+ ///
+ /// let a_cow_str_error = Cow::from("a str error");
+ /// let a_boxed_error = Box::<Error>::from(a_cow_str_error);
+ /// assert!(mem::size_of::<Box<dyn Error>>() == mem::size_of_val(&a_boxed_error))
+ /// ```
+ fn from(err: Cow<'a, str>) -> Box<dyn Error> {
+ From::from(String::from(err))
+ }
+}
+
+#[unstable(feature = "never_type", issue = "35121")]
+impl Error for ! {
+ fn description(&self) -> &str { *self }
+}
+
+#[unstable(feature = "allocator_api",
+ reason = "the precise API and guarantees it provides may be tweaked.",
+ issue = "32838")]
+impl Error for AllocErr {
+ fn description(&self) -> &str {
+ "memory allocation failed"
+ }
+}
+
+#[unstable(feature = "allocator_api",
+ reason = "the precise API and guarantees it provides may be tweaked.",
+ issue = "32838")]
+impl Error for LayoutErr {
+ fn description(&self) -> &str {
+ "invalid parameters to Layout::from_size_align"
+ }
+}
+
+#[unstable(feature = "allocator_api",
+ reason = "the precise API and guarantees it provides may be tweaked.",
+ issue = "32838")]
+impl Error for CannotReallocInPlace {
+ fn description(&self) -> &str {
+ CannotReallocInPlace::description(self)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Error for str::ParseBoolError {
+ fn description(&self) -> &str { "failed to parse bool" }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Error for str::Utf8Error {
+ fn description(&self) -> &str {
+ "invalid utf-8: corrupt contents"
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Error for num::ParseIntError {
+ fn description(&self) -> &str {
+ self.__description()
+ }
+}
+
+#[stable(feature = "try_from", since = "1.34.0")]
+impl Error for num::TryFromIntError {
+ fn description(&self) -> &str {
+ self.__description()
+ }
+}
+
+#[stable(feature = "try_from", since = "1.34.0")]
+impl Error for array::TryFromSliceError {
+ fn description(&self) -> &str {
+ self.__description()
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Error for num::ParseFloatError {
+ fn description(&self) -> &str {
+ self.__description()
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Error for string::FromUtf8Error {
+ fn description(&self) -> &str {
+ "invalid utf-8"
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Error for string::FromUtf16Error {
+ fn description(&self) -> &str {
+ "invalid utf-16"
+ }
+}
+
+#[stable(feature = "str_parse_error2", since = "1.8.0")]
+impl Error for string::ParseError {
+ fn description(&self) -> &str {
+ match *self {}
+ }
+}
+
+#[stable(feature = "decode_utf16", since = "1.9.0")]
+impl Error for char::DecodeUtf16Error {
+ fn description(&self) -> &str {
+ "unpaired surrogate found"
+ }
+}
+
+#[stable(feature = "box_error", since = "1.8.0")]
+impl<T: Error> Error for Box<T> {
+ fn description(&self) -> &str {
+ Error::description(&**self)
+ }
+
+ #[allow(deprecated)]
+ fn cause(&self) -> Option<&dyn Error> {
+ Error::cause(&**self)
+ }
+}
+
+#[stable(feature = "fmt_error", since = "1.11.0")]
+impl Error for fmt::Error {
+ fn description(&self) -> &str {
+ "an error occurred when formatting an argument"
+ }
+}
+
+#[stable(feature = "try_borrow", since = "1.13.0")]
+impl Error for cell::BorrowError {
+ fn description(&self) -> &str {
+ "already mutably borrowed"
+ }
+}
+
+#[stable(feature = "try_borrow", since = "1.13.0")]
+impl Error for cell::BorrowMutError {
+ fn description(&self) -> &str {
+ "already borrowed"
+ }
+}
+
+#[stable(feature = "try_from", since = "1.34.0")]
+impl Error for char::CharTryFromError {
+ fn description(&self) -> &str {
+ "converted integer out of range for `char`"
+ }
+}
+
+#[stable(feature = "char_from_str", since = "1.20.0")]
+impl Error for char::ParseCharError {
+ fn description(&self) -> &str {
+ self.__description()
+ }
+}
+
+// copied from any.rs
+impl dyn Error + 'static {
+ /// Returns `true` if the boxed type is the same as `T`
+ #[stable(feature = "error_downcast", since = "1.3.0")]
+ #[inline]
+ pub fn is<T: Error + 'static>(&self) -> bool {
+ // Get TypeId of the type this function is instantiated with
+ let t = TypeId::of::<T>();
+
+ // Get TypeId of the type in the trait object
+ let boxed = self.type_id();
+
+ // Compare both TypeIds on equality
+ t == boxed
+ }
+
+ /// Returns some reference to the boxed value if it is of type `T`, or
+ /// `None` if it isn't.
+ #[stable(feature = "error_downcast", since = "1.3.0")]
+ #[inline]
+ pub fn downcast_ref<T: Error + 'static>(&self) -> Option<&T> {
+ if self.is::<T>() {
+ unsafe {
+ Some(&*(self as *const dyn Error as *const T))
+ }
+ } else {
+ None
+ }
+ }
+
+ /// Returns some mutable reference to the boxed value if it is of type `T`, or
+ /// `None` if it isn't.
+ #[stable(feature = "error_downcast", since = "1.3.0")]
+ #[inline]
+ pub fn downcast_mut<T: Error + 'static>(&mut self) -> Option<&mut T> {
+ if self.is::<T>() {
+ unsafe {
+ Some(&mut *(self as *mut dyn Error as *mut T))
+ }
+ } else {
+ None
+ }
+ }
+}
+
+impl dyn Error + 'static + Send {
+ /// Forwards to the method defined on the type `Any`.
+ #[stable(feature = "error_downcast", since = "1.3.0")]
+ #[inline]
+ pub fn is<T: Error + 'static>(&self) -> bool {
+ <dyn Error + 'static>::is::<T>(self)
+ }
+
+ /// Forwards to the method defined on the type `Any`.
+ #[stable(feature = "error_downcast", since = "1.3.0")]
+ #[inline]
+ pub fn downcast_ref<T: Error + 'static>(&self) -> Option<&T> {
+ <dyn Error + 'static>::downcast_ref::<T>(self)
+ }
+
+ /// Forwards to the method defined on the type `Any`.
+ #[stable(feature = "error_downcast", since = "1.3.0")]
+ #[inline]
+ pub fn downcast_mut<T: Error + 'static>(&mut self) -> Option<&mut T> {
+ <dyn Error + 'static>::downcast_mut::<T>(self)
+ }
+}
+
+impl dyn Error + 'static + Send + Sync {
+ /// Forwards to the method defined on the type `Any`.
+ #[stable(feature = "error_downcast", since = "1.3.0")]
+ #[inline]
+ pub fn is<T: Error + 'static>(&self) -> bool {
+ <dyn Error + 'static>::is::<T>(self)
+ }
+
+ /// Forwards to the method defined on the type `Any`.
+ #[stable(feature = "error_downcast", since = "1.3.0")]
+ #[inline]
+ pub fn downcast_ref<T: Error + 'static>(&self) -> Option<&T> {
+ <dyn Error + 'static>::downcast_ref::<T>(self)
+ }
+
+ /// Forwards to the method defined on the type `Any`.
+ #[stable(feature = "error_downcast", since = "1.3.0")]
+ #[inline]
+ pub fn downcast_mut<T: Error + 'static>(&mut self) -> Option<&mut T> {
+ <dyn Error + 'static>::downcast_mut::<T>(self)
+ }
+}
+
+impl dyn Error {
+ #[inline]
+ #[stable(feature = "error_downcast", since = "1.3.0")]
+ /// Attempt to downcast the box to a concrete type.
+ pub fn downcast<T: Error + 'static>(self: Box<Self>) -> Result<Box<T>, Box<dyn Error>> {
+ if self.is::<T>() {
+ unsafe {
+ let raw: *mut dyn Error = Box::into_raw(self);
+ Ok(Box::from_raw(raw as *mut T))
+ }
+ } else {
+ Err(self)
+ }
+ }
+
+ /// Returns an iterator starting with the current error and continuing with
+ /// recursively calling [`source`].
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(error_iter)]
+ /// use std::error::Error;
+ /// use std::fmt;
+ ///
+ /// #[derive(Debug)]
+ /// struct A;
+ ///
+ /// #[derive(Debug)]
+ /// struct B(Option<Box<dyn Error + 'static>>);
+ ///
+ /// impl fmt::Display for A {
+ /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ /// write!(f, "A")
+ /// }
+ /// }
+ ///
+ /// impl fmt::Display for B {
+ /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ /// write!(f, "B")
+ /// }
+ /// }
+ ///
+ /// impl Error for A {}
+ ///
+ /// impl Error for B {
+ /// fn source(&self) -> Option<&(dyn Error + 'static)> {
+ /// self.0.as_ref().map(|e| e.as_ref())
+ /// }
+ /// }
+ ///
+ /// let b = B(Some(Box::new(A)));
+ ///
+ /// // let err : Box<Error> = b.into(); // or
+ /// let err = &b as &(dyn Error);
+ ///
+ /// let mut iter = err.iter_chain();
+ ///
+ /// assert_eq!("B".to_string(), iter.next().unwrap().to_string());
+ /// assert_eq!("A".to_string(), iter.next().unwrap().to_string());
+ /// assert!(iter.next().is_none());
+ /// assert!(iter.next().is_none());
+ /// ```
+ ///
+ /// [`source`]: trait.Error.html#method.source
+ #[unstable(feature = "error_iter", issue = "58520")]
+ #[inline]
+ pub fn iter_chain(&self) -> ErrorIter<'_> {
+ ErrorIter {
+ current: Some(self),
+ }
+ }
+
+ /// Returns an iterator starting with the [`source`] of this error
+ /// and continuing with recursively calling [`source`].
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(error_iter)]
+ /// use std::error::Error;
+ /// use std::fmt;
+ ///
+ /// #[derive(Debug)]
+ /// struct A;
+ ///
+ /// #[derive(Debug)]
+ /// struct B(Option<Box<dyn Error + 'static>>);
+ ///
+ /// #[derive(Debug)]
+ /// struct C(Option<Box<dyn Error + 'static>>);
+ ///
+ /// impl fmt::Display for A {
+ /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ /// write!(f, "A")
+ /// }
+ /// }
+ ///
+ /// impl fmt::Display for B {
+ /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ /// write!(f, "B")
+ /// }
+ /// }
+ ///
+ /// impl fmt::Display for C {
+ /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ /// write!(f, "C")
+ /// }
+ /// }
+ ///
+ /// impl Error for A {}
+ ///
+ /// impl Error for B {
+ /// fn source(&self) -> Option<&(dyn Error + 'static)> {
+ /// self.0.as_ref().map(|e| e.as_ref())
+ /// }
+ /// }
+ ///
+ /// impl Error for C {
+ /// fn source(&self) -> Option<&(dyn Error + 'static)> {
+ /// self.0.as_ref().map(|e| e.as_ref())
+ /// }
+ /// }
+ ///
+ /// let b = B(Some(Box::new(A)));
+ /// let c = C(Some(Box::new(b)));
+ ///
+ /// // let err : Box<Error> = c.into(); // or
+ /// let err = &c as &(dyn Error);
+ ///
+ /// let mut iter = err.iter_sources();
+ ///
+ /// assert_eq!("B".to_string(), iter.next().unwrap().to_string());
+ /// assert_eq!("A".to_string(), iter.next().unwrap().to_string());
+ /// assert!(iter.next().is_none());
+ /// assert!(iter.next().is_none());
+ /// ```
+ ///
+ /// [`source`]: trait.Error.html#method.source
+ #[inline]
+ #[unstable(feature = "error_iter", issue = "58520")]
+ pub fn iter_sources(&self) -> ErrorIter<'_> {
+ ErrorIter {
+ current: self.source(),
+ }
+ }
+}
+
+/// An iterator over [`Error`]
+///
+/// [`Error`]: trait.Error.html
+#[unstable(feature = "error_iter", issue = "58520")]
+#[derive(Copy, Clone, Debug)]
+pub struct ErrorIter<'a> {
+ current: Option<&'a (dyn Error + 'static)>,
+}
+
+#[unstable(feature = "error_iter", issue = "58520")]
+impl<'a> Iterator for ErrorIter<'a> {
+ type Item = &'a (dyn Error + 'static);
+
+ fn next(&mut self) -> Option<Self::Item> {
+ let current = self.current;
+ self.current = self.current.and_then(Error::source);
+ current
+ }
+}
+
+impl dyn Error + Send {
+ #[inline]
+ #[stable(feature = "error_downcast", since = "1.3.0")]
+ /// Attempt to downcast the box to a concrete type.
+ pub fn downcast<T: Error + 'static>(self: Box<Self>)
+ -> Result<Box<T>, Box<dyn Error + Send>> {
+ let err: Box<dyn Error> = self;
+ <dyn Error>::downcast(err).map_err(|s| unsafe {
+ // reapply the Send marker
+ transmute::<Box<dyn Error>, Box<dyn Error + Send>>(s)
+ })
+ }
+}
+
+impl dyn Error + Send + Sync {
+ #[inline]
+ #[stable(feature = "error_downcast", since = "1.3.0")]
+ /// Attempt to downcast the box to a concrete type.
+ pub fn downcast<T: Error + 'static>(self: Box<Self>)
+ -> Result<Box<T>, Box<Self>> {
+ let err: Box<dyn Error> = self;
+ <dyn Error>::downcast(err).map_err(|s| unsafe {
+ // reapply the Send+Sync marker
+ transmute::<Box<dyn Error>, Box<dyn Error + Send + Sync>>(s)
+ })
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::Error;
+ use crate::fmt;
+
+ #[derive(Debug, PartialEq)]
+ struct A;
+ #[derive(Debug, PartialEq)]
+ struct B;
+
+ impl fmt::Display for A {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "A")
+ }
+ }
+ impl fmt::Display for B {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "B")
+ }
+ }
+
+ impl Error for A {
+ fn description(&self) -> &str { "A-desc" }
+ }
+ impl Error for B {
+ fn description(&self) -> &str { "A-desc" }
+ }
+
+ #[test]
+ fn downcasting() {
+ let mut a = A;
+ let a = &mut a as &mut (dyn Error + 'static);
+ assert_eq!(a.downcast_ref::<A>(), Some(&A));
+ assert_eq!(a.downcast_ref::<B>(), None);
+ assert_eq!(a.downcast_mut::<A>(), Some(&mut A));
+ assert_eq!(a.downcast_mut::<B>(), None);
+
+ let a: Box<dyn Error> = Box::new(A);
+ match a.downcast::<B>() {
+ Ok(..) => panic!("expected error"),
+ Err(e) => assert_eq!(*e.downcast::<A>().unwrap(), A),
+ }
+ }
+}
diff --git a/src/libstd/f32.rs b/src/libstd/f32.rs
new file mode 100644
index 0000000..133540e
--- /dev/null
+++ b/src/libstd/f32.rs
@@ -0,0 +1,1612 @@
+//! This module provides constants which are specific to the implementation
+//! of the `f32` floating point data type.
+//!
+//! *[See also the `f32` primitive type](../../std/primitive.f32.html).*
+//!
+//! Mathematically significant numbers are provided in the `consts` sub-module.
+
+#![stable(feature = "rust1", since = "1.0.0")]
+#![allow(missing_docs)]
+
+#[cfg(not(test))]
+use crate::intrinsics;
+#[cfg(not(test))]
+use crate::sys::cmath;
+
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use core::f32::{RADIX, MANTISSA_DIGITS, DIGITS, EPSILON};
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use core::f32::{MIN_EXP, MAX_EXP, MIN_10_EXP};
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use core::f32::{MAX_10_EXP, NAN, INFINITY, NEG_INFINITY};
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use core::f32::{MIN, MIN_POSITIVE, MAX};
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use core::f32::consts;
+
+#[cfg(not(test))]
+#[lang = "f32_runtime"]
+impl f32 {
+ /// Returns the largest integer less than or equal to a number.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let f = 3.7_f32;
+ /// let g = 3.0_f32;
+ /// let h = -3.7_f32;
+ ///
+ /// assert_eq!(f.floor(), 3.0);
+ /// assert_eq!(g.floor(), 3.0);
+ /// assert_eq!(h.floor(), -4.0);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn floor(self) -> f32 {
+ // On MSVC LLVM will lower many math intrinsics to a call to the
+ // corresponding function. On MSVC, however, many of these functions
+ // aren't actually available as symbols to call, but rather they are all
+ // `static inline` functions in header files. This means that from a C
+ // perspective it's "compatible", but not so much from an ABI
+ // perspective (which we're worried about).
+ //
+ // The inline header functions always just cast to a f64 and do their
+ // operation, so we do that here as well, but only for MSVC targets.
+ //
+ // Note that there are many MSVC-specific float operations which
+ // redirect to this comment, so `floorf` is just one case of a missing
+ // function on MSVC, but there are many others elsewhere.
+ #[cfg(target_env = "msvc")]
+ return (self as f64).floor() as f32;
+ #[cfg(not(target_env = "msvc"))]
+ return unsafe { intrinsics::floorf32(self) };
+ }
+
+ /// Returns the smallest integer greater than or equal to a number.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let f = 3.01_f32;
+ /// let g = 4.0_f32;
+ ///
+ /// assert_eq!(f.ceil(), 4.0);
+ /// assert_eq!(g.ceil(), 4.0);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn ceil(self) -> f32 {
+ // see notes above in `floor`
+ #[cfg(target_env = "msvc")]
+ return (self as f64).ceil() as f32;
+ #[cfg(not(target_env = "msvc"))]
+ return unsafe { intrinsics::ceilf32(self) };
+ }
+
+ /// Returns the nearest integer to a number. Round half-way cases away from
+ /// `0.0`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let f = 3.3_f32;
+ /// let g = -3.3_f32;
+ ///
+ /// assert_eq!(f.round(), 3.0);
+ /// assert_eq!(g.round(), -3.0);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn round(self) -> f32 {
+ unsafe { intrinsics::roundf32(self) }
+ }
+
+ /// Returns the integer part of a number.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let f = 3.7_f32;
+ /// let g = 3.0_f32;
+ /// let h = -3.7_f32;
+ ///
+ /// assert_eq!(f.trunc(), 3.0);
+ /// assert_eq!(g.trunc(), 3.0);
+ /// assert_eq!(h.trunc(), -3.0);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn trunc(self) -> f32 {
+ unsafe { intrinsics::truncf32(self) }
+ }
+
+ /// Returns the fractional part of a number.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::f32;
+ ///
+ /// let x = 3.5_f32;
+ /// let y = -3.5_f32;
+ /// let abs_difference_x = (x.fract() - 0.5).abs();
+ /// let abs_difference_y = (y.fract() - (-0.5)).abs();
+ ///
+ /// assert!(abs_difference_x <= f32::EPSILON);
+ /// assert!(abs_difference_y <= f32::EPSILON);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn fract(self) -> f32 { self - self.trunc() }
+
+ /// Computes the absolute value of `self`. Returns `NAN` if the
+ /// number is `NAN`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::f32;
+ ///
+ /// let x = 3.5_f32;
+ /// let y = -3.5_f32;
+ ///
+ /// let abs_difference_x = (x.abs() - x).abs();
+ /// let abs_difference_y = (y.abs() - (-y)).abs();
+ ///
+ /// assert!(abs_difference_x <= f32::EPSILON);
+ /// assert!(abs_difference_y <= f32::EPSILON);
+ ///
+ /// assert!(f32::NAN.abs().is_nan());
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn abs(self) -> f32 {
+ unsafe { intrinsics::fabsf32(self) }
+ }
+
+ /// Returns a number that represents the sign of `self`.
+ ///
+ /// - `1.0` if the number is positive, `+0.0` or `INFINITY`
+ /// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY`
+ /// - `NAN` if the number is `NAN`
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::f32;
+ ///
+ /// let f = 3.5_f32;
+ ///
+ /// assert_eq!(f.signum(), 1.0);
+ /// assert_eq!(f32::NEG_INFINITY.signum(), -1.0);
+ ///
+ /// assert!(f32::NAN.signum().is_nan());
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn signum(self) -> f32 {
+ if self.is_nan() {
+ NAN
+ } else {
+ unsafe { intrinsics::copysignf32(1.0, self) }
+ }
+ }
+
+ /// Returns a number composed of the magnitude of `self` and the sign of
+ /// `sign`.
+ ///
+ /// Equal to `self` if the sign of `self` and `sign` are the same, otherwise
+ /// equal to `-self`. If `self` is a `NAN`, then a `NAN` with the sign of
+ /// `sign` is returned.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::f32;
+ ///
+ /// let f = 3.5_f32;
+ ///
+ /// assert_eq!(f.copysign(0.42), 3.5_f32);
+ /// assert_eq!(f.copysign(-0.42), -3.5_f32);
+ /// assert_eq!((-f).copysign(0.42), 3.5_f32);
+ /// assert_eq!((-f).copysign(-0.42), -3.5_f32);
+ ///
+ /// assert!(f32::NAN.copysign(1.0).is_nan());
+ /// ```
+ #[inline]
+ #[must_use]
+ #[stable(feature = "copysign", since = "1.35.0")]
+ pub fn copysign(self, sign: f32) -> f32 {
+ unsafe { intrinsics::copysignf32(self, sign) }
+ }
+
+ /// Fused multiply-add. Computes `(self * a) + b` with only one rounding
+ /// error, yielding a more accurate result than an unfused multiply-add.
+ ///
+ /// Using `mul_add` can be more performant than an unfused multiply-add if
+ /// the target architecture has a dedicated `fma` CPU instruction.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::f32;
+ ///
+ /// let m = 10.0_f32;
+ /// let x = 4.0_f32;
+ /// let b = 60.0_f32;
+ ///
+ /// // 100.0
+ /// let abs_difference = (m.mul_add(x, b) - (m*x + b)).abs();
+ ///
+ /// assert!(abs_difference <= f32::EPSILON);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn mul_add(self, a: f32, b: f32) -> f32 {
+ unsafe { intrinsics::fmaf32(self, a, b) }
+ }
+
+ /// Calculates Euclidean division, the matching method for `rem_euclid`.
+ ///
+ /// This computes the integer `n` such that
+ /// `self = n * rhs + self.rem_euclid(rhs)`.
+ /// In other words, the result is `self / rhs` rounded to the integer `n`
+ /// such that `self >= n * rhs`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(euclidean_division)]
+ /// let a: f32 = 7.0;
+ /// let b = 4.0;
+ /// assert_eq!(a.div_euclid(b), 1.0); // 7.0 > 4.0 * 1.0
+ /// assert_eq!((-a).div_euclid(b), -2.0); // -7.0 >= 4.0 * -2.0
+ /// assert_eq!(a.div_euclid(-b), -1.0); // 7.0 >= -4.0 * -1.0
+ /// assert_eq!((-a).div_euclid(-b), 2.0); // -7.0 >= -4.0 * 2.0
+ /// ```
+ #[inline]
+ #[unstable(feature = "euclidean_division", issue = "49048")]
+ pub fn div_euclid(self, rhs: f32) -> f32 {
+ let q = (self / rhs).trunc();
+ if self % rhs < 0.0 {
+ return if rhs > 0.0 { q - 1.0 } else { q + 1.0 }
+ }
+ q
+ }
+
+ /// Calculates the least nonnegative remainder of `self (mod rhs)`.
+ ///
+ /// 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_euclid(rhs) * rhs + self.rem_euclid(rhs)`
+ /// approximatively.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(euclidean_division)]
+ /// let a: f32 = 7.0;
+ /// let b = 4.0;
+ /// assert_eq!(a.rem_euclid(b), 3.0);
+ /// assert_eq!((-a).rem_euclid(b), 1.0);
+ /// assert_eq!(a.rem_euclid(-b), 3.0);
+ /// assert_eq!((-a).rem_euclid(-b), 1.0);
+ /// // limitation due to round-off error
+ /// assert!((-std::f32::EPSILON).rem_euclid(3.0) != 0.0);
+ /// ```
+ #[inline]
+ #[unstable(feature = "euclidean_division", issue = "49048")]
+ pub fn rem_euclid(self, rhs: f32) -> f32 {
+ let r = self % rhs;
+ if r < 0.0 {
+ r + rhs.abs()
+ } else {
+ r
+ }
+ }
+
+
+ /// Raises a number to an integer power.
+ ///
+ /// Using this function is generally faster than using `powf`
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::f32;
+ ///
+ /// let x = 2.0_f32;
+ /// let abs_difference = (x.powi(2) - x*x).abs();
+ ///
+ /// assert!(abs_difference <= f32::EPSILON);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn powi(self, n: i32) -> f32 {
+ unsafe { intrinsics::powif32(self, n) }
+ }
+
+ /// Raises a number to a floating point power.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::f32;
+ ///
+ /// let x = 2.0_f32;
+ /// let abs_difference = (x.powf(2.0) - x*x).abs();
+ ///
+ /// assert!(abs_difference <= f32::EPSILON);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn powf(self, n: f32) -> f32 {
+ // see notes above in `floor`
+ #[cfg(target_env = "msvc")]
+ return (self as f64).powf(n as f64) as f32;
+ #[cfg(not(target_env = "msvc"))]
+ return unsafe { intrinsics::powf32(self, n) };
+ }
+
+ /// Takes the square root of a number.
+ ///
+ /// Returns NaN if `self` is a negative number.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::f32;
+ ///
+ /// let positive = 4.0_f32;
+ /// let negative = -4.0_f32;
+ ///
+ /// let abs_difference = (positive.sqrt() - 2.0).abs();
+ ///
+ /// assert!(abs_difference <= f32::EPSILON);
+ /// assert!(negative.sqrt().is_nan());
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn sqrt(self) -> f32 {
+ if self < 0.0 {
+ NAN
+ } else {
+ unsafe { intrinsics::sqrtf32(self) }
+ }
+ }
+
+ /// Returns `e^(self)`, (the exponential function).
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::f32;
+ ///
+ /// let one = 1.0f32;
+ /// // e^1
+ /// let e = one.exp();
+ ///
+ /// // ln(e) - 1 == 0
+ /// let abs_difference = (e.ln() - 1.0).abs();
+ ///
+ /// assert!(abs_difference <= f32::EPSILON);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn exp(self) -> f32 {
+ // see notes above in `floor`
+ #[cfg(target_env = "msvc")]
+ return (self as f64).exp() as f32;
+ #[cfg(not(target_env = "msvc"))]
+ return unsafe { intrinsics::expf32(self) };
+ }
+
+ /// Returns `2^(self)`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::f32;
+ ///
+ /// let f = 2.0f32;
+ ///
+ /// // 2^2 - 4 == 0
+ /// let abs_difference = (f.exp2() - 4.0).abs();
+ ///
+ /// assert!(abs_difference <= f32::EPSILON);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn exp2(self) -> f32 {
+ unsafe { intrinsics::exp2f32(self) }
+ }
+
+ /// Returns the natural logarithm of the number.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::f32;
+ ///
+ /// let one = 1.0f32;
+ /// // e^1
+ /// let e = one.exp();
+ ///
+ /// // ln(e) - 1 == 0
+ /// let abs_difference = (e.ln() - 1.0).abs();
+ ///
+ /// assert!(abs_difference <= f32::EPSILON);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn ln(self) -> f32 {
+ // see notes above in `floor`
+ #[cfg(target_env = "msvc")]
+ return (self as f64).ln() as f32;
+ #[cfg(not(target_env = "msvc"))]
+ return unsafe { intrinsics::logf32(self) };
+ }
+
+ /// Returns the logarithm of the number with respect to an arbitrary base.
+ ///
+ /// The result may not be correctly rounded owing to implementation details;
+ /// `self.log2()` can produce more accurate results for base 2, and
+ /// `self.log10()` can produce more accurate results for base 10.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::f32;
+ ///
+ /// let five = 5.0f32;
+ ///
+ /// // log5(5) - 1 == 0
+ /// let abs_difference = (five.log(5.0) - 1.0).abs();
+ ///
+ /// assert!(abs_difference <= f32::EPSILON);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn log(self, base: f32) -> f32 { self.ln() / base.ln() }
+
+ /// Returns the base 2 logarithm of the number.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::f32;
+ ///
+ /// let two = 2.0f32;
+ ///
+ /// // log2(2) - 1 == 0
+ /// let abs_difference = (two.log2() - 1.0).abs();
+ ///
+ /// assert!(abs_difference <= f32::EPSILON);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn log2(self) -> f32 {
+ #[cfg(target_os = "android")]
+ return crate::sys::android::log2f32(self);
+ #[cfg(not(target_os = "android"))]
+ return unsafe { intrinsics::log2f32(self) };
+ }
+
+ /// Returns the base 10 logarithm of the number.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::f32;
+ ///
+ /// let ten = 10.0f32;
+ ///
+ /// // log10(10) - 1 == 0
+ /// let abs_difference = (ten.log10() - 1.0).abs();
+ ///
+ /// assert!(abs_difference <= f32::EPSILON);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn log10(self) -> f32 {
+ // see notes above in `floor`
+ #[cfg(target_env = "msvc")]
+ return (self as f64).log10() as f32;
+ #[cfg(not(target_env = "msvc"))]
+ return unsafe { intrinsics::log10f32(self) };
+ }
+
+ /// The positive difference of two numbers.
+ ///
+ /// * If `self <= other`: `0:0`
+ /// * Else: `self - other`
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::f32;
+ ///
+ /// let x = 3.0f32;
+ /// let y = -3.0f32;
+ ///
+ /// let abs_difference_x = (x.abs_sub(1.0) - 2.0).abs();
+ /// let abs_difference_y = (y.abs_sub(1.0) - 0.0).abs();
+ ///
+ /// assert!(abs_difference_x <= f32::EPSILON);
+ /// assert!(abs_difference_y <= f32::EPSILON);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ #[rustc_deprecated(since = "1.10.0",
+ reason = "you probably meant `(self - other).abs()`: \
+ this operation is `(self - other).max(0.0)` \
+ except that `abs_sub` also propagates NaNs (also \
+ known as `fdimf` in C). If you truly need the positive \
+ difference, consider using that expression or the C function \
+ `fdimf`, depending on how you wish to handle NaN (please consider \
+ filing an issue describing your use-case too).")]
+ pub fn abs_sub(self, other: f32) -> f32 {
+ unsafe { cmath::fdimf(self, other) }
+ }
+
+ /// Takes the cubic root of a number.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::f32;
+ ///
+ /// let x = 8.0f32;
+ ///
+ /// // x^(1/3) - 2 == 0
+ /// let abs_difference = (x.cbrt() - 2.0).abs();
+ ///
+ /// assert!(abs_difference <= f32::EPSILON);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn cbrt(self) -> f32 {
+ unsafe { cmath::cbrtf(self) }
+ }
+
+ /// Calculates the length of the hypotenuse of a right-angle triangle given
+ /// legs of length `x` and `y`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::f32;
+ ///
+ /// let x = 2.0f32;
+ /// let y = 3.0f32;
+ ///
+ /// // sqrt(x^2 + y^2)
+ /// let abs_difference = (x.hypot(y) - (x.powi(2) + y.powi(2)).sqrt()).abs();
+ ///
+ /// assert!(abs_difference <= f32::EPSILON);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn hypot(self, other: f32) -> f32 {
+ unsafe { cmath::hypotf(self, other) }
+ }
+
+ /// Computes the sine of a number (in radians).
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::f32;
+ ///
+ /// let x = f32::consts::PI/2.0;
+ ///
+ /// let abs_difference = (x.sin() - 1.0).abs();
+ ///
+ /// assert!(abs_difference <= f32::EPSILON);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn sin(self) -> f32 {
+ // see notes in `core::f32::Float::floor`
+ #[cfg(target_env = "msvc")]
+ return (self as f64).sin() as f32;
+ #[cfg(not(target_env = "msvc"))]
+ return unsafe { intrinsics::sinf32(self) };
+ }
+
+ /// Computes the cosine of a number (in radians).
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::f32;
+ ///
+ /// let x = 2.0*f32::consts::PI;
+ ///
+ /// let abs_difference = (x.cos() - 1.0).abs();
+ ///
+ /// assert!(abs_difference <= f32::EPSILON);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn cos(self) -> f32 {
+ // see notes in `core::f32::Float::floor`
+ #[cfg(target_env = "msvc")]
+ return (self as f64).cos() as f32;
+ #[cfg(not(target_env = "msvc"))]
+ return unsafe { intrinsics::cosf32(self) };
+ }
+
+ /// Computes the tangent of a number (in radians).
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::f32;
+ ///
+ /// let x = f32::consts::PI / 4.0;
+ /// let abs_difference = (x.tan() - 1.0).abs();
+ ///
+ /// assert!(abs_difference <= f32::EPSILON);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn tan(self) -> f32 {
+ unsafe { cmath::tanf(self) }
+ }
+
+ /// Computes the arcsine of a number. Return value is in radians in
+ /// the range [-pi/2, pi/2] or NaN if the number is outside the range
+ /// [-1, 1].
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::f32;
+ ///
+ /// let f = f32::consts::PI / 2.0;
+ ///
+ /// // asin(sin(pi/2))
+ /// let abs_difference = (f.sin().asin() - f32::consts::PI / 2.0).abs();
+ ///
+ /// assert!(abs_difference <= f32::EPSILON);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn asin(self) -> f32 {
+ unsafe { cmath::asinf(self) }
+ }
+
+ /// Computes the arccosine of a number. Return value is in radians in
+ /// the range [0, pi] or NaN if the number is outside the range
+ /// [-1, 1].
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::f32;
+ ///
+ /// let f = f32::consts::PI / 4.0;
+ ///
+ /// // acos(cos(pi/4))
+ /// let abs_difference = (f.cos().acos() - f32::consts::PI / 4.0).abs();
+ ///
+ /// assert!(abs_difference <= f32::EPSILON);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn acos(self) -> f32 {
+ unsafe { cmath::acosf(self) }
+ }
+
+ /// Computes the arctangent of a number. Return value is in radians in the
+ /// range [-pi/2, pi/2];
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::f32;
+ ///
+ /// let f = 1.0f32;
+ ///
+ /// // atan(tan(1))
+ /// let abs_difference = (f.tan().atan() - 1.0).abs();
+ ///
+ /// assert!(abs_difference <= f32::EPSILON);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn atan(self) -> f32 {
+ unsafe { cmath::atanf(self) }
+ }
+
+ /// Computes the four quadrant arctangent of `self` (`y`) and `other` (`x`) in radians.
+ ///
+ /// * `x = 0`, `y = 0`: `0`
+ /// * `x >= 0`: `arctan(y/x)` -> `[-pi/2, pi/2]`
+ /// * `y >= 0`: `arctan(y/x) + pi` -> `(pi/2, pi]`
+ /// * `y < 0`: `arctan(y/x) - pi` -> `(-pi, -pi/2)`
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::f32;
+ ///
+ /// let pi = f32::consts::PI;
+ /// // Positive angles measured counter-clockwise
+ /// // from positive x axis
+ /// // -pi/4 radians (45 deg clockwise)
+ /// let x1 = 3.0f32;
+ /// let y1 = -3.0f32;
+ ///
+ /// // 3pi/4 radians (135 deg counter-clockwise)
+ /// let x2 = -3.0f32;
+ /// let y2 = 3.0f32;
+ ///
+ /// let abs_difference_1 = (y1.atan2(x1) - (-pi/4.0)).abs();
+ /// let abs_difference_2 = (y2.atan2(x2) - 3.0*pi/4.0).abs();
+ ///
+ /// assert!(abs_difference_1 <= f32::EPSILON);
+ /// assert!(abs_difference_2 <= f32::EPSILON);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn atan2(self, other: f32) -> f32 {
+ unsafe { cmath::atan2f(self, other) }
+ }
+
+ /// Simultaneously computes the sine and cosine of the number, `x`. Returns
+ /// `(sin(x), cos(x))`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::f32;
+ ///
+ /// let x = f32::consts::PI/4.0;
+ /// let f = x.sin_cos();
+ ///
+ /// let abs_difference_0 = (f.0 - x.sin()).abs();
+ /// let abs_difference_1 = (f.1 - x.cos()).abs();
+ ///
+ /// assert!(abs_difference_0 <= f32::EPSILON);
+ /// assert!(abs_difference_1 <= f32::EPSILON);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn sin_cos(self) -> (f32, f32) {
+ (self.sin(), self.cos())
+ }
+
+ /// Returns `e^(self) - 1` in a way that is accurate even if the
+ /// number is close to zero.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::f32;
+ ///
+ /// let x = 6.0f32;
+ ///
+ /// // e^(ln(6)) - 1
+ /// let abs_difference = (x.ln().exp_m1() - 5.0).abs();
+ ///
+ /// assert!(abs_difference <= f32::EPSILON);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn exp_m1(self) -> f32 {
+ unsafe { cmath::expm1f(self) }
+ }
+
+ /// Returns `ln(1+n)` (natural logarithm) more accurately than if
+ /// the operations were performed separately.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::f32;
+ ///
+ /// let x = f32::consts::E - 1.0;
+ ///
+ /// // ln(1 + (e - 1)) == ln(e) == 1
+ /// let abs_difference = (x.ln_1p() - 1.0).abs();
+ ///
+ /// assert!(abs_difference <= f32::EPSILON);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn ln_1p(self) -> f32 {
+ unsafe { cmath::log1pf(self) }
+ }
+
+ /// Hyperbolic sine function.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::f32;
+ ///
+ /// let e = f32::consts::E;
+ /// let x = 1.0f32;
+ ///
+ /// let f = x.sinh();
+ /// // Solving sinh() at 1 gives `(e^2-1)/(2e)`
+ /// let g = (e*e - 1.0)/(2.0*e);
+ /// let abs_difference = (f - g).abs();
+ ///
+ /// assert!(abs_difference <= f32::EPSILON);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn sinh(self) -> f32 {
+ unsafe { cmath::sinhf(self) }
+ }
+
+ /// Hyperbolic cosine function.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::f32;
+ ///
+ /// let e = f32::consts::E;
+ /// let x = 1.0f32;
+ /// let f = x.cosh();
+ /// // Solving cosh() at 1 gives this result
+ /// let g = (e*e + 1.0)/(2.0*e);
+ /// let abs_difference = (f - g).abs();
+ ///
+ /// // Same result
+ /// assert!(abs_difference <= f32::EPSILON);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn cosh(self) -> f32 {
+ unsafe { cmath::coshf(self) }
+ }
+
+ /// Hyperbolic tangent function.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::f32;
+ ///
+ /// let e = f32::consts::E;
+ /// let x = 1.0f32;
+ ///
+ /// let f = x.tanh();
+ /// // Solving tanh() at 1 gives `(1 - e^(-2))/(1 + e^(-2))`
+ /// let g = (1.0 - e.powi(-2))/(1.0 + e.powi(-2));
+ /// let abs_difference = (f - g).abs();
+ ///
+ /// assert!(abs_difference <= f32::EPSILON);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn tanh(self) -> f32 {
+ unsafe { cmath::tanhf(self) }
+ }
+
+ /// Inverse hyperbolic sine function.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::f32;
+ ///
+ /// let x = 1.0f32;
+ /// let f = x.sinh().asinh();
+ ///
+ /// let abs_difference = (f - x).abs();
+ ///
+ /// assert!(abs_difference <= f32::EPSILON);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn asinh(self) -> f32 {
+ if self == NEG_INFINITY {
+ NEG_INFINITY
+ } else {
+ (self + ((self * self) + 1.0).sqrt()).ln()
+ }
+ }
+
+ /// Inverse hyperbolic cosine function.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::f32;
+ ///
+ /// let x = 1.0f32;
+ /// let f = x.cosh().acosh();
+ ///
+ /// let abs_difference = (f - x).abs();
+ ///
+ /// assert!(abs_difference <= f32::EPSILON);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn acosh(self) -> f32 {
+ match self {
+ x if x < 1.0 => crate::f32::NAN,
+ x => (x + ((x * x) - 1.0).sqrt()).ln(),
+ }
+ }
+
+ /// Inverse hyperbolic tangent function.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::f32;
+ ///
+ /// let e = f32::consts::E;
+ /// let f = e.tanh().atanh();
+ ///
+ /// let abs_difference = (f - e).abs();
+ ///
+ /// assert!(abs_difference <= 1e-5);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn atanh(self) -> f32 {
+ 0.5 * ((2.0 * self) / (1.0 - self)).ln_1p()
+ }
+
+ /// Restrict a value to a certain interval unless it is NaN.
+ ///
+ /// Returns `max` if `self` is greater than `max`, and `min` if `self` is
+ /// less than `min`. Otherwise this returns `self`.
+ ///
+ /// Not that this function returns NaN if the initial value was NaN as
+ /// well.
+ ///
+ /// # Panics
+ ///
+ /// Panics if `min > max`, `min` is NaN, or `max` is NaN.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(clamp)]
+ /// assert!((-3.0f32).clamp(-2.0, 1.0) == -2.0);
+ /// assert!((0.0f32).clamp(-2.0, 1.0) == 0.0);
+ /// assert!((2.0f32).clamp(-2.0, 1.0) == 1.0);
+ /// assert!((std::f32::NAN).clamp(-2.0, 1.0).is_nan());
+ /// ```
+ #[unstable(feature = "clamp", issue = "44095")]
+ #[inline]
+ pub fn clamp(self, min: f32, max: f32) -> f32 {
+ assert!(min <= max);
+ let mut x = self;
+ if x < min { x = min; }
+ if x > max { x = max; }
+ x
+ }
+
+}
+
+#[cfg(test)]
+mod tests {
+ use crate::f32;
+ use crate::f32::*;
+ use crate::num::*;
+ use crate::num::FpCategory as Fp;
+
+ #[test]
+ fn test_num_f32() {
+ test_num(10f32, 2f32);
+ }
+
+ #[test]
+ fn test_min_nan() {
+ assert_eq!(NAN.min(2.0), 2.0);
+ assert_eq!(2.0f32.min(NAN), 2.0);
+ }
+
+ #[test]
+ fn test_max_nan() {
+ assert_eq!(NAN.max(2.0), 2.0);
+ assert_eq!(2.0f32.max(NAN), 2.0);
+ }
+
+ #[test]
+ fn test_nan() {
+ let nan: f32 = f32::NAN;
+ assert!(nan.is_nan());
+ assert!(!nan.is_infinite());
+ assert!(!nan.is_finite());
+ assert!(!nan.is_normal());
+ assert!(nan.is_sign_positive());
+ assert!(!nan.is_sign_negative());
+ assert_eq!(Fp::Nan, nan.classify());
+ }
+
+ #[test]
+ fn test_infinity() {
+ let inf: f32 = f32::INFINITY;
+ assert!(inf.is_infinite());
+ assert!(!inf.is_finite());
+ assert!(inf.is_sign_positive());
+ assert!(!inf.is_sign_negative());
+ assert!(!inf.is_nan());
+ assert!(!inf.is_normal());
+ assert_eq!(Fp::Infinite, inf.classify());
+ }
+
+ #[test]
+ fn test_neg_infinity() {
+ let neg_inf: f32 = f32::NEG_INFINITY;
+ assert!(neg_inf.is_infinite());
+ assert!(!neg_inf.is_finite());
+ assert!(!neg_inf.is_sign_positive());
+ assert!(neg_inf.is_sign_negative());
+ assert!(!neg_inf.is_nan());
+ assert!(!neg_inf.is_normal());
+ assert_eq!(Fp::Infinite, neg_inf.classify());
+ }
+
+ #[test]
+ fn test_zero() {
+ let zero: f32 = 0.0f32;
+ assert_eq!(0.0, zero);
+ assert!(!zero.is_infinite());
+ assert!(zero.is_finite());
+ assert!(zero.is_sign_positive());
+ assert!(!zero.is_sign_negative());
+ assert!(!zero.is_nan());
+ assert!(!zero.is_normal());
+ assert_eq!(Fp::Zero, zero.classify());
+ }
+
+ #[test]
+ fn test_neg_zero() {
+ let neg_zero: f32 = -0.0;
+ assert_eq!(0.0, neg_zero);
+ assert!(!neg_zero.is_infinite());
+ assert!(neg_zero.is_finite());
+ assert!(!neg_zero.is_sign_positive());
+ assert!(neg_zero.is_sign_negative());
+ assert!(!neg_zero.is_nan());
+ assert!(!neg_zero.is_normal());
+ assert_eq!(Fp::Zero, neg_zero.classify());
+ }
+
+ #[test]
+ fn test_one() {
+ let one: f32 = 1.0f32;
+ assert_eq!(1.0, one);
+ assert!(!one.is_infinite());
+ assert!(one.is_finite());
+ assert!(one.is_sign_positive());
+ assert!(!one.is_sign_negative());
+ assert!(!one.is_nan());
+ assert!(one.is_normal());
+ assert_eq!(Fp::Normal, one.classify());
+ }
+
+ #[test]
+ fn test_is_nan() {
+ let nan: f32 = f32::NAN;
+ let inf: f32 = f32::INFINITY;
+ let neg_inf: f32 = f32::NEG_INFINITY;
+ assert!(nan.is_nan());
+ assert!(!0.0f32.is_nan());
+ assert!(!5.3f32.is_nan());
+ assert!(!(-10.732f32).is_nan());
+ assert!(!inf.is_nan());
+ assert!(!neg_inf.is_nan());
+ }
+
+ #[test]
+ fn test_is_infinite() {
+ let nan: f32 = f32::NAN;
+ let inf: f32 = f32::INFINITY;
+ let neg_inf: f32 = f32::NEG_INFINITY;
+ assert!(!nan.is_infinite());
+ assert!(inf.is_infinite());
+ assert!(neg_inf.is_infinite());
+ assert!(!0.0f32.is_infinite());
+ assert!(!42.8f32.is_infinite());
+ assert!(!(-109.2f32).is_infinite());
+ }
+
+ #[test]
+ fn test_is_finite() {
+ let nan: f32 = f32::NAN;
+ let inf: f32 = f32::INFINITY;
+ let neg_inf: f32 = f32::NEG_INFINITY;
+ assert!(!nan.is_finite());
+ assert!(!inf.is_finite());
+ assert!(!neg_inf.is_finite());
+ assert!(0.0f32.is_finite());
+ assert!(42.8f32.is_finite());
+ assert!((-109.2f32).is_finite());
+ }
+
+ #[test]
+ fn test_is_normal() {
+ let nan: f32 = f32::NAN;
+ let inf: f32 = f32::INFINITY;
+ let neg_inf: f32 = f32::NEG_INFINITY;
+ let zero: f32 = 0.0f32;
+ let neg_zero: f32 = -0.0;
+ assert!(!nan.is_normal());
+ assert!(!inf.is_normal());
+ assert!(!neg_inf.is_normal());
+ assert!(!zero.is_normal());
+ assert!(!neg_zero.is_normal());
+ assert!(1f32.is_normal());
+ assert!(1e-37f32.is_normal());
+ assert!(!1e-38f32.is_normal());
+ }
+
+ #[test]
+ fn test_classify() {
+ let nan: f32 = f32::NAN;
+ let inf: f32 = f32::INFINITY;
+ let neg_inf: f32 = f32::NEG_INFINITY;
+ let zero: f32 = 0.0f32;
+ let neg_zero: f32 = -0.0;
+ assert_eq!(nan.classify(), Fp::Nan);
+ assert_eq!(inf.classify(), Fp::Infinite);
+ assert_eq!(neg_inf.classify(), Fp::Infinite);
+ assert_eq!(zero.classify(), Fp::Zero);
+ assert_eq!(neg_zero.classify(), Fp::Zero);
+ assert_eq!(1f32.classify(), Fp::Normal);
+ assert_eq!(1e-37f32.classify(), Fp::Normal);
+ assert_eq!(1e-38f32.classify(), Fp::Subnormal);
+ }
+
+ #[test]
+ fn test_floor() {
+ assert_approx_eq!(1.0f32.floor(), 1.0f32);
+ assert_approx_eq!(1.3f32.floor(), 1.0f32);
+ assert_approx_eq!(1.5f32.floor(), 1.0f32);
+ assert_approx_eq!(1.7f32.floor(), 1.0f32);
+ assert_approx_eq!(0.0f32.floor(), 0.0f32);
+ assert_approx_eq!((-0.0f32).floor(), -0.0f32);
+ assert_approx_eq!((-1.0f32).floor(), -1.0f32);
+ assert_approx_eq!((-1.3f32).floor(), -2.0f32);
+ assert_approx_eq!((-1.5f32).floor(), -2.0f32);
+ assert_approx_eq!((-1.7f32).floor(), -2.0f32);
+ }
+
+ #[test]
+ fn test_ceil() {
+ assert_approx_eq!(1.0f32.ceil(), 1.0f32);
+ assert_approx_eq!(1.3f32.ceil(), 2.0f32);
+ assert_approx_eq!(1.5f32.ceil(), 2.0f32);
+ assert_approx_eq!(1.7f32.ceil(), 2.0f32);
+ assert_approx_eq!(0.0f32.ceil(), 0.0f32);
+ assert_approx_eq!((-0.0f32).ceil(), -0.0f32);
+ assert_approx_eq!((-1.0f32).ceil(), -1.0f32);
+ assert_approx_eq!((-1.3f32).ceil(), -1.0f32);
+ assert_approx_eq!((-1.5f32).ceil(), -1.0f32);
+ assert_approx_eq!((-1.7f32).ceil(), -1.0f32);
+ }
+
+ #[test]
+ fn test_round() {
+ assert_approx_eq!(1.0f32.round(), 1.0f32);
+ assert_approx_eq!(1.3f32.round(), 1.0f32);
+ assert_approx_eq!(1.5f32.round(), 2.0f32);
+ assert_approx_eq!(1.7f32.round(), 2.0f32);
+ assert_approx_eq!(0.0f32.round(), 0.0f32);
+ assert_approx_eq!((-0.0f32).round(), -0.0f32);
+ assert_approx_eq!((-1.0f32).round(), -1.0f32);
+ assert_approx_eq!((-1.3f32).round(), -1.0f32);
+ assert_approx_eq!((-1.5f32).round(), -2.0f32);
+ assert_approx_eq!((-1.7f32).round(), -2.0f32);
+ }
+
+ #[test]
+ fn test_trunc() {
+ assert_approx_eq!(1.0f32.trunc(), 1.0f32);
+ assert_approx_eq!(1.3f32.trunc(), 1.0f32);
+ assert_approx_eq!(1.5f32.trunc(), 1.0f32);
+ assert_approx_eq!(1.7f32.trunc(), 1.0f32);
+ assert_approx_eq!(0.0f32.trunc(), 0.0f32);
+ assert_approx_eq!((-0.0f32).trunc(), -0.0f32);
+ assert_approx_eq!((-1.0f32).trunc(), -1.0f32);
+ assert_approx_eq!((-1.3f32).trunc(), -1.0f32);
+ assert_approx_eq!((-1.5f32).trunc(), -1.0f32);
+ assert_approx_eq!((-1.7f32).trunc(), -1.0f32);
+ }
+
+ #[test]
+ fn test_fract() {
+ assert_approx_eq!(1.0f32.fract(), 0.0f32);
+ assert_approx_eq!(1.3f32.fract(), 0.3f32);
+ assert_approx_eq!(1.5f32.fract(), 0.5f32);
+ assert_approx_eq!(1.7f32.fract(), 0.7f32);
+ assert_approx_eq!(0.0f32.fract(), 0.0f32);
+ assert_approx_eq!((-0.0f32).fract(), -0.0f32);
+ assert_approx_eq!((-1.0f32).fract(), -0.0f32);
+ assert_approx_eq!((-1.3f32).fract(), -0.3f32);
+ assert_approx_eq!((-1.5f32).fract(), -0.5f32);
+ assert_approx_eq!((-1.7f32).fract(), -0.7f32);
+ }
+
+ #[test]
+ fn test_abs() {
+ assert_eq!(INFINITY.abs(), INFINITY);
+ assert_eq!(1f32.abs(), 1f32);
+ assert_eq!(0f32.abs(), 0f32);
+ assert_eq!((-0f32).abs(), 0f32);
+ assert_eq!((-1f32).abs(), 1f32);
+ assert_eq!(NEG_INFINITY.abs(), INFINITY);
+ assert_eq!((1f32/NEG_INFINITY).abs(), 0f32);
+ assert!(NAN.abs().is_nan());
+ }
+
+ #[test]
+ fn test_signum() {
+ assert_eq!(INFINITY.signum(), 1f32);
+ assert_eq!(1f32.signum(), 1f32);
+ assert_eq!(0f32.signum(), 1f32);
+ assert_eq!((-0f32).signum(), -1f32);
+ assert_eq!((-1f32).signum(), -1f32);
+ assert_eq!(NEG_INFINITY.signum(), -1f32);
+ assert_eq!((1f32/NEG_INFINITY).signum(), -1f32);
+ assert!(NAN.signum().is_nan());
+ }
+
+ #[test]
+ fn test_is_sign_positive() {
+ assert!(INFINITY.is_sign_positive());
+ assert!(1f32.is_sign_positive());
+ assert!(0f32.is_sign_positive());
+ assert!(!(-0f32).is_sign_positive());
+ assert!(!(-1f32).is_sign_positive());
+ assert!(!NEG_INFINITY.is_sign_positive());
+ assert!(!(1f32/NEG_INFINITY).is_sign_positive());
+ assert!(NAN.is_sign_positive());
+ assert!(!(-NAN).is_sign_positive());
+ }
+
+ #[test]
+ fn test_is_sign_negative() {
+ assert!(!INFINITY.is_sign_negative());
+ assert!(!1f32.is_sign_negative());
+ assert!(!0f32.is_sign_negative());
+ assert!((-0f32).is_sign_negative());
+ assert!((-1f32).is_sign_negative());
+ assert!(NEG_INFINITY.is_sign_negative());
+ assert!((1f32/NEG_INFINITY).is_sign_negative());
+ assert!(!NAN.is_sign_negative());
+ assert!((-NAN).is_sign_negative());
+ }
+
+ #[test]
+ fn test_mul_add() {
+ let nan: f32 = f32::NAN;
+ let inf: f32 = f32::INFINITY;
+ let neg_inf: f32 = f32::NEG_INFINITY;
+ assert_approx_eq!(12.3f32.mul_add(4.5, 6.7), 62.05);
+ assert_approx_eq!((-12.3f32).mul_add(-4.5, -6.7), 48.65);
+ assert_approx_eq!(0.0f32.mul_add(8.9, 1.2), 1.2);
+ assert_approx_eq!(3.4f32.mul_add(-0.0, 5.6), 5.6);
+ assert!(nan.mul_add(7.8, 9.0).is_nan());
+ assert_eq!(inf.mul_add(7.8, 9.0), inf);
+ assert_eq!(neg_inf.mul_add(7.8, 9.0), neg_inf);
+ assert_eq!(8.9f32.mul_add(inf, 3.2), inf);
+ assert_eq!((-3.2f32).mul_add(2.4, neg_inf), neg_inf);
+ }
+
+ #[test]
+ fn test_recip() {
+ let nan: f32 = f32::NAN;
+ let inf: f32 = f32::INFINITY;
+ let neg_inf: f32 = f32::NEG_INFINITY;
+ assert_eq!(1.0f32.recip(), 1.0);
+ assert_eq!(2.0f32.recip(), 0.5);
+ assert_eq!((-0.4f32).recip(), -2.5);
+ assert_eq!(0.0f32.recip(), inf);
+ assert!(nan.recip().is_nan());
+ assert_eq!(inf.recip(), 0.0);
+ assert_eq!(neg_inf.recip(), 0.0);
+ }
+
+ #[test]
+ fn test_powi() {
+ let nan: f32 = f32::NAN;
+ let inf: f32 = f32::INFINITY;
+ let neg_inf: f32 = f32::NEG_INFINITY;
+ assert_eq!(1.0f32.powi(1), 1.0);
+ assert_approx_eq!((-3.1f32).powi(2), 9.61);
+ assert_approx_eq!(5.9f32.powi(-2), 0.028727);
+ assert_eq!(8.3f32.powi(0), 1.0);
+ assert!(nan.powi(2).is_nan());
+ assert_eq!(inf.powi(3), inf);
+ assert_eq!(neg_inf.powi(2), inf);
+ }
+
+ #[test]
+ fn test_powf() {
+ let nan: f32 = f32::NAN;
+ let inf: f32 = f32::INFINITY;
+ let neg_inf: f32 = f32::NEG_INFINITY;
+ assert_eq!(1.0f32.powf(1.0), 1.0);
+ assert_approx_eq!(3.4f32.powf(4.5), 246.408218);
+ assert_approx_eq!(2.7f32.powf(-3.2), 0.041652);
+ assert_approx_eq!((-3.1f32).powf(2.0), 9.61);
+ assert_approx_eq!(5.9f32.powf(-2.0), 0.028727);
+ assert_eq!(8.3f32.powf(0.0), 1.0);
+ assert!(nan.powf(2.0).is_nan());
+ assert_eq!(inf.powf(2.0), inf);
+ assert_eq!(neg_inf.powf(3.0), neg_inf);
+ }
+
+ #[test]
+ fn test_sqrt_domain() {
+ assert!(NAN.sqrt().is_nan());
+ assert!(NEG_INFINITY.sqrt().is_nan());
+ assert!((-1.0f32).sqrt().is_nan());
+ assert_eq!((-0.0f32).sqrt(), -0.0);
+ assert_eq!(0.0f32.sqrt(), 0.0);
+ assert_eq!(1.0f32.sqrt(), 1.0);
+ assert_eq!(INFINITY.sqrt(), INFINITY);
+ }
+
+ #[test]
+ fn test_exp() {
+ assert_eq!(1.0, 0.0f32.exp());
+ assert_approx_eq!(2.718282, 1.0f32.exp());
+ assert_approx_eq!(148.413162, 5.0f32.exp());
+
+ let inf: f32 = f32::INFINITY;
+ let neg_inf: f32 = f32::NEG_INFINITY;
+ let nan: f32 = f32::NAN;
+ assert_eq!(inf, inf.exp());
+ assert_eq!(0.0, neg_inf.exp());
+ assert!(nan.exp().is_nan());
+ }
+
+ #[test]
+ fn test_exp2() {
+ assert_eq!(32.0, 5.0f32.exp2());
+ assert_eq!(1.0, 0.0f32.exp2());
+
+ let inf: f32 = f32::INFINITY;
+ let neg_inf: f32 = f32::NEG_INFINITY;
+ let nan: f32 = f32::NAN;
+ assert_eq!(inf, inf.exp2());
+ assert_eq!(0.0, neg_inf.exp2());
+ assert!(nan.exp2().is_nan());
+ }
+
+ #[test]
+ fn test_ln() {
+ let nan: f32 = f32::NAN;
+ let inf: f32 = f32::INFINITY;
+ let neg_inf: f32 = f32::NEG_INFINITY;
+ assert_approx_eq!(1.0f32.exp().ln(), 1.0);
+ assert!(nan.ln().is_nan());
+ assert_eq!(inf.ln(), inf);
+ assert!(neg_inf.ln().is_nan());
+ assert!((-2.3f32).ln().is_nan());
+ assert_eq!((-0.0f32).ln(), neg_inf);
+ assert_eq!(0.0f32.ln(), neg_inf);
+ assert_approx_eq!(4.0f32.ln(), 1.386294);
+ }
+
+ #[test]
+ fn test_log() {
+ let nan: f32 = f32::NAN;
+ let inf: f32 = f32::INFINITY;
+ let neg_inf: f32 = f32::NEG_INFINITY;
+ assert_eq!(10.0f32.log(10.0), 1.0);
+ assert_approx_eq!(2.3f32.log(3.5), 0.664858);
+ assert_eq!(1.0f32.exp().log(1.0f32.exp()), 1.0);
+ assert!(1.0f32.log(1.0).is_nan());
+ assert!(1.0f32.log(-13.9).is_nan());
+ assert!(nan.log(2.3).is_nan());
+ assert_eq!(inf.log(10.0), inf);
+ assert!(neg_inf.log(8.8).is_nan());
+ assert!((-2.3f32).log(0.1).is_nan());
+ assert_eq!((-0.0f32).log(2.0), neg_inf);
+ assert_eq!(0.0f32.log(7.0), neg_inf);
+ }
+
+ #[test]
+ fn test_log2() {
+ let nan: f32 = f32::NAN;
+ let inf: f32 = f32::INFINITY;
+ let neg_inf: f32 = f32::NEG_INFINITY;
+ assert_approx_eq!(10.0f32.log2(), 3.321928);
+ assert_approx_eq!(2.3f32.log2(), 1.201634);
+ assert_approx_eq!(1.0f32.exp().log2(), 1.442695);
+ assert!(nan.log2().is_nan());
+ assert_eq!(inf.log2(), inf);
+ assert!(neg_inf.log2().is_nan());
+ assert!((-2.3f32).log2().is_nan());
+ assert_eq!((-0.0f32).log2(), neg_inf);
+ assert_eq!(0.0f32.log2(), neg_inf);
+ }
+
+ #[test]
+ fn test_log10() {
+ let nan: f32 = f32::NAN;
+ let inf: f32 = f32::INFINITY;
+ let neg_inf: f32 = f32::NEG_INFINITY;
+ assert_eq!(10.0f32.log10(), 1.0);
+ assert_approx_eq!(2.3f32.log10(), 0.361728);
+ assert_approx_eq!(1.0f32.exp().log10(), 0.434294);
+ assert_eq!(1.0f32.log10(), 0.0);
+ assert!(nan.log10().is_nan());
+ assert_eq!(inf.log10(), inf);
+ assert!(neg_inf.log10().is_nan());
+ assert!((-2.3f32).log10().is_nan());
+ assert_eq!((-0.0f32).log10(), neg_inf);
+ assert_eq!(0.0f32.log10(), neg_inf);
+ }
+
+ #[test]
+ fn test_to_degrees() {
+ let pi: f32 = consts::PI;
+ let nan: f32 = f32::NAN;
+ let inf: f32 = f32::INFINITY;
+ let neg_inf: f32 = f32::NEG_INFINITY;
+ assert_eq!(0.0f32.to_degrees(), 0.0);
+ assert_approx_eq!((-5.8f32).to_degrees(), -332.315521);
+ assert_eq!(pi.to_degrees(), 180.0);
+ assert!(nan.to_degrees().is_nan());
+ assert_eq!(inf.to_degrees(), inf);
+ assert_eq!(neg_inf.to_degrees(), neg_inf);
+ assert_eq!(1_f32.to_degrees(), 57.2957795130823208767981548141051703);
+ }
+
+ #[test]
+ fn test_to_radians() {
+ let pi: f32 = consts::PI;
+ let nan: f32 = f32::NAN;
+ let inf: f32 = f32::INFINITY;
+ let neg_inf: f32 = f32::NEG_INFINITY;
+ assert_eq!(0.0f32.to_radians(), 0.0);
+ assert_approx_eq!(154.6f32.to_radians(), 2.698279);
+ assert_approx_eq!((-332.31f32).to_radians(), -5.799903);
+ assert_eq!(180.0f32.to_radians(), pi);
+ assert!(nan.to_radians().is_nan());
+ assert_eq!(inf.to_radians(), inf);
+ assert_eq!(neg_inf.to_radians(), neg_inf);
+ }
+
+ #[test]
+ fn test_asinh() {
+ assert_eq!(0.0f32.asinh(), 0.0f32);
+ assert_eq!((-0.0f32).asinh(), -0.0f32);
+
+ let inf: f32 = f32::INFINITY;
+ let neg_inf: f32 = f32::NEG_INFINITY;
+ let nan: f32 = f32::NAN;
+ assert_eq!(inf.asinh(), inf);
+ assert_eq!(neg_inf.asinh(), neg_inf);
+ assert!(nan.asinh().is_nan());
+ assert_approx_eq!(2.0f32.asinh(), 1.443635475178810342493276740273105f32);
+ assert_approx_eq!((-2.0f32).asinh(), -1.443635475178810342493276740273105f32);
+ }
+
+ #[test]
+ fn test_acosh() {
+ assert_eq!(1.0f32.acosh(), 0.0f32);
+ assert!(0.999f32.acosh().is_nan());
+
+ let inf: f32 = f32::INFINITY;
+ let neg_inf: f32 = f32::NEG_INFINITY;
+ let nan: f32 = f32::NAN;
+ assert_eq!(inf.acosh(), inf);
+ assert!(neg_inf.acosh().is_nan());
+ assert!(nan.acosh().is_nan());
+ assert_approx_eq!(2.0f32.acosh(), 1.31695789692481670862504634730796844f32);
+ assert_approx_eq!(3.0f32.acosh(), 1.76274717403908605046521864995958461f32);
+ }
+
+ #[test]
+ fn test_atanh() {
+ assert_eq!(0.0f32.atanh(), 0.0f32);
+ assert_eq!((-0.0f32).atanh(), -0.0f32);
+
+ let inf32: f32 = f32::INFINITY;
+ let neg_inf32: f32 = f32::NEG_INFINITY;
+ assert_eq!(1.0f32.atanh(), inf32);
+ assert_eq!((-1.0f32).atanh(), neg_inf32);
+
+ assert!(2f64.atanh().atanh().is_nan());
+ assert!((-2f64).atanh().atanh().is_nan());
+
+ let inf64: f32 = f32::INFINITY;
+ let neg_inf64: f32 = f32::NEG_INFINITY;
+ let nan32: f32 = f32::NAN;
+ assert!(inf64.atanh().is_nan());
+ assert!(neg_inf64.atanh().is_nan());
+ assert!(nan32.atanh().is_nan());
+
+ assert_approx_eq!(0.5f32.atanh(), 0.54930614433405484569762261846126285f32);
+ assert_approx_eq!((-0.5f32).atanh(), -0.54930614433405484569762261846126285f32);
+ }
+
+ #[test]
+ fn test_real_consts() {
+ use super::consts;
+
+ let pi: f32 = consts::PI;
+ let frac_pi_2: f32 = consts::FRAC_PI_2;
+ let frac_pi_3: f32 = consts::FRAC_PI_3;
+ let frac_pi_4: f32 = consts::FRAC_PI_4;
+ let frac_pi_6: f32 = consts::FRAC_PI_6;
+ let frac_pi_8: f32 = consts::FRAC_PI_8;
+ let frac_1_pi: f32 = consts::FRAC_1_PI;
+ let frac_2_pi: f32 = consts::FRAC_2_PI;
+ let frac_2_sqrtpi: f32 = consts::FRAC_2_SQRT_PI;
+ let sqrt2: f32 = consts::SQRT_2;
+ let frac_1_sqrt2: f32 = consts::FRAC_1_SQRT_2;
+ let e: f32 = consts::E;
+ let log2_e: f32 = consts::LOG2_E;
+ let log10_e: f32 = consts::LOG10_E;
+ let ln_2: f32 = consts::LN_2;
+ let ln_10: f32 = consts::LN_10;
+
+ assert_approx_eq!(frac_pi_2, pi / 2f32);
+ assert_approx_eq!(frac_pi_3, pi / 3f32);
+ assert_approx_eq!(frac_pi_4, pi / 4f32);
+ assert_approx_eq!(frac_pi_6, pi / 6f32);
+ assert_approx_eq!(frac_pi_8, pi / 8f32);
+ assert_approx_eq!(frac_1_pi, 1f32 / pi);
+ assert_approx_eq!(frac_2_pi, 2f32 / pi);
+ assert_approx_eq!(frac_2_sqrtpi, 2f32 / pi.sqrt());
+ assert_approx_eq!(sqrt2, 2f32.sqrt());
+ assert_approx_eq!(frac_1_sqrt2, 1f32 / 2f32.sqrt());
+ assert_approx_eq!(log2_e, e.log2());
+ assert_approx_eq!(log10_e, e.log10());
+ assert_approx_eq!(ln_2, 2f32.ln());
+ assert_approx_eq!(ln_10, 10f32.ln());
+ }
+
+ #[test]
+ fn test_float_bits_conv() {
+ assert_eq!((1f32).to_bits(), 0x3f800000);
+ assert_eq!((12.5f32).to_bits(), 0x41480000);
+ assert_eq!((1337f32).to_bits(), 0x44a72000);
+ assert_eq!((-14.25f32).to_bits(), 0xc1640000);
+ assert_approx_eq!(f32::from_bits(0x3f800000), 1.0);
+ assert_approx_eq!(f32::from_bits(0x41480000), 12.5);
+ assert_approx_eq!(f32::from_bits(0x44a72000), 1337.0);
+ assert_approx_eq!(f32::from_bits(0xc1640000), -14.25);
+
+ // Check that NaNs roundtrip their bits regardless of signalingness
+ // 0xA is 0b1010; 0x5 is 0b0101 -- so these two together clobbers all the mantissa bits
+ let masked_nan1 = f32::NAN.to_bits() ^ 0x002A_AAAA;
+ let masked_nan2 = f32::NAN.to_bits() ^ 0x0055_5555;
+ assert!(f32::from_bits(masked_nan1).is_nan());
+ assert!(f32::from_bits(masked_nan2).is_nan());
+
+ assert_eq!(f32::from_bits(masked_nan1).to_bits(), masked_nan1);
+ assert_eq!(f32::from_bits(masked_nan2).to_bits(), masked_nan2);
+ }
+
+ #[test]
+ #[should_panic]
+ fn test_clamp_min_greater_than_max() {
+ 1.0f32.clamp(3.0, 1.0);
+ }
+
+ #[test]
+ #[should_panic]
+ fn test_clamp_min_is_nan() {
+ 1.0f32.clamp(NAN, 1.0);
+ }
+
+ #[test]
+ #[should_panic]
+ fn test_clamp_max_is_nan() {
+ 1.0f32.clamp(3.0, NAN);
+ }
+}
diff --git a/src/libstd/f64.rs b/src/libstd/f64.rs
new file mode 100644
index 0000000..87467ae
--- /dev/null
+++ b/src/libstd/f64.rs
@@ -0,0 +1,1552 @@
+//! This module provides constants which are specific to the implementation
+//! of the `f64` floating point data type.
+//!
+//! *[See also the `f64` primitive type](../../std/primitive.f64.html).*
+//!
+//! Mathematically significant numbers are provided in the `consts` sub-module.
+
+#![stable(feature = "rust1", since = "1.0.0")]
+#![allow(missing_docs)]
+
+#[cfg(not(test))]
+use crate::intrinsics;
+#[cfg(not(test))]
+use crate::sys::cmath;
+
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use core::f64::{RADIX, MANTISSA_DIGITS, DIGITS, EPSILON};
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use core::f64::{MIN_EXP, MAX_EXP, MIN_10_EXP};
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use core::f64::{MAX_10_EXP, NAN, INFINITY, NEG_INFINITY};
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use core::f64::{MIN, MIN_POSITIVE, MAX};
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use core::f64::consts;
+
+#[cfg(not(test))]
+#[lang = "f64_runtime"]
+impl f64 {
+ /// Returns the largest integer less than or equal to a number.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let f = 3.7_f64;
+ /// let g = 3.0_f64;
+ /// let h = -3.7_f64;
+ ///
+ /// assert_eq!(f.floor(), 3.0);
+ /// assert_eq!(g.floor(), 3.0);
+ /// assert_eq!(h.floor(), -4.0);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn floor(self) -> f64 {
+ unsafe { intrinsics::floorf64(self) }
+ }
+
+ /// Returns the smallest integer greater than or equal to a number.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let f = 3.01_f64;
+ /// let g = 4.0_f64;
+ ///
+ /// assert_eq!(f.ceil(), 4.0);
+ /// assert_eq!(g.ceil(), 4.0);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn ceil(self) -> f64 {
+ unsafe { intrinsics::ceilf64(self) }
+ }
+
+ /// Returns the nearest integer to a number. Round half-way cases away from
+ /// `0.0`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let f = 3.3_f64;
+ /// let g = -3.3_f64;
+ ///
+ /// assert_eq!(f.round(), 3.0);
+ /// assert_eq!(g.round(), -3.0);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn round(self) -> f64 {
+ unsafe { intrinsics::roundf64(self) }
+ }
+
+ /// Returns the integer part of a number.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let f = 3.7_f64;
+ /// let g = 3.0_f64;
+ /// let h = -3.7_f64;
+ ///
+ /// assert_eq!(f.trunc(), 3.0);
+ /// assert_eq!(g.trunc(), 3.0);
+ /// assert_eq!(h.trunc(), -3.0);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn trunc(self) -> f64 {
+ unsafe { intrinsics::truncf64(self) }
+ }
+
+ /// Returns the fractional part of a number.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let x = 3.5_f64;
+ /// let y = -3.5_f64;
+ /// let abs_difference_x = (x.fract() - 0.5).abs();
+ /// let abs_difference_y = (y.fract() - (-0.5)).abs();
+ ///
+ /// assert!(abs_difference_x < 1e-10);
+ /// assert!(abs_difference_y < 1e-10);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn fract(self) -> f64 { self - self.trunc() }
+
+ /// Computes the absolute value of `self`. Returns `NAN` if the
+ /// number is `NAN`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::f64;
+ ///
+ /// let x = 3.5_f64;
+ /// let y = -3.5_f64;
+ ///
+ /// let abs_difference_x = (x.abs() - x).abs();
+ /// let abs_difference_y = (y.abs() - (-y)).abs();
+ ///
+ /// assert!(abs_difference_x < 1e-10);
+ /// assert!(abs_difference_y < 1e-10);
+ ///
+ /// assert!(f64::NAN.abs().is_nan());
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn abs(self) -> f64 {
+ unsafe { intrinsics::fabsf64(self) }
+ }
+
+ /// Returns a number that represents the sign of `self`.
+ ///
+ /// - `1.0` if the number is positive, `+0.0` or `INFINITY`
+ /// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY`
+ /// - `NAN` if the number is `NAN`
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::f64;
+ ///
+ /// let f = 3.5_f64;
+ ///
+ /// assert_eq!(f.signum(), 1.0);
+ /// assert_eq!(f64::NEG_INFINITY.signum(), -1.0);
+ ///
+ /// assert!(f64::NAN.signum().is_nan());
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn signum(self) -> f64 {
+ if self.is_nan() {
+ NAN
+ } else {
+ unsafe { intrinsics::copysignf64(1.0, self) }
+ }
+ }
+
+ /// Returns a number composed of the magnitude of `self` and the sign of
+ /// `sign`.
+ ///
+ /// Equal to `self` if the sign of `self` and `sign` are the same, otherwise
+ /// equal to `-self`. If `self` is a `NAN`, then a `NAN` with the sign of
+ /// `sign` is returned.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::f64;
+ ///
+ /// let f = 3.5_f64;
+ ///
+ /// assert_eq!(f.copysign(0.42), 3.5_f64);
+ /// assert_eq!(f.copysign(-0.42), -3.5_f64);
+ /// assert_eq!((-f).copysign(0.42), 3.5_f64);
+ /// assert_eq!((-f).copysign(-0.42), -3.5_f64);
+ ///
+ /// assert!(f64::NAN.copysign(1.0).is_nan());
+ /// ```
+ #[inline]
+ #[must_use]
+ #[stable(feature = "copysign", since = "1.35.0")]
+ pub fn copysign(self, sign: f64) -> f64 {
+ unsafe { intrinsics::copysignf64(self, sign) }
+ }
+
+ /// Fused multiply-add. Computes `(self * a) + b` with only one rounding
+ /// error, yielding a more accurate result than an unfused multiply-add.
+ ///
+ /// Using `mul_add` can be more performant than an unfused multiply-add if
+ /// the target architecture has a dedicated `fma` CPU instruction.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let m = 10.0_f64;
+ /// let x = 4.0_f64;
+ /// let b = 60.0_f64;
+ ///
+ /// // 100.0
+ /// let abs_difference = (m.mul_add(x, b) - (m*x + b)).abs();
+ ///
+ /// assert!(abs_difference < 1e-10);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn mul_add(self, a: f64, b: f64) -> f64 {
+ unsafe { intrinsics::fmaf64(self, a, b) }
+ }
+
+ /// Calculates Euclidean division, the matching method for `rem_euclid`.
+ ///
+ /// This computes the integer `n` such that
+ /// `self = n * rhs + self.rem_euclid(rhs)`.
+ /// In other words, the result is `self / rhs` rounded to the integer `n`
+ /// such that `self >= n * rhs`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(euclidean_division)]
+ /// let a: f64 = 7.0;
+ /// let b = 4.0;
+ /// assert_eq!(a.div_euclid(b), 1.0); // 7.0 > 4.0 * 1.0
+ /// assert_eq!((-a).div_euclid(b), -2.0); // -7.0 >= 4.0 * -2.0
+ /// assert_eq!(a.div_euclid(-b), -1.0); // 7.0 >= -4.0 * -1.0
+ /// assert_eq!((-a).div_euclid(-b), 2.0); // -7.0 >= -4.0 * 2.0
+ /// ```
+ #[inline]
+ #[unstable(feature = "euclidean_division", issue = "49048")]
+ pub fn div_euclid(self, rhs: f64) -> f64 {
+ let q = (self / rhs).trunc();
+ if self % rhs < 0.0 {
+ return if rhs > 0.0 { q - 1.0 } else { q + 1.0 }
+ }
+ q
+ }
+
+ /// Calculates the least nonnegative remainder of `self (mod rhs)`.
+ ///
+ /// 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_euclid(rhs) * rhs + self.rem_euclid(rhs)`
+ /// approximatively.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(euclidean_division)]
+ /// let a: f64 = 7.0;
+ /// let b = 4.0;
+ /// assert_eq!(a.rem_euclid(b), 3.0);
+ /// assert_eq!((-a).rem_euclid(b), 1.0);
+ /// assert_eq!(a.rem_euclid(-b), 3.0);
+ /// assert_eq!((-a).rem_euclid(-b), 1.0);
+ /// // limitation due to round-off error
+ /// assert!((-std::f64::EPSILON).rem_euclid(3.0) != 0.0);
+ /// ```
+ #[inline]
+ #[unstable(feature = "euclidean_division", issue = "49048")]
+ pub fn rem_euclid(self, rhs: f64) -> f64 {
+ let r = self % rhs;
+ if r < 0.0 {
+ r + rhs.abs()
+ } else {
+ r
+ }
+ }
+
+ /// Raises a number to an integer power.
+ ///
+ /// Using this function is generally faster than using `powf`
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let x = 2.0_f64;
+ /// let abs_difference = (x.powi(2) - x*x).abs();
+ ///
+ /// assert!(abs_difference < 1e-10);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn powi(self, n: i32) -> f64 {
+ unsafe { intrinsics::powif64(self, n) }
+ }
+
+ /// Raises a number to a floating point power.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let x = 2.0_f64;
+ /// let abs_difference = (x.powf(2.0) - x*x).abs();
+ ///
+ /// assert!(abs_difference < 1e-10);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn powf(self, n: f64) -> f64 {
+ unsafe { intrinsics::powf64(self, n) }
+ }
+
+ /// Takes the square root of a number.
+ ///
+ /// Returns NaN if `self` is a negative number.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let positive = 4.0_f64;
+ /// let negative = -4.0_f64;
+ ///
+ /// let abs_difference = (positive.sqrt() - 2.0).abs();
+ ///
+ /// assert!(abs_difference < 1e-10);
+ /// assert!(negative.sqrt().is_nan());
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn sqrt(self) -> f64 {
+ if self < 0.0 {
+ NAN
+ } else {
+ unsafe { intrinsics::sqrtf64(self) }
+ }
+ }
+
+ /// Returns `e^(self)`, (the exponential function).
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let one = 1.0_f64;
+ /// // e^1
+ /// let e = one.exp();
+ ///
+ /// // ln(e) - 1 == 0
+ /// let abs_difference = (e.ln() - 1.0).abs();
+ ///
+ /// assert!(abs_difference < 1e-10);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn exp(self) -> f64 {
+ unsafe { intrinsics::expf64(self) }
+ }
+
+ /// Returns `2^(self)`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let f = 2.0_f64;
+ ///
+ /// // 2^2 - 4 == 0
+ /// let abs_difference = (f.exp2() - 4.0).abs();
+ ///
+ /// assert!(abs_difference < 1e-10);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn exp2(self) -> f64 {
+ unsafe { intrinsics::exp2f64(self) }
+ }
+
+ /// Returns the natural logarithm of the number.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let one = 1.0_f64;
+ /// // e^1
+ /// let e = one.exp();
+ ///
+ /// // ln(e) - 1 == 0
+ /// let abs_difference = (e.ln() - 1.0).abs();
+ ///
+ /// assert!(abs_difference < 1e-10);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn ln(self) -> f64 {
+ self.log_wrapper(|n| { unsafe { intrinsics::logf64(n) } })
+ }
+
+ /// Returns the logarithm of the number with respect to an arbitrary base.
+ ///
+ /// The result may not be correctly rounded owing to implementation details;
+ /// `self.log2()` can produce more accurate results for base 2, and
+ /// `self.log10()` can produce more accurate results for base 10.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let five = 5.0_f64;
+ ///
+ /// // log5(5) - 1 == 0
+ /// let abs_difference = (five.log(5.0) - 1.0).abs();
+ ///
+ /// assert!(abs_difference < 1e-10);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn log(self, base: f64) -> f64 { self.ln() / base.ln() }
+
+ /// Returns the base 2 logarithm of the number.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let two = 2.0_f64;
+ ///
+ /// // log2(2) - 1 == 0
+ /// let abs_difference = (two.log2() - 1.0).abs();
+ ///
+ /// assert!(abs_difference < 1e-10);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn log2(self) -> f64 {
+ self.log_wrapper(|n| {
+ #[cfg(target_os = "android")]
+ return crate::sys::android::log2f64(n);
+ #[cfg(not(target_os = "android"))]
+ return unsafe { intrinsics::log2f64(n) };
+ })
+ }
+
+ /// Returns the base 10 logarithm of the number.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let ten = 10.0_f64;
+ ///
+ /// // log10(10) - 1 == 0
+ /// let abs_difference = (ten.log10() - 1.0).abs();
+ ///
+ /// assert!(abs_difference < 1e-10);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn log10(self) -> f64 {
+ self.log_wrapper(|n| { unsafe { intrinsics::log10f64(n) } })
+ }
+
+ /// The positive difference of two numbers.
+ ///
+ /// * If `self <= other`: `0:0`
+ /// * Else: `self - other`
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let x = 3.0_f64;
+ /// let y = -3.0_f64;
+ ///
+ /// let abs_difference_x = (x.abs_sub(1.0) - 2.0).abs();
+ /// let abs_difference_y = (y.abs_sub(1.0) - 0.0).abs();
+ ///
+ /// assert!(abs_difference_x < 1e-10);
+ /// assert!(abs_difference_y < 1e-10);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ #[rustc_deprecated(since = "1.10.0",
+ reason = "you probably meant `(self - other).abs()`: \
+ this operation is `(self - other).max(0.0)` \
+ except that `abs_sub` also propagates NaNs (also \
+ known as `fdim` in C). If you truly need the positive \
+ difference, consider using that expression or the C function \
+ `fdim`, depending on how you wish to handle NaN (please consider \
+ filing an issue describing your use-case too).")]
+ pub fn abs_sub(self, other: f64) -> f64 {
+ unsafe { cmath::fdim(self, other) }
+ }
+
+ /// Takes the cubic root of a number.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let x = 8.0_f64;
+ ///
+ /// // x^(1/3) - 2 == 0
+ /// let abs_difference = (x.cbrt() - 2.0).abs();
+ ///
+ /// assert!(abs_difference < 1e-10);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn cbrt(self) -> f64 {
+ unsafe { cmath::cbrt(self) }
+ }
+
+ /// Calculates the length of the hypotenuse of a right-angle triangle given
+ /// legs of length `x` and `y`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let x = 2.0_f64;
+ /// let y = 3.0_f64;
+ ///
+ /// // sqrt(x^2 + y^2)
+ /// let abs_difference = (x.hypot(y) - (x.powi(2) + y.powi(2)).sqrt()).abs();
+ ///
+ /// assert!(abs_difference < 1e-10);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn hypot(self, other: f64) -> f64 {
+ unsafe { cmath::hypot(self, other) }
+ }
+
+ /// Computes the sine of a number (in radians).
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::f64;
+ ///
+ /// let x = f64::consts::PI/2.0;
+ ///
+ /// let abs_difference = (x.sin() - 1.0).abs();
+ ///
+ /// assert!(abs_difference < 1e-10);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn sin(self) -> f64 {
+ unsafe { intrinsics::sinf64(self) }
+ }
+
+ /// Computes the cosine of a number (in radians).
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::f64;
+ ///
+ /// let x = 2.0*f64::consts::PI;
+ ///
+ /// let abs_difference = (x.cos() - 1.0).abs();
+ ///
+ /// assert!(abs_difference < 1e-10);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn cos(self) -> f64 {
+ unsafe { intrinsics::cosf64(self) }
+ }
+
+ /// Computes the tangent of a number (in radians).
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::f64;
+ ///
+ /// let x = f64::consts::PI/4.0;
+ /// let abs_difference = (x.tan() - 1.0).abs();
+ ///
+ /// assert!(abs_difference < 1e-14);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn tan(self) -> f64 {
+ unsafe { cmath::tan(self) }
+ }
+
+ /// Computes the arcsine of a number. Return value is in radians in
+ /// the range [-pi/2, pi/2] or NaN if the number is outside the range
+ /// [-1, 1].
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::f64;
+ ///
+ /// let f = f64::consts::PI / 2.0;
+ ///
+ /// // asin(sin(pi/2))
+ /// let abs_difference = (f.sin().asin() - f64::consts::PI / 2.0).abs();
+ ///
+ /// assert!(abs_difference < 1e-10);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn asin(self) -> f64 {
+ unsafe { cmath::asin(self) }
+ }
+
+ /// Computes the arccosine of a number. Return value is in radians in
+ /// the range [0, pi] or NaN if the number is outside the range
+ /// [-1, 1].
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::f64;
+ ///
+ /// let f = f64::consts::PI / 4.0;
+ ///
+ /// // acos(cos(pi/4))
+ /// let abs_difference = (f.cos().acos() - f64::consts::PI / 4.0).abs();
+ ///
+ /// assert!(abs_difference < 1e-10);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn acos(self) -> f64 {
+ unsafe { cmath::acos(self) }
+ }
+
+ /// Computes the arctangent of a number. Return value is in radians in the
+ /// range [-pi/2, pi/2];
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let f = 1.0_f64;
+ ///
+ /// // atan(tan(1))
+ /// let abs_difference = (f.tan().atan() - 1.0).abs();
+ ///
+ /// assert!(abs_difference < 1e-10);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn atan(self) -> f64 {
+ unsafe { cmath::atan(self) }
+ }
+
+ /// Computes the four quadrant arctangent of `self` (`y`) and `other` (`x`) in radians.
+ ///
+ /// * `x = 0`, `y = 0`: `0`
+ /// * `x >= 0`: `arctan(y/x)` -> `[-pi/2, pi/2]`
+ /// * `y >= 0`: `arctan(y/x) + pi` -> `(pi/2, pi]`
+ /// * `y < 0`: `arctan(y/x) - pi` -> `(-pi, -pi/2)`
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::f64;
+ ///
+ /// let pi = f64::consts::PI;
+ /// // Positive angles measured counter-clockwise
+ /// // from positive x axis
+ /// // -pi/4 radians (45 deg clockwise)
+ /// let x1 = 3.0_f64;
+ /// let y1 = -3.0_f64;
+ ///
+ /// // 3pi/4 radians (135 deg counter-clockwise)
+ /// let x2 = -3.0_f64;
+ /// let y2 = 3.0_f64;
+ ///
+ /// let abs_difference_1 = (y1.atan2(x1) - (-pi/4.0)).abs();
+ /// let abs_difference_2 = (y2.atan2(x2) - 3.0*pi/4.0).abs();
+ ///
+ /// assert!(abs_difference_1 < 1e-10);
+ /// assert!(abs_difference_2 < 1e-10);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn atan2(self, other: f64) -> f64 {
+ unsafe { cmath::atan2(self, other) }
+ }
+
+ /// Simultaneously computes the sine and cosine of the number, `x`. Returns
+ /// `(sin(x), cos(x))`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::f64;
+ ///
+ /// let x = f64::consts::PI/4.0;
+ /// let f = x.sin_cos();
+ ///
+ /// let abs_difference_0 = (f.0 - x.sin()).abs();
+ /// let abs_difference_1 = (f.1 - x.cos()).abs();
+ ///
+ /// assert!(abs_difference_0 < 1e-10);
+ /// assert!(abs_difference_1 < 1e-10);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn sin_cos(self) -> (f64, f64) {
+ (self.sin(), self.cos())
+ }
+
+ /// Returns `e^(self) - 1` in a way that is accurate even if the
+ /// number is close to zero.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let x = 7.0_f64;
+ ///
+ /// // e^(ln(7)) - 1
+ /// let abs_difference = (x.ln().exp_m1() - 6.0).abs();
+ ///
+ /// assert!(abs_difference < 1e-10);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn exp_m1(self) -> f64 {
+ unsafe { cmath::expm1(self) }
+ }
+
+ /// Returns `ln(1+n)` (natural logarithm) more accurately than if
+ /// the operations were performed separately.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::f64;
+ ///
+ /// let x = f64::consts::E - 1.0;
+ ///
+ /// // ln(1 + (e - 1)) == ln(e) == 1
+ /// let abs_difference = (x.ln_1p() - 1.0).abs();
+ ///
+ /// assert!(abs_difference < 1e-10);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn ln_1p(self) -> f64 {
+ unsafe { cmath::log1p(self) }
+ }
+
+ /// Hyperbolic sine function.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::f64;
+ ///
+ /// let e = f64::consts::E;
+ /// let x = 1.0_f64;
+ ///
+ /// let f = x.sinh();
+ /// // Solving sinh() at 1 gives `(e^2-1)/(2e)`
+ /// let g = (e*e - 1.0)/(2.0*e);
+ /// let abs_difference = (f - g).abs();
+ ///
+ /// assert!(abs_difference < 1e-10);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn sinh(self) -> f64 {
+ unsafe { cmath::sinh(self) }
+ }
+
+ /// Hyperbolic cosine function.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::f64;
+ ///
+ /// let e = f64::consts::E;
+ /// let x = 1.0_f64;
+ /// let f = x.cosh();
+ /// // Solving cosh() at 1 gives this result
+ /// let g = (e*e + 1.0)/(2.0*e);
+ /// let abs_difference = (f - g).abs();
+ ///
+ /// // Same result
+ /// assert!(abs_difference < 1.0e-10);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn cosh(self) -> f64 {
+ unsafe { cmath::cosh(self) }
+ }
+
+ /// Hyperbolic tangent function.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::f64;
+ ///
+ /// let e = f64::consts::E;
+ /// let x = 1.0_f64;
+ ///
+ /// let f = x.tanh();
+ /// // Solving tanh() at 1 gives `(1 - e^(-2))/(1 + e^(-2))`
+ /// let g = (1.0 - e.powi(-2))/(1.0 + e.powi(-2));
+ /// let abs_difference = (f - g).abs();
+ ///
+ /// assert!(abs_difference < 1.0e-10);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn tanh(self) -> f64 {
+ unsafe { cmath::tanh(self) }
+ }
+
+ /// Inverse hyperbolic sine function.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let x = 1.0_f64;
+ /// let f = x.sinh().asinh();
+ ///
+ /// let abs_difference = (f - x).abs();
+ ///
+ /// assert!(abs_difference < 1.0e-10);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn asinh(self) -> f64 {
+ if self == NEG_INFINITY {
+ NEG_INFINITY
+ } else {
+ (self + ((self * self) + 1.0).sqrt()).ln()
+ }
+ }
+
+ /// Inverse hyperbolic cosine function.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let x = 1.0_f64;
+ /// let f = x.cosh().acosh();
+ ///
+ /// let abs_difference = (f - x).abs();
+ ///
+ /// assert!(abs_difference < 1.0e-10);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn acosh(self) -> f64 {
+ match self {
+ x if x < 1.0 => NAN,
+ x => (x + ((x * x) - 1.0).sqrt()).ln(),
+ }
+ }
+
+ /// Inverse hyperbolic tangent function.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::f64;
+ ///
+ /// let e = f64::consts::E;
+ /// let f = e.tanh().atanh();
+ ///
+ /// let abs_difference = (f - e).abs();
+ ///
+ /// assert!(abs_difference < 1.0e-10);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn atanh(self) -> f64 {
+ 0.5 * ((2.0 * self) / (1.0 - self)).ln_1p()
+ }
+
+ /// Restrict a value to a certain interval unless it is NaN.
+ ///
+ /// Returns `max` if `self` is greater than `max`, and `min` if `self` is
+ /// less than `min`. Otherwise this returns `self`.
+ ///
+ /// Not that this function returns NaN if the initial value was NaN as
+ /// well.
+ ///
+ /// # Panics
+ ///
+ /// Panics if `min > max`, `min` is NaN, or `max` is NaN.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(clamp)]
+ /// assert!((-3.0f64).clamp(-2.0, 1.0) == -2.0);
+ /// assert!((0.0f64).clamp(-2.0, 1.0) == 0.0);
+ /// assert!((2.0f64).clamp(-2.0, 1.0) == 1.0);
+ /// assert!((std::f64::NAN).clamp(-2.0, 1.0).is_nan());
+ /// ```
+ #[unstable(feature = "clamp", issue = "44095")]
+ #[inline]
+ pub fn clamp(self, min: f64, max: f64) -> f64 {
+ assert!(min <= max);
+ let mut x = self;
+ if x < min { x = min; }
+ if x > max { x = max; }
+ x
+ }
+
+ // Solaris/Illumos requires a wrapper around log, log2, and log10 functions
+ // because of their non-standard behavior (e.g., log(-n) returns -Inf instead
+ // of expected NaN).
+ fn log_wrapper<F: Fn(f64) -> f64>(self, log_fn: F) -> f64 {
+ if !cfg!(target_os = "solaris") {
+ log_fn(self)
+ } else {
+ if self.is_finite() {
+ if self > 0.0 {
+ log_fn(self)
+ } else if self == 0.0 {
+ NEG_INFINITY // log(0) = -Inf
+ } else {
+ NAN // log(-n) = NaN
+ }
+ } else if self.is_nan() {
+ self // log(NaN) = NaN
+ } else if self > 0.0 {
+ self // log(Inf) = Inf
+ } else {
+ NAN // log(-Inf) = NaN
+ }
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use crate::f64;
+ use crate::f64::*;
+ use crate::num::*;
+ use crate::num::FpCategory as Fp;
+
+ #[test]
+ fn test_num_f64() {
+ test_num(10f64, 2f64);
+ }
+
+ #[test]
+ fn test_min_nan() {
+ assert_eq!(NAN.min(2.0), 2.0);
+ assert_eq!(2.0f64.min(NAN), 2.0);
+ }
+
+ #[test]
+ fn test_max_nan() {
+ assert_eq!(NAN.max(2.0), 2.0);
+ assert_eq!(2.0f64.max(NAN), 2.0);
+ }
+
+ #[test]
+ fn test_nan() {
+ let nan: f64 = NAN;
+ assert!(nan.is_nan());
+ assert!(!nan.is_infinite());
+ assert!(!nan.is_finite());
+ assert!(!nan.is_normal());
+ assert!(nan.is_sign_positive());
+ assert!(!nan.is_sign_negative());
+ assert_eq!(Fp::Nan, nan.classify());
+ }
+
+ #[test]
+ fn test_infinity() {
+ let inf: f64 = INFINITY;
+ assert!(inf.is_infinite());
+ assert!(!inf.is_finite());
+ assert!(inf.is_sign_positive());
+ assert!(!inf.is_sign_negative());
+ assert!(!inf.is_nan());
+ assert!(!inf.is_normal());
+ assert_eq!(Fp::Infinite, inf.classify());
+ }
+
+ #[test]
+ fn test_neg_infinity() {
+ let neg_inf: f64 = NEG_INFINITY;
+ assert!(neg_inf.is_infinite());
+ assert!(!neg_inf.is_finite());
+ assert!(!neg_inf.is_sign_positive());
+ assert!(neg_inf.is_sign_negative());
+ assert!(!neg_inf.is_nan());
+ assert!(!neg_inf.is_normal());
+ assert_eq!(Fp::Infinite, neg_inf.classify());
+ }
+
+ #[test]
+ fn test_zero() {
+ let zero: f64 = 0.0f64;
+ assert_eq!(0.0, zero);
+ assert!(!zero.is_infinite());
+ assert!(zero.is_finite());
+ assert!(zero.is_sign_positive());
+ assert!(!zero.is_sign_negative());
+ assert!(!zero.is_nan());
+ assert!(!zero.is_normal());
+ assert_eq!(Fp::Zero, zero.classify());
+ }
+
+ #[test]
+ fn test_neg_zero() {
+ let neg_zero: f64 = -0.0;
+ assert_eq!(0.0, neg_zero);
+ assert!(!neg_zero.is_infinite());
+ assert!(neg_zero.is_finite());
+ assert!(!neg_zero.is_sign_positive());
+ assert!(neg_zero.is_sign_negative());
+ assert!(!neg_zero.is_nan());
+ assert!(!neg_zero.is_normal());
+ assert_eq!(Fp::Zero, neg_zero.classify());
+ }
+
+ #[cfg_attr(all(target_arch = "wasm32", target_os = "emscripten"), ignore)] // issue 42630
+ #[test]
+ fn test_one() {
+ let one: f64 = 1.0f64;
+ assert_eq!(1.0, one);
+ assert!(!one.is_infinite());
+ assert!(one.is_finite());
+ assert!(one.is_sign_positive());
+ assert!(!one.is_sign_negative());
+ assert!(!one.is_nan());
+ assert!(one.is_normal());
+ assert_eq!(Fp::Normal, one.classify());
+ }
+
+ #[test]
+ fn test_is_nan() {
+ let nan: f64 = NAN;
+ let inf: f64 = INFINITY;
+ let neg_inf: f64 = NEG_INFINITY;
+ assert!(nan.is_nan());
+ assert!(!0.0f64.is_nan());
+ assert!(!5.3f64.is_nan());
+ assert!(!(-10.732f64).is_nan());
+ assert!(!inf.is_nan());
+ assert!(!neg_inf.is_nan());
+ }
+
+ #[test]
+ fn test_is_infinite() {
+ let nan: f64 = NAN;
+ let inf: f64 = INFINITY;
+ let neg_inf: f64 = NEG_INFINITY;
+ assert!(!nan.is_infinite());
+ assert!(inf.is_infinite());
+ assert!(neg_inf.is_infinite());
+ assert!(!0.0f64.is_infinite());
+ assert!(!42.8f64.is_infinite());
+ assert!(!(-109.2f64).is_infinite());
+ }
+
+ #[test]
+ fn test_is_finite() {
+ let nan: f64 = NAN;
+ let inf: f64 = INFINITY;
+ let neg_inf: f64 = NEG_INFINITY;
+ assert!(!nan.is_finite());
+ assert!(!inf.is_finite());
+ assert!(!neg_inf.is_finite());
+ assert!(0.0f64.is_finite());
+ assert!(42.8f64.is_finite());
+ assert!((-109.2f64).is_finite());
+ }
+
+ #[cfg_attr(all(target_arch = "wasm32", target_os = "emscripten"), ignore)] // issue 42630
+ #[test]
+ fn test_is_normal() {
+ let nan: f64 = NAN;
+ let inf: f64 = INFINITY;
+ let neg_inf: f64 = NEG_INFINITY;
+ let zero: f64 = 0.0f64;
+ let neg_zero: f64 = -0.0;
+ assert!(!nan.is_normal());
+ assert!(!inf.is_normal());
+ assert!(!neg_inf.is_normal());
+ assert!(!zero.is_normal());
+ assert!(!neg_zero.is_normal());
+ assert!(1f64.is_normal());
+ assert!(1e-307f64.is_normal());
+ assert!(!1e-308f64.is_normal());
+ }
+
+ #[cfg_attr(all(target_arch = "wasm32", target_os = "emscripten"), ignore)] // issue 42630
+ #[test]
+ fn test_classify() {
+ let nan: f64 = NAN;
+ let inf: f64 = INFINITY;
+ let neg_inf: f64 = NEG_INFINITY;
+ let zero: f64 = 0.0f64;
+ let neg_zero: f64 = -0.0;
+ assert_eq!(nan.classify(), Fp::Nan);
+ assert_eq!(inf.classify(), Fp::Infinite);
+ assert_eq!(neg_inf.classify(), Fp::Infinite);
+ assert_eq!(zero.classify(), Fp::Zero);
+ assert_eq!(neg_zero.classify(), Fp::Zero);
+ assert_eq!(1e-307f64.classify(), Fp::Normal);
+ assert_eq!(1e-308f64.classify(), Fp::Subnormal);
+ }
+
+ #[test]
+ fn test_floor() {
+ assert_approx_eq!(1.0f64.floor(), 1.0f64);
+ assert_approx_eq!(1.3f64.floor(), 1.0f64);
+ assert_approx_eq!(1.5f64.floor(), 1.0f64);
+ assert_approx_eq!(1.7f64.floor(), 1.0f64);
+ assert_approx_eq!(0.0f64.floor(), 0.0f64);
+ assert_approx_eq!((-0.0f64).floor(), -0.0f64);
+ assert_approx_eq!((-1.0f64).floor(), -1.0f64);
+ assert_approx_eq!((-1.3f64).floor(), -2.0f64);
+ assert_approx_eq!((-1.5f64).floor(), -2.0f64);
+ assert_approx_eq!((-1.7f64).floor(), -2.0f64);
+ }
+
+ #[test]
+ fn test_ceil() {
+ assert_approx_eq!(1.0f64.ceil(), 1.0f64);
+ assert_approx_eq!(1.3f64.ceil(), 2.0f64);
+ assert_approx_eq!(1.5f64.ceil(), 2.0f64);
+ assert_approx_eq!(1.7f64.ceil(), 2.0f64);
+ assert_approx_eq!(0.0f64.ceil(), 0.0f64);
+ assert_approx_eq!((-0.0f64).ceil(), -0.0f64);
+ assert_approx_eq!((-1.0f64).ceil(), -1.0f64);
+ assert_approx_eq!((-1.3f64).ceil(), -1.0f64);
+ assert_approx_eq!((-1.5f64).ceil(), -1.0f64);
+ assert_approx_eq!((-1.7f64).ceil(), -1.0f64);
+ }
+
+ #[test]
+ fn test_round() {
+ assert_approx_eq!(1.0f64.round(), 1.0f64);
+ assert_approx_eq!(1.3f64.round(), 1.0f64);
+ assert_approx_eq!(1.5f64.round(), 2.0f64);
+ assert_approx_eq!(1.7f64.round(), 2.0f64);
+ assert_approx_eq!(0.0f64.round(), 0.0f64);
+ assert_approx_eq!((-0.0f64).round(), -0.0f64);
+ assert_approx_eq!((-1.0f64).round(), -1.0f64);
+ assert_approx_eq!((-1.3f64).round(), -1.0f64);
+ assert_approx_eq!((-1.5f64).round(), -2.0f64);
+ assert_approx_eq!((-1.7f64).round(), -2.0f64);
+ }
+
+ #[test]
+ fn test_trunc() {
+ assert_approx_eq!(1.0f64.trunc(), 1.0f64);
+ assert_approx_eq!(1.3f64.trunc(), 1.0f64);
+ assert_approx_eq!(1.5f64.trunc(), 1.0f64);
+ assert_approx_eq!(1.7f64.trunc(), 1.0f64);
+ assert_approx_eq!(0.0f64.trunc(), 0.0f64);
+ assert_approx_eq!((-0.0f64).trunc(), -0.0f64);
+ assert_approx_eq!((-1.0f64).trunc(), -1.0f64);
+ assert_approx_eq!((-1.3f64).trunc(), -1.0f64);
+ assert_approx_eq!((-1.5f64).trunc(), -1.0f64);
+ assert_approx_eq!((-1.7f64).trunc(), -1.0f64);
+ }
+
+ #[test]
+ fn test_fract() {
+ assert_approx_eq!(1.0f64.fract(), 0.0f64);
+ assert_approx_eq!(1.3f64.fract(), 0.3f64);
+ assert_approx_eq!(1.5f64.fract(), 0.5f64);
+ assert_approx_eq!(1.7f64.fract(), 0.7f64);
+ assert_approx_eq!(0.0f64.fract(), 0.0f64);
+ assert_approx_eq!((-0.0f64).fract(), -0.0f64);
+ assert_approx_eq!((-1.0f64).fract(), -0.0f64);
+ assert_approx_eq!((-1.3f64).fract(), -0.3f64);
+ assert_approx_eq!((-1.5f64).fract(), -0.5f64);
+ assert_approx_eq!((-1.7f64).fract(), -0.7f64);
+ }
+
+ #[test]
+ fn test_abs() {
+ assert_eq!(INFINITY.abs(), INFINITY);
+ assert_eq!(1f64.abs(), 1f64);
+ assert_eq!(0f64.abs(), 0f64);
+ assert_eq!((-0f64).abs(), 0f64);
+ assert_eq!((-1f64).abs(), 1f64);
+ assert_eq!(NEG_INFINITY.abs(), INFINITY);
+ assert_eq!((1f64/NEG_INFINITY).abs(), 0f64);
+ assert!(NAN.abs().is_nan());
+ }
+
+ #[test]
+ fn test_signum() {
+ assert_eq!(INFINITY.signum(), 1f64);
+ assert_eq!(1f64.signum(), 1f64);
+ assert_eq!(0f64.signum(), 1f64);
+ assert_eq!((-0f64).signum(), -1f64);
+ assert_eq!((-1f64).signum(), -1f64);
+ assert_eq!(NEG_INFINITY.signum(), -1f64);
+ assert_eq!((1f64/NEG_INFINITY).signum(), -1f64);
+ assert!(NAN.signum().is_nan());
+ }
+
+ #[test]
+ fn test_is_sign_positive() {
+ assert!(INFINITY.is_sign_positive());
+ assert!(1f64.is_sign_positive());
+ assert!(0f64.is_sign_positive());
+ assert!(!(-0f64).is_sign_positive());
+ assert!(!(-1f64).is_sign_positive());
+ assert!(!NEG_INFINITY.is_sign_positive());
+ assert!(!(1f64/NEG_INFINITY).is_sign_positive());
+ assert!(NAN.is_sign_positive());
+ assert!(!(-NAN).is_sign_positive());
+ }
+
+ #[test]
+ fn test_is_sign_negative() {
+ assert!(!INFINITY.is_sign_negative());
+ assert!(!1f64.is_sign_negative());
+ assert!(!0f64.is_sign_negative());
+ assert!((-0f64).is_sign_negative());
+ assert!((-1f64).is_sign_negative());
+ assert!(NEG_INFINITY.is_sign_negative());
+ assert!((1f64/NEG_INFINITY).is_sign_negative());
+ assert!(!NAN.is_sign_negative());
+ assert!((-NAN).is_sign_negative());
+ }
+
+ #[test]
+ fn test_mul_add() {
+ let nan: f64 = NAN;
+ let inf: f64 = INFINITY;
+ let neg_inf: f64 = NEG_INFINITY;
+ assert_approx_eq!(12.3f64.mul_add(4.5, 6.7), 62.05);
+ assert_approx_eq!((-12.3f64).mul_add(-4.5, -6.7), 48.65);
+ assert_approx_eq!(0.0f64.mul_add(8.9, 1.2), 1.2);
+ assert_approx_eq!(3.4f64.mul_add(-0.0, 5.6), 5.6);
+ assert!(nan.mul_add(7.8, 9.0).is_nan());
+ assert_eq!(inf.mul_add(7.8, 9.0), inf);
+ assert_eq!(neg_inf.mul_add(7.8, 9.0), neg_inf);
+ assert_eq!(8.9f64.mul_add(inf, 3.2), inf);
+ assert_eq!((-3.2f64).mul_add(2.4, neg_inf), neg_inf);
+ }
+
+ #[test]
+ fn test_recip() {
+ let nan: f64 = NAN;
+ let inf: f64 = INFINITY;
+ let neg_inf: f64 = NEG_INFINITY;
+ assert_eq!(1.0f64.recip(), 1.0);
+ assert_eq!(2.0f64.recip(), 0.5);
+ assert_eq!((-0.4f64).recip(), -2.5);
+ assert_eq!(0.0f64.recip(), inf);
+ assert!(nan.recip().is_nan());
+ assert_eq!(inf.recip(), 0.0);
+ assert_eq!(neg_inf.recip(), 0.0);
+ }
+
+ #[test]
+ fn test_powi() {
+ let nan: f64 = NAN;
+ let inf: f64 = INFINITY;
+ let neg_inf: f64 = NEG_INFINITY;
+ assert_eq!(1.0f64.powi(1), 1.0);
+ assert_approx_eq!((-3.1f64).powi(2), 9.61);
+ assert_approx_eq!(5.9f64.powi(-2), 0.028727);
+ assert_eq!(8.3f64.powi(0), 1.0);
+ assert!(nan.powi(2).is_nan());
+ assert_eq!(inf.powi(3), inf);
+ assert_eq!(neg_inf.powi(2), inf);
+ }
+
+ #[test]
+ fn test_powf() {
+ let nan: f64 = NAN;
+ let inf: f64 = INFINITY;
+ let neg_inf: f64 = NEG_INFINITY;
+ assert_eq!(1.0f64.powf(1.0), 1.0);
+ assert_approx_eq!(3.4f64.powf(4.5), 246.408183);
+ assert_approx_eq!(2.7f64.powf(-3.2), 0.041652);
+ assert_approx_eq!((-3.1f64).powf(2.0), 9.61);
+ assert_approx_eq!(5.9f64.powf(-2.0), 0.028727);
+ assert_eq!(8.3f64.powf(0.0), 1.0);
+ assert!(nan.powf(2.0).is_nan());
+ assert_eq!(inf.powf(2.0), inf);
+ assert_eq!(neg_inf.powf(3.0), neg_inf);
+ }
+
+ #[test]
+ fn test_sqrt_domain() {
+ assert!(NAN.sqrt().is_nan());
+ assert!(NEG_INFINITY.sqrt().is_nan());
+ assert!((-1.0f64).sqrt().is_nan());
+ assert_eq!((-0.0f64).sqrt(), -0.0);
+ assert_eq!(0.0f64.sqrt(), 0.0);
+ assert_eq!(1.0f64.sqrt(), 1.0);
+ assert_eq!(INFINITY.sqrt(), INFINITY);
+ }
+
+ #[test]
+ fn test_exp() {
+ assert_eq!(1.0, 0.0f64.exp());
+ assert_approx_eq!(2.718282, 1.0f64.exp());
+ assert_approx_eq!(148.413159, 5.0f64.exp());
+
+ let inf: f64 = INFINITY;
+ let neg_inf: f64 = NEG_INFINITY;
+ let nan: f64 = NAN;
+ assert_eq!(inf, inf.exp());
+ assert_eq!(0.0, neg_inf.exp());
+ assert!(nan.exp().is_nan());
+ }
+
+ #[test]
+ fn test_exp2() {
+ assert_eq!(32.0, 5.0f64.exp2());
+ assert_eq!(1.0, 0.0f64.exp2());
+
+ let inf: f64 = INFINITY;
+ let neg_inf: f64 = NEG_INFINITY;
+ let nan: f64 = NAN;
+ assert_eq!(inf, inf.exp2());
+ assert_eq!(0.0, neg_inf.exp2());
+ assert!(nan.exp2().is_nan());
+ }
+
+ #[test]
+ fn test_ln() {
+ let nan: f64 = NAN;
+ let inf: f64 = INFINITY;
+ let neg_inf: f64 = NEG_INFINITY;
+ assert_approx_eq!(1.0f64.exp().ln(), 1.0);
+ assert!(nan.ln().is_nan());
+ assert_eq!(inf.ln(), inf);
+ assert!(neg_inf.ln().is_nan());
+ assert!((-2.3f64).ln().is_nan());
+ assert_eq!((-0.0f64).ln(), neg_inf);
+ assert_eq!(0.0f64.ln(), neg_inf);
+ assert_approx_eq!(4.0f64.ln(), 1.386294);
+ }
+
+ #[test]
+ fn test_log() {
+ let nan: f64 = NAN;
+ let inf: f64 = INFINITY;
+ let neg_inf: f64 = NEG_INFINITY;
+ assert_eq!(10.0f64.log(10.0), 1.0);
+ assert_approx_eq!(2.3f64.log(3.5), 0.664858);
+ assert_eq!(1.0f64.exp().log(1.0f64.exp()), 1.0);
+ assert!(1.0f64.log(1.0).is_nan());
+ assert!(1.0f64.log(-13.9).is_nan());
+ assert!(nan.log(2.3).is_nan());
+ assert_eq!(inf.log(10.0), inf);
+ assert!(neg_inf.log(8.8).is_nan());
+ assert!((-2.3f64).log(0.1).is_nan());
+ assert_eq!((-0.0f64).log(2.0), neg_inf);
+ assert_eq!(0.0f64.log(7.0), neg_inf);
+ }
+
+ #[test]
+ fn test_log2() {
+ let nan: f64 = NAN;
+ let inf: f64 = INFINITY;
+ let neg_inf: f64 = NEG_INFINITY;
+ assert_approx_eq!(10.0f64.log2(), 3.321928);
+ assert_approx_eq!(2.3f64.log2(), 1.201634);
+ assert_approx_eq!(1.0f64.exp().log2(), 1.442695);
+ assert!(nan.log2().is_nan());
+ assert_eq!(inf.log2(), inf);
+ assert!(neg_inf.log2().is_nan());
+ assert!((-2.3f64).log2().is_nan());
+ assert_eq!((-0.0f64).log2(), neg_inf);
+ assert_eq!(0.0f64.log2(), neg_inf);
+ }
+
+ #[test]
+ fn test_log10() {
+ let nan: f64 = NAN;
+ let inf: f64 = INFINITY;
+ let neg_inf: f64 = NEG_INFINITY;
+ assert_eq!(10.0f64.log10(), 1.0);
+ assert_approx_eq!(2.3f64.log10(), 0.361728);
+ assert_approx_eq!(1.0f64.exp().log10(), 0.434294);
+ assert_eq!(1.0f64.log10(), 0.0);
+ assert!(nan.log10().is_nan());
+ assert_eq!(inf.log10(), inf);
+ assert!(neg_inf.log10().is_nan());
+ assert!((-2.3f64).log10().is_nan());
+ assert_eq!((-0.0f64).log10(), neg_inf);
+ assert_eq!(0.0f64.log10(), neg_inf);
+ }
+
+ #[test]
+ fn test_to_degrees() {
+ let pi: f64 = consts::PI;
+ let nan: f64 = NAN;
+ let inf: f64 = INFINITY;
+ let neg_inf: f64 = NEG_INFINITY;
+ assert_eq!(0.0f64.to_degrees(), 0.0);
+ assert_approx_eq!((-5.8f64).to_degrees(), -332.315521);
+ assert_eq!(pi.to_degrees(), 180.0);
+ assert!(nan.to_degrees().is_nan());
+ assert_eq!(inf.to_degrees(), inf);
+ assert_eq!(neg_inf.to_degrees(), neg_inf);
+ }
+
+ #[test]
+ fn test_to_radians() {
+ let pi: f64 = consts::PI;
+ let nan: f64 = NAN;
+ let inf: f64 = INFINITY;
+ let neg_inf: f64 = NEG_INFINITY;
+ assert_eq!(0.0f64.to_radians(), 0.0);
+ assert_approx_eq!(154.6f64.to_radians(), 2.698279);
+ assert_approx_eq!((-332.31f64).to_radians(), -5.799903);
+ assert_eq!(180.0f64.to_radians(), pi);
+ assert!(nan.to_radians().is_nan());
+ assert_eq!(inf.to_radians(), inf);
+ assert_eq!(neg_inf.to_radians(), neg_inf);
+ }
+
+ #[test]
+ fn test_asinh() {
+ assert_eq!(0.0f64.asinh(), 0.0f64);
+ assert_eq!((-0.0f64).asinh(), -0.0f64);
+
+ let inf: f64 = INFINITY;
+ let neg_inf: f64 = NEG_INFINITY;
+ let nan: f64 = NAN;
+ assert_eq!(inf.asinh(), inf);
+ assert_eq!(neg_inf.asinh(), neg_inf);
+ assert!(nan.asinh().is_nan());
+ assert_approx_eq!(2.0f64.asinh(), 1.443635475178810342493276740273105f64);
+ assert_approx_eq!((-2.0f64).asinh(), -1.443635475178810342493276740273105f64);
+ }
+
+ #[test]
+ fn test_acosh() {
+ assert_eq!(1.0f64.acosh(), 0.0f64);
+ assert!(0.999f64.acosh().is_nan());
+
+ let inf: f64 = INFINITY;
+ let neg_inf: f64 = NEG_INFINITY;
+ let nan: f64 = NAN;
+ assert_eq!(inf.acosh(), inf);
+ assert!(neg_inf.acosh().is_nan());
+ assert!(nan.acosh().is_nan());
+ assert_approx_eq!(2.0f64.acosh(), 1.31695789692481670862504634730796844f64);
+ assert_approx_eq!(3.0f64.acosh(), 1.76274717403908605046521864995958461f64);
+ }
+
+ #[test]
+ fn test_atanh() {
+ assert_eq!(0.0f64.atanh(), 0.0f64);
+ assert_eq!((-0.0f64).atanh(), -0.0f64);
+
+ let inf: f64 = INFINITY;
+ let neg_inf: f64 = NEG_INFINITY;
+ let nan: f64 = NAN;
+ assert_eq!(1.0f64.atanh(), inf);
+ assert_eq!((-1.0f64).atanh(), neg_inf);
+ assert!(2f64.atanh().atanh().is_nan());
+ assert!((-2f64).atanh().atanh().is_nan());
+ assert!(inf.atanh().is_nan());
+ assert!(neg_inf.atanh().is_nan());
+ assert!(nan.atanh().is_nan());
+ assert_approx_eq!(0.5f64.atanh(), 0.54930614433405484569762261846126285f64);
+ assert_approx_eq!((-0.5f64).atanh(), -0.54930614433405484569762261846126285f64);
+ }
+
+ #[test]
+ fn test_real_consts() {
+ use super::consts;
+ let pi: f64 = consts::PI;
+ let frac_pi_2: f64 = consts::FRAC_PI_2;
+ let frac_pi_3: f64 = consts::FRAC_PI_3;
+ let frac_pi_4: f64 = consts::FRAC_PI_4;
+ let frac_pi_6: f64 = consts::FRAC_PI_6;
+ let frac_pi_8: f64 = consts::FRAC_PI_8;
+ let frac_1_pi: f64 = consts::FRAC_1_PI;
+ let frac_2_pi: f64 = consts::FRAC_2_PI;
+ let frac_2_sqrtpi: f64 = consts::FRAC_2_SQRT_PI;
+ let sqrt2: f64 = consts::SQRT_2;
+ let frac_1_sqrt2: f64 = consts::FRAC_1_SQRT_2;
+ let e: f64 = consts::E;
+ let log2_e: f64 = consts::LOG2_E;
+ let log10_e: f64 = consts::LOG10_E;
+ let ln_2: f64 = consts::LN_2;
+ let ln_10: f64 = consts::LN_10;
+
+ assert_approx_eq!(frac_pi_2, pi / 2f64);
+ assert_approx_eq!(frac_pi_3, pi / 3f64);
+ assert_approx_eq!(frac_pi_4, pi / 4f64);
+ assert_approx_eq!(frac_pi_6, pi / 6f64);
+ assert_approx_eq!(frac_pi_8, pi / 8f64);
+ assert_approx_eq!(frac_1_pi, 1f64 / pi);
+ assert_approx_eq!(frac_2_pi, 2f64 / pi);
+ assert_approx_eq!(frac_2_sqrtpi, 2f64 / pi.sqrt());
+ assert_approx_eq!(sqrt2, 2f64.sqrt());
+ assert_approx_eq!(frac_1_sqrt2, 1f64 / 2f64.sqrt());
+ assert_approx_eq!(log2_e, e.log2());
+ assert_approx_eq!(log10_e, e.log10());
+ assert_approx_eq!(ln_2, 2f64.ln());
+ assert_approx_eq!(ln_10, 10f64.ln());
+ }
+
+ #[test]
+ fn test_float_bits_conv() {
+ assert_eq!((1f64).to_bits(), 0x3ff0000000000000);
+ assert_eq!((12.5f64).to_bits(), 0x4029000000000000);
+ assert_eq!((1337f64).to_bits(), 0x4094e40000000000);
+ assert_eq!((-14.25f64).to_bits(), 0xc02c800000000000);
+ assert_approx_eq!(f64::from_bits(0x3ff0000000000000), 1.0);
+ assert_approx_eq!(f64::from_bits(0x4029000000000000), 12.5);
+ assert_approx_eq!(f64::from_bits(0x4094e40000000000), 1337.0);
+ assert_approx_eq!(f64::from_bits(0xc02c800000000000), -14.25);
+
+ // Check that NaNs roundtrip their bits regardless of signalingness
+ // 0xA is 0b1010; 0x5 is 0b0101 -- so these two together clobbers all the mantissa bits
+ let masked_nan1 = f64::NAN.to_bits() ^ 0x000A_AAAA_AAAA_AAAA;
+ let masked_nan2 = f64::NAN.to_bits() ^ 0x0005_5555_5555_5555;
+ assert!(f64::from_bits(masked_nan1).is_nan());
+ assert!(f64::from_bits(masked_nan2).is_nan());
+
+ assert_eq!(f64::from_bits(masked_nan1).to_bits(), masked_nan1);
+ assert_eq!(f64::from_bits(masked_nan2).to_bits(), masked_nan2);
+ }
+
+ #[test]
+ #[should_panic]
+ fn test_clamp_min_greater_than_max() {
+ 1.0f64.clamp(3.0, 1.0);
+ }
+
+ #[test]
+ #[should_panic]
+ fn test_clamp_min_is_nan() {
+ 1.0f64.clamp(NAN, 1.0);
+ }
+
+ #[test]
+ #[should_panic]
+ fn test_clamp_max_is_nan() {
+ 1.0f64.clamp(3.0, NAN);
+ }
+}
diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs
new file mode 100644
index 0000000..f93583d
--- /dev/null
+++ b/src/libstd/ffi/c_str.rs
@@ -0,0 +1,1474 @@
+use crate::ascii;
+use crate::borrow::{Cow, Borrow};
+use crate::cmp::Ordering;
+use crate::error::Error;
+use crate::fmt::{self, Write};
+use crate::io;
+use crate::mem;
+use crate::memchr;
+use crate::ops;
+use crate::os::raw::c_char;
+use crate::ptr;
+use crate::rc::Rc;
+use crate::slice;
+use crate::str::{self, Utf8Error};
+use crate::sync::Arc;
+use crate::sys;
+
+/// A type representing an owned, C-compatible, nul-terminated string with no nul bytes in the
+/// middle.
+///
+/// This type serves the purpose of being able to safely generate a
+/// C-compatible string from a Rust byte slice or vector. An instance of this
+/// type is a static guarantee that the underlying bytes contain no interior 0
+/// bytes ("nul characters") and that the final byte is 0 ("nul terminator").
+///
+/// `CString` is to [`&CStr`] as [`String`] is to [`&str`]: the former
+/// in each pair are owned strings; the latter are borrowed
+/// references.
+///
+/// # Creating a `CString`
+///
+/// A `CString` is created from either a byte slice or a byte vector,
+/// or anything that implements [`Into`]`<`[`Vec`]`<`[`u8`]`>>` (for
+/// example, you can build a `CString` straight out of a [`String`] or
+/// a [`&str`], since both implement that trait).
+///
+/// The [`new`] method will actually check that the provided `&[u8]`
+/// does not have 0 bytes in the middle, and return an error if it
+/// finds one.
+///
+/// # Extracting a raw pointer to the whole C string
+///
+/// `CString` implements a [`as_ptr`] method through the [`Deref`]
+/// trait. This method will give you a `*const c_char` which you can
+/// feed directly to extern functions that expect a nul-terminated
+/// string, like C's `strdup()`.
+///
+/// # Extracting a slice of the whole C string
+///
+/// Alternatively, you can obtain a `&[`[`u8`]`]` slice from a
+/// `CString` with the [`as_bytes`] method. Slices produced in this
+/// way do *not* contain the trailing nul terminator. This is useful
+/// when you will be calling an extern function that takes a `*const
+/// u8` argument which is not necessarily nul-terminated, plus another
+/// argument with the length of the string — like C's `strndup()`.
+/// You can of course get the slice's length with its
+/// [`len`][slice.len] method.
+///
+/// If you need a `&[`[`u8`]`]` slice *with* the nul terminator, you
+/// can use [`as_bytes_with_nul`] instead.
+///
+/// Once you have the kind of slice you need (with or without a nul
+/// terminator), you can call the slice's own
+/// [`as_ptr`][slice.as_ptr] method to get a raw pointer to pass to
+/// extern functions. See the documentation for that function for a
+/// discussion on ensuring the lifetime of the raw pointer.
+///
+/// [`Into`]: ../convert/trait.Into.html
+/// [`Vec`]: ../vec/struct.Vec.html
+/// [`String`]: ../string/struct.String.html
+/// [`&str`]: ../primitive.str.html
+/// [`u8`]: ../primitive.u8.html
+/// [`new`]: #method.new
+/// [`as_bytes`]: #method.as_bytes
+/// [`as_bytes_with_nul`]: #method.as_bytes_with_nul
+/// [`as_ptr`]: #method.as_ptr
+/// [slice.as_ptr]: ../primitive.slice.html#method.as_ptr
+/// [slice.len]: ../primitive.slice.html#method.len
+/// [`Deref`]: ../ops/trait.Deref.html
+/// [`CStr`]: struct.CStr.html
+/// [`&CStr`]: struct.CStr.html
+///
+/// # Examples
+///
+/// ```ignore (extern-declaration)
+/// # fn main() {
+/// use std::ffi::CString;
+/// use std::os::raw::c_char;
+///
+/// extern {
+/// fn my_printer(s: *const c_char);
+/// }
+///
+/// // We are certain that our string doesn't have 0 bytes in the middle,
+/// // so we can .expect()
+/// let c_to_print = CString::new("Hello, world!").expect("CString::new failed");
+/// unsafe {
+/// my_printer(c_to_print.as_ptr());
+/// }
+/// # }
+/// ```
+///
+/// # Safety
+///
+/// `CString` is intended for working with traditional C-style strings
+/// (a sequence of non-nul bytes terminated by a single nul byte); the
+/// primary use case for these kinds of strings is interoperating with C-like
+/// code. Often you will need to transfer ownership to/from that external
+/// code. It is strongly recommended that you thoroughly read through the
+/// documentation of `CString` before use, as improper ownership management
+/// of `CString` instances can lead to invalid memory accesses, memory leaks,
+/// and other memory errors.
+
+#[derive(PartialEq, PartialOrd, Eq, Ord, Hash, Clone)]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct CString {
+ // Invariant 1: the slice ends with a zero byte and has a length of at least one.
+ // Invariant 2: the slice contains only one zero byte.
+ // Improper usage of unsafe function can break Invariant 2, but not Invariant 1.
+ inner: Box<[u8]>,
+}
+
+/// Representation of a borrowed C string.
+///
+/// This type represents a borrowed reference to a nul-terminated
+/// array of bytes. It can be constructed safely from a `&[`[`u8`]`]`
+/// slice, or unsafely from a raw `*const c_char`. It can then be
+/// converted to a Rust [`&str`] by performing UTF-8 validation, or
+/// into an owned [`CString`].
+///
+/// `&CStr` is to [`CString`] as [`&str`] is to [`String`]: the former
+/// in each pair are borrowed references; the latter are owned
+/// strings.
+///
+/// Note that this structure is **not** `repr(C)` and is not recommended to be
+/// placed in the signatures of FFI functions. Instead, safe wrappers of FFI
+/// functions may leverage the unsafe [`from_ptr`] constructor to provide a safe
+/// interface to other consumers.
+///
+/// # Examples
+///
+/// Inspecting a foreign C string:
+///
+/// ```ignore (extern-declaration)
+/// use std::ffi::CStr;
+/// use std::os::raw::c_char;
+///
+/// extern { fn my_string() -> *const c_char; }
+///
+/// unsafe {
+/// let slice = CStr::from_ptr(my_string());
+/// println!("string buffer size without nul terminator: {}", slice.to_bytes().len());
+/// }
+/// ```
+///
+/// Passing a Rust-originating C string:
+///
+/// ```ignore (extern-declaration)
+/// use std::ffi::{CString, CStr};
+/// use std::os::raw::c_char;
+///
+/// fn work(data: &CStr) {
+/// extern { fn work_with(data: *const c_char); }
+///
+/// unsafe { work_with(data.as_ptr()) }
+/// }
+///
+/// let s = CString::new("data data data data").expect("CString::new failed");
+/// work(&s);
+/// ```
+///
+/// Converting a foreign C string into a Rust [`String`]:
+///
+/// ```ignore (extern-declaration)
+/// use std::ffi::CStr;
+/// use std::os::raw::c_char;
+///
+/// extern { fn my_string() -> *const c_char; }
+///
+/// fn my_string_safe() -> String {
+/// unsafe {
+/// CStr::from_ptr(my_string()).to_string_lossy().into_owned()
+/// }
+/// }
+///
+/// println!("string: {}", my_string_safe());
+/// ```
+///
+/// [`u8`]: ../primitive.u8.html
+/// [`&str`]: ../primitive.str.html
+/// [`String`]: ../string/struct.String.html
+/// [`CString`]: struct.CString.html
+/// [`from_ptr`]: #method.from_ptr
+#[derive(Hash)]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct CStr {
+ // FIXME: this should not be represented with a DST slice but rather with
+ // just a raw `c_char` along with some form of marker to make
+ // this an unsized type. Essentially `sizeof(&CStr)` should be the
+ // same as `sizeof(&c_char)` but `CStr` should be an unsized type.
+ inner: [c_char]
+}
+
+/// An error indicating that an interior nul byte was found.
+///
+/// While Rust strings may contain nul bytes in the middle, C strings
+/// can't, as that byte would effectively truncate the string.
+///
+/// This error is created by the [`new`][`CString::new`] method on
+/// [`CString`]. See its documentation for more.
+///
+/// [`CString`]: struct.CString.html
+/// [`CString::new`]: struct.CString.html#method.new
+///
+/// # Examples
+///
+/// ```
+/// use std::ffi::{CString, NulError};
+///
+/// let _: NulError = CString::new(b"f\0oo".to_vec()).unwrap_err();
+/// ```
+#[derive(Clone, PartialEq, Eq, Debug)]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct NulError(usize, Vec<u8>);
+
+/// An error indicating that a nul byte was not in the expected position.
+///
+/// The slice used to create a [`CStr`] must have one and only one nul
+/// byte at the end of the slice.
+///
+/// This error is created by the
+/// [`from_bytes_with_nul`][`CStr::from_bytes_with_nul`] method on
+/// [`CStr`]. See its documentation for more.
+///
+/// [`CStr`]: struct.CStr.html
+/// [`CStr::from_bytes_with_nul`]: struct.CStr.html#method.from_bytes_with_nul
+///
+/// # Examples
+///
+/// ```
+/// use std::ffi::{CStr, FromBytesWithNulError};
+///
+/// let _: FromBytesWithNulError = CStr::from_bytes_with_nul(b"f\0oo").unwrap_err();
+/// ```
+#[derive(Clone, PartialEq, Eq, Debug)]
+#[stable(feature = "cstr_from_bytes", since = "1.10.0")]
+pub struct FromBytesWithNulError {
+ kind: FromBytesWithNulErrorKind,
+}
+
+#[derive(Clone, PartialEq, Eq, Debug)]
+enum FromBytesWithNulErrorKind {
+ InteriorNul(usize),
+ NotNulTerminated,
+}
+
+impl FromBytesWithNulError {
+ fn interior_nul(pos: usize) -> FromBytesWithNulError {
+ FromBytesWithNulError {
+ kind: FromBytesWithNulErrorKind::InteriorNul(pos),
+ }
+ }
+ fn not_nul_terminated() -> FromBytesWithNulError {
+ FromBytesWithNulError {
+ kind: FromBytesWithNulErrorKind::NotNulTerminated,
+ }
+ }
+}
+
+/// An error indicating invalid UTF-8 when converting a [`CString`] into a [`String`].
+///
+/// `CString` is just a wrapper over a buffer of bytes with a nul
+/// terminator; [`into_string`][`CString::into_string`] performs UTF-8
+/// validation on those bytes and may return this error.
+///
+/// This `struct` is created by the
+/// [`into_string`][`CString::into_string`] method on [`CString`]. See
+/// its documentation for more.
+///
+/// [`String`]: ../string/struct.String.html
+/// [`CString`]: struct.CString.html
+/// [`CString::into_string`]: struct.CString.html#method.into_string
+#[derive(Clone, PartialEq, Eq, Debug)]
+#[stable(feature = "cstring_into", since = "1.7.0")]
+pub struct IntoStringError {
+ inner: CString,
+ error: Utf8Error,
+}
+
+impl CString {
+ /// Creates a new C-compatible string from a container of bytes.
+ ///
+ /// This function will consume the provided data and use the
+ /// underlying bytes to construct a new string, ensuring that
+ /// there is a trailing 0 byte. This trailing 0 byte will be
+ /// appended by this function; the provided data should *not*
+ /// contain any 0 bytes in it.
+ ///
+ /// # Examples
+ ///
+ /// ```ignore (extern-declaration)
+ /// use std::ffi::CString;
+ /// use std::os::raw::c_char;
+ ///
+ /// extern { fn puts(s: *const c_char); }
+ ///
+ /// let to_print = CString::new("Hello!").expect("CString::new failed");
+ /// unsafe {
+ /// puts(to_print.as_ptr());
+ /// }
+ /// ```
+ ///
+ /// # Errors
+ ///
+ /// This function will return an error if the supplied bytes contain an
+ /// internal 0 byte. The [`NulError`] returned will contain the bytes as well as
+ /// the position of the nul byte.
+ ///
+ /// [`NulError`]: struct.NulError.html
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn new<T: Into<Vec<u8>>>(t: T) -> Result<CString, NulError> {
+ Self::_new(t.into())
+ }
+
+ fn _new(bytes: Vec<u8>) -> Result<CString, NulError> {
+ match memchr::memchr(0, &bytes) {
+ Some(i) => Err(NulError(i, bytes)),
+ None => Ok(unsafe { CString::from_vec_unchecked(bytes) }),
+ }
+ }
+
+ /// Creates a C-compatible string by consuming a byte vector,
+ /// without checking for interior 0 bytes.
+ ///
+ /// This method is equivalent to [`new`] except that no runtime assertion
+ /// is made that `v` contains no 0 bytes, and it requires an actual
+ /// byte vector, not anything that can be converted to one with Into.
+ ///
+ /// [`new`]: #method.new
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ffi::CString;
+ ///
+ /// let raw = b"foo".to_vec();
+ /// unsafe {
+ /// let c_string = CString::from_vec_unchecked(raw);
+ /// }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub unsafe fn from_vec_unchecked(mut v: Vec<u8>) -> CString {
+ v.reserve_exact(1);
+ v.push(0);
+ CString { inner: v.into_boxed_slice() }
+ }
+
+ /// Retakes ownership of a `CString` that was transferred to C via [`into_raw`].
+ ///
+ /// Additionally, the length of the string will be recalculated from the pointer.
+ ///
+ /// # Safety
+ ///
+ /// This should only ever be called with a pointer that was earlier
+ /// obtained by calling [`into_raw`] on a `CString`. Other usage (e.g., trying to take
+ /// ownership of a string that was allocated by foreign code) is likely to lead
+ /// to undefined behavior or allocator corruption.
+ ///
+ /// > **Note:** If you need to borrow a string that was allocated by
+ /// > foreign code, use [`CStr`]. If you need to take ownership of
+ /// > a string that was allocated by foreign code, you will need to
+ /// > make your own provisions for freeing it appropriately, likely
+ /// > with the foreign code's API to do that.
+ ///
+ /// [`into_raw`]: #method.into_raw
+ /// [`CStr`]: struct.CStr.html
+ ///
+ /// # Examples
+ ///
+ /// Creates a `CString`, pass ownership to an `extern` function (via raw pointer), then retake
+ /// ownership with `from_raw`:
+ ///
+ /// ```ignore (extern-declaration)
+ /// use std::ffi::CString;
+ /// use std::os::raw::c_char;
+ ///
+ /// extern {
+ /// fn some_extern_function(s: *mut c_char);
+ /// }
+ ///
+ /// let c_string = CString::new("Hello!").expect("CString::new failed");
+ /// let raw = c_string.into_raw();
+ /// unsafe {
+ /// some_extern_function(raw);
+ /// let c_string = CString::from_raw(raw);
+ /// }
+ /// ```
+ #[stable(feature = "cstr_memory", since = "1.4.0")]
+ pub unsafe fn from_raw(ptr: *mut c_char) -> CString {
+ let len = sys::strlen(ptr) + 1; // Including the NUL byte
+ let slice = slice::from_raw_parts_mut(ptr, len as usize);
+ CString { inner: Box::from_raw(slice as *mut [c_char] as *mut [u8]) }
+ }
+
+ /// Consumes the `CString` and transfers ownership of the string to a C caller.
+ ///
+ /// The pointer which this function returns must be returned to Rust and reconstituted using
+ /// [`from_raw`] to be properly deallocated. Specifically, one
+ /// should *not* use the standard C `free()` function to deallocate
+ /// this string.
+ ///
+ /// Failure to call [`from_raw`] will lead to a memory leak.
+ ///
+ /// [`from_raw`]: #method.from_raw
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ffi::CString;
+ ///
+ /// let c_string = CString::new("foo").expect("CString::new failed");
+ ///
+ /// let ptr = c_string.into_raw();
+ ///
+ /// unsafe {
+ /// assert_eq!(b'f', *ptr as u8);
+ /// assert_eq!(b'o', *ptr.offset(1) as u8);
+ /// assert_eq!(b'o', *ptr.offset(2) as u8);
+ /// assert_eq!(b'\0', *ptr.offset(3) as u8);
+ ///
+ /// // retake pointer to free memory
+ /// let _ = CString::from_raw(ptr);
+ /// }
+ /// ```
+ #[inline]
+ #[stable(feature = "cstr_memory", since = "1.4.0")]
+ pub fn into_raw(self) -> *mut c_char {
+ Box::into_raw(self.into_inner()) as *mut c_char
+ }
+
+ /// Converts the `CString` into a [`String`] if it contains valid UTF-8 data.
+ ///
+ /// On failure, ownership of the original `CString` is returned.
+ ///
+ /// [`String`]: ../string/struct.String.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ffi::CString;
+ ///
+ /// let valid_utf8 = vec![b'f', b'o', b'o'];
+ /// let cstring = CString::new(valid_utf8).expect("CString::new failed");
+ /// assert_eq!(cstring.into_string().expect("into_string() call failed"), "foo");
+ ///
+ /// let invalid_utf8 = vec![b'f', 0xff, b'o', b'o'];
+ /// let cstring = CString::new(invalid_utf8).expect("CString::new failed");
+ /// let err = cstring.into_string().err().expect("into_string().err() failed");
+ /// assert_eq!(err.utf8_error().valid_up_to(), 1);
+ /// ```
+
+ #[stable(feature = "cstring_into", since = "1.7.0")]
+ pub fn into_string(self) -> Result<String, IntoStringError> {
+ String::from_utf8(self.into_bytes())
+ .map_err(|e| IntoStringError {
+ error: e.utf8_error(),
+ inner: unsafe { CString::from_vec_unchecked(e.into_bytes()) },
+ })
+ }
+
+ /// Consumes the `CString` and returns the underlying byte buffer.
+ ///
+ /// The returned buffer does **not** contain the trailing nul
+ /// terminator, and it is guaranteed to not have any interior nul
+ /// bytes.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ffi::CString;
+ ///
+ /// let c_string = CString::new("foo").expect("CString::new failed");
+ /// let bytes = c_string.into_bytes();
+ /// assert_eq!(bytes, vec![b'f', b'o', b'o']);
+ /// ```
+ #[stable(feature = "cstring_into", since = "1.7.0")]
+ pub fn into_bytes(self) -> Vec<u8> {
+ let mut vec = self.into_inner().into_vec();
+ let _nul = vec.pop();
+ debug_assert_eq!(_nul, Some(0u8));
+ vec
+ }
+
+ /// Equivalent to the [`into_bytes`] function except that the returned vector
+ /// includes the trailing nul terminator.
+ ///
+ /// [`into_bytes`]: #method.into_bytes
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ffi::CString;
+ ///
+ /// let c_string = CString::new("foo").expect("CString::new failed");
+ /// let bytes = c_string.into_bytes_with_nul();
+ /// assert_eq!(bytes, vec![b'f', b'o', b'o', b'\0']);
+ /// ```
+ #[stable(feature = "cstring_into", since = "1.7.0")]
+ pub fn into_bytes_with_nul(self) -> Vec<u8> {
+ self.into_inner().into_vec()
+ }
+
+ /// Returns the contents of this `CString` as a slice of bytes.
+ ///
+ /// The returned slice does **not** contain the trailing nul
+ /// terminator, and it is guaranteed to not have any interior nul
+ /// bytes. If you need the nul terminator, use
+ /// [`as_bytes_with_nul`] instead.
+ ///
+ /// [`as_bytes_with_nul`]: #method.as_bytes_with_nul
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ffi::CString;
+ ///
+ /// let c_string = CString::new("foo").expect("CString::new failed");
+ /// let bytes = c_string.as_bytes();
+ /// assert_eq!(bytes, &[b'f', b'o', b'o']);
+ /// ```
+ #[inline]
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn as_bytes(&self) -> &[u8] {
+ &self.inner[..self.inner.len() - 1]
+ }
+
+ /// Equivalent to the [`as_bytes`] function except that the returned slice
+ /// includes the trailing nul terminator.
+ ///
+ /// [`as_bytes`]: #method.as_bytes
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ffi::CString;
+ ///
+ /// let c_string = CString::new("foo").expect("CString::new failed");
+ /// let bytes = c_string.as_bytes_with_nul();
+ /// assert_eq!(bytes, &[b'f', b'o', b'o', b'\0']);
+ /// ```
+ #[inline]
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn as_bytes_with_nul(&self) -> &[u8] {
+ &self.inner
+ }
+
+ /// Extracts a [`CStr`] slice containing the entire string.
+ ///
+ /// [`CStr`]: struct.CStr.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ffi::{CString, CStr};
+ ///
+ /// let c_string = CString::new(b"foo".to_vec()).expect("CString::new failed");
+ /// let c_str = c_string.as_c_str();
+ /// assert_eq!(c_str,
+ /// CStr::from_bytes_with_nul(b"foo\0").expect("CStr::from_bytes_with_nul failed"));
+ /// ```
+ #[inline]
+ #[stable(feature = "as_c_str", since = "1.20.0")]
+ pub fn as_c_str(&self) -> &CStr {
+ &*self
+ }
+
+ /// Converts this `CString` into a boxed [`CStr`].
+ ///
+ /// [`CStr`]: struct.CStr.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ffi::{CString, CStr};
+ ///
+ /// let c_string = CString::new(b"foo".to_vec()).expect("CString::new failed");
+ /// let boxed = c_string.into_boxed_c_str();
+ /// assert_eq!(&*boxed,
+ /// CStr::from_bytes_with_nul(b"foo\0").expect("CStr::from_bytes_with_nul failed"));
+ /// ```
+ #[stable(feature = "into_boxed_c_str", since = "1.20.0")]
+ pub fn into_boxed_c_str(self) -> Box<CStr> {
+ unsafe { Box::from_raw(Box::into_raw(self.into_inner()) as *mut CStr) }
+ }
+
+ /// Bypass "move out of struct which implements [`Drop`] trait" restriction.
+ ///
+ /// [`Drop`]: ../ops/trait.Drop.html
+ fn into_inner(self) -> Box<[u8]> {
+ unsafe {
+ let result = ptr::read(&self.inner);
+ mem::forget(self);
+ result
+ }
+ }
+}
+
+// Turns this `CString` into an empty string to prevent
+// memory unsafe code from working by accident. Inline
+// to prevent LLVM from optimizing it away in debug builds.
+#[stable(feature = "cstring_drop", since = "1.13.0")]
+impl Drop for CString {
+ #[inline]
+ fn drop(&mut self) {
+ unsafe { *self.inner.get_unchecked_mut(0) = 0; }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl ops::Deref for CString {
+ type Target = CStr;
+
+ #[inline]
+ fn deref(&self) -> &CStr {
+ unsafe { CStr::from_bytes_with_nul_unchecked(self.as_bytes_with_nul()) }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl fmt::Debug for CString {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt::Debug::fmt(&**self, f)
+ }
+}
+
+#[stable(feature = "cstring_into", since = "1.7.0")]
+impl From<CString> for Vec<u8> {
+ /// Converts a [`CString`] into a [`Vec`]`<u8>`.
+ ///
+ /// The conversion consumes the [`CString`], and removes the terminating NUL byte.
+ ///
+ /// [`Vec`]: ../vec/struct.Vec.html
+ /// [`CString`]: ../ffi/struct.CString.html
+ #[inline]
+ fn from(s: CString) -> Vec<u8> {
+ s.into_bytes()
+ }
+}
+
+#[stable(feature = "cstr_debug", since = "1.3.0")]
+impl fmt::Debug for CStr {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "\"")?;
+ for byte in self.to_bytes().iter().flat_map(|&b| ascii::escape_default(b)) {
+ f.write_char(byte as char)?;
+ }
+ write!(f, "\"")
+ }
+}
+
+#[stable(feature = "cstr_default", since = "1.10.0")]
+impl Default for &CStr {
+ fn default() -> Self {
+ const SLICE: &[c_char] = &[0];
+ unsafe { CStr::from_ptr(SLICE.as_ptr()) }
+ }
+}
+
+#[stable(feature = "cstr_default", since = "1.10.0")]
+impl Default for CString {
+ /// Creates an empty `CString`.
+ fn default() -> CString {
+ let a: &CStr = Default::default();
+ a.to_owned()
+ }
+}
+
+#[stable(feature = "cstr_borrow", since = "1.3.0")]
+impl Borrow<CStr> for CString {
+ #[inline]
+ fn borrow(&self) -> &CStr { self }
+}
+
+#[stable(feature = "cstring_from_cow_cstr", since = "1.28.0")]
+impl<'a> From<Cow<'a, CStr>> for CString {
+ #[inline]
+ fn from(s: Cow<'a, CStr>) -> Self {
+ s.into_owned()
+ }
+}
+
+#[stable(feature = "box_from_c_str", since = "1.17.0")]
+impl From<&CStr> for Box<CStr> {
+ fn from(s: &CStr) -> Box<CStr> {
+ let boxed: Box<[u8]> = Box::from(s.to_bytes_with_nul());
+ unsafe { Box::from_raw(Box::into_raw(boxed) as *mut CStr) }
+ }
+}
+
+#[stable(feature = "c_string_from_box", since = "1.18.0")]
+impl From<Box<CStr>> for CString {
+ /// Converts a [`Box`]`<CStr>` into a [`CString`] without copying or allocating.
+ ///
+ /// [`Box`]: ../boxed/struct.Box.html
+ /// [`CString`]: ../ffi/struct.CString.html
+ #[inline]
+ fn from(s: Box<CStr>) -> CString {
+ s.into_c_string()
+ }
+}
+
+#[stable(feature = "more_box_slice_clone", since = "1.29.0")]
+impl Clone for Box<CStr> {
+ #[inline]
+ fn clone(&self) -> Self {
+ (**self).into()
+ }
+}
+
+#[stable(feature = "box_from_c_string", since = "1.20.0")]
+impl From<CString> for Box<CStr> {
+ /// Converts a [`CString`] into a [`Box`]`<CStr>` without copying or allocating.
+ ///
+ /// [`CString`]: ../ffi/struct.CString.html
+ /// [`Box`]: ../boxed/struct.Box.html
+ #[inline]
+ fn from(s: CString) -> Box<CStr> {
+ s.into_boxed_c_str()
+ }
+}
+
+#[stable(feature = "cow_from_cstr", since = "1.28.0")]
+impl<'a> From<CString> for Cow<'a, CStr> {
+ #[inline]
+ fn from(s: CString) -> Cow<'a, CStr> {
+ Cow::Owned(s)
+ }
+}
+
+#[stable(feature = "cow_from_cstr", since = "1.28.0")]
+impl<'a> From<&'a CStr> for Cow<'a, CStr> {
+ #[inline]
+ fn from(s: &'a CStr) -> Cow<'a, CStr> {
+ Cow::Borrowed(s)
+ }
+}
+
+#[stable(feature = "cow_from_cstr", since = "1.28.0")]
+impl<'a> From<&'a CString> for Cow<'a, CStr> {
+ #[inline]
+ fn from(s: &'a CString) -> Cow<'a, CStr> {
+ Cow::Borrowed(s.as_c_str())
+ }
+}
+
+#[stable(feature = "shared_from_slice2", since = "1.24.0")]
+impl From<CString> for Arc<CStr> {
+ /// Converts a [`CString`] into a [`Arc`]`<CStr>` without copying or allocating.
+ ///
+ /// [`CString`]: ../ffi/struct.CString.html
+ /// [`Arc`]: ../sync/struct.Arc.html
+ #[inline]
+ fn from(s: CString) -> Arc<CStr> {
+ let arc: Arc<[u8]> = Arc::from(s.into_inner());
+ unsafe { Arc::from_raw(Arc::into_raw(arc) as *const CStr) }
+ }
+}
+
+#[stable(feature = "shared_from_slice2", since = "1.24.0")]
+impl From<&CStr> for Arc<CStr> {
+ #[inline]
+ fn from(s: &CStr) -> Arc<CStr> {
+ let arc: Arc<[u8]> = Arc::from(s.to_bytes_with_nul());
+ unsafe { Arc::from_raw(Arc::into_raw(arc) as *const CStr) }
+ }
+}
+
+#[stable(feature = "shared_from_slice2", since = "1.24.0")]
+impl From<CString> for Rc<CStr> {
+ /// Converts a [`CString`] into a [`Rc`]`<CStr>` without copying or allocating.
+ ///
+ /// [`CString`]: ../ffi/struct.CString.html
+ /// [`Rc`]: ../rc/struct.Rc.html
+ #[inline]
+ fn from(s: CString) -> Rc<CStr> {
+ let rc: Rc<[u8]> = Rc::from(s.into_inner());
+ unsafe { Rc::from_raw(Rc::into_raw(rc) as *const CStr) }
+ }
+}
+
+#[stable(feature = "shared_from_slice2", since = "1.24.0")]
+impl From<&CStr> for Rc<CStr> {
+ #[inline]
+ fn from(s: &CStr) -> Rc<CStr> {
+ let rc: Rc<[u8]> = Rc::from(s.to_bytes_with_nul());
+ unsafe { Rc::from_raw(Rc::into_raw(rc) as *const CStr) }
+ }
+}
+
+#[stable(feature = "default_box_extra", since = "1.17.0")]
+impl Default for Box<CStr> {
+ fn default() -> Box<CStr> {
+ let boxed: Box<[u8]> = Box::from([0]);
+ unsafe { Box::from_raw(Box::into_raw(boxed) as *mut CStr) }
+ }
+}
+
+impl NulError {
+ /// Returns the position of the nul byte in the slice that caused
+ /// [`CString::new`] to fail.
+ ///
+ /// [`CString::new`]: struct.CString.html#method.new
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ffi::CString;
+ ///
+ /// let nul_error = CString::new("foo\0bar").unwrap_err();
+ /// assert_eq!(nul_error.nul_position(), 3);
+ ///
+ /// let nul_error = CString::new("foo bar\0").unwrap_err();
+ /// assert_eq!(nul_error.nul_position(), 7);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn nul_position(&self) -> usize { self.0 }
+
+ /// Consumes this error, returning the underlying vector of bytes which
+ /// generated the error in the first place.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ffi::CString;
+ ///
+ /// let nul_error = CString::new("foo\0bar").unwrap_err();
+ /// assert_eq!(nul_error.into_vec(), b"foo\0bar");
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn into_vec(self) -> Vec<u8> { self.1 }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Error for NulError {
+ fn description(&self) -> &str { "nul byte found in data" }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl fmt::Display for NulError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "nul byte found in provided data at position: {}", self.0)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl From<NulError> for io::Error {
+ /// Converts a [`NulError`] into a [`io::Error`].
+ ///
+ /// [`NulError`]: ../ffi/struct.NulError.html
+ /// [`io::Error`]: ../io/struct.Error.html
+ fn from(_: NulError) -> io::Error {
+ io::Error::new(io::ErrorKind::InvalidInput,
+ "data provided contains a nul byte")
+ }
+}
+
+#[stable(feature = "frombyteswithnulerror_impls", since = "1.17.0")]
+impl Error for FromBytesWithNulError {
+ fn description(&self) -> &str {
+ match self.kind {
+ FromBytesWithNulErrorKind::InteriorNul(..) =>
+ "data provided contains an interior nul byte",
+ FromBytesWithNulErrorKind::NotNulTerminated =>
+ "data provided is not nul terminated",
+ }
+ }
+}
+
+#[stable(feature = "frombyteswithnulerror_impls", since = "1.17.0")]
+impl fmt::Display for FromBytesWithNulError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.write_str(self.description())?;
+ if let FromBytesWithNulErrorKind::InteriorNul(pos) = self.kind {
+ write!(f, " at byte pos {}", pos)?;
+ }
+ Ok(())
+ }
+}
+
+impl IntoStringError {
+ /// Consumes this error, returning original [`CString`] which generated the
+ /// error.
+ ///
+ /// [`CString`]: struct.CString.html
+ #[stable(feature = "cstring_into", since = "1.7.0")]
+ pub fn into_cstring(self) -> CString {
+ self.inner
+ }
+
+ /// Access the underlying UTF-8 error that was the cause of this error.
+ #[stable(feature = "cstring_into", since = "1.7.0")]
+ pub fn utf8_error(&self) -> Utf8Error {
+ self.error
+ }
+}
+
+#[stable(feature = "cstring_into", since = "1.7.0")]
+impl Error for IntoStringError {
+ fn description(&self) -> &str {
+ "C string contained non-utf8 bytes"
+ }
+
+ fn cause(&self) -> Option<&dyn Error> {
+ Some(&self.error)
+ }
+}
+
+#[stable(feature = "cstring_into", since = "1.7.0")]
+impl fmt::Display for IntoStringError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ self.description().fmt(f)
+ }
+}
+
+impl CStr {
+ /// Wraps a raw C string with a safe C string wrapper.
+ ///
+ /// This function will wrap the provided `ptr` with a `CStr` wrapper, which
+ /// allows inspection and interoperation of non-owned C strings. This method
+ /// is unsafe for a number of reasons:
+ ///
+ /// * There is no guarantee to the validity of `ptr`.
+ /// * The returned lifetime is not guaranteed to be the actual lifetime of
+ /// `ptr`.
+ /// * There is no guarantee that the memory pointed to by `ptr` contains a
+ /// valid nul terminator byte at the end of the string.
+ /// * It is not guaranteed that the memory pointed by `ptr` won't change
+ /// before the `CStr` has been destroyed.
+ ///
+ /// > **Note**: This operation is intended to be a 0-cost cast but it is
+ /// > currently implemented with an up-front calculation of the length of
+ /// > the string. This is not guaranteed to always be the case.
+ ///
+ /// # Examples
+ ///
+ /// ```ignore (extern-declaration)
+ /// # fn main() {
+ /// use std::ffi::CStr;
+ /// use std::os::raw::c_char;
+ ///
+ /// extern {
+ /// fn my_string() -> *const c_char;
+ /// }
+ ///
+ /// unsafe {
+ /// let slice = CStr::from_ptr(my_string());
+ /// println!("string returned: {}", slice.to_str().unwrap());
+ /// }
+ /// # }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub unsafe fn from_ptr<'a>(ptr: *const c_char) -> &'a CStr {
+ let len = sys::strlen(ptr);
+ let ptr = ptr as *const u8;
+ CStr::from_bytes_with_nul_unchecked(slice::from_raw_parts(ptr, len as usize + 1))
+ }
+
+ /// Creates a C string wrapper from a byte slice.
+ ///
+ /// This function will cast the provided `bytes` to a `CStr`
+ /// wrapper after ensuring that the byte slice is nul-terminated
+ /// and does not contain any interior nul bytes.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ffi::CStr;
+ ///
+ /// let cstr = CStr::from_bytes_with_nul(b"hello\0");
+ /// assert!(cstr.is_ok());
+ /// ```
+ ///
+ /// Creating a `CStr` without a trailing nul terminator is an error:
+ ///
+ /// ```
+ /// use std::ffi::CStr;
+ ///
+ /// let c_str = CStr::from_bytes_with_nul(b"hello");
+ /// assert!(c_str.is_err());
+ /// ```
+ ///
+ /// Creating a `CStr` with an interior nul byte is an error:
+ ///
+ /// ```
+ /// use std::ffi::CStr;
+ ///
+ /// let c_str = CStr::from_bytes_with_nul(b"he\0llo\0");
+ /// assert!(c_str.is_err());
+ /// ```
+ #[stable(feature = "cstr_from_bytes", since = "1.10.0")]
+ pub fn from_bytes_with_nul(bytes: &[u8])
+ -> Result<&CStr, FromBytesWithNulError> {
+ let nul_pos = memchr::memchr(0, bytes);
+ if let Some(nul_pos) = nul_pos {
+ if nul_pos + 1 != bytes.len() {
+ return Err(FromBytesWithNulError::interior_nul(nul_pos));
+ }
+ Ok(unsafe { CStr::from_bytes_with_nul_unchecked(bytes) })
+ } else {
+ Err(FromBytesWithNulError::not_nul_terminated())
+ }
+ }
+
+ /// Unsafely creates a C string wrapper from a byte slice.
+ ///
+ /// This function will cast the provided `bytes` to a `CStr` wrapper without
+ /// performing any sanity checks. The provided slice **must** be nul-terminated
+ /// and not contain any interior nul bytes.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ffi::{CStr, CString};
+ ///
+ /// unsafe {
+ /// let cstring = CString::new("hello").expect("CString::new failed");
+ /// let cstr = CStr::from_bytes_with_nul_unchecked(cstring.to_bytes_with_nul());
+ /// assert_eq!(cstr, &*cstring);
+ /// }
+ /// ```
+ #[inline]
+ #[stable(feature = "cstr_from_bytes", since = "1.10.0")]
+ #[rustc_const_unstable(feature = "const_cstr_unchecked")]
+ pub const unsafe fn from_bytes_with_nul_unchecked(bytes: &[u8]) -> &CStr {
+ &*(bytes as *const [u8] as *const CStr)
+ }
+
+ /// Returns the inner pointer to this C string.
+ ///
+ /// The returned pointer will be valid for as long as `self` is, and points
+ /// to a contiguous region of memory terminated with a 0 byte to represent
+ /// the end of the string.
+ ///
+ /// **WARNING**
+ ///
+ /// It is your responsibility to make sure that the underlying memory is not
+ /// freed too early. For example, the following code will cause undefined
+ /// behavior when `ptr` is used inside the `unsafe` block:
+ ///
+ /// ```no_run
+ /// # #![allow(unused_must_use)]
+ /// use std::ffi::{CString};
+ ///
+ /// let ptr = CString::new("Hello").expect("CString::new failed").as_ptr();
+ /// unsafe {
+ /// // `ptr` is dangling
+ /// *ptr;
+ /// }
+ /// ```
+ ///
+ /// This happens because the pointer returned by `as_ptr` does not carry any
+ /// lifetime information and the [`CString`] is deallocated immediately after
+ /// the `CString::new("Hello").expect("CString::new failed").as_ptr()` expression is evaluated.
+ /// To fix the problem, bind the `CString` to a local variable:
+ ///
+ /// ```no_run
+ /// # #![allow(unused_must_use)]
+ /// use std::ffi::{CString};
+ ///
+ /// let hello = CString::new("Hello").expect("CString::new failed");
+ /// let ptr = hello.as_ptr();
+ /// unsafe {
+ /// // `ptr` is valid because `hello` is in scope
+ /// *ptr;
+ /// }
+ /// ```
+ ///
+ /// This way, the lifetime of the `CString` in `hello` encompasses
+ /// the lifetime of `ptr` and the `unsafe` block.
+ ///
+ /// [`CString`]: struct.CString.html
+ #[inline]
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub const fn as_ptr(&self) -> *const c_char {
+ self.inner.as_ptr()
+ }
+
+ /// Converts this C string to a byte slice.
+ ///
+ /// The returned slice will **not** contain the trailing nul terminator that this C
+ /// string has.
+ ///
+ /// > **Note**: This method is currently implemented as a constant-time
+ /// > cast, but it is planned to alter its definition in the future to
+ /// > perform the length calculation whenever this method is called.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ffi::CStr;
+ ///
+ /// let c_str = CStr::from_bytes_with_nul(b"foo\0").expect("CStr::from_bytes_with_nul failed");
+ /// assert_eq!(c_str.to_bytes(), b"foo");
+ /// ```
+ #[inline]
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn to_bytes(&self) -> &[u8] {
+ let bytes = self.to_bytes_with_nul();
+ &bytes[..bytes.len() - 1]
+ }
+
+ /// Converts this C string to a byte slice containing the trailing 0 byte.
+ ///
+ /// This function is the equivalent of [`to_bytes`] except that it will retain
+ /// the trailing nul terminator instead of chopping it off.
+ ///
+ /// > **Note**: This method is currently implemented as a 0-cost cast, but
+ /// > it is planned to alter its definition in the future to perform the
+ /// > length calculation whenever this method is called.
+ ///
+ /// [`to_bytes`]: #method.to_bytes
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ffi::CStr;
+ ///
+ /// let c_str = CStr::from_bytes_with_nul(b"foo\0").expect("CStr::from_bytes_with_nul failed");
+ /// assert_eq!(c_str.to_bytes_with_nul(), b"foo\0");
+ /// ```
+ #[inline]
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn to_bytes_with_nul(&self) -> &[u8] {
+ unsafe { &*(&self.inner as *const [c_char] as *const [u8]) }
+ }
+
+ /// Yields a [`&str`] slice if the `CStr` contains valid UTF-8.
+ ///
+ /// If the contents of the `CStr` are valid UTF-8 data, this
+ /// function will return the corresponding [`&str`] slice. Otherwise,
+ /// it will return an error with details of where UTF-8 validation failed.
+ ///
+ /// > **Note**: This method is currently implemented to check for validity
+ /// > after a constant-time cast, but it is planned to alter its definition
+ /// > in the future to perform the length calculation in addition to the
+ /// > UTF-8 check whenever this method is called.
+ ///
+ /// [`&str`]: ../primitive.str.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ffi::CStr;
+ ///
+ /// let c_str = CStr::from_bytes_with_nul(b"foo\0").expect("CStr::from_bytes_with_nul failed");
+ /// assert_eq!(c_str.to_str(), Ok("foo"));
+ /// ```
+ #[stable(feature = "cstr_to_str", since = "1.4.0")]
+ pub fn to_str(&self) -> Result<&str, str::Utf8Error> {
+ // N.B., when `CStr` is changed to perform the length check in `.to_bytes()`
+ // instead of in `from_ptr()`, it may be worth considering if this should
+ // be rewritten to do the UTF-8 check inline with the length calculation
+ // instead of doing it afterwards.
+ str::from_utf8(self.to_bytes())
+ }
+
+ /// Converts a `CStr` into a [`Cow`]`<`[`str`]`>`.
+ ///
+ /// If the contents of the `CStr` are valid UTF-8 data, this
+ /// function will return a [`Cow`]`::`[`Borrowed`]`(`[`&str`]`)`
+ /// with the corresponding [`&str`] slice. Otherwise, it will
+ /// replace any invalid UTF-8 sequences with
+ /// [`U+FFFD REPLACEMENT CHARACTER`][U+FFFD] and return a
+ /// [`Cow`]`::`[`Owned`]`(`[`String`]`)` with the result.
+ ///
+ /// > **Note**: This method is currently implemented to check for validity
+ /// > after a constant-time cast, but it is planned to alter its definition
+ /// > in the future to perform the length calculation in addition to the
+ /// > UTF-8 check whenever this method is called.
+ ///
+ /// [`Cow`]: ../borrow/enum.Cow.html
+ /// [`Borrowed`]: ../borrow/enum.Cow.html#variant.Borrowed
+ /// [`Owned`]: ../borrow/enum.Cow.html#variant.Owned
+ /// [`str`]: ../primitive.str.html
+ /// [`String`]: ../string/struct.String.html
+ /// [U+FFFD]: ../char/constant.REPLACEMENT_CHARACTER.html
+ ///
+ /// # Examples
+ ///
+ /// Calling `to_string_lossy` on a `CStr` containing valid UTF-8:
+ ///
+ /// ```
+ /// use std::borrow::Cow;
+ /// use std::ffi::CStr;
+ ///
+ /// let c_str = CStr::from_bytes_with_nul(b"Hello World\0")
+ /// .expect("CStr::from_bytes_with_nul failed");
+ /// assert_eq!(c_str.to_string_lossy(), Cow::Borrowed("Hello World"));
+ /// ```
+ ///
+ /// Calling `to_string_lossy` on a `CStr` containing invalid UTF-8:
+ ///
+ /// ```
+ /// use std::borrow::Cow;
+ /// use std::ffi::CStr;
+ ///
+ /// let c_str = CStr::from_bytes_with_nul(b"Hello \xF0\x90\x80World\0")
+ /// .expect("CStr::from_bytes_with_nul failed");
+ /// assert_eq!(
+ /// c_str.to_string_lossy(),
+ /// Cow::Owned(String::from("Hello �World")) as Cow<'_, str>
+ /// );
+ /// ```
+ #[stable(feature = "cstr_to_str", since = "1.4.0")]
+ pub fn to_string_lossy(&self) -> Cow<'_, str> {
+ String::from_utf8_lossy(self.to_bytes())
+ }
+
+ /// Converts a [`Box`]`<CStr>` into a [`CString`] without copying or allocating.
+ ///
+ /// [`Box`]: ../boxed/struct.Box.html
+ /// [`CString`]: struct.CString.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ffi::CString;
+ ///
+ /// let c_string = CString::new(b"foo".to_vec()).expect("CString::new failed");
+ /// let boxed = c_string.into_boxed_c_str();
+ /// assert_eq!(boxed.into_c_string(), CString::new("foo").expect("CString::new failed"));
+ /// ```
+ #[stable(feature = "into_boxed_c_str", since = "1.20.0")]
+ pub fn into_c_string(self: Box<CStr>) -> CString {
+ let raw = Box::into_raw(self) as *mut [u8];
+ CString { inner: unsafe { Box::from_raw(raw) } }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl PartialEq for CStr {
+ fn eq(&self, other: &CStr) -> bool {
+ self.to_bytes().eq(other.to_bytes())
+ }
+}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Eq for CStr {}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl PartialOrd for CStr {
+ fn partial_cmp(&self, other: &CStr) -> Option<Ordering> {
+ self.to_bytes().partial_cmp(&other.to_bytes())
+ }
+}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Ord for CStr {
+ fn cmp(&self, other: &CStr) -> Ordering {
+ self.to_bytes().cmp(&other.to_bytes())
+ }
+}
+
+#[stable(feature = "cstr_borrow", since = "1.3.0")]
+impl ToOwned for CStr {
+ type Owned = CString;
+
+ fn to_owned(&self) -> CString {
+ CString { inner: self.to_bytes_with_nul().into() }
+ }
+}
+
+#[stable(feature = "cstring_asref", since = "1.7.0")]
+impl From<&CStr> for CString {
+ fn from(s: &CStr) -> CString {
+ s.to_owned()
+ }
+}
+
+#[stable(feature = "cstring_asref", since = "1.7.0")]
+impl ops::Index<ops::RangeFull> for CString {
+ type Output = CStr;
+
+ #[inline]
+ fn index(&self, _index: ops::RangeFull) -> &CStr {
+ self
+ }
+}
+
+#[stable(feature = "cstring_asref", since = "1.7.0")]
+impl AsRef<CStr> for CStr {
+ #[inline]
+ fn as_ref(&self) -> &CStr {
+ self
+ }
+}
+
+#[stable(feature = "cstring_asref", since = "1.7.0")]
+impl AsRef<CStr> for CString {
+ #[inline]
+ fn as_ref(&self) -> &CStr {
+ self
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use crate::os::raw::c_char;
+ use crate::borrow::Cow::{Borrowed, Owned};
+ use crate::hash::{Hash, Hasher};
+ use crate::collections::hash_map::DefaultHasher;
+ use crate::rc::Rc;
+ use crate::sync::Arc;
+
+ #[test]
+ fn c_to_rust() {
+ let data = b"123\0";
+ let ptr = data.as_ptr() as *const c_char;
+ unsafe {
+ assert_eq!(CStr::from_ptr(ptr).to_bytes(), b"123");
+ assert_eq!(CStr::from_ptr(ptr).to_bytes_with_nul(), b"123\0");
+ }
+ }
+
+ #[test]
+ fn simple() {
+ let s = CString::new("1234").unwrap();
+ assert_eq!(s.as_bytes(), b"1234");
+ assert_eq!(s.as_bytes_with_nul(), b"1234\0");
+ }
+
+ #[test]
+ fn build_with_zero1() {
+ assert!(CString::new(&b"\0"[..]).is_err());
+ }
+ #[test]
+ fn build_with_zero2() {
+ assert!(CString::new(vec![0]).is_err());
+ }
+
+ #[test]
+ fn build_with_zero3() {
+ unsafe {
+ let s = CString::from_vec_unchecked(vec![0]);
+ assert_eq!(s.as_bytes(), b"\0");
+ }
+ }
+
+ #[test]
+ fn formatted() {
+ let s = CString::new(&b"abc\x01\x02\n\xE2\x80\xA6\xFF"[..]).unwrap();
+ assert_eq!(format!("{:?}", s), r#""abc\x01\x02\n\xe2\x80\xa6\xff""#);
+ }
+
+ #[test]
+ fn borrowed() {
+ unsafe {
+ let s = CStr::from_ptr(b"12\0".as_ptr() as *const _);
+ assert_eq!(s.to_bytes(), b"12");
+ assert_eq!(s.to_bytes_with_nul(), b"12\0");
+ }
+ }
+
+ #[test]
+ fn to_str() {
+ let data = b"123\xE2\x80\xA6\0";
+ let ptr = data.as_ptr() as *const c_char;
+ unsafe {
+ assert_eq!(CStr::from_ptr(ptr).to_str(), Ok("123…"));
+ assert_eq!(CStr::from_ptr(ptr).to_string_lossy(), Borrowed("123…"));
+ }
+ let data = b"123\xE2\0";
+ let ptr = data.as_ptr() as *const c_char;
+ unsafe {
+ assert!(CStr::from_ptr(ptr).to_str().is_err());
+ assert_eq!(CStr::from_ptr(ptr).to_string_lossy(), Owned::<str>(format!("123\u{FFFD}")));
+ }
+ }
+
+ #[test]
+ fn to_owned() {
+ let data = b"123\0";
+ let ptr = data.as_ptr() as *const c_char;
+
+ let owned = unsafe { CStr::from_ptr(ptr).to_owned() };
+ assert_eq!(owned.as_bytes_with_nul(), data);
+ }
+
+ #[test]
+ fn equal_hash() {
+ let data = b"123\xE2\xFA\xA6\0";
+ let ptr = data.as_ptr() as *const c_char;
+ let cstr: &'static CStr = unsafe { CStr::from_ptr(ptr) };
+
+ let mut s = DefaultHasher::new();
+ cstr.hash(&mut s);
+ let cstr_hash = s.finish();
+ let mut s = DefaultHasher::new();
+ CString::new(&data[..data.len() - 1]).unwrap().hash(&mut s);
+ let cstring_hash = s.finish();
+
+ assert_eq!(cstr_hash, cstring_hash);
+ }
+
+ #[test]
+ fn from_bytes_with_nul() {
+ let data = b"123\0";
+ let cstr = CStr::from_bytes_with_nul(data);
+ assert_eq!(cstr.map(CStr::to_bytes), Ok(&b"123"[..]));
+ let cstr = CStr::from_bytes_with_nul(data);
+ assert_eq!(cstr.map(CStr::to_bytes_with_nul), Ok(&b"123\0"[..]));
+
+ unsafe {
+ let cstr = CStr::from_bytes_with_nul(data);
+ let cstr_unchecked = CStr::from_bytes_with_nul_unchecked(data);
+ assert_eq!(cstr, Ok(cstr_unchecked));
+ }
+ }
+
+ #[test]
+ fn from_bytes_with_nul_unterminated() {
+ let data = b"123";
+ let cstr = CStr::from_bytes_with_nul(data);
+ assert!(cstr.is_err());
+ }
+
+ #[test]
+ fn from_bytes_with_nul_interior() {
+ let data = b"1\023\0";
+ let cstr = CStr::from_bytes_with_nul(data);
+ assert!(cstr.is_err());
+ }
+
+ #[test]
+ fn into_boxed() {
+ let orig: &[u8] = b"Hello, world!\0";
+ let cstr = CStr::from_bytes_with_nul(orig).unwrap();
+ let boxed: Box<CStr> = Box::from(cstr);
+ let cstring = cstr.to_owned().into_boxed_c_str().into_c_string();
+ assert_eq!(cstr, &*boxed);
+ assert_eq!(&*boxed, &*cstring);
+ assert_eq!(&*cstring, cstr);
+ }
+
+ #[test]
+ fn boxed_default() {
+ let boxed = <Box<CStr>>::default();
+ assert_eq!(boxed.to_bytes_with_nul(), &[0]);
+ }
+
+ #[test]
+ fn into_rc() {
+ let orig: &[u8] = b"Hello, world!\0";
+ let cstr = CStr::from_bytes_with_nul(orig).unwrap();
+ let rc: Rc<CStr> = Rc::from(cstr);
+ let arc: Arc<CStr> = Arc::from(cstr);
+
+ assert_eq!(&*rc, cstr);
+ assert_eq!(&*arc, cstr);
+
+ let rc2: Rc<CStr> = Rc::from(cstr.to_owned());
+ let arc2: Arc<CStr> = Arc::from(cstr.to_owned());
+
+ assert_eq!(&*rc2, cstr);
+ assert_eq!(&*arc2, cstr);
+ }
+
+ #[test]
+ fn cstr_const_constructor() {
+ const CSTR: &CStr = unsafe {
+ CStr::from_bytes_with_nul_unchecked(b"Hello, world!\0")
+ };
+
+ assert_eq!(CSTR.to_str().unwrap(), "Hello, world!");
+ }
+}
diff --git a/src/libstd/ffi/mod.rs b/src/libstd/ffi/mod.rs
new file mode 100644
index 0000000..7a38f0e
--- /dev/null
+++ b/src/libstd/ffi/mod.rs
@@ -0,0 +1,176 @@
+//! Utilities related to FFI bindings.
+//!
+//! This module provides utilities to handle data across non-Rust
+//! interfaces, like other programming languages and the underlying
+//! operating system. It is mainly of use for FFI (Foreign Function
+//! Interface) bindings and code that needs to exchange C-like strings
+//! with other languages.
+//!
+//! # Overview
+//!
+//! Rust represents owned strings with the [`String`] type, and
+//! borrowed slices of strings with the [`str`] primitive. Both are
+//! always in UTF-8 encoding, and may contain nul bytes in the middle,
+//! i.e., if you look at the bytes that make up the string, there may
+//! be a `\0` among them. Both `String` and `str` store their length
+//! explicitly; there are no nul terminators at the end of strings
+//! like in C.
+//!
+//! C strings are different from Rust strings:
+//!
+//! * **Encodings** - Rust strings are UTF-8, but C strings may use
+//! other encodings. If you are using a string from C, you should
+//! check its encoding explicitly, rather than just assuming that it
+//! is UTF-8 like you can do in Rust.
+//!
+//! * **Character size** - C strings may use `char` or `wchar_t`-sized
+//! characters; please **note** that C's `char` is different from Rust's.
+//! The C standard leaves the actual sizes of those types open to
+//! interpretation, but defines different APIs for strings made up of
+//! each character type. Rust strings are always UTF-8, so different
+//! Unicode characters will be encoded in a variable number of bytes
+//! each. The Rust type [`char`] represents a '[Unicode scalar
+//! value]', which is similar to, but not the same as, a '[Unicode
+//! code point]'.
+//!
+//! * **Nul terminators and implicit string lengths** - Often, C
+//! strings are nul-terminated, i.e., they have a `\0` character at the
+//! end. The length of a string buffer is not stored, but has to be
+//! calculated; to compute the length of a string, C code must
+//! manually call a function like `strlen()` for `char`-based strings,
+//! or `wcslen()` for `wchar_t`-based ones. Those functions return
+//! the number of characters in the string excluding the nul
+//! terminator, so the buffer length is really `len+1` characters.
+//! Rust strings don't have a nul terminator; their length is always
+//! stored and does not need to be calculated. While in Rust
+//! accessing a string's length is a O(1) operation (because the
+//! length is stored); in C it is an O(length) operation because the
+//! length needs to be computed by scanning the string for the nul
+//! terminator.
+//!
+//! * **Internal nul characters** - When C strings have a nul
+//! terminator character, this usually means that they cannot have nul
+//! characters in the middle — a nul character would essentially
+//! truncate the string. Rust strings *can* have nul characters in
+//! the middle, because nul does not have to mark the end of the
+//! string in Rust.
+//!
+//! # Representations of non-Rust strings
+//!
+//! [`CString`] and [`CStr`] are useful when you need to transfer
+//! UTF-8 strings to and from languages with a C ABI, like Python.
+//!
+//! * **From Rust to C:** [`CString`] represents an owned, C-friendly
+//! string: it is nul-terminated, and has no internal nul characters.
+//! Rust code can create a [`CString`] out of a normal string (provided
+//! that the string doesn't have nul characters in the middle), and
+//! then use a variety of methods to obtain a raw `*mut `[`u8`] that can
+//! then be passed as an argument to functions which use the C
+//! conventions for strings.
+//!
+//! * **From C to Rust:** [`CStr`] represents a borrowed C string; it
+//! is what you would use to wrap a raw `*const `[`u8`] that you got from
+//! a C function. A [`CStr`] is guaranteed to be a nul-terminated array
+//! of bytes. Once you have a [`CStr`], you can convert it to a Rust
+//! [`&str`][`str`] if it's valid UTF-8, or lossily convert it by adding
+//! replacement characters.
+//!
+//! [`OsString`] and [`OsStr`] are useful when you need to transfer
+//! strings to and from the operating system itself, or when capturing
+//! the output of external commands. Conversions between [`OsString`],
+//! [`OsStr`] and Rust strings work similarly to those for [`CString`]
+//! and [`CStr`].
+//!
+//! * [`OsString`] represents an owned string in whatever
+//! representation the operating system prefers. In the Rust standard
+//! library, various APIs that transfer strings to/from the operating
+//! system use [`OsString`] instead of plain strings. For example,
+//! [`env::var_os()`] is used to query environment variables; it
+//! returns an [`Option`]`<`[`OsString`]`>`. If the environment variable
+//! exists you will get a [`Some`]`(os_string)`, which you can *then* try to
+//! convert to a Rust string. This yields a [`Result<>`], so that
+//! your code can detect errors in case the environment variable did
+//! not in fact contain valid Unicode data.
+//!
+//! * [`OsStr`] represents a borrowed reference to a string in a
+//! format that can be passed to the operating system. It can be
+//! converted into an UTF-8 Rust string slice in a similar way to
+//! [`OsString`].
+//!
+//! # Conversions
+//!
+//! ## On Unix
+//!
+//! On Unix, [`OsStr`] implements the
+//! `std::os::unix::ffi::`[`OsStrExt`][unix.OsStrExt] trait, which
+//! augments it with two methods, [`from_bytes`] and [`as_bytes`].
+//! These do inexpensive conversions from and to UTF-8 byte slices.
+//!
+//! Additionally, on Unix [`OsString`] implements the
+//! `std::os::unix::ffi::`[`OsStringExt`][unix.OsStringExt] trait,
+//! which provides [`from_vec`] and [`into_vec`] methods that consume
+//! their arguments, and take or produce vectors of [`u8`].
+//!
+//! ## On Windows
+//!
+//! On Windows, [`OsStr`] implements the
+//! `std::os::windows::ffi::`[`OsStrExt`][windows.OsStrExt] trait,
+//! which provides an [`encode_wide`] method. This provides an
+//! iterator that can be [`collect`]ed into a vector of [`u16`].
+//!
+//! Additionally, on Windows [`OsString`] implements the
+//! `std::os::windows:ffi::`[`OsStringExt`][windows.OsStringExt]
+//! trait, which provides a [`from_wide`] method. The result of this
+//! method is an [`OsString`] which can be round-tripped to a Windows
+//! string losslessly.
+//!
+//! [`String`]: ../string/struct.String.html
+//! [`str`]: ../primitive.str.html
+//! [`char`]: ../primitive.char.html
+//! [`u8`]: ../primitive.u8.html
+//! [`u16`]: ../primitive.u16.html
+//! [Unicode scalar value]: http://www.unicode.org/glossary/#unicode_scalar_value
+//! [Unicode code point]: http://www.unicode.org/glossary/#code_point
+//! [`CString`]: struct.CString.html
+//! [`CStr`]: struct.CStr.html
+//! [`OsString`]: struct.OsString.html
+//! [`OsStr`]: struct.OsStr.html
+//! [`env::set_var()`]: ../env/fn.set_var.html
+//! [`env::var_os()`]: ../env/fn.var_os.html
+//! [`Result<>`]: ../result/enum.Result.html
+//! [unix.OsStringExt]: ../os/unix/ffi/trait.OsStringExt.html
+//! [`from_vec`]: ../os/unix/ffi/trait.OsStringExt.html#tymethod.from_vec
+//! [`into_vec`]: ../os/unix/ffi/trait.OsStringExt.html#tymethod.into_vec
+//! [unix.OsStrExt]: ../os/unix/ffi/trait.OsStrExt.html
+//! [`from_bytes`]: ../os/unix/ffi/trait.OsStrExt.html#tymethod.from_bytes
+//! [`as_bytes`]: ../os/unix/ffi/trait.OsStrExt.html#tymethod.as_bytes
+//! [`OsStrExt`]: ../os/unix/ffi/trait.OsStrExt.html
+//! [windows.OsStrExt]: ../os/windows/ffi/trait.OsStrExt.html
+//! [`encode_wide`]: ../os/windows/ffi/trait.OsStrExt.html#tymethod.encode_wide
+//! [`collect`]: ../iter/trait.Iterator.html#method.collect
+//! [windows.OsStringExt]: ../os/windows/ffi/trait.OsStringExt.html
+//! [`from_wide`]: ../os/windows/ffi/trait.OsStringExt.html#tymethod.from_wide
+//! [`Option`]: ../option/enum.Option.html
+//! [`Some`]: ../option/enum.Option.html#variant.Some
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use self::c_str::{CString, CStr, NulError, IntoStringError};
+#[stable(feature = "cstr_from_bytes", since = "1.10.0")]
+pub use self::c_str::{FromBytesWithNulError};
+
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use self::os_str::{OsString, OsStr};
+
+#[stable(feature = "raw_os", since = "1.1.0")]
+pub use core::ffi::c_void;
+
+#[unstable(feature = "c_variadic",
+ reason = "the `c_variadic` feature has not been properly tested on \
+ all supported platforms",
+ issue = "44930")]
+pub use core::ffi::VaList;
+
+mod c_str;
+mod os_str;
diff --git a/src/libstd/ffi/os_str.rs b/src/libstd/ffi/os_str.rs
new file mode 100644
index 0000000..13aee78
--- /dev/null
+++ b/src/libstd/ffi/os_str.rs
@@ -0,0 +1,1136 @@
+use crate::borrow::{Borrow, Cow};
+use crate::fmt;
+use crate::ops;
+use crate::cmp;
+use crate::hash::{Hash, Hasher};
+use crate::rc::Rc;
+use crate::sync::Arc;
+
+use crate::sys::os_str::{Buf, Slice};
+use crate::sys_common::{AsInner, IntoInner, FromInner};
+
+/// A type that can represent owned, mutable platform-native strings, but is
+/// cheaply inter-convertible with Rust strings.
+///
+/// The need for this type arises from the fact that:
+///
+/// * On Unix systems, strings are often arbitrary sequences of non-zero
+/// bytes, in many cases interpreted as UTF-8.
+///
+/// * On Windows, strings are often arbitrary sequences of non-zero 16-bit
+/// values, interpreted as UTF-16 when it is valid to do so.
+///
+/// * In Rust, strings are always valid UTF-8, which may contain zeros.
+///
+/// `OsString` and [`OsStr`] bridge this gap by simultaneously representing Rust
+/// and platform-native string values, and in particular allowing a Rust string
+/// to be converted into an "OS" string with no cost if possible. A consequence
+/// of this is that `OsString` instances are *not* `NUL` terminated; in order
+/// to pass to e.g., Unix system call, you should create a [`CStr`].
+///
+/// `OsString` is to [`&OsStr`] as [`String`] is to [`&str`]: the former
+/// in each pair are owned strings; the latter are borrowed
+/// references.
+///
+/// Note, `OsString` and `OsStr` internally do not necessarily hold strings in
+/// the form native to the platform; While on Unix, strings are stored as a
+/// sequence of 8-bit values, on Windows, where strings are 16-bit value based
+/// as just discussed, strings are also actually stored as a sequence of 8-bit
+/// values, encoded in a less-strict variant of UTF-8. This is useful to
+/// understand when handling capacity and length values.
+///
+/// # Creating an `OsString`
+///
+/// **From a Rust string**: `OsString` implements
+/// [`From`]`<`[`String`]`>`, so you can use `my_string.from` to
+/// create an `OsString` from a normal Rust string.
+///
+/// **From slices:** Just like you can start with an empty Rust
+/// [`String`] and then [`push_str`][String.push_str] `&str`
+/// sub-string slices into it, you can create an empty `OsString` with
+/// the [`new`] method and then push string slices into it with the
+/// [`push`] method.
+///
+/// # Extracting a borrowed reference to the whole OS string
+///
+/// You can use the [`as_os_str`] method to get an `&`[`OsStr`] from
+/// an `OsString`; this is effectively a borrowed reference to the
+/// whole string.
+///
+/// # Conversions
+///
+/// See the [module's toplevel documentation about conversions][conversions] for a discussion on
+/// the traits which `OsString` implements for [conversions] from/to native representations.
+///
+/// [`OsStr`]: struct.OsStr.html
+/// [`&OsStr`]: struct.OsStr.html
+/// [`CStr`]: struct.CStr.html
+/// [`From`]: ../convert/trait.From.html
+/// [`String`]: ../string/struct.String.html
+/// [`&str`]: ../primitive.str.html
+/// [`u8`]: ../primitive.u8.html
+/// [`u16`]: ../primitive.u16.html
+/// [String.push_str]: ../string/struct.String.html#method.push_str
+/// [`new`]: #method.new
+/// [`push`]: #method.push
+/// [`as_os_str`]: #method.as_os_str
+/// [conversions]: index.html#conversions
+#[derive(Clone)]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct OsString {
+ inner: Buf
+}
+
+/// Borrowed reference to an OS string (see [`OsString`]).
+///
+/// This type represents a borrowed reference to a string in the operating system's preferred
+/// representation.
+///
+/// `&OsStr` is to [`OsString`] as [`&str`] is to [`String`]: the former in each pair are borrowed
+/// references; the latter are owned strings.
+///
+/// See the [module's toplevel documentation about conversions][conversions] for a discussion on
+/// the traits which `OsStr` implements for [conversions] from/to native representations.
+///
+/// [`OsString`]: struct.OsString.html
+/// [`&str`]: ../primitive.str.html
+/// [`String`]: ../string/struct.String.html
+/// [conversions]: index.html#conversions
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct OsStr {
+ inner: Slice
+}
+
+impl OsString {
+ /// Constructs a new empty `OsString`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ffi::OsString;
+ ///
+ /// let os_string = OsString::new();
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn new() -> OsString {
+ OsString { inner: Buf::from_string(String::new()) }
+ }
+
+ /// Converts to an [`OsStr`] slice.
+ ///
+ /// [`OsStr`]: struct.OsStr.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ffi::{OsString, OsStr};
+ ///
+ /// let os_string = OsString::from("foo");
+ /// let os_str = OsStr::new("foo");
+ /// assert_eq!(os_string.as_os_str(), os_str);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn as_os_str(&self) -> &OsStr {
+ self
+ }
+
+ /// Converts the `OsString` into a [`String`] if it contains valid Unicode data.
+ ///
+ /// On failure, ownership of the original `OsString` is returned.
+ ///
+ /// [`String`]: ../../std/string/struct.String.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ffi::OsString;
+ ///
+ /// let os_string = OsString::from("foo");
+ /// let string = os_string.into_string();
+ /// assert_eq!(string, Ok(String::from("foo")));
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn into_string(self) -> Result<String, OsString> {
+ self.inner.into_string().map_err(|buf| OsString { inner: buf} )
+ }
+
+ /// Extends the string with the given [`&OsStr`] slice.
+ ///
+ /// [`&OsStr`]: struct.OsStr.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ffi::OsString;
+ ///
+ /// let mut os_string = OsString::from("foo");
+ /// os_string.push("bar");
+ /// assert_eq!(&os_string, "foobar");
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn push<T: AsRef<OsStr>>(&mut self, s: T) {
+ self.inner.push_slice(&s.as_ref().inner)
+ }
+
+ /// Creates a new `OsString` with the given capacity.
+ ///
+ /// The string will be able to hold exactly `capacity` length units of other
+ /// OS strings without reallocating. If `capacity` is 0, the string will not
+ /// allocate.
+ ///
+ /// See main `OsString` documentation information about encoding.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ffi::OsString;
+ ///
+ /// let mut os_string = OsString::with_capacity(10);
+ /// let capacity = os_string.capacity();
+ ///
+ /// // This push is done without reallocating
+ /// os_string.push("foo");
+ ///
+ /// assert_eq!(capacity, os_string.capacity());
+ /// ```
+ #[stable(feature = "osstring_simple_functions", since = "1.9.0")]
+ pub fn with_capacity(capacity: usize) -> OsString {
+ OsString {
+ inner: Buf::with_capacity(capacity)
+ }
+ }
+
+ /// Truncates the `OsString` to zero length.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ffi::OsString;
+ ///
+ /// let mut os_string = OsString::from("foo");
+ /// assert_eq!(&os_string, "foo");
+ ///
+ /// os_string.clear();
+ /// assert_eq!(&os_string, "");
+ /// ```
+ #[stable(feature = "osstring_simple_functions", since = "1.9.0")]
+ pub fn clear(&mut self) {
+ self.inner.clear()
+ }
+
+ /// Returns the capacity this `OsString` can hold without reallocating.
+ ///
+ /// See `OsString` introduction for information about encoding.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ffi::OsString;
+ ///
+ /// let mut os_string = OsString::with_capacity(10);
+ /// assert!(os_string.capacity() >= 10);
+ /// ```
+ #[stable(feature = "osstring_simple_functions", since = "1.9.0")]
+ pub fn capacity(&self) -> usize {
+ self.inner.capacity()
+ }
+
+ /// Reserves capacity for at least `additional` more capacity to be inserted
+ /// in the given `OsString`.
+ ///
+ /// The collection may reserve more space to avoid frequent reallocations.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ffi::OsString;
+ ///
+ /// let mut s = OsString::new();
+ /// s.reserve(10);
+ /// assert!(s.capacity() >= 10);
+ /// ```
+ #[stable(feature = "osstring_simple_functions", since = "1.9.0")]
+ pub fn reserve(&mut self, additional: usize) {
+ self.inner.reserve(additional)
+ }
+
+ /// Reserves the minimum capacity for exactly `additional` more capacity to
+ /// be inserted in the given `OsString`. Does nothing if the capacity is
+ /// already sufficient.
+ ///
+ /// Note that the allocator may give the collection more space than it
+ /// requests. Therefore, capacity can not be relied upon to be precisely
+ /// minimal. Prefer reserve if future insertions are expected.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ffi::OsString;
+ ///
+ /// let mut s = OsString::new();
+ /// s.reserve_exact(10);
+ /// assert!(s.capacity() >= 10);
+ /// ```
+ #[stable(feature = "osstring_simple_functions", since = "1.9.0")]
+ pub fn reserve_exact(&mut self, additional: usize) {
+ self.inner.reserve_exact(additional)
+ }
+
+ /// Shrinks the capacity of the `OsString` to match its length.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ffi::OsString;
+ ///
+ /// let mut s = OsString::from("foo");
+ ///
+ /// s.reserve(100);
+ /// assert!(s.capacity() >= 100);
+ ///
+ /// s.shrink_to_fit();
+ /// assert_eq!(3, s.capacity());
+ /// ```
+ #[stable(feature = "osstring_shrink_to_fit", since = "1.19.0")]
+ pub fn shrink_to_fit(&mut self) {
+ self.inner.shrink_to_fit()
+ }
+
+ /// Shrinks the capacity of the `OsString` with a lower bound.
+ ///
+ /// The capacity will remain at least as large as both the length
+ /// and the supplied value.
+ ///
+ /// Panics if the current capacity is smaller than the supplied
+ /// minimum capacity.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(shrink_to)]
+ /// use std::ffi::OsString;
+ ///
+ /// let mut s = OsString::from("foo");
+ ///
+ /// s.reserve(100);
+ /// assert!(s.capacity() >= 100);
+ ///
+ /// s.shrink_to(10);
+ /// assert!(s.capacity() >= 10);
+ /// s.shrink_to(0);
+ /// assert!(s.capacity() >= 3);
+ /// ```
+ #[inline]
+ #[unstable(feature = "shrink_to", reason = "new API", issue="56431")]
+ pub fn shrink_to(&mut self, min_capacity: usize) {
+ self.inner.shrink_to(min_capacity)
+ }
+
+ /// Converts this `OsString` into a boxed [`OsStr`].
+ ///
+ /// [`OsStr`]: struct.OsStr.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ffi::{OsString, OsStr};
+ ///
+ /// let s = OsString::from("hello");
+ ///
+ /// let b: Box<OsStr> = s.into_boxed_os_str();
+ /// ```
+ #[stable(feature = "into_boxed_os_str", since = "1.20.0")]
+ pub fn into_boxed_os_str(self) -> Box<OsStr> {
+ let rw = Box::into_raw(self.inner.into_box()) as *mut OsStr;
+ unsafe { Box::from_raw(rw) }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl From<String> for OsString {
+ /// Converts a [`String`] into a [`OsString`].
+ ///
+ /// The conversion copies the data, and includes an allocation on the heap.
+ fn from(s: String) -> OsString {
+ OsString { inner: Buf::from_string(s) }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T: ?Sized + AsRef<OsStr>> From<&T> for OsString {
+ fn from(s: &T) -> OsString {
+ s.as_ref().to_os_string()
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl ops::Index<ops::RangeFull> for OsString {
+ type Output = OsStr;
+
+ #[inline]
+ fn index(&self, _index: ops::RangeFull) -> &OsStr {
+ OsStr::from_inner(self.inner.as_slice())
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl ops::Deref for OsString {
+ type Target = OsStr;
+
+ #[inline]
+ fn deref(&self) -> &OsStr {
+ &self[..]
+ }
+}
+
+#[stable(feature = "osstring_default", since = "1.9.0")]
+impl Default for OsString {
+ /// Constructs an empty `OsString`.
+ #[inline]
+ fn default() -> OsString {
+ OsString::new()
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl fmt::Debug for OsString {
+ fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt::Debug::fmt(&**self, formatter)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl PartialEq for OsString {
+ fn eq(&self, other: &OsString) -> bool {
+ &**self == &**other
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl PartialEq<str> for OsString {
+ fn eq(&self, other: &str) -> bool {
+ &**self == other
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl PartialEq<OsString> for str {
+ fn eq(&self, other: &OsString) -> bool {
+ &**other == self
+ }
+}
+
+#[stable(feature = "os_str_str_ref_eq", since = "1.29.0")]
+impl PartialEq<&str> for OsString {
+ fn eq(&self, other: &&str) -> bool {
+ **self == **other
+ }
+}
+
+#[stable(feature = "os_str_str_ref_eq", since = "1.29.0")]
+impl<'a> PartialEq<OsString> for &'a str {
+ fn eq(&self, other: &OsString) -> bool {
+ **other == **self
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Eq for OsString {}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl PartialOrd for OsString {
+ #[inline]
+ fn partial_cmp(&self, other: &OsString) -> Option<cmp::Ordering> {
+ (&**self).partial_cmp(&**other)
+ }
+ #[inline]
+ fn lt(&self, other: &OsString) -> bool { &**self < &**other }
+ #[inline]
+ fn le(&self, other: &OsString) -> bool { &**self <= &**other }
+ #[inline]
+ fn gt(&self, other: &OsString) -> bool { &**self > &**other }
+ #[inline]
+ fn ge(&self, other: &OsString) -> bool { &**self >= &**other }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl PartialOrd<str> for OsString {
+ #[inline]
+ fn partial_cmp(&self, other: &str) -> Option<cmp::Ordering> {
+ (&**self).partial_cmp(other)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Ord for OsString {
+ #[inline]
+ fn cmp(&self, other: &OsString) -> cmp::Ordering {
+ (&**self).cmp(&**other)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Hash for OsString {
+ #[inline]
+ fn hash<H: Hasher>(&self, state: &mut H) {
+ (&**self).hash(state)
+ }
+}
+
+impl OsStr {
+ /// Coerces into an `OsStr` slice.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ffi::OsStr;
+ ///
+ /// let os_str = OsStr::new("foo");
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn new<S: AsRef<OsStr> + ?Sized>(s: &S) -> &OsStr {
+ s.as_ref()
+ }
+
+ fn from_inner(inner: &Slice) -> &OsStr {
+ unsafe { &*(inner as *const Slice as *const OsStr) }
+ }
+
+ /// Yields a [`&str`] slice if the `OsStr` is valid Unicode.
+ ///
+ /// This conversion may entail doing a check for UTF-8 validity.
+ ///
+ /// [`&str`]: ../../std/primitive.str.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ffi::OsStr;
+ ///
+ /// let os_str = OsStr::new("foo");
+ /// assert_eq!(os_str.to_str(), Some("foo"));
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn to_str(&self) -> Option<&str> {
+ self.inner.to_str()
+ }
+
+ /// Converts an `OsStr` to a [`Cow`]`<`[`str`]`>`.
+ ///
+ /// Any non-Unicode sequences are replaced with
+ /// [`U+FFFD REPLACEMENT CHARACTER`][U+FFFD].
+ ///
+ /// [`Cow`]: ../../std/borrow/enum.Cow.html
+ /// [`str`]: ../../std/primitive.str.html
+ /// [U+FFFD]: ../../std/char/constant.REPLACEMENT_CHARACTER.html
+ ///
+ /// # Examples
+ ///
+ /// Calling `to_string_lossy` on an `OsStr` with invalid unicode:
+ ///
+ /// ```
+ /// // Note, due to differences in how Unix and Windows represent strings,
+ /// // we are forced to complicate this example, setting up example `OsStr`s
+ /// // with different source data and via different platform extensions.
+ /// // Understand that in reality you could end up with such example invalid
+ /// // sequences simply through collecting user command line arguments, for
+ /// // example.
+ ///
+ /// #[cfg(any(unix, target_os = "redox"))] {
+ /// use std::ffi::OsStr;
+ /// use std::os::unix::ffi::OsStrExt;
+ ///
+ /// // Here, the values 0x66 and 0x6f correspond to 'f' and 'o'
+ /// // respectively. The value 0x80 is a lone continuation byte, invalid
+ /// // in a UTF-8 sequence.
+ /// let source = [0x66, 0x6f, 0x80, 0x6f];
+ /// let os_str = OsStr::from_bytes(&source[..]);
+ ///
+ /// assert_eq!(os_str.to_string_lossy(), "fo�o");
+ /// }
+ /// #[cfg(windows)] {
+ /// use std::ffi::OsString;
+ /// use std::os::windows::prelude::*;
+ ///
+ /// // Here the values 0x0066 and 0x006f correspond to 'f' and 'o'
+ /// // respectively. The value 0xD800 is a lone surrogate half, invalid
+ /// // in a UTF-16 sequence.
+ /// let source = [0x0066, 0x006f, 0xD800, 0x006f];
+ /// let os_string = OsString::from_wide(&source[..]);
+ /// let os_str = os_string.as_os_str();
+ ///
+ /// assert_eq!(os_str.to_string_lossy(), "fo�o");
+ /// }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn to_string_lossy(&self) -> Cow<'_, str> {
+ self.inner.to_string_lossy()
+ }
+
+ /// Copies the slice into an owned [`OsString`].
+ ///
+ /// [`OsString`]: struct.OsString.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ffi::{OsStr, OsString};
+ ///
+ /// let os_str = OsStr::new("foo");
+ /// let os_string = os_str.to_os_string();
+ /// assert_eq!(os_string, OsString::from("foo"));
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn to_os_string(&self) -> OsString {
+ OsString { inner: self.inner.to_owned() }
+ }
+
+ /// Checks whether the `OsStr` is empty.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ffi::OsStr;
+ ///
+ /// let os_str = OsStr::new("");
+ /// assert!(os_str.is_empty());
+ ///
+ /// let os_str = OsStr::new("foo");
+ /// assert!(!os_str.is_empty());
+ /// ```
+ #[stable(feature = "osstring_simple_functions", since = "1.9.0")]
+ pub fn is_empty(&self) -> bool {
+ self.inner.inner.is_empty()
+ }
+
+ /// Returns the length of this `OsStr`.
+ ///
+ /// Note that this does **not** return the number of bytes in the string in
+ /// OS string form.
+ ///
+ /// The length returned is that of the underlying storage used by `OsStr`;
+ /// As discussed in the [`OsString`] introduction, [`OsString`] and `OsStr`
+ /// store strings in a form best suited for cheap inter-conversion between
+ /// native-platform and Rust string forms, which may differ significantly
+ /// from both of them, including in storage size and encoding.
+ ///
+ /// This number is simply useful for passing to other methods, like
+ /// [`OsString::with_capacity`] to avoid reallocations.
+ ///
+ /// [`OsString`]: struct.OsString.html
+ /// [`OsString::with_capacity`]: struct.OsString.html#method.with_capacity
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ffi::OsStr;
+ ///
+ /// let os_str = OsStr::new("");
+ /// assert_eq!(os_str.len(), 0);
+ ///
+ /// let os_str = OsStr::new("foo");
+ /// assert_eq!(os_str.len(), 3);
+ /// ```
+ #[stable(feature = "osstring_simple_functions", since = "1.9.0")]
+ pub fn len(&self) -> usize {
+ self.inner.inner.len()
+ }
+
+ /// Converts a [`Box`]`<OsStr>` into an [`OsString`] without copying or allocating.
+ ///
+ /// [`Box`]: ../boxed/struct.Box.html
+ /// [`OsString`]: struct.OsString.html
+ #[stable(feature = "into_boxed_os_str", since = "1.20.0")]
+ pub fn into_os_string(self: Box<OsStr>) -> OsString {
+ let boxed = unsafe { Box::from_raw(Box::into_raw(self) as *mut Slice) };
+ OsString { inner: Buf::from_box(boxed) }
+ }
+
+ /// Gets the underlying byte representation.
+ ///
+ /// Note: it is *crucial* that this API is private, to avoid
+ /// revealing the internal, platform-specific encodings.
+ fn bytes(&self) -> &[u8] {
+ unsafe { &*(&self.inner as *const _ as *const [u8]) }
+ }
+}
+
+#[stable(feature = "box_from_os_str", since = "1.17.0")]
+impl From<&OsStr> for Box<OsStr> {
+ fn from(s: &OsStr) -> Box<OsStr> {
+ let rw = Box::into_raw(s.inner.into_box()) as *mut OsStr;
+ unsafe { Box::from_raw(rw) }
+ }
+}
+
+#[stable(feature = "os_string_from_box", since = "1.18.0")]
+impl From<Box<OsStr>> for OsString {
+ /// Converts a `Box<OsStr>` into a `OsString` without copying or allocating.
+ ///
+ /// [`Box`]: ../boxed/struct.Box.html
+ /// [`OsString`]: ../ffi/struct.OsString.html
+ fn from(boxed: Box<OsStr>) -> OsString {
+ boxed.into_os_string()
+ }
+}
+
+#[stable(feature = "box_from_os_string", since = "1.20.0")]
+impl From<OsString> for Box<OsStr> {
+ /// Converts a [`OsString`] into a [`Box`]`<OsStr>` without copying or allocating.
+ ///
+ /// [`Box`]: ../boxed/struct.Box.html
+ /// [`OsString`]: ../ffi/struct.OsString.html
+ fn from(s: OsString) -> Box<OsStr> {
+ s.into_boxed_os_str()
+ }
+}
+
+#[stable(feature = "more_box_slice_clone", since = "1.29.0")]
+impl Clone for Box<OsStr> {
+ #[inline]
+ fn clone(&self) -> Self {
+ self.to_os_string().into_boxed_os_str()
+ }
+}
+
+#[stable(feature = "shared_from_slice2", since = "1.24.0")]
+impl From<OsString> for Arc<OsStr> {
+ /// Converts a [`OsString`] into a [`Arc`]`<OsStr>` without copying or allocating.
+ ///
+ /// [`Arc`]: ../sync/struct.Arc.html
+ /// [`OsString`]: ../ffi/struct.OsString.html
+ #[inline]
+ fn from(s: OsString) -> Arc<OsStr> {
+ let arc = s.inner.into_arc();
+ unsafe { Arc::from_raw(Arc::into_raw(arc) as *const OsStr) }
+ }
+}
+
+#[stable(feature = "shared_from_slice2", since = "1.24.0")]
+impl From<&OsStr> for Arc<OsStr> {
+ #[inline]
+ fn from(s: &OsStr) -> Arc<OsStr> {
+ let arc = s.inner.into_arc();
+ unsafe { Arc::from_raw(Arc::into_raw(arc) as *const OsStr) }
+ }
+}
+
+#[stable(feature = "shared_from_slice2", since = "1.24.0")]
+impl From<OsString> for Rc<OsStr> {
+ /// Converts a [`OsString`] into a [`Rc`]`<OsStr>` without copying or allocating.
+ ///
+ /// [`Rc`]: ../rc/struct.Rc.html
+ /// [`OsString`]: ../ffi/struct.OsString.html
+ #[inline]
+ fn from(s: OsString) -> Rc<OsStr> {
+ let rc = s.inner.into_rc();
+ unsafe { Rc::from_raw(Rc::into_raw(rc) as *const OsStr) }
+ }
+}
+
+#[stable(feature = "shared_from_slice2", since = "1.24.0")]
+impl From<&OsStr> for Rc<OsStr> {
+ #[inline]
+ fn from(s: &OsStr) -> Rc<OsStr> {
+ let rc = s.inner.into_rc();
+ unsafe { Rc::from_raw(Rc::into_raw(rc) as *const OsStr) }
+ }
+}
+
+#[stable(feature = "cow_from_osstr", since = "1.28.0")]
+impl<'a> From<OsString> for Cow<'a, OsStr> {
+ #[inline]
+ fn from(s: OsString) -> Cow<'a, OsStr> {
+ Cow::Owned(s)
+ }
+}
+
+#[stable(feature = "cow_from_osstr", since = "1.28.0")]
+impl<'a> From<&'a OsStr> for Cow<'a, OsStr> {
+ #[inline]
+ fn from(s: &'a OsStr) -> Cow<'a, OsStr> {
+ Cow::Borrowed(s)
+ }
+}
+
+#[stable(feature = "cow_from_osstr", since = "1.28.0")]
+impl<'a> From<&'a OsString> for Cow<'a, OsStr> {
+ #[inline]
+ fn from(s: &'a OsString) -> Cow<'a, OsStr> {
+ Cow::Borrowed(s.as_os_str())
+ }
+}
+
+#[stable(feature = "osstring_from_cow_osstr", since = "1.28.0")]
+impl<'a> From<Cow<'a, OsStr>> for OsString {
+ #[inline]
+ fn from(s: Cow<'a, OsStr>) -> Self {
+ s.into_owned()
+ }
+}
+
+#[stable(feature = "box_default_extra", since = "1.17.0")]
+impl Default for Box<OsStr> {
+ fn default() -> Box<OsStr> {
+ let rw = Box::into_raw(Slice::empty_box()) as *mut OsStr;
+ unsafe { Box::from_raw(rw) }
+ }
+}
+
+#[stable(feature = "osstring_default", since = "1.9.0")]
+impl Default for &OsStr {
+ /// Creates an empty `OsStr`.
+ #[inline]
+ fn default() -> Self {
+ OsStr::new("")
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl PartialEq for OsStr {
+ fn eq(&self, other: &OsStr) -> bool {
+ self.bytes().eq(other.bytes())
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl PartialEq<str> for OsStr {
+ fn eq(&self, other: &str) -> bool {
+ *self == *OsStr::new(other)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl PartialEq<OsStr> for str {
+ fn eq(&self, other: &OsStr) -> bool {
+ *other == *OsStr::new(self)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Eq for OsStr {}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl PartialOrd for OsStr {
+ #[inline]
+ fn partial_cmp(&self, other: &OsStr) -> Option<cmp::Ordering> {
+ self.bytes().partial_cmp(other.bytes())
+ }
+ #[inline]
+ fn lt(&self, other: &OsStr) -> bool { self.bytes().lt(other.bytes()) }
+ #[inline]
+ fn le(&self, other: &OsStr) -> bool { self.bytes().le(other.bytes()) }
+ #[inline]
+ fn gt(&self, other: &OsStr) -> bool { self.bytes().gt(other.bytes()) }
+ #[inline]
+ fn ge(&self, other: &OsStr) -> bool { self.bytes().ge(other.bytes()) }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl PartialOrd<str> for OsStr {
+ #[inline]
+ fn partial_cmp(&self, other: &str) -> Option<cmp::Ordering> {
+ self.partial_cmp(OsStr::new(other))
+ }
+}
+
+// FIXME (#19470): cannot provide PartialOrd<OsStr> for str until we
+// have more flexible coherence rules.
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Ord for OsStr {
+ #[inline]
+ fn cmp(&self, other: &OsStr) -> cmp::Ordering { self.bytes().cmp(other.bytes()) }
+}
+
+macro_rules! impl_cmp {
+ ($lhs:ty, $rhs: ty) => {
+ #[stable(feature = "cmp_os_str", since = "1.8.0")]
+ impl<'a, 'b> PartialEq<$rhs> for $lhs {
+ #[inline]
+ fn eq(&self, other: &$rhs) -> bool { <OsStr as PartialEq>::eq(self, other) }
+ }
+
+ #[stable(feature = "cmp_os_str", since = "1.8.0")]
+ impl<'a, 'b> PartialEq<$lhs> for $rhs {
+ #[inline]
+ fn eq(&self, other: &$lhs) -> bool { <OsStr as PartialEq>::eq(self, other) }
+ }
+
+ #[stable(feature = "cmp_os_str", since = "1.8.0")]
+ impl<'a, 'b> PartialOrd<$rhs> for $lhs {
+ #[inline]
+ fn partial_cmp(&self, other: &$rhs) -> Option<cmp::Ordering> {
+ <OsStr as PartialOrd>::partial_cmp(self, other)
+ }
+ }
+
+ #[stable(feature = "cmp_os_str", since = "1.8.0")]
+ impl<'a, 'b> PartialOrd<$lhs> for $rhs {
+ #[inline]
+ fn partial_cmp(&self, other: &$lhs) -> Option<cmp::Ordering> {
+ <OsStr as PartialOrd>::partial_cmp(self, other)
+ }
+ }
+ }
+}
+
+impl_cmp!(OsString, OsStr);
+impl_cmp!(OsString, &'a OsStr);
+impl_cmp!(Cow<'a, OsStr>, OsStr);
+impl_cmp!(Cow<'a, OsStr>, &'b OsStr);
+impl_cmp!(Cow<'a, OsStr>, OsString);
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Hash for OsStr {
+ #[inline]
+ fn hash<H: Hasher>(&self, state: &mut H) {
+ self.bytes().hash(state)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl fmt::Debug for OsStr {
+ fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt::Debug::fmt(&self.inner, formatter)
+ }
+}
+
+impl OsStr {
+ pub(crate) fn display(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt::Display::fmt(&self.inner, formatter)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Borrow<OsStr> for OsString {
+ fn borrow(&self) -> &OsStr { &self[..] }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl ToOwned for OsStr {
+ type Owned = OsString;
+ fn to_owned(&self) -> OsString {
+ self.to_os_string()
+ }
+ fn clone_into(&self, target: &mut OsString) {
+ target.clear();
+ target.push(self);
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRef<OsStr> for OsStr {
+ fn as_ref(&self) -> &OsStr {
+ self
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRef<OsStr> for OsString {
+ fn as_ref(&self) -> &OsStr {
+ self
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRef<OsStr> for str {
+ fn as_ref(&self) -> &OsStr {
+ OsStr::from_inner(Slice::from_str(self))
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRef<OsStr> for String {
+ fn as_ref(&self) -> &OsStr {
+ (&**self).as_ref()
+ }
+}
+
+impl FromInner<Buf> for OsString {
+ fn from_inner(buf: Buf) -> OsString {
+ OsString { inner: buf }
+ }
+}
+
+impl IntoInner<Buf> for OsString {
+ fn into_inner(self) -> Buf {
+ self.inner
+ }
+}
+
+impl AsInner<Slice> for OsStr {
+ #[inline]
+ fn as_inner(&self) -> &Slice {
+ &self.inner
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use crate::sys_common::{AsInner, IntoInner};
+
+ use crate::rc::Rc;
+ use crate::sync::Arc;
+
+ #[test]
+ fn test_os_string_with_capacity() {
+ let os_string = OsString::with_capacity(0);
+ assert_eq!(0, os_string.inner.into_inner().capacity());
+
+ let os_string = OsString::with_capacity(10);
+ assert_eq!(10, os_string.inner.into_inner().capacity());
+
+ let mut os_string = OsString::with_capacity(0);
+ os_string.push("abc");
+ assert!(os_string.inner.into_inner().capacity() >= 3);
+ }
+
+ #[test]
+ fn test_os_string_clear() {
+ let mut os_string = OsString::from("abc");
+ assert_eq!(3, os_string.inner.as_inner().len());
+
+ os_string.clear();
+ assert_eq!(&os_string, "");
+ assert_eq!(0, os_string.inner.as_inner().len());
+ }
+
+ #[test]
+ fn test_os_string_capacity() {
+ let os_string = OsString::with_capacity(0);
+ assert_eq!(0, os_string.capacity());
+
+ let os_string = OsString::with_capacity(10);
+ assert_eq!(10, os_string.capacity());
+
+ let mut os_string = OsString::with_capacity(0);
+ os_string.push("abc");
+ assert!(os_string.capacity() >= 3);
+ }
+
+ #[test]
+ fn test_os_string_reserve() {
+ let mut os_string = OsString::new();
+ assert_eq!(os_string.capacity(), 0);
+
+ os_string.reserve(2);
+ assert!(os_string.capacity() >= 2);
+
+ for _ in 0..16 {
+ os_string.push("a");
+ }
+
+ assert!(os_string.capacity() >= 16);
+ os_string.reserve(16);
+ assert!(os_string.capacity() >= 32);
+
+ os_string.push("a");
+
+ os_string.reserve(16);
+ assert!(os_string.capacity() >= 33)
+ }
+
+ #[test]
+ fn test_os_string_reserve_exact() {
+ let mut os_string = OsString::new();
+ assert_eq!(os_string.capacity(), 0);
+
+ os_string.reserve_exact(2);
+ assert!(os_string.capacity() >= 2);
+
+ for _ in 0..16 {
+ os_string.push("a");
+ }
+
+ assert!(os_string.capacity() >= 16);
+ os_string.reserve_exact(16);
+ assert!(os_string.capacity() >= 32);
+
+ os_string.push("a");
+
+ os_string.reserve_exact(16);
+ assert!(os_string.capacity() >= 33)
+ }
+
+ #[test]
+ fn test_os_string_default() {
+ let os_string: OsString = Default::default();
+ assert_eq!("", &os_string);
+ }
+
+ #[test]
+ fn test_os_str_is_empty() {
+ let mut os_string = OsString::new();
+ assert!(os_string.is_empty());
+
+ os_string.push("abc");
+ assert!(!os_string.is_empty());
+
+ os_string.clear();
+ assert!(os_string.is_empty());
+ }
+
+ #[test]
+ fn test_os_str_len() {
+ let mut os_string = OsString::new();
+ assert_eq!(0, os_string.len());
+
+ os_string.push("abc");
+ assert_eq!(3, os_string.len());
+
+ os_string.clear();
+ assert_eq!(0, os_string.len());
+ }
+
+ #[test]
+ fn test_os_str_default() {
+ let os_str: &OsStr = Default::default();
+ assert_eq!("", os_str);
+ }
+
+ #[test]
+ fn into_boxed() {
+ let orig = "Hello, world!";
+ let os_str = OsStr::new(orig);
+ let boxed: Box<OsStr> = Box::from(os_str);
+ let os_string = os_str.to_owned().into_boxed_os_str().into_os_string();
+ assert_eq!(os_str, &*boxed);
+ assert_eq!(&*boxed, &*os_string);
+ assert_eq!(&*os_string, os_str);
+ }
+
+ #[test]
+ fn boxed_default() {
+ let boxed = <Box<OsStr>>::default();
+ assert!(boxed.is_empty());
+ }
+
+ #[test]
+ fn test_os_str_clone_into() {
+ let mut os_string = OsString::with_capacity(123);
+ os_string.push("hello");
+ let os_str = OsStr::new("bonjour");
+ os_str.clone_into(&mut os_string);
+ assert_eq!(os_str, os_string);
+ assert!(os_string.capacity() >= 123);
+ }
+
+ #[test]
+ fn into_rc() {
+ let orig = "Hello, world!";
+ let os_str = OsStr::new(orig);
+ let rc: Rc<OsStr> = Rc::from(os_str);
+ let arc: Arc<OsStr> = Arc::from(os_str);
+
+ assert_eq!(&*rc, os_str);
+ assert_eq!(&*arc, os_str);
+
+ let rc2: Rc<OsStr> = Rc::from(os_str.to_owned());
+ let arc2: Arc<OsStr> = Arc::from(os_str.to_owned());
+
+ assert_eq!(&*rc2, os_str);
+ assert_eq!(&*arc2, os_str);
+ }
+}
diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs
new file mode 100644
index 0000000..14ff4d7
--- /dev/null
+++ b/src/libstd/fs.rs
@@ -0,0 +1,3396 @@
+//! Filesystem manipulation operations.
+//!
+//! This module contains basic methods to manipulate the contents of the local
+//! filesystem. All methods in this module represent cross-platform filesystem
+//! operations. Extra platform-specific functionality can be found in the
+//! extension traits of `std::os::$platform`.
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+use crate::fmt;
+use crate::ffi::OsString;
+use crate::io::{self, SeekFrom, Seek, Read, Initializer, Write};
+use crate::path::{Path, PathBuf};
+use crate::sys::fs as fs_imp;
+use crate::sys_common::{AsInnerMut, FromInner, AsInner, IntoInner};
+use crate::time::SystemTime;
+
+/// A reference to an open file on the filesystem.
+///
+/// An instance of a `File` can be read and/or written depending on what options
+/// it was opened with. Files also implement [`Seek`] to alter the logical cursor
+/// that the file contains internally.
+///
+/// Files are automatically closed when they go out of scope. Errors detected
+/// on closing are ignored by the implementation of `Drop`. Use the method
+/// [`sync_all`] if these errors must be manually handled.
+///
+/// # Examples
+///
+/// Creates a new file and write bytes to it:
+///
+/// ```no_run
+/// use std::fs::File;
+/// use std::io::prelude::*;
+///
+/// fn main() -> std::io::Result<()> {
+/// let mut file = File::create("foo.txt")?;
+/// file.write_all(b"Hello, world!")?;
+/// Ok(())
+/// }
+/// ```
+///
+/// Read the contents of a file into a [`String`]:
+///
+/// ```no_run
+/// use std::fs::File;
+/// use std::io::prelude::*;
+///
+/// fn main() -> std::io::Result<()> {
+/// let mut file = File::open("foo.txt")?;
+/// let mut contents = String::new();
+/// file.read_to_string(&mut contents)?;
+/// assert_eq!(contents, "Hello, world!");
+/// Ok(())
+/// }
+/// ```
+///
+/// It can be more efficient to read the contents of a file with a buffered
+/// [`Read`]er. This can be accomplished with [`BufReader<R>`]:
+///
+/// ```no_run
+/// use std::fs::File;
+/// use std::io::BufReader;
+/// use std::io::prelude::*;
+///
+/// fn main() -> std::io::Result<()> {
+/// let file = File::open("foo.txt")?;
+/// let mut buf_reader = BufReader::new(file);
+/// let mut contents = String::new();
+/// buf_reader.read_to_string(&mut contents)?;
+/// assert_eq!(contents, "Hello, world!");
+/// Ok(())
+/// }
+/// ```
+///
+/// Note that, although read and write methods require a `&mut File`, because
+/// of the interfaces for [`Read`] and [`Write`], the holder of a `&File` can
+/// still modify the file, either through methods that take `&File` or by
+/// retrieving the underlying OS object and modifying the file that way.
+/// Additionally, many operating systems allow concurrent modification of files
+/// by different processes. Avoid assuming that holding a `&File` means that the
+/// file will not change.
+///
+/// [`Seek`]: ../io/trait.Seek.html
+/// [`String`]: ../string/struct.String.html
+/// [`Read`]: ../io/trait.Read.html
+/// [`Write`]: ../io/trait.Write.html
+/// [`BufReader<R>`]: ../io/struct.BufReader.html
+/// [`sync_all`]: struct.File.html#method.sync_all
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct File {
+ inner: fs_imp::File,
+}
+
+/// Metadata information about a file.
+///
+/// This structure is returned from the [`metadata`] or
+/// [`symlink_metadata`] function or method and represents known
+/// metadata about a file such as its permissions, size, modification
+/// times, etc.
+///
+/// [`metadata`]: fn.metadata.html
+/// [`symlink_metadata`]: fn.symlink_metadata.html
+#[stable(feature = "rust1", since = "1.0.0")]
+#[derive(Clone)]
+pub struct Metadata(fs_imp::FileAttr);
+
+/// Iterator over the entries in a directory.
+///
+/// This iterator is returned from the [`read_dir`] function of this module and
+/// will yield instances of [`io::Result`]`<`[`DirEntry`]`>`. Through a [`DirEntry`]
+/// information like the entry's path and possibly other metadata can be
+/// learned.
+///
+/// # Errors
+///
+/// This [`io::Result`] will be an [`Err`] if there's some sort of intermittent
+/// IO error during iteration.
+///
+/// [`read_dir`]: fn.read_dir.html
+/// [`DirEntry`]: struct.DirEntry.html
+/// [`io::Result`]: ../io/type.Result.html
+/// [`Err`]: ../result/enum.Result.html#variant.Err
+#[stable(feature = "rust1", since = "1.0.0")]
+#[derive(Debug)]
+pub struct ReadDir(fs_imp::ReadDir);
+
+/// Entries returned by the [`ReadDir`] iterator.
+///
+/// [`ReadDir`]: struct.ReadDir.html
+///
+/// An instance of `DirEntry` represents an entry inside of a directory on the
+/// filesystem. Each entry can be inspected via methods to learn about the full
+/// path or possibly other metadata through per-platform extension traits.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct DirEntry(fs_imp::DirEntry);
+
+/// Options and flags which can be used to configure how a file is opened.
+///
+/// This builder exposes the ability to configure how a [`File`] is opened and
+/// what operations are permitted on the open file. The [`File::open`] and
+/// [`File::create`] methods are aliases for commonly used options using this
+/// builder.
+///
+/// [`File`]: struct.File.html
+/// [`File::open`]: struct.File.html#method.open
+/// [`File::create`]: struct.File.html#method.create
+///
+/// Generally speaking, when using `OpenOptions`, you'll first call [`new`],
+/// then chain calls to methods to set each option, then call [`open`],
+/// passing the path of the file you're trying to open. This will give you a
+/// [`io::Result`][result] with a [`File`][file] inside that you can further
+/// operate on.
+///
+/// [`new`]: struct.OpenOptions.html#method.new
+/// [`open`]: struct.OpenOptions.html#method.open
+/// [result]: ../io/type.Result.html
+/// [file]: struct.File.html
+///
+/// # Examples
+///
+/// Opening a file to read:
+///
+/// ```no_run
+/// use std::fs::OpenOptions;
+///
+/// let file = OpenOptions::new().read(true).open("foo.txt");
+/// ```
+///
+/// Opening a file for both reading and writing, as well as creating it if it
+/// doesn't exist:
+///
+/// ```no_run
+/// use std::fs::OpenOptions;
+///
+/// let file = OpenOptions::new()
+/// .read(true)
+/// .write(true)
+/// .create(true)
+/// .open("foo.txt");
+/// ```
+#[derive(Clone, Debug)]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct OpenOptions(fs_imp::OpenOptions);
+
+/// Representation of the various permissions on a file.
+///
+/// This module only currently provides one bit of information, [`readonly`],
+/// which is exposed on all currently supported platforms. Unix-specific
+/// functionality, such as mode bits, is available through the
+/// [`PermissionsExt`] trait.
+///
+/// [`readonly`]: struct.Permissions.html#method.readonly
+/// [`PermissionsExt`]: ../os/unix/fs/trait.PermissionsExt.html
+#[derive(Clone, PartialEq, Eq, Debug)]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct Permissions(fs_imp::FilePermissions);
+
+/// A structure representing a type of file with accessors for each file type.
+/// It is returned by [`Metadata::file_type`] method.
+///
+/// [`Metadata::file_type`]: struct.Metadata.html#method.file_type
+#[stable(feature = "file_type", since = "1.1.0")]
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
+pub struct FileType(fs_imp::FileType);
+
+/// A builder used to create directories in various manners.
+///
+/// This builder also supports platform-specific options.
+#[stable(feature = "dir_builder", since = "1.6.0")]
+#[derive(Debug)]
+pub struct DirBuilder {
+ inner: fs_imp::DirBuilder,
+ recursive: bool,
+}
+
+/// Indicates how large a buffer to pre-allocate before reading the entire file.
+fn initial_buffer_size(file: &File) -> usize {
+ // Allocate one extra byte so the buffer doesn't need to grow before the
+ // final `read` call at the end of the file. Don't worry about `usize`
+ // overflow because reading will fail regardless in that case.
+ file.metadata().map(|m| m.len() as usize + 1).unwrap_or(0)
+}
+
+/// Read the entire contents of a file into a bytes vector.
+///
+/// This is a convenience function for using [`File::open`] and [`read_to_end`]
+/// with fewer imports and without an intermediate variable. It pre-allocates a
+/// buffer based on the file size when available, so it is generally faster than
+/// reading into a vector created with `Vec::new()`.
+///
+/// [`File::open`]: struct.File.html#method.open
+/// [`read_to_end`]: ../io/trait.Read.html#method.read_to_end
+///
+/// # Errors
+///
+/// This function will return an error if `path` does not already exist.
+/// Other errors may also be returned according to [`OpenOptions::open`].
+///
+/// [`OpenOptions::open`]: struct.OpenOptions.html#method.open
+///
+/// It will also return an error if it encounters while reading an error
+/// of a kind other than [`ErrorKind::Interrupted`].
+///
+/// [`ErrorKind::Interrupted`]: ../../std/io/enum.ErrorKind.html#variant.Interrupted
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::fs;
+/// use std::net::SocketAddr;
+///
+/// fn main() -> Result<(), Box<dyn std::error::Error + 'static>> {
+/// let foo: SocketAddr = String::from_utf8_lossy(&fs::read("address.txt")?).parse()?;
+/// Ok(())
+/// }
+/// ```
+#[stable(feature = "fs_read_write_bytes", since = "1.26.0")]
+pub fn read<P: AsRef<Path>>(path: P) -> io::Result<Vec<u8>> {
+ fn inner(path: &Path) -> io::Result<Vec<u8>> {
+ let mut file = File::open(path)?;
+ let mut bytes = Vec::with_capacity(initial_buffer_size(&file));
+ file.read_to_end(&mut bytes)?;
+ Ok(bytes)
+ }
+ inner(path.as_ref())
+}
+
+/// Read the entire contents of a file into a string.
+///
+/// This is a convenience function for using [`File::open`] and [`read_to_string`]
+/// with fewer imports and without an intermediate variable. It pre-allocates a
+/// buffer based on the file size when available, so it is generally faster than
+/// reading into a string created with `String::new()`.
+///
+/// [`File::open`]: struct.File.html#method.open
+/// [`read_to_string`]: ../io/trait.Read.html#method.read_to_string
+///
+/// # Errors
+///
+/// This function will return an error if `path` does not already exist.
+/// Other errors may also be returned according to [`OpenOptions::open`].
+///
+/// [`OpenOptions::open`]: struct.OpenOptions.html#method.open
+///
+/// It will also return an error if it encounters while reading an error
+/// of a kind other than [`ErrorKind::Interrupted`],
+/// or if the contents of the file are not valid UTF-8.
+///
+/// [`ErrorKind::Interrupted`]: ../../std/io/enum.ErrorKind.html#variant.Interrupted
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::fs;
+/// use std::net::SocketAddr;
+///
+/// fn main() -> Result<(), Box<dyn std::error::Error + 'static>> {
+/// let foo: SocketAddr = fs::read_to_string("address.txt")?.parse()?;
+/// Ok(())
+/// }
+/// ```
+#[stable(feature = "fs_read_write", since = "1.26.0")]
+pub fn read_to_string<P: AsRef<Path>>(path: P) -> io::Result<String> {
+ fn inner(path: &Path) -> io::Result<String> {
+ let mut file = File::open(path)?;
+ let mut string = String::with_capacity(initial_buffer_size(&file));
+ file.read_to_string(&mut string)?;
+ Ok(string)
+ }
+ inner(path.as_ref())
+}
+
+/// Write a slice as the entire contents of a file.
+///
+/// This function will create a file if it does not exist,
+/// and will entirely replace its contents if it does.
+///
+/// This is a convenience function for using [`File::create`] and [`write_all`]
+/// with fewer imports.
+///
+/// [`File::create`]: struct.File.html#method.create
+/// [`write_all`]: ../io/trait.Write.html#method.write_all
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::fs;
+///
+/// fn main() -> std::io::Result<()> {
+/// fs::write("foo.txt", b"Lorem ipsum")?;
+/// fs::write("bar.txt", "dolor sit")?;
+/// Ok(())
+/// }
+/// ```
+#[stable(feature = "fs_read_write_bytes", since = "1.26.0")]
+pub fn write<P: AsRef<Path>, C: AsRef<[u8]>>(path: P, contents: C) -> io::Result<()> {
+ fn inner(path: &Path, contents: &[u8]) -> io::Result<()> {
+ File::create(path)?.write_all(contents)
+ }
+ inner(path.as_ref(), contents.as_ref())
+}
+
+impl File {
+ /// Attempts to open a file in read-only mode.
+ ///
+ /// See the [`OpenOptions::open`] method for more details.
+ ///
+ /// # Errors
+ ///
+ /// This function will return an error if `path` does not already exist.
+ /// Other errors may also be returned according to [`OpenOptions::open`].
+ ///
+ /// [`OpenOptions::open`]: struct.OpenOptions.html#method.open
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs::File;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let mut f = File::open("foo.txt")?;
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn open<P: AsRef<Path>>(path: P) -> io::Result<File> {
+ OpenOptions::new().read(true).open(path.as_ref())
+ }
+
+ /// Opens a file in write-only mode.
+ ///
+ /// This function will create a file if it does not exist,
+ /// and will truncate it if it does.
+ ///
+ /// See the [`OpenOptions::open`] function for more details.
+ ///
+ /// [`OpenOptions::open`]: struct.OpenOptions.html#method.open
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs::File;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let mut f = File::create("foo.txt")?;
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn create<P: AsRef<Path>>(path: P) -> io::Result<File> {
+ OpenOptions::new().write(true).create(true).truncate(true).open(path.as_ref())
+ }
+
+ /// Attempts to sync all OS-internal metadata to disk.
+ ///
+ /// This function will attempt to ensure that all in-memory data reaches the
+ /// filesystem before returning.
+ ///
+ /// This can be used to handle errors that would otherwise only be caught
+ /// when the `File` is closed. Dropping a file will ignore errors in
+ /// synchronizing this in-memory data.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs::File;
+ /// use std::io::prelude::*;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let mut f = File::create("foo.txt")?;
+ /// f.write_all(b"Hello, world!")?;
+ ///
+ /// f.sync_all()?;
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn sync_all(&self) -> io::Result<()> {
+ self.inner.fsync()
+ }
+
+ /// This function is similar to [`sync_all`], except that it may not
+ /// synchronize file metadata to the filesystem.
+ ///
+ /// This is intended for use cases that must synchronize content, but don't
+ /// need the metadata on disk. The goal of this method is to reduce disk
+ /// operations.
+ ///
+ /// Note that some platforms may simply implement this in terms of
+ /// [`sync_all`].
+ ///
+ /// [`sync_all`]: struct.File.html#method.sync_all
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs::File;
+ /// use std::io::prelude::*;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let mut f = File::create("foo.txt")?;
+ /// f.write_all(b"Hello, world!")?;
+ ///
+ /// f.sync_data()?;
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn sync_data(&self) -> io::Result<()> {
+ self.inner.datasync()
+ }
+
+ /// Truncates or extends the underlying file, updating the size of
+ /// this file to become `size`.
+ ///
+ /// If the `size` is less than the current file's size, then the file will
+ /// be shrunk. If it is greater than the current file's size, then the file
+ /// will be extended to `size` and have all of the intermediate data filled
+ /// in with 0s.
+ ///
+ /// The file's cursor isn't changed. In particular, if the cursor was at the
+ /// end and the file is shrunk using this operation, the cursor will now be
+ /// past the end.
+ ///
+ /// # Errors
+ ///
+ /// This function will return an error if the file is not opened for writing.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs::File;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let mut f = File::create("foo.txt")?;
+ /// f.set_len(10)?;
+ /// Ok(())
+ /// }
+ /// ```
+ ///
+ /// Note that this method alters the content of the underlying file, even
+ /// though it takes `&self` rather than `&mut self`.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn set_len(&self, size: u64) -> io::Result<()> {
+ self.inner.truncate(size)
+ }
+
+ /// Queries metadata about the underlying file.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs::File;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let mut f = File::open("foo.txt")?;
+ /// let metadata = f.metadata()?;
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn metadata(&self) -> io::Result<Metadata> {
+ self.inner.file_attr().map(Metadata)
+ }
+
+ /// Creates a new `File` instance that shares the same underlying file handle
+ /// as the existing `File` instance. Reads, writes, and seeks will affect
+ /// both `File` instances simultaneously.
+ ///
+ /// # Examples
+ ///
+ /// Creates two handles for a file named `foo.txt`:
+ ///
+ /// ```no_run
+ /// use std::fs::File;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let mut file = File::open("foo.txt")?;
+ /// let file_copy = file.try_clone()?;
+ /// Ok(())
+ /// }
+ /// ```
+ ///
+ /// Assuming there’s a file named `foo.txt` with contents `abcdef\n`, create
+ /// two handles, seek one of them, and read the remaining bytes from the
+ /// other handle:
+ ///
+ /// ```no_run
+ /// use std::fs::File;
+ /// use std::io::SeekFrom;
+ /// use std::io::prelude::*;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let mut file = File::open("foo.txt")?;
+ /// let mut file_copy = file.try_clone()?;
+ ///
+ /// file.seek(SeekFrom::Start(3))?;
+ ///
+ /// let mut contents = vec![];
+ /// file_copy.read_to_end(&mut contents)?;
+ /// assert_eq!(contents, b"def\n");
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "file_try_clone", since = "1.9.0")]
+ pub fn try_clone(&self) -> io::Result<File> {
+ Ok(File {
+ inner: self.inner.duplicate()?
+ })
+ }
+
+ /// Changes the permissions on the underlying file.
+ ///
+ /// # Platform-specific behavior
+ ///
+ /// This function currently corresponds to the `fchmod` function on Unix and
+ /// the `SetFileInformationByHandle` function on Windows. Note that, this
+ /// [may change in the future][changes].
+ ///
+ /// [changes]: ../io/index.html#platform-specific-behavior
+ ///
+ /// # Errors
+ ///
+ /// This function will return an error if the user lacks permission change
+ /// attributes on the underlying file. It may also return an error in other
+ /// os-specific unspecified cases.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// fn main() -> std::io::Result<()> {
+ /// use std::fs::File;
+ ///
+ /// let file = File::open("foo.txt")?;
+ /// let mut perms = file.metadata()?.permissions();
+ /// perms.set_readonly(true);
+ /// file.set_permissions(perms)?;
+ /// Ok(())
+ /// }
+ /// ```
+ ///
+ /// Note that this method alters the permissions of the underlying file,
+ /// even though it takes `&self` rather than `&mut self`.
+ #[stable(feature = "set_permissions_atomic", since = "1.16.0")]
+ pub fn set_permissions(&self, perm: Permissions) -> io::Result<()> {
+ self.inner.set_permissions(perm.0)
+ }
+}
+
+impl AsInner<fs_imp::File> for File {
+ fn as_inner(&self) -> &fs_imp::File { &self.inner }
+}
+impl FromInner<fs_imp::File> for File {
+ fn from_inner(f: fs_imp::File) -> File {
+ File { inner: f }
+ }
+}
+impl IntoInner<fs_imp::File> for File {
+ fn into_inner(self) -> fs_imp::File {
+ self.inner
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl fmt::Debug for File {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ self.inner.fmt(f)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Read for File {
+ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+ self.inner.read(buf)
+ }
+
+ #[inline]
+ unsafe fn initializer(&self) -> Initializer {
+ Initializer::nop()
+ }
+}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Write for File {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ self.inner.write(buf)
+ }
+ fn flush(&mut self) -> io::Result<()> { self.inner.flush() }
+}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Seek for File {
+ fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
+ self.inner.seek(pos)
+ }
+}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Read for &File {
+ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+ self.inner.read(buf)
+ }
+
+ #[inline]
+ unsafe fn initializer(&self) -> Initializer {
+ Initializer::nop()
+ }
+}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Write for &File {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ self.inner.write(buf)
+ }
+ fn flush(&mut self) -> io::Result<()> { self.inner.flush() }
+}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Seek for &File {
+ fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
+ self.inner.seek(pos)
+ }
+}
+
+impl OpenOptions {
+ /// Creates a blank new set of options ready for configuration.
+ ///
+ /// All options are initially set to `false`.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs::OpenOptions;
+ ///
+ /// let mut options = OpenOptions::new();
+ /// let file = options.read(true).open("foo.txt");
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn new() -> OpenOptions {
+ OpenOptions(fs_imp::OpenOptions::new())
+ }
+
+ /// Sets the option for read access.
+ ///
+ /// This option, when true, will indicate that the file should be
+ /// `read`-able if opened.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs::OpenOptions;
+ ///
+ /// let file = OpenOptions::new().read(true).open("foo.txt");
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn read(&mut self, read: bool) -> &mut OpenOptions {
+ self.0.read(read); self
+ }
+
+ /// Sets the option for write access.
+ ///
+ /// This option, when true, will indicate that the file should be
+ /// `write`-able if opened.
+ ///
+ /// If the file already exists, any write calls on it will overwrite its
+ /// contents, without truncating it.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs::OpenOptions;
+ ///
+ /// let file = OpenOptions::new().write(true).open("foo.txt");
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn write(&mut self, write: bool) -> &mut OpenOptions {
+ self.0.write(write); self
+ }
+
+ /// Sets the option for the append mode.
+ ///
+ /// This option, when true, means that writes will append to a file instead
+ /// of overwriting previous contents.
+ /// Note that setting `.write(true).append(true)` has the same effect as
+ /// setting only `.append(true)`.
+ ///
+ /// For most filesystems, the operating system guarantees that all writes are
+ /// atomic: no writes get mangled because another process writes at the same
+ /// time.
+ ///
+ /// One maybe obvious note when using append-mode: make sure that all data
+ /// that belongs together is written to the file in one operation. This
+ /// can be done by concatenating strings before passing them to [`write()`],
+ /// or using a buffered writer (with a buffer of adequate size),
+ /// and calling [`flush()`] when the message is complete.
+ ///
+ /// If a file is opened with both read and append access, beware that after
+ /// opening, and after every write, the position for reading may be set at the
+ /// end of the file. So, before writing, save the current position (using
+ /// [`seek`]`(`[`SeekFrom`]`::`[`Current`]`(0))`), and restore it before the next read.
+ ///
+ /// ## Note
+ ///
+ /// This function doesn't create the file if it doesn't exist. Use the [`create`]
+ /// method to do so.
+ ///
+ /// [`write()`]: ../../std/fs/struct.File.html#method.write
+ /// [`flush()`]: ../../std/fs/struct.File.html#method.flush
+ /// [`seek`]: ../../std/fs/struct.File.html#method.seek
+ /// [`SeekFrom`]: ../../std/io/enum.SeekFrom.html
+ /// [`Current`]: ../../std/io/enum.SeekFrom.html#variant.Current
+ /// [`create`]: #method.create
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs::OpenOptions;
+ ///
+ /// let file = OpenOptions::new().append(true).open("foo.txt");
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn append(&mut self, append: bool) -> &mut OpenOptions {
+ self.0.append(append); self
+ }
+
+ /// Sets the option for truncating a previous file.
+ ///
+ /// If a file is successfully opened with this option set it will truncate
+ /// the file to 0 length if it already exists.
+ ///
+ /// The file must be opened with write access for truncate to work.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs::OpenOptions;
+ ///
+ /// let file = OpenOptions::new().write(true).truncate(true).open("foo.txt");
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn truncate(&mut self, truncate: bool) -> &mut OpenOptions {
+ self.0.truncate(truncate); self
+ }
+
+ /// Sets the option for creating a new file.
+ ///
+ /// This option indicates whether a new file will be created if the file
+ /// does not yet already exist.
+ ///
+ /// In order for the file to be created, [`write`] or [`append`] access must
+ /// be used.
+ ///
+ /// [`write`]: #method.write
+ /// [`append`]: #method.append
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs::OpenOptions;
+ ///
+ /// let file = OpenOptions::new().write(true).create(true).open("foo.txt");
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn create(&mut self, create: bool) -> &mut OpenOptions {
+ self.0.create(create); self
+ }
+
+ /// Sets the option to always create a new file.
+ ///
+ /// This option indicates whether a new file will be created.
+ /// No file is allowed to exist at the target location, also no (dangling)
+ /// symlink.
+ ///
+ /// This option is useful because it is atomic. Otherwise between checking
+ /// whether a file exists and creating a new one, the file may have been
+ /// created by another process (a TOCTOU race condition / attack).
+ ///
+ /// If `.create_new(true)` is set, [`.create()`] and [`.truncate()`] are
+ /// ignored.
+ ///
+ /// The file must be opened with write or append access in order to create
+ /// a new file.
+ ///
+ /// [`.create()`]: #method.create
+ /// [`.truncate()`]: #method.truncate
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs::OpenOptions;
+ ///
+ /// let file = OpenOptions::new().write(true)
+ /// .create_new(true)
+ /// .open("foo.txt");
+ /// ```
+ #[stable(feature = "expand_open_options2", since = "1.9.0")]
+ pub fn create_new(&mut self, create_new: bool) -> &mut OpenOptions {
+ self.0.create_new(create_new); self
+ }
+
+ /// Opens a file at `path` with the options specified by `self`.
+ ///
+ /// # Errors
+ ///
+ /// This function will return an error under a number of different
+ /// circumstances. Some of these error conditions are listed here, together
+ /// with their [`ErrorKind`]. The mapping to [`ErrorKind`]s is not part of
+ /// the compatibility contract of the function, especially the `Other` kind
+ /// might change to more specific kinds in the future.
+ ///
+ /// * [`NotFound`]: The specified file does not exist and neither `create`
+ /// or `create_new` is set.
+ /// * [`NotFound`]: One of the directory components of the file path does
+ /// not exist.
+ /// * [`PermissionDenied`]: The user lacks permission to get the specified
+ /// access rights for the file.
+ /// * [`PermissionDenied`]: The user lacks permission to open one of the
+ /// directory components of the specified path.
+ /// * [`AlreadyExists`]: `create_new` was specified and the file already
+ /// exists.
+ /// * [`InvalidInput`]: Invalid combinations of open options (truncate
+ /// without write access, no access mode set, etc.).
+ /// * [`Other`]: One of the directory components of the specified file path
+ /// was not, in fact, a directory.
+ /// * [`Other`]: Filesystem-level errors: full disk, write permission
+ /// requested on a read-only file system, exceeded disk quota, too many
+ /// open files, too long filename, too many symbolic links in the
+ /// specified path (Unix-like systems only), etc.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs::OpenOptions;
+ ///
+ /// let file = OpenOptions::new().open("foo.txt");
+ /// ```
+ ///
+ /// [`ErrorKind`]: ../io/enum.ErrorKind.html
+ /// [`AlreadyExists`]: ../io/enum.ErrorKind.html#variant.AlreadyExists
+ /// [`InvalidInput`]: ../io/enum.ErrorKind.html#variant.InvalidInput
+ /// [`NotFound`]: ../io/enum.ErrorKind.html#variant.NotFound
+ /// [`Other`]: ../io/enum.ErrorKind.html#variant.Other
+ /// [`PermissionDenied`]: ../io/enum.ErrorKind.html#variant.PermissionDenied
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn open<P: AsRef<Path>>(&self, path: P) -> io::Result<File> {
+ self._open(path.as_ref())
+ }
+
+ fn _open(&self, path: &Path) -> io::Result<File> {
+ let inner = fs_imp::File::open(path, &self.0)?;
+ Ok(File { inner })
+ }
+}
+
+impl AsInner<fs_imp::OpenOptions> for OpenOptions {
+ fn as_inner(&self) -> &fs_imp::OpenOptions { &self.0 }
+}
+
+impl AsInnerMut<fs_imp::OpenOptions> for OpenOptions {
+ fn as_inner_mut(&mut self) -> &mut fs_imp::OpenOptions { &mut self.0 }
+}
+
+impl Metadata {
+ /// Returns the file type for this metadata.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// fn main() -> std::io::Result<()> {
+ /// use std::fs;
+ ///
+ /// let metadata = fs::metadata("foo.txt")?;
+ ///
+ /// println!("{:?}", metadata.file_type());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "file_type", since = "1.1.0")]
+ pub fn file_type(&self) -> FileType {
+ FileType(self.0.file_type())
+ }
+
+ /// Returns `true` if this metadata is for a directory. The
+ /// result is mutually exclusive to the result of
+ /// [`is_file`], and will be false for symlink metadata
+ /// obtained from [`symlink_metadata`].
+ ///
+ /// [`is_file`]: struct.Metadata.html#method.is_file
+ /// [`symlink_metadata`]: fn.symlink_metadata.html
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// fn main() -> std::io::Result<()> {
+ /// use std::fs;
+ ///
+ /// let metadata = fs::metadata("foo.txt")?;
+ ///
+ /// assert!(!metadata.is_dir());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn is_dir(&self) -> bool { self.file_type().is_dir() }
+
+ /// Returns `true` if this metadata is for a regular file. The
+ /// result is mutually exclusive to the result of
+ /// [`is_dir`], and will be false for symlink metadata
+ /// obtained from [`symlink_metadata`].
+ ///
+ /// [`is_dir`]: struct.Metadata.html#method.is_dir
+ /// [`symlink_metadata`]: fn.symlink_metadata.html
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let metadata = fs::metadata("foo.txt")?;
+ ///
+ /// assert!(metadata.is_file());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn is_file(&self) -> bool { self.file_type().is_file() }
+
+ /// Returns the size of the file, in bytes, this metadata is for.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let metadata = fs::metadata("foo.txt")?;
+ ///
+ /// assert_eq!(0, metadata.len());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn len(&self) -> u64 { self.0.size() }
+
+ /// Returns the permissions of the file this metadata is for.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let metadata = fs::metadata("foo.txt")?;
+ ///
+ /// assert!(!metadata.permissions().readonly());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn permissions(&self) -> Permissions {
+ Permissions(self.0.perm())
+ }
+
+ /// Returns the last modification time listed in this metadata.
+ ///
+ /// The returned value corresponds to the `mtime` field of `stat` on Unix
+ /// platforms and the `ftLastWriteTime` field on Windows platforms.
+ ///
+ /// # Errors
+ ///
+ /// This field may not be available on all platforms, and will return an
+ /// `Err` on platforms where it is not available.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let metadata = fs::metadata("foo.txt")?;
+ ///
+ /// if let Ok(time) = metadata.modified() {
+ /// println!("{:?}", time);
+ /// } else {
+ /// println!("Not supported on this platform");
+ /// }
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "fs_time", since = "1.10.0")]
+ pub fn modified(&self) -> io::Result<SystemTime> {
+ self.0.modified().map(FromInner::from_inner)
+ }
+
+ /// Returns the last access time of this metadata.
+ ///
+ /// The returned value corresponds to the `atime` field of `stat` on Unix
+ /// platforms and the `ftLastAccessTime` field on Windows platforms.
+ ///
+ /// Note that not all platforms will keep this field update in a file's
+ /// metadata, for example Windows has an option to disable updating this
+ /// time when files are accessed and Linux similarly has `noatime`.
+ ///
+ /// # Errors
+ ///
+ /// This field may not be available on all platforms, and will return an
+ /// `Err` on platforms where it is not available.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let metadata = fs::metadata("foo.txt")?;
+ ///
+ /// if let Ok(time) = metadata.accessed() {
+ /// println!("{:?}", time);
+ /// } else {
+ /// println!("Not supported on this platform");
+ /// }
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "fs_time", since = "1.10.0")]
+ pub fn accessed(&self) -> io::Result<SystemTime> {
+ self.0.accessed().map(FromInner::from_inner)
+ }
+
+ /// Returns the creation time listed in this metadata.
+ ///
+ /// The returned value corresponds to the `birthtime` field of `stat` on
+ /// Unix platforms and the `ftCreationTime` field on Windows platforms.
+ ///
+ /// # Errors
+ ///
+ /// This field may not be available on all platforms, and will return an
+ /// `Err` on platforms where it is not available.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let metadata = fs::metadata("foo.txt")?;
+ ///
+ /// if let Ok(time) = metadata.created() {
+ /// println!("{:?}", time);
+ /// } else {
+ /// println!("Not supported on this platform");
+ /// }
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "fs_time", since = "1.10.0")]
+ pub fn created(&self) -> io::Result<SystemTime> {
+ self.0.created().map(FromInner::from_inner)
+ }
+}
+
+#[stable(feature = "std_debug", since = "1.16.0")]
+impl fmt::Debug for Metadata {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("Metadata")
+ .field("file_type", &self.file_type())
+ .field("is_dir", &self.is_dir())
+ .field("is_file", &self.is_file())
+ .field("permissions", &self.permissions())
+ .field("modified", &self.modified())
+ .field("accessed", &self.accessed())
+ .field("created", &self.created())
+ .finish()
+ }
+}
+
+impl AsInner<fs_imp::FileAttr> for Metadata {
+ fn as_inner(&self) -> &fs_imp::FileAttr { &self.0 }
+}
+
+impl FromInner<fs_imp::FileAttr> for Metadata {
+ fn from_inner(attr: fs_imp::FileAttr) -> Metadata { Metadata(attr) }
+}
+
+impl Permissions {
+ /// Returns `true` if these permissions describe a readonly (unwritable) file.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs::File;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let mut f = File::create("foo.txt")?;
+ /// let metadata = f.metadata()?;
+ ///
+ /// assert_eq!(false, metadata.permissions().readonly());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn readonly(&self) -> bool { self.0.readonly() }
+
+ /// Modifies the readonly flag for this set of permissions. If the
+ /// `readonly` argument is `true`, using the resulting `Permission` will
+ /// update file permissions to forbid writing. Conversely, if it's `false`,
+ /// using the resulting `Permission` will update file permissions to allow
+ /// writing.
+ ///
+ /// This operation does **not** modify the filesystem. To modify the
+ /// filesystem use the [`fs::set_permissions`] function.
+ ///
+ /// [`fs::set_permissions`]: fn.set_permissions.html
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs::File;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let f = File::create("foo.txt")?;
+ /// let metadata = f.metadata()?;
+ /// let mut permissions = metadata.permissions();
+ ///
+ /// permissions.set_readonly(true);
+ ///
+ /// // filesystem doesn't change
+ /// assert_eq!(false, metadata.permissions().readonly());
+ ///
+ /// // just this particular `permissions`.
+ /// assert_eq!(true, permissions.readonly());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn set_readonly(&mut self, readonly: bool) {
+ self.0.set_readonly(readonly)
+ }
+}
+
+impl FileType {
+ /// Tests whether this file type represents a directory. The
+ /// result is mutually exclusive to the results of
+ /// [`is_file`] and [`is_symlink`]; only zero or one of these
+ /// tests may pass.
+ ///
+ /// [`is_file`]: struct.FileType.html#method.is_file
+ /// [`is_symlink`]: struct.FileType.html#method.is_symlink
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// fn main() -> std::io::Result<()> {
+ /// use std::fs;
+ ///
+ /// let metadata = fs::metadata("foo.txt")?;
+ /// let file_type = metadata.file_type();
+ ///
+ /// assert_eq!(file_type.is_dir(), false);
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "file_type", since = "1.1.0")]
+ pub fn is_dir(&self) -> bool { self.0.is_dir() }
+
+ /// Tests whether this file type represents a regular file.
+ /// The result is mutually exclusive to the results of
+ /// [`is_dir`] and [`is_symlink`]; only zero or one of these
+ /// tests may pass.
+ ///
+ /// [`is_dir`]: struct.FileType.html#method.is_dir
+ /// [`is_symlink`]: struct.FileType.html#method.is_symlink
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// fn main() -> std::io::Result<()> {
+ /// use std::fs;
+ ///
+ /// let metadata = fs::metadata("foo.txt")?;
+ /// let file_type = metadata.file_type();
+ ///
+ /// assert_eq!(file_type.is_file(), true);
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "file_type", since = "1.1.0")]
+ pub fn is_file(&self) -> bool { self.0.is_file() }
+
+ /// Tests whether this file type represents a symbolic link.
+ /// The result is mutually exclusive to the results of
+ /// [`is_dir`] and [`is_file`]; only zero or one of these
+ /// tests may pass.
+ ///
+ /// The underlying [`Metadata`] struct needs to be retrieved
+ /// with the [`fs::symlink_metadata`] function and not the
+ /// [`fs::metadata`] function. The [`fs::metadata`] function
+ /// follows symbolic links, so [`is_symlink`] would always
+ /// return `false` for the target file.
+ ///
+ /// [`Metadata`]: struct.Metadata.html
+ /// [`fs::metadata`]: fn.metadata.html
+ /// [`fs::symlink_metadata`]: fn.symlink_metadata.html
+ /// [`is_dir`]: struct.FileType.html#method.is_dir
+ /// [`is_file`]: struct.FileType.html#method.is_file
+ /// [`is_symlink`]: struct.FileType.html#method.is_symlink
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let metadata = fs::symlink_metadata("foo.txt")?;
+ /// let file_type = metadata.file_type();
+ ///
+ /// assert_eq!(file_type.is_symlink(), false);
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "file_type", since = "1.1.0")]
+ pub fn is_symlink(&self) -> bool { self.0.is_symlink() }
+}
+
+impl AsInner<fs_imp::FileType> for FileType {
+ fn as_inner(&self) -> &fs_imp::FileType { &self.0 }
+}
+
+impl FromInner<fs_imp::FilePermissions> for Permissions {
+ fn from_inner(f: fs_imp::FilePermissions) -> Permissions {
+ Permissions(f)
+ }
+}
+
+impl AsInner<fs_imp::FilePermissions> for Permissions {
+ fn as_inner(&self) -> &fs_imp::FilePermissions { &self.0 }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Iterator for ReadDir {
+ type Item = io::Result<DirEntry>;
+
+ fn next(&mut self) -> Option<io::Result<DirEntry>> {
+ self.0.next().map(|entry| entry.map(DirEntry))
+ }
+}
+
+impl DirEntry {
+ /// Returns the full path to the file that this entry represents.
+ ///
+ /// The full path is created by joining the original path to `read_dir`
+ /// with the filename of this entry.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// for entry in fs::read_dir(".")? {
+ /// let dir = entry?;
+ /// println!("{:?}", dir.path());
+ /// }
+ /// Ok(())
+ /// }
+ /// ```
+ ///
+ /// This prints output like:
+ ///
+ /// ```text
+ /// "./whatever.txt"
+ /// "./foo.html"
+ /// "./hello_world.rs"
+ /// ```
+ ///
+ /// The exact text, of course, depends on what files you have in `.`.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn path(&self) -> PathBuf { self.0.path() }
+
+ /// Returns the metadata for the file that this entry points at.
+ ///
+ /// This function will not traverse symlinks if this entry points at a
+ /// symlink.
+ ///
+ /// # Platform-specific behavior
+ ///
+ /// On Windows this function is cheap to call (no extra system calls
+ /// needed), but on Unix platforms this function is the equivalent of
+ /// calling `symlink_metadata` on the path.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::fs;
+ ///
+ /// if let Ok(entries) = fs::read_dir(".") {
+ /// for entry in entries {
+ /// if let Ok(entry) = entry {
+ /// // Here, `entry` is a `DirEntry`.
+ /// if let Ok(metadata) = entry.metadata() {
+ /// // Now let's show our entry's permissions!
+ /// println!("{:?}: {:?}", entry.path(), metadata.permissions());
+ /// } else {
+ /// println!("Couldn't get metadata for {:?}", entry.path());
+ /// }
+ /// }
+ /// }
+ /// }
+ /// ```
+ #[stable(feature = "dir_entry_ext", since = "1.1.0")]
+ pub fn metadata(&self) -> io::Result<Metadata> {
+ self.0.metadata().map(Metadata)
+ }
+
+ /// Returns the file type for the file that this entry points at.
+ ///
+ /// This function will not traverse symlinks if this entry points at a
+ /// symlink.
+ ///
+ /// # Platform-specific behavior
+ ///
+ /// On Windows and most Unix platforms this function is free (no extra
+ /// system calls needed), but some Unix platforms may require the equivalent
+ /// call to `symlink_metadata` to learn about the target file type.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::fs;
+ ///
+ /// if let Ok(entries) = fs::read_dir(".") {
+ /// for entry in entries {
+ /// if let Ok(entry) = entry {
+ /// // Here, `entry` is a `DirEntry`.
+ /// if let Ok(file_type) = entry.file_type() {
+ /// // Now let's show our entry's file type!
+ /// println!("{:?}: {:?}", entry.path(), file_type);
+ /// } else {
+ /// println!("Couldn't get file type for {:?}", entry.path());
+ /// }
+ /// }
+ /// }
+ /// }
+ /// ```
+ #[stable(feature = "dir_entry_ext", since = "1.1.0")]
+ pub fn file_type(&self) -> io::Result<FileType> {
+ self.0.file_type().map(FileType)
+ }
+
+ /// Returns the bare file name of this directory entry without any other
+ /// leading path component.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::fs;
+ ///
+ /// if let Ok(entries) = fs::read_dir(".") {
+ /// for entry in entries {
+ /// if let Ok(entry) = entry {
+ /// // Here, `entry` is a `DirEntry`.
+ /// println!("{:?}", entry.file_name());
+ /// }
+ /// }
+ /// }
+ /// ```
+ #[stable(feature = "dir_entry_ext", since = "1.1.0")]
+ pub fn file_name(&self) -> OsString {
+ self.0.file_name()
+ }
+}
+
+#[stable(feature = "dir_entry_debug", since = "1.13.0")]
+impl fmt::Debug for DirEntry {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_tuple("DirEntry")
+ .field(&self.path())
+ .finish()
+ }
+}
+
+impl AsInner<fs_imp::DirEntry> for DirEntry {
+ fn as_inner(&self) -> &fs_imp::DirEntry { &self.0 }
+}
+
+/// Removes a file from the filesystem.
+///
+/// Note that there is no
+/// guarantee that the file is immediately deleted (e.g., depending on
+/// platform, other open file descriptors may prevent immediate removal).
+///
+/// # Platform-specific behavior
+///
+/// This function currently corresponds to the `unlink` function on Unix
+/// and the `DeleteFile` function on Windows.
+/// Note that, this [may change in the future][changes].
+///
+/// [changes]: ../io/index.html#platform-specific-behavior
+///
+/// # Errors
+///
+/// This function will return an error in the following situations, but is not
+/// limited to just these cases:
+///
+/// * `path` points to a directory.
+/// * The user lacks permissions to remove the file.
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::fs;
+///
+/// fn main() -> std::io::Result<()> {
+/// fs::remove_file("a.txt")?;
+/// Ok(())
+/// }
+/// ```
+#[stable(feature = "rust1", since = "1.0.0")]
+pub fn remove_file<P: AsRef<Path>>(path: P) -> io::Result<()> {
+ fs_imp::unlink(path.as_ref())
+}
+
+/// Given a path, query the file system to get information about a file,
+/// directory, etc.
+///
+/// This function will traverse symbolic links to query information about the
+/// destination file.
+///
+/// # Platform-specific behavior
+///
+/// This function currently corresponds to the `stat` function on Unix
+/// and the `GetFileAttributesEx` function on Windows.
+/// Note that, this [may change in the future][changes].
+///
+/// [changes]: ../io/index.html#platform-specific-behavior
+///
+/// # Errors
+///
+/// This function will return an error in the following situations, but is not
+/// limited to just these cases:
+///
+/// * The user lacks permissions to perform `metadata` call on `path`.
+/// * `path` does not exist.
+///
+/// # Examples
+///
+/// ```rust,no_run
+/// use std::fs;
+///
+/// fn main() -> std::io::Result<()> {
+/// let attr = fs::metadata("/some/file/path.txt")?;
+/// // inspect attr ...
+/// Ok(())
+/// }
+/// ```
+#[stable(feature = "rust1", since = "1.0.0")]
+pub fn metadata<P: AsRef<Path>>(path: P) -> io::Result<Metadata> {
+ fs_imp::stat(path.as_ref()).map(Metadata)
+}
+
+/// Query the metadata about a file without following symlinks.
+///
+/// # Platform-specific behavior
+///
+/// This function currently corresponds to the `lstat` function on Unix
+/// and the `GetFileAttributesEx` function on Windows.
+/// Note that, this [may change in the future][changes].
+///
+/// [changes]: ../io/index.html#platform-specific-behavior
+///
+/// # Errors
+///
+/// This function will return an error in the following situations, but is not
+/// limited to just these cases:
+///
+/// * The user lacks permissions to perform `metadata` call on `path`.
+/// * `path` does not exist.
+///
+/// # Examples
+///
+/// ```rust,no_run
+/// use std::fs;
+///
+/// fn main() -> std::io::Result<()> {
+/// let attr = fs::symlink_metadata("/some/file/path.txt")?;
+/// // inspect attr ...
+/// Ok(())
+/// }
+/// ```
+#[stable(feature = "symlink_metadata", since = "1.1.0")]
+pub fn symlink_metadata<P: AsRef<Path>>(path: P) -> io::Result<Metadata> {
+ fs_imp::lstat(path.as_ref()).map(Metadata)
+}
+
+/// Rename a file or directory to a new name, replacing the original file if
+/// `to` already exists.
+///
+/// This will not work if the new name is on a different mount point.
+///
+/// # Platform-specific behavior
+///
+/// This function currently corresponds to the `rename` function on Unix
+/// and the `MoveFileEx` function with the `MOVEFILE_REPLACE_EXISTING` flag on Windows.
+///
+/// Because of this, the behavior when both `from` and `to` exist differs. On
+/// Unix, if `from` is a directory, `to` must also be an (empty) directory. If
+/// `from` is not a directory, `to` must also be not a directory. In contrast,
+/// on Windows, `from` can be anything, but `to` must *not* be a directory.
+///
+/// Note that, this [may change in the future][changes].
+///
+/// [changes]: ../io/index.html#platform-specific-behavior
+///
+/// # Errors
+///
+/// This function will return an error in the following situations, but is not
+/// limited to just these cases:
+///
+/// * `from` does not exist.
+/// * The user lacks permissions to view contents.
+/// * `from` and `to` are on separate filesystems.
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::fs;
+///
+/// fn main() -> std::io::Result<()> {
+/// fs::rename("a.txt", "b.txt")?; // Rename a.txt to b.txt
+/// Ok(())
+/// }
+/// ```
+#[stable(feature = "rust1", since = "1.0.0")]
+pub fn rename<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<()> {
+ fs_imp::rename(from.as_ref(), to.as_ref())
+}
+
+/// Copies the contents of one file to another. This function will also
+/// copy the permission bits of the original file to the destination file.
+///
+/// This function will **overwrite** the contents of `to`.
+///
+/// Note that if `from` and `to` both point to the same file, then the file
+/// will likely get truncated by this operation.
+///
+/// On success, the total number of bytes copied is returned and it is equal to
+/// the length of the `to` file as reported by `metadata`.
+///
+/// If you’re wanting to copy the contents of one file to another and you’re
+/// working with [`File`]s, see the [`io::copy`] function.
+///
+/// [`io::copy`]: ../io/fn.copy.html
+/// [`File`]: ./struct.File.html
+///
+/// # Platform-specific behavior
+///
+/// This function currently corresponds to the `open` function in Unix
+/// with `O_RDONLY` for `from` and `O_WRONLY`, `O_CREAT`, and `O_TRUNC` for `to`.
+/// `O_CLOEXEC` is set for returned file descriptors.
+/// On Windows, this function currently corresponds to `CopyFileEx`. Alternate
+/// NTFS streams are copied but only the size of the main stream is returned by
+/// this function. On MacOS, this function corresponds to `copyfile` with
+/// `COPYFILE_ALL`.
+/// Note that, this [may change in the future][changes].
+///
+/// [changes]: ../io/index.html#platform-specific-behavior
+///
+/// # Errors
+///
+/// This function will return an error in the following situations, but is not
+/// limited to just these cases:
+///
+/// * The `from` path is not a file.
+/// * The `from` file does not exist.
+/// * The current process does not have the permission rights to access
+/// `from` or write `to`.
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::fs;
+///
+/// fn main() -> std::io::Result<()> {
+/// fs::copy("foo.txt", "bar.txt")?; // Copy foo.txt to bar.txt
+/// Ok(())
+/// }
+/// ```
+#[stable(feature = "rust1", since = "1.0.0")]
+pub fn copy<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<u64> {
+ fs_imp::copy(from.as_ref(), to.as_ref())
+}
+
+/// Creates a new hard link on the filesystem.
+///
+/// The `dst` path will be a link pointing to the `src` path. Note that systems
+/// often require these two paths to both be located on the same filesystem.
+///
+/// # Platform-specific behavior
+///
+/// This function currently corresponds to the `link` function on Unix
+/// and the `CreateHardLink` function on Windows.
+/// Note that, this [may change in the future][changes].
+///
+/// [changes]: ../io/index.html#platform-specific-behavior
+///
+/// # Errors
+///
+/// This function will return an error in the following situations, but is not
+/// limited to just these cases:
+///
+/// * The `src` path is not a file or doesn't exist.
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::fs;
+///
+/// fn main() -> std::io::Result<()> {
+/// fs::hard_link("a.txt", "b.txt")?; // Hard link a.txt to b.txt
+/// Ok(())
+/// }
+/// ```
+#[stable(feature = "rust1", since = "1.0.0")]
+pub fn hard_link<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()> {
+ fs_imp::link(src.as_ref(), dst.as_ref())
+}
+
+/// Creates a new symbolic link on the filesystem.
+///
+/// The `dst` path will be a symbolic link pointing to the `src` path.
+/// On Windows, this will be a file symlink, not a directory symlink;
+/// for this reason, the platform-specific [`std::os::unix::fs::symlink`]
+/// and [`std::os::windows::fs::symlink_file`] or [`symlink_dir`] should be
+/// used instead to make the intent explicit.
+///
+/// [`std::os::unix::fs::symlink`]: ../os/unix/fs/fn.symlink.html
+/// [`std::os::windows::fs::symlink_file`]: ../os/windows/fs/fn.symlink_file.html
+/// [`symlink_dir`]: ../os/windows/fs/fn.symlink_dir.html
+///
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::fs;
+///
+/// fn main() -> std::io::Result<()> {
+/// fs::soft_link("a.txt", "b.txt")?;
+/// Ok(())
+/// }
+/// ```
+#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_deprecated(since = "1.1.0",
+ reason = "replaced with std::os::unix::fs::symlink and \
+ std::os::windows::fs::{symlink_file, symlink_dir}")]
+pub fn soft_link<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()> {
+ fs_imp::symlink(src.as_ref(), dst.as_ref())
+}
+
+/// Reads a symbolic link, returning the file that the link points to.
+///
+/// # Platform-specific behavior
+///
+/// This function currently corresponds to the `readlink` function on Unix
+/// and the `CreateFile` function with `FILE_FLAG_OPEN_REPARSE_POINT` and
+/// `FILE_FLAG_BACKUP_SEMANTICS` flags on Windows.
+/// Note that, this [may change in the future][changes].
+///
+/// [changes]: ../io/index.html#platform-specific-behavior
+///
+/// # Errors
+///
+/// This function will return an error in the following situations, but is not
+/// limited to just these cases:
+///
+/// * `path` is not a symbolic link.
+/// * `path` does not exist.
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::fs;
+///
+/// fn main() -> std::io::Result<()> {
+/// let path = fs::read_link("a.txt")?;
+/// Ok(())
+/// }
+/// ```
+#[stable(feature = "rust1", since = "1.0.0")]
+pub fn read_link<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> {
+ fs_imp::readlink(path.as_ref())
+}
+
+/// Returns the canonical, absolute form of a path with all intermediate
+/// components normalized and symbolic links resolved.
+///
+/// # Platform-specific behavior
+///
+/// This function currently corresponds to the `realpath` function on Unix
+/// and the `CreateFile` and `GetFinalPathNameByHandle` functions on Windows.
+/// Note that, this [may change in the future][changes].
+///
+/// On Windows, this converts the path to use [extended length path][path]
+/// syntax, which allows your program to use longer path names, but means you
+/// can only join backslash-delimited paths to it, and it may be incompatible
+/// with other applications (if passed to the application on the command-line,
+/// or written to a file another application may read).
+///
+/// [changes]: ../io/index.html#platform-specific-behavior
+/// [path]: https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx#maxpath
+///
+/// # Errors
+///
+/// This function will return an error in the following situations, but is not
+/// limited to just these cases:
+///
+/// * `path` does not exist.
+/// * A non-final component in path is not a directory.
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::fs;
+///
+/// fn main() -> std::io::Result<()> {
+/// let path = fs::canonicalize("../a/../foo.txt")?;
+/// Ok(())
+/// }
+/// ```
+#[stable(feature = "fs_canonicalize", since = "1.5.0")]
+pub fn canonicalize<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> {
+ fs_imp::canonicalize(path.as_ref())
+}
+
+/// Creates a new, empty directory at the provided path
+///
+/// # Platform-specific behavior
+///
+/// This function currently corresponds to the `mkdir` function on Unix
+/// and the `CreateDirectory` function on Windows.
+/// Note that, this [may change in the future][changes].
+///
+/// [changes]: ../io/index.html#platform-specific-behavior
+///
+/// **NOTE**: If a parent of the given path doesn't exist, this function will
+/// return an error. To create a directory and all its missing parents at the
+/// same time, use the [`create_dir_all`] function.
+///
+/// # Errors
+///
+/// This function will return an error in the following situations, but is not
+/// limited to just these cases:
+///
+/// * User lacks permissions to create directory at `path`.
+/// * A parent of the given path doesn't exist. (To create a directory and all
+/// its missing parents at the same time, use the [`create_dir_all`]
+/// function.)
+/// * `path` already exists.
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::fs;
+///
+/// fn main() -> std::io::Result<()> {
+/// fs::create_dir("/some/dir")?;
+/// Ok(())
+/// }
+/// ```
+#[stable(feature = "rust1", since = "1.0.0")]
+pub fn create_dir<P: AsRef<Path>>(path: P) -> io::Result<()> {
+ DirBuilder::new().create(path.as_ref())
+}
+
+/// Recursively create a directory and all of its parent components if they
+/// are missing.
+///
+/// # Platform-specific behavior
+///
+/// This function currently corresponds to the `mkdir` function on Unix
+/// and the `CreateDirectory` function on Windows.
+/// Note that, this [may change in the future][changes].
+///
+/// [changes]: ../io/index.html#platform-specific-behavior
+///
+/// # Errors
+///
+/// This function will return an error in the following situations, but is not
+/// limited to just these cases:
+///
+/// * If any directory in the path specified by `path`
+/// does not already exist and it could not be created otherwise. The specific
+/// error conditions for when a directory is being created (after it is
+/// determined to not exist) are outlined by [`fs::create_dir`].
+///
+/// Notable exception is made for situations where any of the directories
+/// specified in the `path` could not be created as it was being created concurrently.
+/// Such cases are considered to be successful. That is, calling `create_dir_all`
+/// concurrently from multiple threads or processes is guaranteed not to fail
+/// due to a race condition with itself.
+///
+/// [`fs::create_dir`]: fn.create_dir.html
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::fs;
+///
+/// fn main() -> std::io::Result<()> {
+/// fs::create_dir_all("/some/dir")?;
+/// Ok(())
+/// }
+/// ```
+#[stable(feature = "rust1", since = "1.0.0")]
+pub fn create_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()> {
+ DirBuilder::new().recursive(true).create(path.as_ref())
+}
+
+/// Removes an existing, empty directory.
+///
+/// # Platform-specific behavior
+///
+/// This function currently corresponds to the `rmdir` function on Unix
+/// and the `RemoveDirectory` function on Windows.
+/// Note that, this [may change in the future][changes].
+///
+/// [changes]: ../io/index.html#platform-specific-behavior
+///
+/// # Errors
+///
+/// This function will return an error in the following situations, but is not
+/// limited to just these cases:
+///
+/// * The user lacks permissions to remove the directory at the provided `path`.
+/// * The directory isn't empty.
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::fs;
+///
+/// fn main() -> std::io::Result<()> {
+/// fs::remove_dir("/some/dir")?;
+/// Ok(())
+/// }
+/// ```
+#[stable(feature = "rust1", since = "1.0.0")]
+pub fn remove_dir<P: AsRef<Path>>(path: P) -> io::Result<()> {
+ fs_imp::rmdir(path.as_ref())
+}
+
+/// Removes a directory at this path, after removing all its contents. Use
+/// carefully!
+///
+/// This function does **not** follow symbolic links and it will simply remove the
+/// symbolic link itself.
+///
+/// # Platform-specific behavior
+///
+/// This function currently corresponds to `opendir`, `lstat`, `rm` and `rmdir` functions on Unix
+/// and the `FindFirstFile`, `GetFileAttributesEx`, `DeleteFile`, and `RemoveDirectory` functions
+/// on Windows.
+/// Note that, this [may change in the future][changes].
+///
+/// [changes]: ../io/index.html#platform-specific-behavior
+///
+/// # Errors
+///
+/// See [`fs::remove_file`] and [`fs::remove_dir`].
+///
+/// [`fs::remove_file`]: fn.remove_file.html
+/// [`fs::remove_dir`]: fn.remove_dir.html
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::fs;
+///
+/// fn main() -> std::io::Result<()> {
+/// fs::remove_dir_all("/some/dir")?;
+/// Ok(())
+/// }
+/// ```
+#[stable(feature = "rust1", since = "1.0.0")]
+pub fn remove_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()> {
+ fs_imp::remove_dir_all(path.as_ref())
+}
+
+/// Returns an iterator over the entries within a directory.
+///
+/// The iterator will yield instances of [`io::Result`]`<`[`DirEntry`]`>`.
+/// New errors may be encountered after an iterator is initially constructed.
+///
+/// [`io::Result`]: ../io/type.Result.html
+/// [`DirEntry`]: struct.DirEntry.html
+///
+/// # Platform-specific behavior
+///
+/// This function currently corresponds to the `opendir` function on Unix
+/// and the `FindFirstFile` function on Windows.
+/// Note that, this [may change in the future][changes].
+///
+/// [changes]: ../io/index.html#platform-specific-behavior
+///
+/// # Errors
+///
+/// This function will return an error in the following situations, but is not
+/// limited to just these cases:
+///
+/// * The provided `path` doesn't exist.
+/// * The process lacks permissions to view the contents.
+/// * The `path` points at a non-directory file.
+///
+/// # Examples
+///
+/// ```
+/// use std::io;
+/// use std::fs::{self, DirEntry};
+/// use std::path::Path;
+///
+/// // one possible implementation of walking a directory only visiting files
+/// fn visit_dirs(dir: &Path, cb: &Fn(&DirEntry)) -> io::Result<()> {
+/// if dir.is_dir() {
+/// for entry in fs::read_dir(dir)? {
+/// let entry = entry?;
+/// let path = entry.path();
+/// if path.is_dir() {
+/// visit_dirs(&path, cb)?;
+/// } else {
+/// cb(&entry);
+/// }
+/// }
+/// }
+/// Ok(())
+/// }
+/// ```
+#[stable(feature = "rust1", since = "1.0.0")]
+pub fn read_dir<P: AsRef<Path>>(path: P) -> io::Result<ReadDir> {
+ fs_imp::readdir(path.as_ref()).map(ReadDir)
+}
+
+/// Changes the permissions found on a file or a directory.
+///
+/// # Platform-specific behavior
+///
+/// This function currently corresponds to the `chmod` function on Unix
+/// and the `SetFileAttributes` function on Windows.
+/// Note that, this [may change in the future][changes].
+///
+/// [changes]: ../io/index.html#platform-specific-behavior
+///
+/// # Errors
+///
+/// This function will return an error in the following situations, but is not
+/// limited to just these cases:
+///
+/// * `path` does not exist.
+/// * The user lacks the permission to change attributes of the file.
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::fs;
+///
+/// fn main() -> std::io::Result<()> {
+/// let mut perms = fs::metadata("foo.txt")?.permissions();
+/// perms.set_readonly(true);
+/// fs::set_permissions("foo.txt", perms)?;
+/// Ok(())
+/// }
+/// ```
+#[stable(feature = "set_permissions", since = "1.1.0")]
+pub fn set_permissions<P: AsRef<Path>>(path: P, perm: Permissions)
+ -> io::Result<()> {
+ fs_imp::set_perm(path.as_ref(), perm.0)
+}
+
+impl DirBuilder {
+ /// Creates a new set of options with default mode/security settings for all
+ /// platforms and also non-recursive.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::fs::DirBuilder;
+ ///
+ /// let builder = DirBuilder::new();
+ /// ```
+ #[stable(feature = "dir_builder", since = "1.6.0")]
+ pub fn new() -> DirBuilder {
+ DirBuilder {
+ inner: fs_imp::DirBuilder::new(),
+ recursive: false,
+ }
+ }
+
+ /// Indicates that directories should be created recursively, creating all
+ /// parent directories. Parents that do not exist are created with the same
+ /// security and permissions settings.
+ ///
+ /// This option defaults to `false`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::fs::DirBuilder;
+ ///
+ /// let mut builder = DirBuilder::new();
+ /// builder.recursive(true);
+ /// ```
+ #[stable(feature = "dir_builder", since = "1.6.0")]
+ pub fn recursive(&mut self, recursive: bool) -> &mut Self {
+ self.recursive = recursive;
+ self
+ }
+
+ /// Creates the specified directory with the options configured in this
+ /// builder.
+ ///
+ /// It is considered an error if the directory already exists unless
+ /// recursive mode is enabled.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs::{self, DirBuilder};
+ ///
+ /// let path = "/tmp/foo/bar/baz";
+ /// DirBuilder::new()
+ /// .recursive(true)
+ /// .create(path).unwrap();
+ ///
+ /// assert!(fs::metadata(path).unwrap().is_dir());
+ /// ```
+ #[stable(feature = "dir_builder", since = "1.6.0")]
+ pub fn create<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
+ self._create(path.as_ref())
+ }
+
+ fn _create(&self, path: &Path) -> io::Result<()> {
+ if self.recursive {
+ self.create_dir_all(path)
+ } else {
+ self.inner.mkdir(path)
+ }
+ }
+
+ fn create_dir_all(&self, path: &Path) -> io::Result<()> {
+ if path == Path::new("") {
+ return Ok(())
+ }
+
+ match self.inner.mkdir(path) {
+ Ok(()) => return Ok(()),
+ Err(ref e) if e.kind() == io::ErrorKind::NotFound => {}
+ Err(_) if path.is_dir() => return Ok(()),
+ Err(e) => return Err(e),
+ }
+ match path.parent() {
+ Some(p) => self.create_dir_all(p)?,
+ None => return Err(io::Error::new(io::ErrorKind::Other, "failed to create whole tree")),
+ }
+ match self.inner.mkdir(path) {
+ Ok(()) => Ok(()),
+ Err(_) if path.is_dir() => Ok(()),
+ Err(e) => Err(e),
+ }
+ }
+}
+
+impl AsInnerMut<fs_imp::DirBuilder> for DirBuilder {
+ fn as_inner_mut(&mut self) -> &mut fs_imp::DirBuilder {
+ &mut self.inner
+ }
+}
+
+#[cfg(all(test, not(any(target_os = "cloudabi", target_os = "emscripten", target_env = "sgx"))))]
+mod tests {
+ use crate::io::prelude::*;
+
+ use crate::fs::{self, File, OpenOptions};
+ use crate::io::{ErrorKind, SeekFrom};
+ use crate::path::Path;
+ use crate::str;
+ use crate::sys_common::io::test::{TempDir, tmpdir};
+ use crate::thread;
+
+ use rand::{rngs::StdRng, FromEntropy, RngCore};
+
+ #[cfg(windows)]
+ use crate::os::windows::fs::{symlink_dir, symlink_file};
+ #[cfg(windows)]
+ use crate::sys::fs::symlink_junction;
+ #[cfg(unix)]
+ use crate::os::unix::fs::symlink as symlink_dir;
+ #[cfg(unix)]
+ use crate::os::unix::fs::symlink as symlink_file;
+ #[cfg(unix)]
+ use crate::os::unix::fs::symlink as symlink_junction;
+
+ macro_rules! check { ($e:expr) => (
+ match $e {
+ Ok(t) => t,
+ Err(e) => panic!("{} failed with: {}", stringify!($e), e),
+ }
+ ) }
+
+ #[cfg(windows)]
+ macro_rules! error { ($e:expr, $s:expr) => (
+ match $e {
+ Ok(_) => panic!("Unexpected success. Should've been: {:?}", $s),
+ Err(ref err) => assert!(err.raw_os_error() == Some($s),
+ format!("`{}` did not have a code of `{}`", err, $s))
+ }
+ ) }
+
+ #[cfg(unix)]
+ macro_rules! error { ($e:expr, $s:expr) => ( error_contains!($e, $s) ) }
+
+ macro_rules! error_contains { ($e:expr, $s:expr) => (
+ match $e {
+ Ok(_) => panic!("Unexpected success. Should've been: {:?}", $s),
+ Err(ref err) => assert!(err.to_string().contains($s),
+ format!("`{}` did not contain `{}`", err, $s))
+ }
+ ) }
+
+ // Several test fail on windows if the user does not have permission to
+ // create symlinks (the `SeCreateSymbolicLinkPrivilege`). Instead of
+ // disabling these test on Windows, use this function to test whether we
+ // have permission, and return otherwise. This way, we still don't run these
+ // tests most of the time, but at least we do if the user has the right
+ // permissions.
+ pub fn got_symlink_permission(tmpdir: &TempDir) -> bool {
+ if cfg!(unix) { return true }
+ let link = tmpdir.join("some_hopefully_unique_link_name");
+
+ match symlink_file(r"nonexisting_target", link) {
+ Ok(_) => true,
+ // ERROR_PRIVILEGE_NOT_HELD = 1314
+ Err(ref err) if err.raw_os_error() == Some(1314) => false,
+ Err(_) => true,
+ }
+ }
+
+ #[test]
+ fn file_test_io_smoke_test() {
+ let message = "it's alright. have a good time";
+ let tmpdir = tmpdir();
+ let filename = &tmpdir.join("file_rt_io_file_test.txt");
+ {
+ let mut write_stream = check!(File::create(filename));
+ check!(write_stream.write(message.as_bytes()));
+ }
+ {
+ let mut read_stream = check!(File::open(filename));
+ let mut read_buf = [0; 1028];
+ let read_str = match check!(read_stream.read(&mut read_buf)) {
+ 0 => panic!("shouldn't happen"),
+ n => str::from_utf8(&read_buf[..n]).unwrap().to_string()
+ };
+ assert_eq!(read_str, message);
+ }
+ check!(fs::remove_file(filename));
+ }
+
+ #[test]
+ fn invalid_path_raises() {
+ let tmpdir = tmpdir();
+ let filename = &tmpdir.join("file_that_does_not_exist.txt");
+ let result = File::open(filename);
+
+ #[cfg(unix)]
+ error!(result, "No such file or directory");
+ #[cfg(windows)]
+ error!(result, 2); // ERROR_FILE_NOT_FOUND
+ }
+
+ #[test]
+ fn file_test_iounlinking_invalid_path_should_raise_condition() {
+ let tmpdir = tmpdir();
+ let filename = &tmpdir.join("file_another_file_that_does_not_exist.txt");
+
+ let result = fs::remove_file(filename);
+
+ #[cfg(unix)]
+ error!(result, "No such file or directory");
+ #[cfg(windows)]
+ error!(result, 2); // ERROR_FILE_NOT_FOUND
+ }
+
+ #[test]
+ fn file_test_io_non_positional_read() {
+ let message: &str = "ten-four";
+ let mut read_mem = [0; 8];
+ let tmpdir = tmpdir();
+ let filename = &tmpdir.join("file_rt_io_file_test_positional.txt");
+ {
+ let mut rw_stream = check!(File::create(filename));
+ check!(rw_stream.write(message.as_bytes()));
+ }
+ {
+ let mut read_stream = check!(File::open(filename));
+ {
+ let read_buf = &mut read_mem[0..4];
+ check!(read_stream.read(read_buf));
+ }
+ {
+ let read_buf = &mut read_mem[4..8];
+ check!(read_stream.read(read_buf));
+ }
+ }
+ check!(fs::remove_file(filename));
+ let read_str = str::from_utf8(&read_mem).unwrap();
+ assert_eq!(read_str, message);
+ }
+
+ #[test]
+ fn file_test_io_seek_and_tell_smoke_test() {
+ let message = "ten-four";
+ let mut read_mem = [0; 4];
+ let set_cursor = 4 as u64;
+ let tell_pos_pre_read;
+ let tell_pos_post_read;
+ let tmpdir = tmpdir();
+ let filename = &tmpdir.join("file_rt_io_file_test_seeking.txt");
+ {
+ let mut rw_stream = check!(File::create(filename));
+ check!(rw_stream.write(message.as_bytes()));
+ }
+ {
+ let mut read_stream = check!(File::open(filename));
+ check!(read_stream.seek(SeekFrom::Start(set_cursor)));
+ tell_pos_pre_read = check!(read_stream.seek(SeekFrom::Current(0)));
+ check!(read_stream.read(&mut read_mem));
+ tell_pos_post_read = check!(read_stream.seek(SeekFrom::Current(0)));
+ }
+ check!(fs::remove_file(filename));
+ let read_str = str::from_utf8(&read_mem).unwrap();
+ assert_eq!(read_str, &message[4..8]);
+ assert_eq!(tell_pos_pre_read, set_cursor);
+ assert_eq!(tell_pos_post_read, message.len() as u64);
+ }
+
+ #[test]
+ fn file_test_io_seek_and_write() {
+ let initial_msg = "food-is-yummy";
+ let overwrite_msg = "-the-bar!!";
+ let final_msg = "foo-the-bar!!";
+ let seek_idx = 3;
+ let mut read_mem = [0; 13];
+ let tmpdir = tmpdir();
+ let filename = &tmpdir.join("file_rt_io_file_test_seek_and_write.txt");
+ {
+ let mut rw_stream = check!(File::create(filename));
+ check!(rw_stream.write(initial_msg.as_bytes()));
+ check!(rw_stream.seek(SeekFrom::Start(seek_idx)));
+ check!(rw_stream.write(overwrite_msg.as_bytes()));
+ }
+ {
+ let mut read_stream = check!(File::open(filename));
+ check!(read_stream.read(&mut read_mem));
+ }
+ check!(fs::remove_file(filename));
+ let read_str = str::from_utf8(&read_mem).unwrap();
+ assert!(read_str == final_msg);
+ }
+
+ #[test]
+ fn file_test_io_seek_shakedown() {
+ // 01234567890123
+ let initial_msg = "qwer-asdf-zxcv";
+ let chunk_one: &str = "qwer";
+ let chunk_two: &str = "asdf";
+ let chunk_three: &str = "zxcv";
+ let mut read_mem = [0; 4];
+ let tmpdir = tmpdir();
+ let filename = &tmpdir.join("file_rt_io_file_test_seek_shakedown.txt");
+ {
+ let mut rw_stream = check!(File::create(filename));
+ check!(rw_stream.write(initial_msg.as_bytes()));
+ }
+ {
+ let mut read_stream = check!(File::open(filename));
+
+ check!(read_stream.seek(SeekFrom::End(-4)));
+ check!(read_stream.read(&mut read_mem));
+ assert_eq!(str::from_utf8(&read_mem).unwrap(), chunk_three);
+
+ check!(read_stream.seek(SeekFrom::Current(-9)));
+ check!(read_stream.read(&mut read_mem));
+ assert_eq!(str::from_utf8(&read_mem).unwrap(), chunk_two);
+
+ check!(read_stream.seek(SeekFrom::Start(0)));
+ check!(read_stream.read(&mut read_mem));
+ assert_eq!(str::from_utf8(&read_mem).unwrap(), chunk_one);
+ }
+ check!(fs::remove_file(filename));
+ }
+
+ #[test]
+ fn file_test_io_eof() {
+ let tmpdir = tmpdir();
+ let filename = tmpdir.join("file_rt_io_file_test_eof.txt");
+ let mut buf = [0; 256];
+ {
+ let oo = OpenOptions::new().create_new(true).write(true).read(true).clone();
+ let mut rw = check!(oo.open(&filename));
+ assert_eq!(check!(rw.read(&mut buf)), 0);
+ assert_eq!(check!(rw.read(&mut buf)), 0);
+ }
+ check!(fs::remove_file(&filename));
+ }
+
+ #[test]
+ #[cfg(unix)]
+ fn file_test_io_read_write_at() {
+ use crate::os::unix::fs::FileExt;
+
+ let tmpdir = tmpdir();
+ let filename = tmpdir.join("file_rt_io_file_test_read_write_at.txt");
+ let mut buf = [0; 256];
+ let write1 = "asdf";
+ let write2 = "qwer-";
+ let write3 = "-zxcv";
+ let content = "qwer-asdf-zxcv";
+ {
+ let oo = OpenOptions::new().create_new(true).write(true).read(true).clone();
+ let mut rw = check!(oo.open(&filename));
+ assert_eq!(check!(rw.write_at(write1.as_bytes(), 5)), write1.len());
+ assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 0);
+ assert_eq!(check!(rw.read_at(&mut buf, 5)), write1.len());
+ assert_eq!(str::from_utf8(&buf[..write1.len()]), Ok(write1));
+ assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 0);
+ assert_eq!(check!(rw.read_at(&mut buf[..write2.len()], 0)), write2.len());
+ assert_eq!(str::from_utf8(&buf[..write2.len()]), Ok("\0\0\0\0\0"));
+ assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 0);
+ assert_eq!(check!(rw.write(write2.as_bytes())), write2.len());
+ assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 5);
+ assert_eq!(check!(rw.read(&mut buf)), write1.len());
+ assert_eq!(str::from_utf8(&buf[..write1.len()]), Ok(write1));
+ assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 9);
+ assert_eq!(check!(rw.read_at(&mut buf[..write2.len()], 0)), write2.len());
+ assert_eq!(str::from_utf8(&buf[..write2.len()]), Ok(write2));
+ assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 9);
+ assert_eq!(check!(rw.write_at(write3.as_bytes(), 9)), write3.len());
+ assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 9);
+ }
+ {
+ let mut read = check!(File::open(&filename));
+ assert_eq!(check!(read.read_at(&mut buf, 0)), content.len());
+ assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content));
+ assert_eq!(check!(read.seek(SeekFrom::Current(0))), 0);
+ assert_eq!(check!(read.seek(SeekFrom::End(-5))), 9);
+ assert_eq!(check!(read.read_at(&mut buf, 0)), content.len());
+ assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content));
+ assert_eq!(check!(read.seek(SeekFrom::Current(0))), 9);
+ assert_eq!(check!(read.read(&mut buf)), write3.len());
+ assert_eq!(str::from_utf8(&buf[..write3.len()]), Ok(write3));
+ assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14);
+ assert_eq!(check!(read.read_at(&mut buf, 0)), content.len());
+ assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content));
+ assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14);
+ assert_eq!(check!(read.read_at(&mut buf, 14)), 0);
+ assert_eq!(check!(read.read_at(&mut buf, 15)), 0);
+ assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14);
+ }
+ check!(fs::remove_file(&filename));
+ }
+
+ #[test]
+ #[cfg(unix)]
+ fn set_get_unix_permissions() {
+ use crate::os::unix::fs::PermissionsExt;
+
+ let tmpdir = tmpdir();
+ let filename = &tmpdir.join("set_get_unix_permissions");
+ check!(fs::create_dir(filename));
+ let mask = 0o7777;
+
+ check!(fs::set_permissions(filename,
+ fs::Permissions::from_mode(0)));
+ let metadata0 = check!(fs::metadata(filename));
+ assert_eq!(mask & metadata0.permissions().mode(), 0);
+
+ check!(fs::set_permissions(filename,
+ fs::Permissions::from_mode(0o1777)));
+ let metadata1 = check!(fs::metadata(filename));
+ assert_eq!(mask & metadata1.permissions().mode(), 0o1777);
+ }
+
+ #[test]
+ #[cfg(windows)]
+ fn file_test_io_seek_read_write() {
+ use crate::os::windows::fs::FileExt;
+
+ let tmpdir = tmpdir();
+ let filename = tmpdir.join("file_rt_io_file_test_seek_read_write.txt");
+ let mut buf = [0; 256];
+ let write1 = "asdf";
+ let write2 = "qwer-";
+ let write3 = "-zxcv";
+ let content = "qwer-asdf-zxcv";
+ {
+ let oo = OpenOptions::new().create_new(true).write(true).read(true).clone();
+ let mut rw = check!(oo.open(&filename));
+ assert_eq!(check!(rw.seek_write(write1.as_bytes(), 5)), write1.len());
+ assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 9);
+ assert_eq!(check!(rw.seek_read(&mut buf, 5)), write1.len());
+ assert_eq!(str::from_utf8(&buf[..write1.len()]), Ok(write1));
+ assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 9);
+ assert_eq!(check!(rw.seek(SeekFrom::Start(0))), 0);
+ assert_eq!(check!(rw.write(write2.as_bytes())), write2.len());
+ assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 5);
+ assert_eq!(check!(rw.read(&mut buf)), write1.len());
+ assert_eq!(str::from_utf8(&buf[..write1.len()]), Ok(write1));
+ assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 9);
+ assert_eq!(check!(rw.seek_read(&mut buf[..write2.len()], 0)), write2.len());
+ assert_eq!(str::from_utf8(&buf[..write2.len()]), Ok(write2));
+ assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 5);
+ assert_eq!(check!(rw.seek_write(write3.as_bytes(), 9)), write3.len());
+ assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 14);
+ }
+ {
+ let mut read = check!(File::open(&filename));
+ assert_eq!(check!(read.seek_read(&mut buf, 0)), content.len());
+ assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content));
+ assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14);
+ assert_eq!(check!(read.seek(SeekFrom::End(-5))), 9);
+ assert_eq!(check!(read.seek_read(&mut buf, 0)), content.len());
+ assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content));
+ assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14);
+ assert_eq!(check!(read.seek(SeekFrom::End(-5))), 9);
+ assert_eq!(check!(read.read(&mut buf)), write3.len());
+ assert_eq!(str::from_utf8(&buf[..write3.len()]), Ok(write3));
+ assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14);
+ assert_eq!(check!(read.seek_read(&mut buf, 0)), content.len());
+ assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content));
+ assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14);
+ assert_eq!(check!(read.seek_read(&mut buf, 14)), 0);
+ assert_eq!(check!(read.seek_read(&mut buf, 15)), 0);
+ }
+ check!(fs::remove_file(&filename));
+ }
+
+ #[test]
+ fn file_test_stat_is_correct_on_is_file() {
+ let tmpdir = tmpdir();
+ let filename = &tmpdir.join("file_stat_correct_on_is_file.txt");
+ {
+ let mut opts = OpenOptions::new();
+ let mut fs = check!(opts.read(true).write(true)
+ .create(true).open(filename));
+ let msg = "hw";
+ fs.write(msg.as_bytes()).unwrap();
+
+ let fstat_res = check!(fs.metadata());
+ assert!(fstat_res.is_file());
+ }
+ let stat_res_fn = check!(fs::metadata(filename));
+ assert!(stat_res_fn.is_file());
+ let stat_res_meth = check!(filename.metadata());
+ assert!(stat_res_meth.is_file());
+ check!(fs::remove_file(filename));
+ }
+
+ #[test]
+ fn file_test_stat_is_correct_on_is_dir() {
+ let tmpdir = tmpdir();
+ let filename = &tmpdir.join("file_stat_correct_on_is_dir");
+ check!(fs::create_dir(filename));
+ let stat_res_fn = check!(fs::metadata(filename));
+ assert!(stat_res_fn.is_dir());
+ let stat_res_meth = check!(filename.metadata());
+ assert!(stat_res_meth.is_dir());
+ check!(fs::remove_dir(filename));
+ }
+
+ #[test]
+ fn file_test_fileinfo_false_when_checking_is_file_on_a_directory() {
+ let tmpdir = tmpdir();
+ let dir = &tmpdir.join("fileinfo_false_on_dir");
+ check!(fs::create_dir(dir));
+ assert!(!dir.is_file());
+ check!(fs::remove_dir(dir));
+ }
+
+ #[test]
+ fn file_test_fileinfo_check_exists_before_and_after_file_creation() {
+ let tmpdir = tmpdir();
+ let file = &tmpdir.join("fileinfo_check_exists_b_and_a.txt");
+ check!(check!(File::create(file)).write(b"foo"));
+ assert!(file.exists());
+ check!(fs::remove_file(file));
+ assert!(!file.exists());
+ }
+
+ #[test]
+ fn file_test_directoryinfo_check_exists_before_and_after_mkdir() {
+ let tmpdir = tmpdir();
+ let dir = &tmpdir.join("before_and_after_dir");
+ assert!(!dir.exists());
+ check!(fs::create_dir(dir));
+ assert!(dir.exists());
+ assert!(dir.is_dir());
+ check!(fs::remove_dir(dir));
+ assert!(!dir.exists());
+ }
+
+ #[test]
+ fn file_test_directoryinfo_readdir() {
+ let tmpdir = tmpdir();
+ let dir = &tmpdir.join("di_readdir");
+ check!(fs::create_dir(dir));
+ let prefix = "foo";
+ for n in 0..3 {
+ let f = dir.join(&format!("{}.txt", n));
+ let mut w = check!(File::create(&f));
+ let msg_str = format!("{}{}", prefix, n.to_string());
+ let msg = msg_str.as_bytes();
+ check!(w.write(msg));
+ }
+ let files = check!(fs::read_dir(dir));
+ let mut mem = [0; 4];
+ for f in files {
+ let f = f.unwrap().path();
+ {
+ let n = f.file_stem().unwrap();
+ check!(check!(File::open(&f)).read(&mut mem));
+ let read_str = str::from_utf8(&mem).unwrap();
+ let expected = format!("{}{}", prefix, n.to_str().unwrap());
+ assert_eq!(expected, read_str);
+ }
+ check!(fs::remove_file(&f));
+ }
+ check!(fs::remove_dir(dir));
+ }
+
+ #[test]
+ fn file_create_new_already_exists_error() {
+ let tmpdir = tmpdir();
+ let file = &tmpdir.join("file_create_new_error_exists");
+ check!(fs::File::create(file));
+ let e = fs::OpenOptions::new().write(true).create_new(true).open(file).unwrap_err();
+ assert_eq!(e.kind(), ErrorKind::AlreadyExists);
+ }
+
+ #[test]
+ fn mkdir_path_already_exists_error() {
+ let tmpdir = tmpdir();
+ let dir = &tmpdir.join("mkdir_error_twice");
+ check!(fs::create_dir(dir));
+ let e = fs::create_dir(dir).unwrap_err();
+ assert_eq!(e.kind(), ErrorKind::AlreadyExists);
+ }
+
+ #[test]
+ fn recursive_mkdir() {
+ let tmpdir = tmpdir();
+ let dir = tmpdir.join("d1/d2");
+ check!(fs::create_dir_all(&dir));
+ assert!(dir.is_dir())
+ }
+
+ #[test]
+ fn recursive_mkdir_failure() {
+ let tmpdir = tmpdir();
+ let dir = tmpdir.join("d1");
+ let file = dir.join("f1");
+
+ check!(fs::create_dir_all(&dir));
+ check!(File::create(&file));
+
+ let result = fs::create_dir_all(&file);
+
+ assert!(result.is_err());
+ }
+
+ #[test]
+ fn concurrent_recursive_mkdir() {
+ for _ in 0..100 {
+ let dir = tmpdir();
+ let mut dir = dir.join("a");
+ for _ in 0..40 {
+ dir = dir.join("a");
+ }
+ let mut join = vec!();
+ for _ in 0..8 {
+ let dir = dir.clone();
+ join.push(thread::spawn(move || {
+ check!(fs::create_dir_all(&dir));
+ }))
+ }
+
+ // No `Display` on result of `join()`
+ join.drain(..).map(|join| join.join().unwrap()).count();
+ }
+ }
+
+ #[test]
+ fn recursive_mkdir_slash() {
+ check!(fs::create_dir_all(Path::new("/")));
+ }
+
+ #[test]
+ fn recursive_mkdir_dot() {
+ check!(fs::create_dir_all(Path::new(".")));
+ }
+
+ #[test]
+ fn recursive_mkdir_empty() {
+ check!(fs::create_dir_all(Path::new("")));
+ }
+
+ #[test]
+ fn recursive_rmdir() {
+ let tmpdir = tmpdir();
+ let d1 = tmpdir.join("d1");
+ let dt = d1.join("t");
+ let dtt = dt.join("t");
+ let d2 = tmpdir.join("d2");
+ let canary = d2.join("do_not_delete");
+ check!(fs::create_dir_all(&dtt));
+ check!(fs::create_dir_all(&d2));
+ check!(check!(File::create(&canary)).write(b"foo"));
+ check!(symlink_junction(&d2, &dt.join("d2")));
+ let _ = symlink_file(&canary, &d1.join("canary"));
+ check!(fs::remove_dir_all(&d1));
+
+ assert!(!d1.is_dir());
+ assert!(canary.exists());
+ }
+
+ #[test]
+ fn recursive_rmdir_of_symlink() {
+ // test we do not recursively delete a symlink but only dirs.
+ let tmpdir = tmpdir();
+ let link = tmpdir.join("d1");
+ let dir = tmpdir.join("d2");
+ let canary = dir.join("do_not_delete");
+ check!(fs::create_dir_all(&dir));
+ check!(check!(File::create(&canary)).write(b"foo"));
+ check!(symlink_junction(&dir, &link));
+ check!(fs::remove_dir_all(&link));
+
+ assert!(!link.is_dir());
+ assert!(canary.exists());
+ }
+
+ #[test]
+ // only Windows makes a distinction between file and directory symlinks.
+ #[cfg(windows)]
+ fn recursive_rmdir_of_file_symlink() {
+ let tmpdir = tmpdir();
+ if !got_symlink_permission(&tmpdir) { return };
+
+ let f1 = tmpdir.join("f1");
+ let f2 = tmpdir.join("f2");
+ check!(check!(File::create(&f1)).write(b"foo"));
+ check!(symlink_file(&f1, &f2));
+ match fs::remove_dir_all(&f2) {
+ Ok(..) => panic!("wanted a failure"),
+ Err(..) => {}
+ }
+ }
+
+ #[test]
+ fn unicode_path_is_dir() {
+ assert!(Path::new(".").is_dir());
+ assert!(!Path::new("test/stdtest/fs.rs").is_dir());
+
+ let tmpdir = tmpdir();
+
+ let mut dirpath = tmpdir.path().to_path_buf();
+ dirpath.push("test-가一ー你好");
+ check!(fs::create_dir(&dirpath));
+ assert!(dirpath.is_dir());
+
+ let mut filepath = dirpath;
+ filepath.push("unicode-file-\u{ac00}\u{4e00}\u{30fc}\u{4f60}\u{597d}.rs");
+ check!(File::create(&filepath)); // ignore return; touch only
+ assert!(!filepath.is_dir());
+ assert!(filepath.exists());
+ }
+
+ #[test]
+ fn unicode_path_exists() {
+ assert!(Path::new(".").exists());
+ assert!(!Path::new("test/nonexistent-bogus-path").exists());
+
+ let tmpdir = tmpdir();
+ let unicode = tmpdir.path();
+ let unicode = unicode.join("test-각丁ー再见");
+ check!(fs::create_dir(&unicode));
+ assert!(unicode.exists());
+ assert!(!Path::new("test/unicode-bogus-path-각丁ー再见").exists());
+ }
+
+ #[test]
+ fn copy_file_does_not_exist() {
+ let from = Path::new("test/nonexistent-bogus-path");
+ let to = Path::new("test/other-bogus-path");
+
+ match fs::copy(&from, &to) {
+ Ok(..) => panic!(),
+ Err(..) => {
+ assert!(!from.exists());
+ assert!(!to.exists());
+ }
+ }
+ }
+
+ #[test]
+ fn copy_src_does_not_exist() {
+ let tmpdir = tmpdir();
+ let from = Path::new("test/nonexistent-bogus-path");
+ let to = tmpdir.join("out.txt");
+ check!(check!(File::create(&to)).write(b"hello"));
+ assert!(fs::copy(&from, &to).is_err());
+ assert!(!from.exists());
+ let mut v = Vec::new();
+ check!(check!(File::open(&to)).read_to_end(&mut v));
+ assert_eq!(v, b"hello");
+ }
+
+ #[test]
+ fn copy_file_ok() {
+ let tmpdir = tmpdir();
+ let input = tmpdir.join("in.txt");
+ let out = tmpdir.join("out.txt");
+
+ check!(check!(File::create(&input)).write(b"hello"));
+ check!(fs::copy(&input, &out));
+ let mut v = Vec::new();
+ check!(check!(File::open(&out)).read_to_end(&mut v));
+ assert_eq!(v, b"hello");
+
+ assert_eq!(check!(input.metadata()).permissions(),
+ check!(out.metadata()).permissions());
+ }
+
+ #[test]
+ fn copy_file_dst_dir() {
+ let tmpdir = tmpdir();
+ let out = tmpdir.join("out");
+
+ check!(File::create(&out));
+ match fs::copy(&*out, tmpdir.path()) {
+ Ok(..) => panic!(), Err(..) => {}
+ }
+ }
+
+ #[test]
+ fn copy_file_dst_exists() {
+ let tmpdir = tmpdir();
+ let input = tmpdir.join("in");
+ let output = tmpdir.join("out");
+
+ check!(check!(File::create(&input)).write("foo".as_bytes()));
+ check!(check!(File::create(&output)).write("bar".as_bytes()));
+ check!(fs::copy(&input, &output));
+
+ let mut v = Vec::new();
+ check!(check!(File::open(&output)).read_to_end(&mut v));
+ assert_eq!(v, b"foo".to_vec());
+ }
+
+ #[test]
+ fn copy_file_src_dir() {
+ let tmpdir = tmpdir();
+ let out = tmpdir.join("out");
+
+ match fs::copy(tmpdir.path(), &out) {
+ Ok(..) => panic!(), Err(..) => {}
+ }
+ assert!(!out.exists());
+ }
+
+ #[test]
+ fn copy_file_preserves_perm_bits() {
+ let tmpdir = tmpdir();
+ let input = tmpdir.join("in.txt");
+ let out = tmpdir.join("out.txt");
+
+ let attr = check!(check!(File::create(&input)).metadata());
+ let mut p = attr.permissions();
+ p.set_readonly(true);
+ check!(fs::set_permissions(&input, p));
+ check!(fs::copy(&input, &out));
+ assert!(check!(out.metadata()).permissions().readonly());
+ check!(fs::set_permissions(&input, attr.permissions()));
+ check!(fs::set_permissions(&out, attr.permissions()));
+ }
+
+ #[test]
+ #[cfg(windows)]
+ fn copy_file_preserves_streams() {
+ let tmp = tmpdir();
+ check!(check!(File::create(tmp.join("in.txt:bunny"))).write("carrot".as_bytes()));
+ assert_eq!(check!(fs::copy(tmp.join("in.txt"), tmp.join("out.txt"))), 0);
+ assert_eq!(check!(tmp.join("out.txt").metadata()).len(), 0);
+ let mut v = Vec::new();
+ check!(check!(File::open(tmp.join("out.txt:bunny"))).read_to_end(&mut v));
+ assert_eq!(v, b"carrot".to_vec());
+ }
+
+ #[test]
+ fn copy_file_returns_metadata_len() {
+ let tmp = tmpdir();
+ let in_path = tmp.join("in.txt");
+ let out_path = tmp.join("out.txt");
+ check!(check!(File::create(&in_path)).write(b"lettuce"));
+ #[cfg(windows)]
+ check!(check!(File::create(tmp.join("in.txt:bunny"))).write(b"carrot"));
+ let copied_len = check!(fs::copy(&in_path, &out_path));
+ assert_eq!(check!(out_path.metadata()).len(), copied_len);
+ }
+
+ #[test]
+ fn copy_file_follows_dst_symlink() {
+ let tmp = tmpdir();
+ if !got_symlink_permission(&tmp) { return };
+
+ let in_path = tmp.join("in.txt");
+ let out_path = tmp.join("out.txt");
+ let out_path_symlink = tmp.join("out_symlink.txt");
+
+ check!(fs::write(&in_path, "foo"));
+ check!(fs::write(&out_path, "bar"));
+ check!(symlink_file(&out_path, &out_path_symlink));
+
+ check!(fs::copy(&in_path, &out_path_symlink));
+
+ assert!(check!(out_path_symlink.symlink_metadata()).file_type().is_symlink());
+ assert_eq!(check!(fs::read(&out_path_symlink)), b"foo".to_vec());
+ assert_eq!(check!(fs::read(&out_path)), b"foo".to_vec());
+ }
+
+ #[test]
+ fn symlinks_work() {
+ let tmpdir = tmpdir();
+ if !got_symlink_permission(&tmpdir) { return };
+
+ let input = tmpdir.join("in.txt");
+ let out = tmpdir.join("out.txt");
+
+ check!(check!(File::create(&input)).write("foobar".as_bytes()));
+ check!(symlink_file(&input, &out));
+ assert!(check!(out.symlink_metadata()).file_type().is_symlink());
+ assert_eq!(check!(fs::metadata(&out)).len(),
+ check!(fs::metadata(&input)).len());
+ let mut v = Vec::new();
+ check!(check!(File::open(&out)).read_to_end(&mut v));
+ assert_eq!(v, b"foobar".to_vec());
+ }
+
+ #[test]
+ fn symlink_noexist() {
+ // Symlinks can point to things that don't exist
+ let tmpdir = tmpdir();
+ if !got_symlink_permission(&tmpdir) { return };
+
+ // Use a relative path for testing. Symlinks get normalized by Windows,
+ // so we may not get the same path back for absolute paths
+ check!(symlink_file(&"foo", &tmpdir.join("bar")));
+ assert_eq!(check!(fs::read_link(&tmpdir.join("bar"))).to_str().unwrap(),
+ "foo");
+ }
+
+ #[test]
+ fn read_link() {
+ if cfg!(windows) {
+ // directory symlink
+ assert_eq!(check!(fs::read_link(r"C:\Users\All Users")).to_str().unwrap(),
+ r"C:\ProgramData");
+ // junction
+ assert_eq!(check!(fs::read_link(r"C:\Users\Default User")).to_str().unwrap(),
+ r"C:\Users\Default");
+ // junction with special permissions
+ assert_eq!(check!(fs::read_link(r"C:\Documents and Settings\")).to_str().unwrap(),
+ r"C:\Users");
+ }
+ let tmpdir = tmpdir();
+ let link = tmpdir.join("link");
+ if !got_symlink_permission(&tmpdir) { return };
+ check!(symlink_file(&"foo", &link));
+ assert_eq!(check!(fs::read_link(&link)).to_str().unwrap(), "foo");
+ }
+
+ #[test]
+ fn readlink_not_symlink() {
+ let tmpdir = tmpdir();
+ match fs::read_link(tmpdir.path()) {
+ Ok(..) => panic!("wanted a failure"),
+ Err(..) => {}
+ }
+ }
+
+ #[test]
+ fn links_work() {
+ let tmpdir = tmpdir();
+ let input = tmpdir.join("in.txt");
+ let out = tmpdir.join("out.txt");
+
+ check!(check!(File::create(&input)).write("foobar".as_bytes()));
+ check!(fs::hard_link(&input, &out));
+ assert_eq!(check!(fs::metadata(&out)).len(),
+ check!(fs::metadata(&input)).len());
+ assert_eq!(check!(fs::metadata(&out)).len(),
+ check!(input.metadata()).len());
+ let mut v = Vec::new();
+ check!(check!(File::open(&out)).read_to_end(&mut v));
+ assert_eq!(v, b"foobar".to_vec());
+
+ // can't link to yourself
+ match fs::hard_link(&input, &input) {
+ Ok(..) => panic!("wanted a failure"),
+ Err(..) => {}
+ }
+ // can't link to something that doesn't exist
+ match fs::hard_link(&tmpdir.join("foo"), &tmpdir.join("bar")) {
+ Ok(..) => panic!("wanted a failure"),
+ Err(..) => {}
+ }
+ }
+
+ #[test]
+ fn chmod_works() {
+ let tmpdir = tmpdir();
+ let file = tmpdir.join("in.txt");
+
+ check!(File::create(&file));
+ let attr = check!(fs::metadata(&file));
+ assert!(!attr.permissions().readonly());
+ let mut p = attr.permissions();
+ p.set_readonly(true);
+ check!(fs::set_permissions(&file, p.clone()));
+ let attr = check!(fs::metadata(&file));
+ assert!(attr.permissions().readonly());
+
+ match fs::set_permissions(&tmpdir.join("foo"), p.clone()) {
+ Ok(..) => panic!("wanted an error"),
+ Err(..) => {}
+ }
+
+ p.set_readonly(false);
+ check!(fs::set_permissions(&file, p));
+ }
+
+ #[test]
+ fn fchmod_works() {
+ let tmpdir = tmpdir();
+ let path = tmpdir.join("in.txt");
+
+ let file = check!(File::create(&path));
+ let attr = check!(fs::metadata(&path));
+ assert!(!attr.permissions().readonly());
+ let mut p = attr.permissions();
+ p.set_readonly(true);
+ check!(file.set_permissions(p.clone()));
+ let attr = check!(fs::metadata(&path));
+ assert!(attr.permissions().readonly());
+
+ p.set_readonly(false);
+ check!(file.set_permissions(p));
+ }
+
+ #[test]
+ fn sync_doesnt_kill_anything() {
+ let tmpdir = tmpdir();
+ let path = tmpdir.join("in.txt");
+
+ let mut file = check!(File::create(&path));
+ check!(file.sync_all());
+ check!(file.sync_data());
+ check!(file.write(b"foo"));
+ check!(file.sync_all());
+ check!(file.sync_data());
+ }
+
+ #[test]
+ fn truncate_works() {
+ let tmpdir = tmpdir();
+ let path = tmpdir.join("in.txt");
+
+ let mut file = check!(File::create(&path));
+ check!(file.write(b"foo"));
+ check!(file.sync_all());
+
+ // Do some simple things with truncation
+ assert_eq!(check!(file.metadata()).len(), 3);
+ check!(file.set_len(10));
+ assert_eq!(check!(file.metadata()).len(), 10);
+ check!(file.write(b"bar"));
+ check!(file.sync_all());
+ assert_eq!(check!(file.metadata()).len(), 10);
+
+ let mut v = Vec::new();
+ check!(check!(File::open(&path)).read_to_end(&mut v));
+ assert_eq!(v, b"foobar\0\0\0\0".to_vec());
+
+ // Truncate to a smaller length, don't seek, and then write something.
+ // Ensure that the intermediate zeroes are all filled in (we have `seek`ed
+ // past the end of the file).
+ check!(file.set_len(2));
+ assert_eq!(check!(file.metadata()).len(), 2);
+ check!(file.write(b"wut"));
+ check!(file.sync_all());
+ assert_eq!(check!(file.metadata()).len(), 9);
+ let mut v = Vec::new();
+ check!(check!(File::open(&path)).read_to_end(&mut v));
+ assert_eq!(v, b"fo\0\0\0\0wut".to_vec());
+ }
+
+ #[test]
+ fn open_flavors() {
+ use crate::fs::OpenOptions as OO;
+ fn c<T: Clone>(t: &T) -> T { t.clone() }
+
+ let tmpdir = tmpdir();
+
+ let mut r = OO::new(); r.read(true);
+ let mut w = OO::new(); w.write(true);
+ let mut rw = OO::new(); rw.read(true).write(true);
+ let mut a = OO::new(); a.append(true);
+ let mut ra = OO::new(); ra.read(true).append(true);
+
+ #[cfg(windows)]
+ let invalid_options = 87; // ERROR_INVALID_PARAMETER
+ #[cfg(unix)]
+ let invalid_options = "Invalid argument";
+
+ // Test various combinations of creation modes and access modes.
+ //
+ // Allowed:
+ // creation mode | read | write | read-write | append | read-append |
+ // :-----------------------|:-----:|:-----:|:----------:|:------:|:-----------:|
+ // not set (open existing) | X | X | X | X | X |
+ // create | | X | X | X | X |
+ // truncate | | X | X | | |
+ // create and truncate | | X | X | | |
+ // create_new | | X | X | X | X |
+ //
+ // tested in reverse order, so 'create_new' creates the file, and 'open existing' opens it.
+
+ // write-only
+ check!(c(&w).create_new(true).open(&tmpdir.join("a")));
+ check!(c(&w).create(true).truncate(true).open(&tmpdir.join("a")));
+ check!(c(&w).truncate(true).open(&tmpdir.join("a")));
+ check!(c(&w).create(true).open(&tmpdir.join("a")));
+ check!(c(&w).open(&tmpdir.join("a")));
+
+ // read-only
+ error!(c(&r).create_new(true).open(&tmpdir.join("b")), invalid_options);
+ error!(c(&r).create(true).truncate(true).open(&tmpdir.join("b")), invalid_options);
+ error!(c(&r).truncate(true).open(&tmpdir.join("b")), invalid_options);
+ error!(c(&r).create(true).open(&tmpdir.join("b")), invalid_options);
+ check!(c(&r).open(&tmpdir.join("a"))); // try opening the file created with write_only
+
+ // read-write
+ check!(c(&rw).create_new(true).open(&tmpdir.join("c")));
+ check!(c(&rw).create(true).truncate(true).open(&tmpdir.join("c")));
+ check!(c(&rw).truncate(true).open(&tmpdir.join("c")));
+ check!(c(&rw).create(true).open(&tmpdir.join("c")));
+ check!(c(&rw).open(&tmpdir.join("c")));
+
+ // append
+ check!(c(&a).create_new(true).open(&tmpdir.join("d")));
+ error!(c(&a).create(true).truncate(true).open(&tmpdir.join("d")), invalid_options);
+ error!(c(&a).truncate(true).open(&tmpdir.join("d")), invalid_options);
+ check!(c(&a).create(true).open(&tmpdir.join("d")));
+ check!(c(&a).open(&tmpdir.join("d")));
+
+ // read-append
+ check!(c(&ra).create_new(true).open(&tmpdir.join("e")));
+ error!(c(&ra).create(true).truncate(true).open(&tmpdir.join("e")), invalid_options);
+ error!(c(&ra).truncate(true).open(&tmpdir.join("e")), invalid_options);
+ check!(c(&ra).create(true).open(&tmpdir.join("e")));
+ check!(c(&ra).open(&tmpdir.join("e")));
+
+ // Test opening a file without setting an access mode
+ let mut blank = OO::new();
+ error!(blank.create(true).open(&tmpdir.join("f")), invalid_options);
+
+ // Test write works
+ check!(check!(File::create(&tmpdir.join("h"))).write("foobar".as_bytes()));
+
+ // Test write fails for read-only
+ check!(r.open(&tmpdir.join("h")));
+ {
+ let mut f = check!(r.open(&tmpdir.join("h")));
+ assert!(f.write("wut".as_bytes()).is_err());
+ }
+
+ // Test write overwrites
+ {
+ let mut f = check!(c(&w).open(&tmpdir.join("h")));
+ check!(f.write("baz".as_bytes()));
+ }
+ {
+ let mut f = check!(c(&r).open(&tmpdir.join("h")));
+ let mut b = vec![0; 6];
+ check!(f.read(&mut b));
+ assert_eq!(b, "bazbar".as_bytes());
+ }
+
+ // Test truncate works
+ {
+ let mut f = check!(c(&w).truncate(true).open(&tmpdir.join("h")));
+ check!(f.write("foo".as_bytes()));
+ }
+ assert_eq!(check!(fs::metadata(&tmpdir.join("h"))).len(), 3);
+
+ // Test append works
+ assert_eq!(check!(fs::metadata(&tmpdir.join("h"))).len(), 3);
+ {
+ let mut f = check!(c(&a).open(&tmpdir.join("h")));
+ check!(f.write("bar".as_bytes()));
+ }
+ assert_eq!(check!(fs::metadata(&tmpdir.join("h"))).len(), 6);
+
+ // Test .append(true) equals .write(true).append(true)
+ {
+ let mut f = check!(c(&w).append(true).open(&tmpdir.join("h")));
+ check!(f.write("baz".as_bytes()));
+ }
+ assert_eq!(check!(fs::metadata(&tmpdir.join("h"))).len(), 9);
+ }
+
+ #[test]
+ fn _assert_send_sync() {
+ fn _assert_send_sync<T: Send + Sync>() {}
+ _assert_send_sync::<OpenOptions>();
+ }
+
+ #[test]
+ fn binary_file() {
+ let mut bytes = [0; 1024];
+ StdRng::from_entropy().fill_bytes(&mut bytes);
+
+ let tmpdir = tmpdir();
+
+ check!(check!(File::create(&tmpdir.join("test"))).write(&bytes));
+ let mut v = Vec::new();
+ check!(check!(File::open(&tmpdir.join("test"))).read_to_end(&mut v));
+ assert!(v == &bytes[..]);
+ }
+
+ #[test]
+ fn write_then_read() {
+ let mut bytes = [0; 1024];
+ StdRng::from_entropy().fill_bytes(&mut bytes);
+
+ let tmpdir = tmpdir();
+
+ check!(fs::write(&tmpdir.join("test"), &bytes[..]));
+ let v = check!(fs::read(&tmpdir.join("test")));
+ assert!(v == &bytes[..]);
+
+ check!(fs::write(&tmpdir.join("not-utf8"), &[0xFF]));
+ error_contains!(fs::read_to_string(&tmpdir.join("not-utf8")),
+ "stream did not contain valid UTF-8");
+
+ let s = "𐁁𐀓𐀠𐀴𐀍";
+ check!(fs::write(&tmpdir.join("utf8"), s.as_bytes()));
+ let string = check!(fs::read_to_string(&tmpdir.join("utf8")));
+ assert_eq!(string, s);
+ }
+
+ #[test]
+ fn file_try_clone() {
+ let tmpdir = tmpdir();
+
+ let mut f1 = check!(OpenOptions::new()
+ .read(true)
+ .write(true)
+ .create(true)
+ .open(&tmpdir.join("test")));
+ let mut f2 = check!(f1.try_clone());
+
+ check!(f1.write_all(b"hello world"));
+ check!(f1.seek(SeekFrom::Start(2)));
+
+ let mut buf = vec![];
+ check!(f2.read_to_end(&mut buf));
+ assert_eq!(buf, b"llo world");
+ drop(f2);
+
+ check!(f1.write_all(b"!"));
+ }
+
+ #[test]
+ #[cfg(not(windows))]
+ fn unlink_readonly() {
+ let tmpdir = tmpdir();
+ let path = tmpdir.join("file");
+ check!(File::create(&path));
+ let mut perm = check!(fs::metadata(&path)).permissions();
+ perm.set_readonly(true);
+ check!(fs::set_permissions(&path, perm));
+ check!(fs::remove_file(&path));
+ }
+
+ #[test]
+ fn mkdir_trailing_slash() {
+ let tmpdir = tmpdir();
+ let path = tmpdir.join("file");
+ check!(fs::create_dir_all(&path.join("a/")));
+ }
+
+ #[test]
+ fn canonicalize_works_simple() {
+ let tmpdir = tmpdir();
+ let tmpdir = fs::canonicalize(tmpdir.path()).unwrap();
+ let file = tmpdir.join("test");
+ File::create(&file).unwrap();
+ assert_eq!(fs::canonicalize(&file).unwrap(), file);
+ }
+
+ #[test]
+ fn realpath_works() {
+ let tmpdir = tmpdir();
+ if !got_symlink_permission(&tmpdir) { return };
+
+ let tmpdir = fs::canonicalize(tmpdir.path()).unwrap();
+ let file = tmpdir.join("test");
+ let dir = tmpdir.join("test2");
+ let link = dir.join("link");
+ let linkdir = tmpdir.join("test3");
+
+ File::create(&file).unwrap();
+ fs::create_dir(&dir).unwrap();
+ symlink_file(&file, &link).unwrap();
+ symlink_dir(&dir, &linkdir).unwrap();
+
+ assert!(link.symlink_metadata().unwrap().file_type().is_symlink());
+
+ assert_eq!(fs::canonicalize(&tmpdir).unwrap(), tmpdir);
+ assert_eq!(fs::canonicalize(&file).unwrap(), file);
+ assert_eq!(fs::canonicalize(&link).unwrap(), file);
+ assert_eq!(fs::canonicalize(&linkdir).unwrap(), dir);
+ assert_eq!(fs::canonicalize(&linkdir.join("link")).unwrap(), file);
+ }
+
+ #[test]
+ fn realpath_works_tricky() {
+ let tmpdir = tmpdir();
+ if !got_symlink_permission(&tmpdir) { return };
+
+ let tmpdir = fs::canonicalize(tmpdir.path()).unwrap();
+ let a = tmpdir.join("a");
+ let b = a.join("b");
+ let c = b.join("c");
+ let d = a.join("d");
+ let e = d.join("e");
+ let f = a.join("f");
+
+ fs::create_dir_all(&b).unwrap();
+ fs::create_dir_all(&d).unwrap();
+ File::create(&f).unwrap();
+ if cfg!(not(windows)) {
+ symlink_dir("../d/e", &c).unwrap();
+ symlink_file("../f", &e).unwrap();
+ }
+ if cfg!(windows) {
+ symlink_dir(r"..\d\e", &c).unwrap();
+ symlink_file(r"..\f", &e).unwrap();
+ }
+
+ assert_eq!(fs::canonicalize(&c).unwrap(), f);
+ assert_eq!(fs::canonicalize(&e).unwrap(), f);
+ }
+
+ #[test]
+ fn dir_entry_methods() {
+ let tmpdir = tmpdir();
+
+ fs::create_dir_all(&tmpdir.join("a")).unwrap();
+ File::create(&tmpdir.join("b")).unwrap();
+
+ for file in tmpdir.path().read_dir().unwrap().map(|f| f.unwrap()) {
+ let fname = file.file_name();
+ match fname.to_str() {
+ Some("a") => {
+ assert!(file.file_type().unwrap().is_dir());
+ assert!(file.metadata().unwrap().is_dir());
+ }
+ Some("b") => {
+ assert!(file.file_type().unwrap().is_file());
+ assert!(file.metadata().unwrap().is_file());
+ }
+ f => panic!("unknown file name: {:?}", f),
+ }
+ }
+ }
+
+ #[test]
+ fn dir_entry_debug() {
+ let tmpdir = tmpdir();
+ File::create(&tmpdir.join("b")).unwrap();
+ let mut read_dir = tmpdir.path().read_dir().unwrap();
+ let dir_entry = read_dir.next().unwrap().unwrap();
+ let actual = format!("{:?}", dir_entry);
+ let expected = format!("DirEntry({:?})", dir_entry.0.path());
+ assert_eq!(actual, expected);
+ }
+
+ #[test]
+ fn read_dir_not_found() {
+ let res = fs::read_dir("/path/that/does/not/exist");
+ assert_eq!(res.err().unwrap().kind(), ErrorKind::NotFound);
+ }
+
+ #[test]
+ fn create_dir_all_with_junctions() {
+ let tmpdir = tmpdir();
+ let target = tmpdir.join("target");
+
+ let junction = tmpdir.join("junction");
+ let b = junction.join("a/b");
+
+ let link = tmpdir.join("link");
+ let d = link.join("c/d");
+
+ fs::create_dir(&target).unwrap();
+
+ check!(symlink_junction(&target, &junction));
+ check!(fs::create_dir_all(&b));
+ // the junction itself is not a directory, but `is_dir()` on a Path
+ // follows links
+ assert!(junction.is_dir());
+ assert!(b.exists());
+
+ if !got_symlink_permission(&tmpdir) { return };
+ check!(symlink_dir(&target, &link));
+ check!(fs::create_dir_all(&d));
+ assert!(link.is_dir());
+ assert!(d.exists());
+ }
+
+ #[test]
+ fn metadata_access_times() {
+ let tmpdir = tmpdir();
+
+ let b = tmpdir.join("b");
+ File::create(&b).unwrap();
+
+ let a = check!(fs::metadata(&tmpdir.path()));
+ let b = check!(fs::metadata(&b));
+
+ assert_eq!(check!(a.accessed()), check!(a.accessed()));
+ assert_eq!(check!(a.modified()), check!(a.modified()));
+ assert_eq!(check!(b.accessed()), check!(b.modified()));
+
+ if cfg!(target_os = "macos") || cfg!(target_os = "windows") {
+ check!(a.created());
+ check!(b.created());
+ }
+ }
+}
diff --git a/src/libstd/future.rs b/src/libstd/future.rs
new file mode 100644
index 0000000..898387c
--- /dev/null
+++ b/src/libstd/future.rs
@@ -0,0 +1,114 @@
+//! Asynchronous values.
+
+use core::cell::Cell;
+use core::marker::Unpin;
+use core::pin::Pin;
+use core::option::Option;
+use core::ptr::NonNull;
+use core::task::{Context, Poll};
+use core::ops::{Drop, Generator, GeneratorState};
+
+#[doc(inline)]
+pub use core::future::*;
+
+/// Wrap a generator in a future.
+///
+/// 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: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
+ // Safe because we're !Unpin + !Drop mapping to a ?Unpin value
+ let gen = unsafe { Pin::map_unchecked_mut(self, |s| &mut s.0) };
+ set_task_context(cx, || match gen.resume() {
+ GeneratorState::Yielded(()) => Poll::Pending,
+ GeneratorState::Complete(x) => Poll::Ready(x),
+ })
+ }
+}
+
+thread_local! {
+ static TLS_CX: Cell<Option<NonNull<Context<'static>>>> = Cell::new(None);
+}
+
+struct SetOnDrop(Option<NonNull<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_context<F, R>(cx: &mut Context<'_>, f: F) -> R
+where
+ F: FnOnce() -> R
+{
+ // transmute the context's lifetime to 'static so we can store it.
+ let cx = unsafe {
+ core::mem::transmute::<&mut Context<'_>, &mut Context<'static>>(cx)
+ };
+ let old_cx = TLS_CX.with(|tls_cx| {
+ tls_cx.replace(Some(NonNull::from(cx)))
+ });
+ let _reset = 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 context has been set or if the context has already been
+/// retrieved by a surrounding call to get_task_context.
+pub fn get_task_context<F, R>(f: F) -> R
+where
+ F: FnOnce(&mut Context<'_>) -> R
+{
+ let cx_ptr = TLS_CX.with(|tls_cx| {
+ // Clear the entry so that nested `get_task_waker` calls
+ // will fail or set their own value.
+ tls_cx.replace(None)
+ });
+ let _reset = SetOnDrop(cx_ptr);
+
+ let mut cx_ptr = cx_ptr.expect(
+ "TLS Context not set. This is a rustc bug. \
+ Please file an issue on https://github.com/rust-lang/rust.");
+
+ // Safety: we've ensured exclusive access to the context by
+ // removing the pointer from TLS, only to be replaced once
+ // we're done with it.
+ //
+ // The pointer that was inserted came from an `&mut Context<'_>`,
+ // so it is safe to treat as mutable.
+ unsafe { f(cx_ptr.as_mut()) }
+}
+
+#[unstable(feature = "gen_future", issue = "50547")]
+/// Polls a future in the current thread-local task waker.
+pub fn poll_with_tls_context<F>(f: Pin<&mut F>) -> Poll<F::Output>
+where
+ F: Future
+{
+ get_task_context(|cx| F::poll(f, cx))
+}
diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs
new file mode 100644
index 0000000..3370a44
--- /dev/null
+++ b/src/libstd/io/buffered.rs
@@ -0,0 +1,1434 @@
+//! Buffering wrappers for I/O traits
+
+use crate::io::prelude::*;
+
+use crate::cmp;
+use crate::error;
+use crate::fmt;
+use crate::io::{self, Initializer, DEFAULT_BUF_SIZE, Error, ErrorKind, SeekFrom, IoVec, IoVecMut};
+use crate::memchr;
+
+/// The `BufReader` struct adds buffering to any reader.
+///
+/// It can be excessively inefficient to work directly with a [`Read`] instance.
+/// For example, every call to [`read`][`TcpStream::read`] on [`TcpStream`]
+/// results in a system call. A `BufReader` performs large, infrequent reads on
+/// the underlying [`Read`] and maintains an in-memory buffer of the results.
+///
+/// `BufReader` can improve the speed of programs that make *small* and
+/// *repeated* read calls to the same file or network socket. It does not
+/// help when reading very large amounts at once, or reading just one or a few
+/// times. It also provides no advantage when reading from a source that is
+/// already in memory, like a `Vec<u8>`.
+///
+/// When the `BufReader` is dropped, the contents of its buffer will be
+/// discarded. Creating multiple instances of a `BufReader` on the same
+/// stream can cause data loss.
+///
+/// [`Read`]: ../../std/io/trait.Read.html
+/// [`TcpStream::read`]: ../../std/net/struct.TcpStream.html#method.read
+/// [`TcpStream`]: ../../std/net/struct.TcpStream.html
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::io::prelude::*;
+/// use std::io::BufReader;
+/// use std::fs::File;
+///
+/// fn main() -> std::io::Result<()> {
+/// let f = File::open("log.txt")?;
+/// let mut reader = BufReader::new(f);
+///
+/// let mut line = String::new();
+/// let len = reader.read_line(&mut line)?;
+/// println!("First line is {} bytes long", len);
+/// Ok(())
+/// }
+/// ```
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct BufReader<R> {
+ inner: R,
+ buf: Box<[u8]>,
+ pos: usize,
+ cap: usize,
+}
+
+impl<R: Read> BufReader<R> {
+ /// Creates a new `BufReader` with a default buffer capacity. The default is currently 8 KB,
+ /// but may change in the future.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::io::BufReader;
+ /// use std::fs::File;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let f = File::open("log.txt")?;
+ /// let reader = BufReader::new(f);
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn new(inner: R) -> BufReader<R> {
+ BufReader::with_capacity(DEFAULT_BUF_SIZE, inner)
+ }
+
+ /// Creates a new `BufReader` with the specified buffer capacity.
+ ///
+ /// # Examples
+ ///
+ /// Creating a buffer with ten bytes of capacity:
+ ///
+ /// ```no_run
+ /// use std::io::BufReader;
+ /// use std::fs::File;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let f = File::open("log.txt")?;
+ /// let reader = BufReader::with_capacity(10, f);
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn with_capacity(cap: usize, inner: R) -> BufReader<R> {
+ unsafe {
+ let mut buffer = Vec::with_capacity(cap);
+ buffer.set_len(cap);
+ inner.initializer().initialize(&mut buffer);
+ BufReader {
+ inner,
+ buf: buffer.into_boxed_slice(),
+ pos: 0,
+ cap: 0,
+ }
+ }
+ }
+}
+
+impl<R> BufReader<R> {
+ /// Gets a reference to the underlying reader.
+ ///
+ /// It is inadvisable to directly read from the underlying reader.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::io::BufReader;
+ /// use std::fs::File;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let f1 = File::open("log.txt")?;
+ /// let reader = BufReader::new(f1);
+ ///
+ /// let f2 = reader.get_ref();
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn get_ref(&self) -> &R { &self.inner }
+
+ /// Gets a mutable reference to the underlying reader.
+ ///
+ /// It is inadvisable to directly read from the underlying reader.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::io::BufReader;
+ /// use std::fs::File;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let f1 = File::open("log.txt")?;
+ /// let mut reader = BufReader::new(f1);
+ ///
+ /// let f2 = reader.get_mut();
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn get_mut(&mut self) -> &mut R { &mut self.inner }
+
+ /// Returns a reference to the internally buffered data.
+ ///
+ /// Unlike `fill_buf`, this will not attempt to fill the buffer if it is empty.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # #![feature(bufreader_buffer)]
+ /// use std::io::{BufReader, BufRead};
+ /// use std::fs::File;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let f = File::open("log.txt")?;
+ /// let mut reader = BufReader::new(f);
+ /// assert!(reader.buffer().is_empty());
+ ///
+ /// if reader.fill_buf()?.len() > 0 {
+ /// assert!(!reader.buffer().is_empty());
+ /// }
+ /// Ok(())
+ /// }
+ /// ```
+ #[unstable(feature = "bufreader_buffer", issue = "45323")]
+ pub fn buffer(&self) -> &[u8] {
+ &self.buf[self.pos..self.cap]
+ }
+
+ /// Unwraps this `BufReader`, returning the underlying reader.
+ ///
+ /// Note that any leftover data in the internal buffer is lost.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::io::BufReader;
+ /// use std::fs::File;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let f1 = File::open("log.txt")?;
+ /// let reader = BufReader::new(f1);
+ ///
+ /// let f2 = reader.into_inner();
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn into_inner(self) -> R { self.inner }
+
+ /// Invalidates all data in the internal buffer.
+ #[inline]
+ fn discard_buffer(&mut self) {
+ self.pos = 0;
+ self.cap = 0;
+ }
+}
+
+impl<R: Seek> BufReader<R> {
+ /// Seeks relative to the current position. If the new position lies within the buffer,
+ /// the buffer will not be flushed, allowing for more efficient seeks.
+ /// This method does not return the location of the underlying reader, so the caller
+ /// must track this information themselves if it is required.
+ #[unstable(feature = "bufreader_seek_relative", issue = "31100")]
+ pub fn seek_relative(&mut self, offset: i64) -> io::Result<()> {
+ let pos = self.pos as u64;
+ if offset < 0 {
+ if let Some(new_pos) = pos.checked_sub((-offset) as u64) {
+ self.pos = new_pos as usize;
+ return Ok(())
+ }
+ } else {
+ if let Some(new_pos) = pos.checked_add(offset as u64) {
+ if new_pos <= self.cap as u64 {
+ self.pos = new_pos as usize;
+ return Ok(())
+ }
+ }
+ }
+ self.seek(SeekFrom::Current(offset)).map(|_|())
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<R: Read> Read for BufReader<R> {
+ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+ // If we don't have any buffered data and we're doing a massive read
+ // (larger than our internal buffer), bypass our internal buffer
+ // entirely.
+ if self.pos == self.cap && buf.len() >= self.buf.len() {
+ self.discard_buffer();
+ return self.inner.read(buf);
+ }
+ let nread = {
+ let mut rem = self.fill_buf()?;
+ rem.read(buf)?
+ };
+ self.consume(nread);
+ Ok(nread)
+ }
+
+ fn read_vectored(&mut self, bufs: &mut [IoVecMut<'_>]) -> io::Result<usize> {
+ let total_len = bufs.iter().map(|b| b.len()).sum::<usize>();
+ if self.pos == self.cap && total_len >= self.buf.len() {
+ self.discard_buffer();
+ return self.inner.read_vectored(bufs);
+ }
+ let nread = {
+ let mut rem = self.fill_buf()?;
+ rem.read_vectored(bufs)?
+ };
+ self.consume(nread);
+ Ok(nread)
+ }
+
+ // we can't skip unconditionally because of the large buffer case in read.
+ unsafe fn initializer(&self) -> Initializer {
+ self.inner.initializer()
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<R: Read> BufRead for BufReader<R> {
+ fn fill_buf(&mut self) -> io::Result<&[u8]> {
+ // If we've reached the end of our internal buffer then we need to fetch
+ // some more data from the underlying reader.
+ // Branch using `>=` instead of the more correct `==`
+ // to tell the compiler that the pos..cap slice is always valid.
+ if self.pos >= self.cap {
+ debug_assert!(self.pos == self.cap);
+ self.cap = self.inner.read(&mut self.buf)?;
+ self.pos = 0;
+ }
+ Ok(&self.buf[self.pos..self.cap])
+ }
+
+ fn consume(&mut self, amt: usize) {
+ self.pos = cmp::min(self.pos + amt, self.cap);
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<R> fmt::Debug for BufReader<R> where R: fmt::Debug {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt.debug_struct("BufReader")
+ .field("reader", &self.inner)
+ .field("buffer", &format_args!("{}/{}", self.cap - self.pos, self.buf.len()))
+ .finish()
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<R: Seek> Seek for BufReader<R> {
+ /// Seek to an offset, in bytes, in the underlying reader.
+ ///
+ /// The position used for seeking with `SeekFrom::Current(_)` is the
+ /// position the underlying reader would be at if the `BufReader` had no
+ /// internal buffer.
+ ///
+ /// Seeking always discards the internal buffer, even if the seek position
+ /// would otherwise fall within it. This guarantees that calling
+ /// `.into_inner()` immediately after a seek yields the underlying reader
+ /// at the same position.
+ ///
+ /// To seek without discarding the internal buffer, use [`BufReader::seek_relative`].
+ ///
+ /// See [`std::io::Seek`] for more details.
+ ///
+ /// Note: In the edge case where you're seeking with `SeekFrom::Current(n)`
+ /// where `n` minus the internal buffer length overflows an `i64`, two
+ /// seeks will be performed instead of one. If the second seek returns
+ /// `Err`, the underlying reader will be left at the same position it would
+ /// have if you called `seek` with `SeekFrom::Current(0)`.
+ ///
+ /// [`BufReader::seek_relative`]: struct.BufReader.html#method.seek_relative
+ /// [`std::io::Seek`]: trait.Seek.html
+ fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
+ let result: u64;
+ if let SeekFrom::Current(n) = pos {
+ let remainder = (self.cap - self.pos) as i64;
+ // it should be safe to assume that remainder fits within an i64 as the alternative
+ // means we managed to allocate 8 exbibytes and that's absurd.
+ // But it's not out of the realm of possibility for some weird underlying reader to
+ // support seeking by i64::min_value() so we need to handle underflow when subtracting
+ // remainder.
+ if let Some(offset) = n.checked_sub(remainder) {
+ result = self.inner.seek(SeekFrom::Current(offset))?;
+ } else {
+ // seek backwards by our remainder, and then by the offset
+ self.inner.seek(SeekFrom::Current(-remainder))?;
+ self.discard_buffer();
+ result = self.inner.seek(SeekFrom::Current(n))?;
+ }
+ } else {
+ // Seeking with Start/End doesn't care about our buffer length.
+ result = self.inner.seek(pos)?;
+ }
+ self.discard_buffer();
+ Ok(result)
+ }
+}
+
+/// Wraps a writer and buffers its output.
+///
+/// It can be excessively inefficient to work directly with something that
+/// implements [`Write`]. For example, every call to
+/// [`write`][`TcpStream::write`] on [`TcpStream`] results in a system call. A
+/// `BufWriter` keeps an in-memory buffer of data and writes it to an underlying
+/// writer in large, infrequent batches.
+///
+/// `BufWriter` can improve the speed of programs that make *small* and
+/// *repeated* write calls to the same file or network socket. It does not
+/// help when writing very large amounts at once, or writing just one or a few
+/// times. It also provides no advantage when writing to a destination that is
+/// in memory, like a `Vec<u8>`.
+///
+/// When the `BufWriter` is dropped, the contents of its buffer will be written
+/// out. However, any errors that happen in the process of flushing the buffer
+/// when the writer is dropped will be ignored. Code that wishes to handle such
+/// errors must manually call [`flush`] before the writer is dropped.
+///
+/// # Examples
+///
+/// Let's write the numbers one through ten to a [`TcpStream`]:
+///
+/// ```no_run
+/// use std::io::prelude::*;
+/// use std::net::TcpStream;
+///
+/// let mut stream = TcpStream::connect("127.0.0.1:34254").unwrap();
+///
+/// for i in 0..10 {
+/// stream.write(&[i+1]).unwrap();
+/// }
+/// ```
+///
+/// Because we're not buffering, we write each one in turn, incurring the
+/// overhead of a system call per byte written. We can fix this with a
+/// `BufWriter`:
+///
+/// ```no_run
+/// use std::io::prelude::*;
+/// use std::io::BufWriter;
+/// use std::net::TcpStream;
+///
+/// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
+///
+/// for i in 0..10 {
+/// stream.write(&[i+1]).unwrap();
+/// }
+/// ```
+///
+/// By wrapping the stream with a `BufWriter`, these ten writes are all grouped
+/// together by the buffer, and will all be written out in one system call when
+/// the `stream` is dropped.
+///
+/// [`Write`]: ../../std/io/trait.Write.html
+/// [`TcpStream::write`]: ../../std/net/struct.TcpStream.html#method.write
+/// [`TcpStream`]: ../../std/net/struct.TcpStream.html
+/// [`flush`]: #method.flush
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct BufWriter<W: Write> {
+ inner: Option<W>,
+ buf: Vec<u8>,
+ // #30888: If the inner writer panics in a call to write, we don't want to
+ // write the buffered data a second time in BufWriter's destructor. This
+ // flag tells the Drop impl if it should skip the flush.
+ panicked: bool,
+}
+
+/// An error returned by `into_inner` which combines an error that
+/// happened while writing out the buffer, and the buffered writer object
+/// which may be used to recover from the condition.
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::io::BufWriter;
+/// use std::net::TcpStream;
+///
+/// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
+///
+/// // do stuff with the stream
+///
+/// // we want to get our `TcpStream` back, so let's try:
+///
+/// let stream = match stream.into_inner() {
+/// Ok(s) => s,
+/// Err(e) => {
+/// // Here, e is an IntoInnerError
+/// panic!("An error occurred");
+/// }
+/// };
+/// ```
+#[derive(Debug)]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct IntoInnerError<W>(W, Error);
+
+impl<W: Write> BufWriter<W> {
+ /// Creates a new `BufWriter` with a default buffer capacity. The default is currently 8 KB,
+ /// but may change in the future.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::io::BufWriter;
+ /// use std::net::TcpStream;
+ ///
+ /// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn new(inner: W) -> BufWriter<W> {
+ BufWriter::with_capacity(DEFAULT_BUF_SIZE, inner)
+ }
+
+ /// Creates a new `BufWriter` with the specified buffer capacity.
+ ///
+ /// # Examples
+ ///
+ /// Creating a buffer with a buffer of a hundred bytes.
+ ///
+ /// ```no_run
+ /// use std::io::BufWriter;
+ /// use std::net::TcpStream;
+ ///
+ /// let stream = TcpStream::connect("127.0.0.1:34254").unwrap();
+ /// let mut buffer = BufWriter::with_capacity(100, stream);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn with_capacity(cap: usize, inner: W) -> BufWriter<W> {
+ BufWriter {
+ inner: Some(inner),
+ buf: Vec::with_capacity(cap),
+ panicked: false,
+ }
+ }
+
+ fn flush_buf(&mut self) -> io::Result<()> {
+ let mut written = 0;
+ let len = self.buf.len();
+ let mut ret = Ok(());
+ while written < len {
+ self.panicked = true;
+ let r = self.inner.as_mut().unwrap().write(&self.buf[written..]);
+ self.panicked = false;
+
+ match r {
+ Ok(0) => {
+ ret = Err(Error::new(ErrorKind::WriteZero,
+ "failed to write the buffered data"));
+ break;
+ }
+ Ok(n) => written += n,
+ Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
+ Err(e) => { ret = Err(e); break }
+
+ }
+ }
+ if written > 0 {
+ self.buf.drain(..written);
+ }
+ ret
+ }
+
+ /// Gets a reference to the underlying writer.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::io::BufWriter;
+ /// use std::net::TcpStream;
+ ///
+ /// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
+ ///
+ /// // we can use reference just like buffer
+ /// let reference = buffer.get_ref();
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn get_ref(&self) -> &W { self.inner.as_ref().unwrap() }
+
+ /// Gets a mutable reference to the underlying writer.
+ ///
+ /// It is inadvisable to directly write to the underlying writer.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::io::BufWriter;
+ /// use std::net::TcpStream;
+ ///
+ /// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
+ ///
+ /// // we can use reference just like buffer
+ /// let reference = buffer.get_mut();
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn get_mut(&mut self) -> &mut W { self.inner.as_mut().unwrap() }
+
+ /// Returns a reference to the internally buffered data.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # #![feature(bufreader_buffer)]
+ /// use std::io::BufWriter;
+ /// use std::net::TcpStream;
+ ///
+ /// let buf_writer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
+ ///
+ /// // See how many bytes are currently buffered
+ /// let bytes_buffered = buf_writer.buffer().len();
+ /// ```
+ #[unstable(feature = "bufreader_buffer", issue = "45323")]
+ pub fn buffer(&self) -> &[u8] {
+ &self.buf
+ }
+
+ /// Unwraps this `BufWriter`, returning the underlying writer.
+ ///
+ /// The buffer is written out before returning the writer.
+ ///
+ /// # Errors
+ ///
+ /// An `Err` will be returned if an error occurs while flushing the buffer.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::io::BufWriter;
+ /// use std::net::TcpStream;
+ ///
+ /// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
+ ///
+ /// // unwrap the TcpStream and flush the buffer
+ /// let stream = buffer.into_inner().unwrap();
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn into_inner(mut self) -> Result<W, IntoInnerError<BufWriter<W>>> {
+ match self.flush_buf() {
+ Err(e) => Err(IntoInnerError(self, e)),
+ Ok(()) => Ok(self.inner.take().unwrap())
+ }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<W: Write> Write for BufWriter<W> {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ if self.buf.len() + buf.len() > self.buf.capacity() {
+ self.flush_buf()?;
+ }
+ if buf.len() >= self.buf.capacity() {
+ self.panicked = true;
+ let r = self.inner.as_mut().unwrap().write(buf);
+ self.panicked = false;
+ r
+ } else {
+ self.buf.write(buf)
+ }
+ }
+
+ fn write_vectored(&mut self, bufs: &[IoVec<'_>]) -> io::Result<usize> {
+ let total_len = bufs.iter().map(|b| b.len()).sum::<usize>();
+ if self.buf.len() + total_len > self.buf.capacity() {
+ self.flush_buf()?;
+ }
+ if total_len >= self.buf.capacity() {
+ self.panicked = true;
+ let r = self.inner.as_mut().unwrap().write_vectored(bufs);
+ self.panicked = false;
+ r
+ } else {
+ self.buf.write_vectored(bufs)
+ }
+ }
+
+ fn flush(&mut self) -> io::Result<()> {
+ self.flush_buf().and_then(|()| self.get_mut().flush())
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<W: Write> fmt::Debug for BufWriter<W> where W: fmt::Debug {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt.debug_struct("BufWriter")
+ .field("writer", &self.inner.as_ref().unwrap())
+ .field("buffer", &format_args!("{}/{}", self.buf.len(), self.buf.capacity()))
+ .finish()
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<W: Write + Seek> Seek for BufWriter<W> {
+ /// Seek to the offset, in bytes, in the underlying writer.
+ ///
+ /// Seeking always writes out the internal buffer before seeking.
+ fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
+ self.flush_buf().and_then(|_| self.get_mut().seek(pos))
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<W: Write> Drop for BufWriter<W> {
+ fn drop(&mut self) {
+ if self.inner.is_some() && !self.panicked {
+ // dtors should not panic, so we ignore a failed flush
+ let _r = self.flush_buf();
+ }
+ }
+}
+
+impl<W> IntoInnerError<W> {
+ /// Returns the error which caused the call to `into_inner()` to fail.
+ ///
+ /// This error was returned when attempting to write the internal buffer.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::io::BufWriter;
+ /// use std::net::TcpStream;
+ ///
+ /// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
+ ///
+ /// // do stuff with the stream
+ ///
+ /// // we want to get our `TcpStream` back, so let's try:
+ ///
+ /// let stream = match stream.into_inner() {
+ /// Ok(s) => s,
+ /// Err(e) => {
+ /// // Here, e is an IntoInnerError, let's log the inner error.
+ /// //
+ /// // We'll just 'log' to stdout for this example.
+ /// println!("{}", e.error());
+ ///
+ /// panic!("An unexpected error occurred.");
+ /// }
+ /// };
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn error(&self) -> &Error { &self.1 }
+
+ /// Returns the buffered writer instance which generated the error.
+ ///
+ /// The returned object can be used for error recovery, such as
+ /// re-inspecting the buffer.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::io::BufWriter;
+ /// use std::net::TcpStream;
+ ///
+ /// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
+ ///
+ /// // do stuff with the stream
+ ///
+ /// // we want to get our `TcpStream` back, so let's try:
+ ///
+ /// let stream = match stream.into_inner() {
+ /// Ok(s) => s,
+ /// Err(e) => {
+ /// // Here, e is an IntoInnerError, let's re-examine the buffer:
+ /// let buffer = e.into_inner();
+ ///
+ /// // do stuff to try to recover
+ ///
+ /// // afterwards, let's just return the stream
+ /// buffer.into_inner().unwrap()
+ /// }
+ /// };
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn into_inner(self) -> W { self.0 }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<W> From<IntoInnerError<W>> for Error {
+ fn from(iie: IntoInnerError<W>) -> Error { iie.1 }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<W: Send + fmt::Debug> error::Error for IntoInnerError<W> {
+ fn description(&self) -> &str {
+ error::Error::description(self.error())
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<W> fmt::Display for IntoInnerError<W> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ self.error().fmt(f)
+ }
+}
+
+/// Wraps a writer and buffers output to it, flushing whenever a newline
+/// (`0x0a`, `'\n'`) is detected.
+///
+/// The [`BufWriter`][bufwriter] struct wraps a writer and buffers its output.
+/// But it only does this batched write when it goes out of scope, or when the
+/// internal buffer is full. Sometimes, you'd prefer to write each line as it's
+/// completed, rather than the entire buffer at once. Enter `LineWriter`. It
+/// does exactly that.
+///
+/// Like [`BufWriter`], a `LineWriter`’s buffer will also be flushed when the
+/// `LineWriter` goes out of scope or when its internal buffer is full.
+///
+/// [bufwriter]: struct.BufWriter.html
+///
+/// If there's still a partial line in the buffer when the `LineWriter` is
+/// dropped, it will flush those contents.
+///
+/// # Examples
+///
+/// We can use `LineWriter` to write one line at a time, significantly
+/// reducing the number of actual writes to the file.
+///
+/// ```no_run
+/// use std::fs::{self, File};
+/// use std::io::prelude::*;
+/// use std::io::LineWriter;
+///
+/// fn main() -> std::io::Result<()> {
+/// let road_not_taken = b"I shall be telling this with a sigh
+/// Somewhere ages and ages hence:
+/// Two roads diverged in a wood, and I -
+/// I took the one less traveled by,
+/// And that has made all the difference.";
+///
+/// let file = File::create("poem.txt")?;
+/// let mut file = LineWriter::new(file);
+///
+/// file.write_all(b"I shall be telling this with a sigh")?;
+///
+/// // No bytes are written until a newline is encountered (or
+/// // the internal buffer is filled).
+/// assert_eq!(fs::read_to_string("poem.txt")?, "");
+/// file.write_all(b"\n")?;
+/// assert_eq!(
+/// fs::read_to_string("poem.txt")?,
+/// "I shall be telling this with a sigh\n",
+/// );
+///
+/// // 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.")?;
+///
+/// // 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(())
+/// }
+/// ```
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct LineWriter<W: Write> {
+ inner: BufWriter<W>,
+ need_flush: bool,
+}
+
+impl<W: Write> LineWriter<W> {
+ /// Creates a new `LineWriter`.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs::File;
+ /// use std::io::LineWriter;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let file = File::create("poem.txt")?;
+ /// let file = LineWriter::new(file);
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn new(inner: W) -> LineWriter<W> {
+ // Lines typically aren't that long, don't use a giant buffer
+ LineWriter::with_capacity(1024, inner)
+ }
+
+ /// Creates a new `LineWriter` with a specified capacity for the internal
+ /// buffer.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs::File;
+ /// use std::io::LineWriter;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let file = File::create("poem.txt")?;
+ /// let file = LineWriter::with_capacity(100, file);
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn with_capacity(cap: usize, inner: W) -> LineWriter<W> {
+ LineWriter {
+ inner: BufWriter::with_capacity(cap, inner),
+ need_flush: false,
+ }
+ }
+
+ /// Gets a reference to the underlying writer.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs::File;
+ /// use std::io::LineWriter;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let file = File::create("poem.txt")?;
+ /// let file = LineWriter::new(file);
+ ///
+ /// let reference = file.get_ref();
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn get_ref(&self) -> &W { self.inner.get_ref() }
+
+ /// Gets a mutable reference to the underlying writer.
+ ///
+ /// Caution must be taken when calling methods on the mutable reference
+ /// returned as extra writes could corrupt the output stream.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs::File;
+ /// use std::io::LineWriter;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let file = File::create("poem.txt")?;
+ /// let mut file = LineWriter::new(file);
+ ///
+ /// // we can use reference just like file
+ /// let reference = file.get_mut();
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn get_mut(&mut self) -> &mut W { self.inner.get_mut() }
+
+ /// Unwraps this `LineWriter`, returning the underlying writer.
+ ///
+ /// The internal buffer is written out before returning the writer.
+ ///
+ /// # Errors
+ ///
+ /// An `Err` will be returned if an error occurs while flushing the buffer.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs::File;
+ /// use std::io::LineWriter;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let file = File::create("poem.txt")?;
+ ///
+ /// let writer: LineWriter<File> = LineWriter::new(file);
+ ///
+ /// let file: File = writer.into_inner()?;
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn into_inner(self) -> Result<W, IntoInnerError<LineWriter<W>>> {
+ self.inner.into_inner().map_err(|IntoInnerError(buf, e)| {
+ IntoInnerError(LineWriter {
+ inner: buf,
+ need_flush: false,
+ }, e)
+ })
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<W: Write> Write for LineWriter<W> {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ if self.need_flush {
+ self.flush()?;
+ }
+
+ // Find the last newline character in the buffer provided. If found then
+ // we're going to write all the data up to that point and then flush,
+ // otherwise we just write the whole block to the underlying writer.
+ let i = match memchr::memrchr(b'\n', buf) {
+ Some(i) => i,
+ None => return self.inner.write(buf),
+ };
+
+
+ // Ok, we're going to write a partial amount of the data given first
+ // followed by flushing the newline. After we've successfully written
+ // some data then we *must* report that we wrote that data, so future
+ // errors are ignored. We set our internal `need_flush` flag, though, in
+ // case flushing fails and we need to try it first next time.
+ let n = self.inner.write(&buf[..=i])?;
+ self.need_flush = true;
+ if self.flush().is_err() || n != i + 1 {
+ return Ok(n)
+ }
+
+ // At this point we successfully wrote `i + 1` bytes and flushed it out,
+ // meaning that the entire line is now flushed out on the screen. While
+ // we can attempt to finish writing the rest of the data provided.
+ // Remember though that we ignore errors here as we've successfully
+ // written data, so we need to report that.
+ match self.inner.write(&buf[i + 1..]) {
+ Ok(i) => Ok(n + i),
+ Err(_) => Ok(n),
+ }
+ }
+
+ fn flush(&mut self) -> io::Result<()> {
+ self.inner.flush()?;
+ self.need_flush = false;
+ Ok(())
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<W: Write> fmt::Debug for LineWriter<W> where W: fmt::Debug {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt.debug_struct("LineWriter")
+ .field("writer", &self.inner.inner)
+ .field("buffer",
+ &format_args!("{}/{}", self.inner.buf.len(), self.inner.buf.capacity()))
+ .finish()
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use crate::io::prelude::*;
+ use crate::io::{self, BufReader, BufWriter, LineWriter, SeekFrom};
+ use crate::sync::atomic::{AtomicUsize, Ordering};
+ use crate::thread;
+
+ /// A dummy reader intended at testing short-reads propagation.
+ pub struct ShortReader {
+ lengths: Vec<usize>,
+ }
+
+ impl Read for ShortReader {
+ fn read(&mut self, _: &mut [u8]) -> io::Result<usize> {
+ if self.lengths.is_empty() {
+ Ok(0)
+ } else {
+ Ok(self.lengths.remove(0))
+ }
+ }
+ }
+
+ #[test]
+ fn test_buffered_reader() {
+ let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4];
+ let mut reader = BufReader::with_capacity(2, inner);
+
+ let mut buf = [0, 0, 0];
+ let nread = reader.read(&mut buf);
+ assert_eq!(nread.unwrap(), 3);
+ assert_eq!(buf, [5, 6, 7]);
+ assert_eq!(reader.buffer(), []);
+
+ let mut buf = [0, 0];
+ let nread = reader.read(&mut buf);
+ assert_eq!(nread.unwrap(), 2);
+ assert_eq!(buf, [0, 1]);
+ assert_eq!(reader.buffer(), []);
+
+ let mut buf = [0];
+ let nread = reader.read(&mut buf);
+ assert_eq!(nread.unwrap(), 1);
+ assert_eq!(buf, [2]);
+ assert_eq!(reader.buffer(), [3]);
+
+ let mut buf = [0, 0, 0];
+ let nread = reader.read(&mut buf);
+ assert_eq!(nread.unwrap(), 1);
+ assert_eq!(buf, [3, 0, 0]);
+ assert_eq!(reader.buffer(), []);
+
+ let nread = reader.read(&mut buf);
+ assert_eq!(nread.unwrap(), 1);
+ assert_eq!(buf, [4, 0, 0]);
+ assert_eq!(reader.buffer(), []);
+
+ assert_eq!(reader.read(&mut buf).unwrap(), 0);
+ }
+
+ #[test]
+ fn test_buffered_reader_seek() {
+ let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4];
+ let mut reader = BufReader::with_capacity(2, io::Cursor::new(inner));
+
+ assert_eq!(reader.seek(SeekFrom::Start(3)).ok(), Some(3));
+ assert_eq!(reader.fill_buf().ok(), Some(&[0, 1][..]));
+ assert_eq!(reader.seek(SeekFrom::Current(0)).ok(), Some(3));
+ assert_eq!(reader.fill_buf().ok(), Some(&[0, 1][..]));
+ assert_eq!(reader.seek(SeekFrom::Current(1)).ok(), Some(4));
+ assert_eq!(reader.fill_buf().ok(), Some(&[1, 2][..]));
+ reader.consume(1);
+ assert_eq!(reader.seek(SeekFrom::Current(-2)).ok(), Some(3));
+ }
+
+ #[test]
+ fn test_buffered_reader_seek_relative() {
+ let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4];
+ let mut reader = BufReader::with_capacity(2, io::Cursor::new(inner));
+
+ assert!(reader.seek_relative(3).is_ok());
+ assert_eq!(reader.fill_buf().ok(), Some(&[0, 1][..]));
+ assert!(reader.seek_relative(0).is_ok());
+ assert_eq!(reader.fill_buf().ok(), Some(&[0, 1][..]));
+ assert!(reader.seek_relative(1).is_ok());
+ assert_eq!(reader.fill_buf().ok(), Some(&[1][..]));
+ assert!(reader.seek_relative(-1).is_ok());
+ assert_eq!(reader.fill_buf().ok(), Some(&[0, 1][..]));
+ assert!(reader.seek_relative(2).is_ok());
+ assert_eq!(reader.fill_buf().ok(), Some(&[2, 3][..]));
+ }
+
+ #[test]
+ fn test_buffered_reader_invalidated_after_read() {
+ let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4];
+ let mut reader = BufReader::with_capacity(3, io::Cursor::new(inner));
+
+ assert_eq!(reader.fill_buf().ok(), Some(&[5, 6, 7][..]));
+ reader.consume(3);
+
+ let mut buffer = [0, 0, 0, 0, 0];
+ assert_eq!(reader.read(&mut buffer).ok(), Some(5));
+ assert_eq!(buffer, [0, 1, 2, 3, 4]);
+
+ assert!(reader.seek_relative(-2).is_ok());
+ let mut buffer = [0, 0];
+ assert_eq!(reader.read(&mut buffer).ok(), Some(2));
+ assert_eq!(buffer, [3, 4]);
+ }
+
+ #[test]
+ fn test_buffered_reader_invalidated_after_seek() {
+ let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4];
+ let mut reader = BufReader::with_capacity(3, io::Cursor::new(inner));
+
+ assert_eq!(reader.fill_buf().ok(), Some(&[5, 6, 7][..]));
+ reader.consume(3);
+
+ assert!(reader.seek(SeekFrom::Current(5)).is_ok());
+
+ assert!(reader.seek_relative(-2).is_ok());
+ let mut buffer = [0, 0];
+ assert_eq!(reader.read(&mut buffer).ok(), Some(2));
+ assert_eq!(buffer, [3, 4]);
+ }
+
+ #[test]
+ fn test_buffered_reader_seek_underflow() {
+ // gimmick reader that yields its position modulo 256 for each byte
+ struct PositionReader {
+ pos: u64
+ }
+ impl Read for PositionReader {
+ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+ let len = buf.len();
+ for x in buf {
+ *x = self.pos as u8;
+ self.pos = self.pos.wrapping_add(1);
+ }
+ Ok(len)
+ }
+ }
+ impl Seek for PositionReader {
+ fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
+ match pos {
+ SeekFrom::Start(n) => {
+ self.pos = n;
+ }
+ SeekFrom::Current(n) => {
+ self.pos = self.pos.wrapping_add(n as u64);
+ }
+ SeekFrom::End(n) => {
+ self.pos = u64::max_value().wrapping_add(n as u64);
+ }
+ }
+ Ok(self.pos)
+ }
+ }
+
+ let mut reader = BufReader::with_capacity(5, PositionReader { pos: 0 });
+ assert_eq!(reader.fill_buf().ok(), Some(&[0, 1, 2, 3, 4][..]));
+ assert_eq!(reader.seek(SeekFrom::End(-5)).ok(), Some(u64::max_value()-5));
+ assert_eq!(reader.fill_buf().ok().map(|s| s.len()), Some(5));
+ // the following seek will require two underlying seeks
+ let expected = 9223372036854775802;
+ assert_eq!(reader.seek(SeekFrom::Current(i64::min_value())).ok(), Some(expected));
+ assert_eq!(reader.fill_buf().ok().map(|s| s.len()), Some(5));
+ // seeking to 0 should empty the buffer.
+ assert_eq!(reader.seek(SeekFrom::Current(0)).ok(), Some(expected));
+ assert_eq!(reader.get_ref().pos, expected);
+ }
+
+ #[test]
+ fn test_buffered_writer() {
+ let inner = Vec::new();
+ let mut writer = BufWriter::with_capacity(2, inner);
+
+ writer.write(&[0, 1]).unwrap();
+ assert_eq!(writer.buffer(), []);
+ assert_eq!(*writer.get_ref(), [0, 1]);
+
+ writer.write(&[2]).unwrap();
+ assert_eq!(writer.buffer(), [2]);
+ assert_eq!(*writer.get_ref(), [0, 1]);
+
+ writer.write(&[3]).unwrap();
+ assert_eq!(writer.buffer(), [2, 3]);
+ assert_eq!(*writer.get_ref(), [0, 1]);
+
+ writer.flush().unwrap();
+ assert_eq!(writer.buffer(), []);
+ assert_eq!(*writer.get_ref(), [0, 1, 2, 3]);
+
+ writer.write(&[4]).unwrap();
+ writer.write(&[5]).unwrap();
+ assert_eq!(writer.buffer(), [4, 5]);
+ assert_eq!(*writer.get_ref(), [0, 1, 2, 3]);
+
+ writer.write(&[6]).unwrap();
+ assert_eq!(writer.buffer(), [6]);
+ assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5]);
+
+ writer.write(&[7, 8]).unwrap();
+ assert_eq!(writer.buffer(), []);
+ assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5, 6, 7, 8]);
+
+ writer.write(&[9, 10, 11]).unwrap();
+ assert_eq!(writer.buffer(), []);
+ assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]);
+
+ writer.flush().unwrap();
+ assert_eq!(writer.buffer(), []);
+ assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]);
+ }
+
+ #[test]
+ fn test_buffered_writer_inner_flushes() {
+ let mut w = BufWriter::with_capacity(3, Vec::new());
+ w.write(&[0, 1]).unwrap();
+ assert_eq!(*w.get_ref(), []);
+ let w = w.into_inner().unwrap();
+ assert_eq!(w, [0, 1]);
+ }
+
+ #[test]
+ fn test_buffered_writer_seek() {
+ let mut w = BufWriter::with_capacity(3, io::Cursor::new(Vec::new()));
+ w.write_all(&[0, 1, 2, 3, 4, 5]).unwrap();
+ w.write_all(&[6, 7]).unwrap();
+ assert_eq!(w.seek(SeekFrom::Current(0)).ok(), Some(8));
+ assert_eq!(&w.get_ref().get_ref()[..], &[0, 1, 2, 3, 4, 5, 6, 7][..]);
+ assert_eq!(w.seek(SeekFrom::Start(2)).ok(), Some(2));
+ w.write_all(&[8, 9]).unwrap();
+ assert_eq!(&w.into_inner().unwrap().into_inner()[..], &[0, 1, 8, 9, 4, 5, 6, 7]);
+ }
+
+ #[test]
+ fn test_read_until() {
+ let inner: &[u8] = &[0, 1, 2, 1, 0];
+ let mut reader = BufReader::with_capacity(2, inner);
+ let mut v = Vec::new();
+ reader.read_until(0, &mut v).unwrap();
+ assert_eq!(v, [0]);
+ v.truncate(0);
+ reader.read_until(2, &mut v).unwrap();
+ assert_eq!(v, [1, 2]);
+ v.truncate(0);
+ reader.read_until(1, &mut v).unwrap();
+ assert_eq!(v, [1]);
+ v.truncate(0);
+ reader.read_until(8, &mut v).unwrap();
+ assert_eq!(v, [0]);
+ v.truncate(0);
+ reader.read_until(9, &mut v).unwrap();
+ assert_eq!(v, []);
+ }
+
+ #[test]
+ fn test_line_buffer_fail_flush() {
+ // Issue #32085
+ struct FailFlushWriter<'a>(&'a mut Vec<u8>);
+
+ impl Write for FailFlushWriter<'_> {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ self.0.extend_from_slice(buf);
+ Ok(buf.len())
+ }
+ fn flush(&mut self) -> io::Result<()> {
+ Err(io::Error::new(io::ErrorKind::Other, "flush failed"))
+ }
+ }
+
+ let mut buf = Vec::new();
+ {
+ let mut writer = LineWriter::new(FailFlushWriter(&mut buf));
+ let to_write = b"abc\ndef";
+ if let Ok(written) = writer.write(to_write) {
+ assert!(written < to_write.len(), "didn't flush on new line");
+ // PASS
+ return;
+ }
+ }
+ assert!(buf.is_empty(), "write returned an error but wrote data");
+ }
+
+ #[test]
+ fn test_line_buffer() {
+ let mut writer = LineWriter::new(Vec::new());
+ writer.write(&[0]).unwrap();
+ assert_eq!(*writer.get_ref(), []);
+ writer.write(&[1]).unwrap();
+ assert_eq!(*writer.get_ref(), []);
+ writer.flush().unwrap();
+ assert_eq!(*writer.get_ref(), [0, 1]);
+ writer.write(&[0, b'\n', 1, b'\n', 2]).unwrap();
+ assert_eq!(*writer.get_ref(), [0, 1, 0, b'\n', 1, b'\n']);
+ writer.flush().unwrap();
+ assert_eq!(*writer.get_ref(), [0, 1, 0, b'\n', 1, b'\n', 2]);
+ writer.write(&[3, b'\n']).unwrap();
+ assert_eq!(*writer.get_ref(), [0, 1, 0, b'\n', 1, b'\n', 2, 3, b'\n']);
+ }
+
+ #[test]
+ fn test_read_line() {
+ let in_buf: &[u8] = b"a\nb\nc";
+ let mut reader = BufReader::with_capacity(2, in_buf);
+ let mut s = String::new();
+ reader.read_line(&mut s).unwrap();
+ assert_eq!(s, "a\n");
+ s.truncate(0);
+ reader.read_line(&mut s).unwrap();
+ assert_eq!(s, "b\n");
+ s.truncate(0);
+ reader.read_line(&mut s).unwrap();
+ assert_eq!(s, "c");
+ s.truncate(0);
+ reader.read_line(&mut s).unwrap();
+ assert_eq!(s, "");
+ }
+
+ #[test]
+ fn test_lines() {
+ let in_buf: &[u8] = b"a\nb\nc";
+ let reader = BufReader::with_capacity(2, in_buf);
+ let mut it = reader.lines();
+ assert_eq!(it.next().unwrap().unwrap(), "a".to_string());
+ assert_eq!(it.next().unwrap().unwrap(), "b".to_string());
+ assert_eq!(it.next().unwrap().unwrap(), "c".to_string());
+ assert!(it.next().is_none());
+ }
+
+ #[test]
+ fn test_short_reads() {
+ let inner = ShortReader{lengths: vec![0, 1, 2, 0, 1, 0]};
+ let mut reader = BufReader::new(inner);
+ let mut buf = [0, 0];
+ assert_eq!(reader.read(&mut buf).unwrap(), 0);
+ assert_eq!(reader.read(&mut buf).unwrap(), 1);
+ assert_eq!(reader.read(&mut buf).unwrap(), 2);
+ assert_eq!(reader.read(&mut buf).unwrap(), 0);
+ assert_eq!(reader.read(&mut buf).unwrap(), 1);
+ assert_eq!(reader.read(&mut buf).unwrap(), 0);
+ assert_eq!(reader.read(&mut buf).unwrap(), 0);
+ }
+
+ #[test]
+ #[should_panic]
+ fn dont_panic_in_drop_on_panicked_flush() {
+ struct FailFlushWriter;
+
+ impl Write for FailFlushWriter {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> { Ok(buf.len()) }
+ fn flush(&mut self) -> io::Result<()> {
+ Err(io::Error::last_os_error())
+ }
+ }
+
+ let writer = FailFlushWriter;
+ let _writer = BufWriter::new(writer);
+
+ // If writer panics *again* due to the flush error then the process will
+ // abort.
+ panic!();
+ }
+
+ #[test]
+ #[cfg_attr(target_os = "emscripten", ignore)]
+ fn panic_in_write_doesnt_flush_in_drop() {
+ static WRITES: AtomicUsize = AtomicUsize::new(0);
+
+ struct PanicWriter;
+
+ impl Write for PanicWriter {
+ fn write(&mut self, _: &[u8]) -> io::Result<usize> {
+ WRITES.fetch_add(1, Ordering::SeqCst);
+ panic!();
+ }
+ fn flush(&mut self) -> io::Result<()> { Ok(()) }
+ }
+
+ thread::spawn(|| {
+ let mut writer = BufWriter::new(PanicWriter);
+ let _ = writer.write(b"hello world");
+ let _ = writer.flush();
+ }).join().unwrap_err();
+
+ assert_eq!(WRITES.load(Ordering::SeqCst), 1);
+ }
+
+ #[bench]
+ fn bench_buffered_reader(b: &mut test::Bencher) {
+ b.iter(|| {
+ BufReader::new(io::empty())
+ });
+ }
+
+ #[bench]
+ fn bench_buffered_writer(b: &mut test::Bencher) {
+ b.iter(|| {
+ BufWriter::new(io::sink())
+ });
+ }
+
+ struct AcceptOneThenFail {
+ written: bool,
+ flushed: bool,
+ }
+
+ impl Write for AcceptOneThenFail {
+ fn write(&mut self, data: &[u8]) -> io::Result<usize> {
+ if !self.written {
+ assert_eq!(data, b"a\nb\n");
+ self.written = true;
+ Ok(data.len())
+ } else {
+ Err(io::Error::new(io::ErrorKind::NotFound, "test"))
+ }
+ }
+
+ fn flush(&mut self) -> io::Result<()> {
+ assert!(self.written);
+ assert!(!self.flushed);
+ self.flushed = true;
+ Err(io::Error::new(io::ErrorKind::Other, "test"))
+ }
+ }
+
+ #[test]
+ fn erroneous_flush_retried() {
+ let a = AcceptOneThenFail {
+ written: false,
+ flushed: false,
+ };
+
+ let mut l = LineWriter::new(a);
+ assert_eq!(l.write(b"a\nb\na").unwrap(), 4);
+ assert!(l.get_ref().written);
+ assert!(l.get_ref().flushed);
+ l.get_mut().flushed = false;
+
+ assert_eq!(l.write(b"a").unwrap_err().kind(), io::ErrorKind::Other)
+ }
+}
diff --git a/src/libstd/io/cursor.rs b/src/libstd/io/cursor.rs
new file mode 100644
index 0000000..247d45c
--- /dev/null
+++ b/src/libstd/io/cursor.rs
@@ -0,0 +1,886 @@
+use crate::io::prelude::*;
+
+use crate::cmp;
+use crate::io::{self, Initializer, SeekFrom, Error, ErrorKind, IoVec, IoVecMut};
+
+use core::convert::TryInto;
+
+/// A `Cursor` wraps an in-memory buffer and provides it with a
+/// [`Seek`] implementation.
+///
+/// `Cursor`s are used with in-memory buffers, anything implementing
+/// `AsRef<[u8]>`, to allow them to implement [`Read`] and/or [`Write`],
+/// allowing these buffers to be used anywhere you might use a reader or writer
+/// that does actual I/O.
+///
+/// The standard library implements some I/O traits on various types which
+/// are commonly used as a buffer, like `Cursor<`[`Vec`]`<u8>>` and
+/// `Cursor<`[`&[u8]`][bytes]`>`.
+///
+/// # Examples
+///
+/// We may want to write bytes to a [`File`] in our production
+/// code, but use an in-memory buffer in our tests. We can do this with
+/// `Cursor`:
+///
+/// [`Seek`]: trait.Seek.html
+/// [`Read`]: ../../std/io/trait.Read.html
+/// [`Write`]: ../../std/io/trait.Write.html
+/// [`Vec`]: ../../std/vec/struct.Vec.html
+/// [bytes]: ../../std/primitive.slice.html
+/// [`File`]: ../fs/struct.File.html
+///
+/// ```no_run
+/// use std::io::prelude::*;
+/// use std::io::{self, SeekFrom};
+/// use std::fs::File;
+///
+/// // a library function we've written
+/// fn write_ten_bytes_at_end<W: Write + Seek>(writer: &mut W) -> io::Result<()> {
+/// writer.seek(SeekFrom::End(-10))?;
+///
+/// for i in 0..10 {
+/// writer.write(&[i])?;
+/// }
+///
+/// // all went well
+/// Ok(())
+/// }
+///
+/// # fn foo() -> io::Result<()> {
+/// // Here's some code that uses this library function.
+/// //
+/// // We might want to use a BufReader here for efficiency, but let's
+/// // keep this example focused.
+/// let mut file = File::create("foo.txt")?;
+///
+/// write_ten_bytes_at_end(&mut file)?;
+/// # Ok(())
+/// # }
+///
+/// // now let's write a test
+/// #[test]
+/// fn test_writes_bytes() {
+/// // setting up a real File is much slower than an in-memory buffer,
+/// // let's use a cursor instead
+/// use std::io::Cursor;
+/// let mut buff = Cursor::new(vec![0; 15]);
+///
+/// write_ten_bytes_at_end(&mut buff).unwrap();
+///
+/// assert_eq!(&buff.get_ref()[5..15], &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
+/// }
+/// ```
+#[stable(feature = "rust1", since = "1.0.0")]
+#[derive(Clone, Debug)]
+pub struct Cursor<T> {
+ inner: T,
+ pos: u64,
+}
+
+impl<T> Cursor<T> {
+ /// Creates a new cursor wrapping the provided underlying in-memory buffer.
+ ///
+ /// Cursor initial position is `0` even if underlying buffer (e.g., `Vec`)
+ /// is not empty. So writing to cursor starts with overwriting `Vec`
+ /// content, not with appending to it.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::io::Cursor;
+ ///
+ /// let buff = Cursor::new(Vec::new());
+ /// # fn force_inference(_: &Cursor<Vec<u8>>) {}
+ /// # force_inference(&buff);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn new(inner: T) -> Cursor<T> {
+ Cursor { pos: 0, inner: inner }
+ }
+
+ /// Consumes this cursor, returning the underlying value.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::io::Cursor;
+ ///
+ /// let buff = Cursor::new(Vec::new());
+ /// # fn force_inference(_: &Cursor<Vec<u8>>) {}
+ /// # force_inference(&buff);
+ ///
+ /// let vec = buff.into_inner();
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn into_inner(self) -> T { self.inner }
+
+ /// Gets a reference to the underlying value in this cursor.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::io::Cursor;
+ ///
+ /// let buff = Cursor::new(Vec::new());
+ /// # fn force_inference(_: &Cursor<Vec<u8>>) {}
+ /// # force_inference(&buff);
+ ///
+ /// let reference = buff.get_ref();
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn get_ref(&self) -> &T { &self.inner }
+
+ /// Gets a mutable reference to the underlying value in this cursor.
+ ///
+ /// Care should be taken to avoid modifying the internal I/O state of the
+ /// underlying value as it may corrupt this cursor's position.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::io::Cursor;
+ ///
+ /// let mut buff = Cursor::new(Vec::new());
+ /// # fn force_inference(_: &Cursor<Vec<u8>>) {}
+ /// # force_inference(&buff);
+ ///
+ /// let reference = buff.get_mut();
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn get_mut(&mut self) -> &mut T { &mut self.inner }
+
+ /// Returns the current position of this cursor.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::io::Cursor;
+ /// use std::io::prelude::*;
+ /// use std::io::SeekFrom;
+ ///
+ /// let mut buff = Cursor::new(vec![1, 2, 3, 4, 5]);
+ ///
+ /// assert_eq!(buff.position(), 0);
+ ///
+ /// buff.seek(SeekFrom::Current(2)).unwrap();
+ /// assert_eq!(buff.position(), 2);
+ ///
+ /// buff.seek(SeekFrom::Current(-1)).unwrap();
+ /// assert_eq!(buff.position(), 1);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn position(&self) -> u64 { self.pos }
+
+ /// Sets the position of this cursor.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::io::Cursor;
+ ///
+ /// let mut buff = Cursor::new(vec![1, 2, 3, 4, 5]);
+ ///
+ /// assert_eq!(buff.position(), 0);
+ ///
+ /// buff.set_position(2);
+ /// assert_eq!(buff.position(), 2);
+ ///
+ /// buff.set_position(4);
+ /// assert_eq!(buff.position(), 4);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn set_position(&mut self, pos: u64) { self.pos = pos; }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T> io::Seek for Cursor<T> where T: AsRef<[u8]> {
+ fn seek(&mut self, style: SeekFrom) -> io::Result<u64> {
+ let (base_pos, offset) = match style {
+ SeekFrom::Start(n) => { self.pos = n; return Ok(n); }
+ SeekFrom::End(n) => (self.inner.as_ref().len() as u64, n),
+ SeekFrom::Current(n) => (self.pos, n),
+ };
+ let new_pos = if offset >= 0 {
+ base_pos.checked_add(offset as u64)
+ } else {
+ base_pos.checked_sub((offset.wrapping_neg()) as u64)
+ };
+ match new_pos {
+ Some(n) => {self.pos = n; Ok(self.pos)}
+ None => Err(Error::new(ErrorKind::InvalidInput,
+ "invalid seek to a negative or overflowing position"))
+ }
+ }
+
+ fn stream_len(&mut self) -> io::Result<u64> {
+ Ok(self.inner.as_ref().len() as u64)
+ }
+
+ fn stream_position(&mut self) -> io::Result<u64> {
+ Ok(self.pos)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T> Read for Cursor<T> where T: AsRef<[u8]> {
+ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+ let n = Read::read(&mut self.fill_buf()?, buf)?;
+ self.pos += n as u64;
+ Ok(n)
+ }
+
+ fn read_vectored(&mut self, bufs: &mut [IoVecMut<'_>]) -> io::Result<usize> {
+ let mut nread = 0;
+ for buf in bufs {
+ let n = self.read(buf)?;
+ nread += n;
+ if n < buf.len() {
+ break;
+ }
+ }
+ Ok(nread)
+ }
+
+ fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
+ let n = buf.len();
+ Read::read_exact(&mut self.fill_buf()?, buf)?;
+ self.pos += n as u64;
+ Ok(())
+ }
+
+ #[inline]
+ unsafe fn initializer(&self) -> Initializer {
+ Initializer::nop()
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T> BufRead for Cursor<T> where T: AsRef<[u8]> {
+ fn fill_buf(&mut self) -> io::Result<&[u8]> {
+ let amt = cmp::min(self.pos, self.inner.as_ref().len() as u64);
+ Ok(&self.inner.as_ref()[(amt as usize)..])
+ }
+ fn consume(&mut self, amt: usize) { self.pos += amt as u64; }
+}
+
+// Non-resizing write implementation
+fn slice_write(pos_mut: &mut u64, slice: &mut [u8], buf: &[u8]) -> io::Result<usize> {
+ let pos = cmp::min(*pos_mut, slice.len() as u64);
+ let amt = (&mut slice[(pos as usize)..]).write(buf)?;
+ *pos_mut += amt as u64;
+ Ok(amt)
+}
+
+fn slice_write_vectored(
+ pos_mut: &mut u64,
+ slice: &mut [u8],
+ bufs: &[IoVec<'_>],
+) -> io::Result<usize>
+{
+ let mut nwritten = 0;
+ for buf in bufs {
+ let n = slice_write(pos_mut, slice, buf)?;
+ nwritten += n;
+ if n < buf.len() {
+ break;
+ }
+ }
+ Ok(nwritten)
+}
+
+// Resizing write implementation
+fn vec_write(pos_mut: &mut u64, vec: &mut Vec<u8>, buf: &[u8]) -> io::Result<usize> {
+ let pos: usize = (*pos_mut).try_into().map_err(|_| {
+ Error::new(ErrorKind::InvalidInput,
+ "cursor position exceeds maximum possible vector length")
+ })?;
+ // Make sure the internal buffer is as least as big as where we
+ // currently are
+ let len = vec.len();
+ if len < pos {
+ // use `resize` so that the zero filling is as efficient as possible
+ vec.resize(pos, 0);
+ }
+ // Figure out what bytes will be used to overwrite what's currently
+ // there (left), and what will be appended on the end (right)
+ {
+ let space = vec.len() - pos;
+ let (left, right) = buf.split_at(cmp::min(space, buf.len()));
+ vec[pos..pos + left.len()].copy_from_slice(left);
+ vec.extend_from_slice(right);
+ }
+
+ // Bump us forward
+ *pos_mut = (pos + buf.len()) as u64;
+ Ok(buf.len())
+}
+
+fn vec_write_vectored(
+ pos_mut: &mut u64,
+ vec: &mut Vec<u8>,
+ bufs: &[IoVec<'_>],
+) -> io::Result<usize>
+{
+ let mut nwritten = 0;
+ for buf in bufs {
+ nwritten += vec_write(pos_mut, vec, buf)?;
+ }
+ Ok(nwritten)
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Write for Cursor<&mut [u8]> {
+ #[inline]
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ slice_write(&mut self.pos, self.inner, buf)
+ }
+
+ #[inline]
+ fn write_vectored(&mut self, bufs: &[IoVec<'_>]) -> io::Result<usize> {
+ slice_write_vectored(&mut self.pos, self.inner, bufs)
+ }
+
+ fn flush(&mut self) -> io::Result<()> { Ok(()) }
+}
+
+#[stable(feature = "cursor_mut_vec", since = "1.25.0")]
+impl Write for Cursor<&mut Vec<u8>> {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ vec_write(&mut self.pos, self.inner, buf)
+ }
+
+ fn write_vectored(&mut self, bufs: &[IoVec<'_>]) -> io::Result<usize> {
+ vec_write_vectored(&mut self.pos, self.inner, bufs)
+ }
+
+ fn flush(&mut self) -> io::Result<()> { Ok(()) }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Write for Cursor<Vec<u8>> {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ vec_write(&mut self.pos, &mut self.inner, buf)
+ }
+
+ fn write_vectored(&mut self, bufs: &[IoVec<'_>]) -> io::Result<usize> {
+ vec_write_vectored(&mut self.pos, &mut self.inner, bufs)
+ }
+
+ fn flush(&mut self) -> io::Result<()> { Ok(()) }
+}
+
+#[stable(feature = "cursor_box_slice", since = "1.5.0")]
+impl Write for Cursor<Box<[u8]>> {
+ #[inline]
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ slice_write(&mut self.pos, &mut self.inner, buf)
+ }
+
+ #[inline]
+ fn write_vectored(&mut self, bufs: &[IoVec<'_>]) -> io::Result<usize> {
+ slice_write_vectored(&mut self.pos, &mut self.inner, bufs)
+ }
+
+ fn flush(&mut self) -> io::Result<()> { Ok(()) }
+}
+
+#[cfg(test)]
+mod tests {
+ use crate::io::prelude::*;
+ use crate::io::{Cursor, SeekFrom, IoVec, IoVecMut};
+
+ #[test]
+ fn test_vec_writer() {
+ let mut writer = Vec::new();
+ assert_eq!(writer.write(&[0]).unwrap(), 1);
+ assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3);
+ assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4);
+ assert_eq!(writer.write_vectored(
+ &[IoVec::new(&[]), IoVec::new(&[8, 9]), IoVec::new(&[10])],
+ ).unwrap(), 3);
+ let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
+ assert_eq!(writer, b);
+ }
+
+ #[test]
+ fn test_mem_writer() {
+ let mut writer = Cursor::new(Vec::new());
+ assert_eq!(writer.write(&[0]).unwrap(), 1);
+ assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3);
+ assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4);
+ assert_eq!(writer.write_vectored(
+ &[IoVec::new(&[]), IoVec::new(&[8, 9]), IoVec::new(&[10])],
+ ).unwrap(), 3);
+ let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
+ assert_eq!(&writer.get_ref()[..], b);
+ }
+
+ #[test]
+ fn test_mem_mut_writer() {
+ let mut vec = Vec::new();
+ let mut writer = Cursor::new(&mut vec);
+ assert_eq!(writer.write(&[0]).unwrap(), 1);
+ assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3);
+ assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4);
+ assert_eq!(writer.write_vectored(
+ &[IoVec::new(&[]), IoVec::new(&[8, 9]), IoVec::new(&[10])],
+ ).unwrap(), 3);
+ let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
+ assert_eq!(&writer.get_ref()[..], b);
+ }
+
+ #[test]
+ fn test_box_slice_writer() {
+ let mut writer = Cursor::new(vec![0u8; 9].into_boxed_slice());
+ assert_eq!(writer.position(), 0);
+ assert_eq!(writer.write(&[0]).unwrap(), 1);
+ assert_eq!(writer.position(), 1);
+ assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3);
+ assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4);
+ assert_eq!(writer.position(), 8);
+ assert_eq!(writer.write(&[]).unwrap(), 0);
+ assert_eq!(writer.position(), 8);
+
+ assert_eq!(writer.write(&[8, 9]).unwrap(), 1);
+ assert_eq!(writer.write(&[10]).unwrap(), 0);
+ let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8];
+ assert_eq!(&**writer.get_ref(), b);
+ }
+
+ #[test]
+ fn test_box_slice_writer_vectored() {
+ let mut writer = Cursor::new(vec![0u8; 9].into_boxed_slice());
+ assert_eq!(writer.position(), 0);
+ assert_eq!(writer.write_vectored(&[IoVec::new(&[0])]).unwrap(), 1);
+ assert_eq!(writer.position(), 1);
+ assert_eq!(
+ writer.write_vectored(&[IoVec::new(&[1, 2, 3]), IoVec::new(&[4, 5, 6, 7])]).unwrap(),
+ 7,
+ );
+ assert_eq!(writer.position(), 8);
+ assert_eq!(writer.write_vectored(&[]).unwrap(), 0);
+ assert_eq!(writer.position(), 8);
+
+ assert_eq!(writer.write_vectored(&[IoVec::new(&[8, 9])]).unwrap(), 1);
+ assert_eq!(writer.write_vectored(&[IoVec::new(&[10])]).unwrap(), 0);
+ let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8];
+ assert_eq!(&**writer.get_ref(), b);
+ }
+
+ #[test]
+ fn test_buf_writer() {
+ let mut buf = [0 as u8; 9];
+ {
+ let mut writer = Cursor::new(&mut buf[..]);
+ assert_eq!(writer.position(), 0);
+ assert_eq!(writer.write(&[0]).unwrap(), 1);
+ assert_eq!(writer.position(), 1);
+ assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3);
+ assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4);
+ assert_eq!(writer.position(), 8);
+ assert_eq!(writer.write(&[]).unwrap(), 0);
+ assert_eq!(writer.position(), 8);
+
+ assert_eq!(writer.write(&[8, 9]).unwrap(), 1);
+ assert_eq!(writer.write(&[10]).unwrap(), 0);
+ }
+ let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8];
+ assert_eq!(buf, b);
+ }
+
+ #[test]
+ fn test_buf_writer_vectored() {
+ let mut buf = [0 as u8; 9];
+ {
+ let mut writer = Cursor::new(&mut buf[..]);
+ assert_eq!(writer.position(), 0);
+ assert_eq!(writer.write_vectored(&[IoVec::new(&[0])]).unwrap(), 1);
+ assert_eq!(writer.position(), 1);
+ assert_eq!(
+ writer.write_vectored(
+ &[IoVec::new(&[1, 2, 3]), IoVec::new(&[4, 5, 6, 7])],
+ ).unwrap(),
+ 7,
+ );
+ assert_eq!(writer.position(), 8);
+ assert_eq!(writer.write_vectored(&[]).unwrap(), 0);
+ assert_eq!(writer.position(), 8);
+
+ assert_eq!(writer.write_vectored(&[IoVec::new(&[8, 9])]).unwrap(), 1);
+ assert_eq!(writer.write_vectored(&[IoVec::new(&[10])]).unwrap(), 0);
+ }
+ let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8];
+ assert_eq!(buf, b);
+ }
+
+ #[test]
+ fn test_buf_writer_seek() {
+ let mut buf = [0 as u8; 8];
+ {
+ let mut writer = Cursor::new(&mut buf[..]);
+ assert_eq!(writer.position(), 0);
+ assert_eq!(writer.write(&[1]).unwrap(), 1);
+ assert_eq!(writer.position(), 1);
+
+ assert_eq!(writer.seek(SeekFrom::Start(2)).unwrap(), 2);
+ assert_eq!(writer.position(), 2);
+ assert_eq!(writer.write(&[2]).unwrap(), 1);
+ assert_eq!(writer.position(), 3);
+
+ assert_eq!(writer.seek(SeekFrom::Current(-2)).unwrap(), 1);
+ assert_eq!(writer.position(), 1);
+ assert_eq!(writer.write(&[3]).unwrap(), 1);
+ assert_eq!(writer.position(), 2);
+
+ assert_eq!(writer.seek(SeekFrom::End(-1)).unwrap(), 7);
+ assert_eq!(writer.position(), 7);
+ assert_eq!(writer.write(&[4]).unwrap(), 1);
+ assert_eq!(writer.position(), 8);
+
+ }
+ let b: &[_] = &[1, 3, 2, 0, 0, 0, 0, 4];
+ assert_eq!(buf, b);
+ }
+
+ #[test]
+ fn test_buf_writer_error() {
+ let mut buf = [0 as u8; 2];
+ let mut writer = Cursor::new(&mut buf[..]);
+ assert_eq!(writer.write(&[0]).unwrap(), 1);
+ assert_eq!(writer.write(&[0, 0]).unwrap(), 1);
+ assert_eq!(writer.write(&[0, 0]).unwrap(), 0);
+ }
+
+ #[test]
+ fn test_mem_reader() {
+ let mut reader = Cursor::new(vec![0, 1, 2, 3, 4, 5, 6, 7]);
+ let mut buf = [];
+ assert_eq!(reader.read(&mut buf).unwrap(), 0);
+ assert_eq!(reader.position(), 0);
+ let mut buf = [0];
+ assert_eq!(reader.read(&mut buf).unwrap(), 1);
+ assert_eq!(reader.position(), 1);
+ let b: &[_] = &[0];
+ assert_eq!(buf, b);
+ let mut buf = [0; 4];
+ assert_eq!(reader.read(&mut buf).unwrap(), 4);
+ assert_eq!(reader.position(), 5);
+ let b: &[_] = &[1, 2, 3, 4];
+ assert_eq!(buf, b);
+ assert_eq!(reader.read(&mut buf).unwrap(), 3);
+ let b: &[_] = &[5, 6, 7];
+ assert_eq!(&buf[..3], b);
+ assert_eq!(reader.read(&mut buf).unwrap(), 0);
+ }
+
+ #[test]
+ fn test_mem_reader_vectored() {
+ let mut reader = Cursor::new(vec![0, 1, 2, 3, 4, 5, 6, 7]);
+ let mut buf = [];
+ assert_eq!(reader.read_vectored(&mut [IoVecMut::new(&mut buf)]).unwrap(), 0);
+ assert_eq!(reader.position(), 0);
+ let mut buf = [0];
+ assert_eq!(
+ reader.read_vectored(&mut [IoVecMut::new(&mut []), IoVecMut::new(&mut buf)]).unwrap(),
+ 1,
+ );
+ assert_eq!(reader.position(), 1);
+ let b: &[_] = &[0];
+ assert_eq!(buf, b);
+ let mut buf1 = [0; 4];
+ let mut buf2 = [0; 4];
+ assert_eq!(
+ reader.read_vectored(
+ &mut [IoVecMut::new(&mut buf1), IoVecMut::new(&mut buf2)],
+ ).unwrap(),
+ 7,
+ );
+ let b1: &[_] = &[1, 2, 3, 4];
+ let b2: &[_] = &[5, 6, 7];
+ assert_eq!(buf1, b1);
+ assert_eq!(&buf2[..3], b2);
+ assert_eq!(reader.read(&mut buf).unwrap(), 0);
+ }
+
+ #[test]
+ fn test_boxed_slice_reader() {
+ let mut reader = Cursor::new(vec![0, 1, 2, 3, 4, 5, 6, 7].into_boxed_slice());
+ let mut buf = [];
+ assert_eq!(reader.read(&mut buf).unwrap(), 0);
+ assert_eq!(reader.position(), 0);
+ let mut buf = [0];
+ assert_eq!(reader.read(&mut buf).unwrap(), 1);
+ assert_eq!(reader.position(), 1);
+ let b: &[_] = &[0];
+ assert_eq!(buf, b);
+ let mut buf = [0; 4];
+ assert_eq!(reader.read(&mut buf).unwrap(), 4);
+ assert_eq!(reader.position(), 5);
+ let b: &[_] = &[1, 2, 3, 4];
+ assert_eq!(buf, b);
+ assert_eq!(reader.read(&mut buf).unwrap(), 3);
+ let b: &[_] = &[5, 6, 7];
+ assert_eq!(&buf[..3], b);
+ assert_eq!(reader.read(&mut buf).unwrap(), 0);
+ }
+
+ #[test]
+ fn test_boxed_slice_reader_vectored() {
+ let mut reader = Cursor::new(vec![0, 1, 2, 3, 4, 5, 6, 7].into_boxed_slice());
+ let mut buf = [];
+ assert_eq!(reader.read_vectored(&mut [IoVecMut::new(&mut buf)]).unwrap(), 0);
+ assert_eq!(reader.position(), 0);
+ let mut buf = [0];
+ assert_eq!(
+ reader.read_vectored(&mut [IoVecMut::new(&mut []), IoVecMut::new(&mut buf)]).unwrap(),
+ 1,
+ );
+ assert_eq!(reader.position(), 1);
+ let b: &[_] = &[0];
+ assert_eq!(buf, b);
+ let mut buf1 = [0; 4];
+ let mut buf2 = [0; 4];
+ assert_eq!(
+ reader.read_vectored(
+ &mut [IoVecMut::new(&mut buf1), IoVecMut::new(&mut buf2)],
+ ).unwrap(),
+ 7,
+ );
+ let b1: &[_] = &[1, 2, 3, 4];
+ let b2: &[_] = &[5, 6, 7];
+ assert_eq!(buf1, b1);
+ assert_eq!(&buf2[..3], b2);
+ assert_eq!(reader.read(&mut buf).unwrap(), 0);
+ }
+
+ #[test]
+ fn read_to_end() {
+ let mut reader = Cursor::new(vec![0, 1, 2, 3, 4, 5, 6, 7]);
+ let mut v = Vec::new();
+ reader.read_to_end(&mut v).unwrap();
+ assert_eq!(v, [0, 1, 2, 3, 4, 5, 6, 7]);
+ }
+
+ #[test]
+ fn test_slice_reader() {
+ let in_buf = vec![0, 1, 2, 3, 4, 5, 6, 7];
+ let reader = &mut &in_buf[..];
+ let mut buf = [];
+ assert_eq!(reader.read(&mut buf).unwrap(), 0);
+ let mut buf = [0];
+ assert_eq!(reader.read(&mut buf).unwrap(), 1);
+ assert_eq!(reader.len(), 7);
+ let b: &[_] = &[0];
+ assert_eq!(&buf[..], b);
+ let mut buf = [0; 4];
+ assert_eq!(reader.read(&mut buf).unwrap(), 4);
+ assert_eq!(reader.len(), 3);
+ let b: &[_] = &[1, 2, 3, 4];
+ assert_eq!(&buf[..], b);
+ assert_eq!(reader.read(&mut buf).unwrap(), 3);
+ let b: &[_] = &[5, 6, 7];
+ assert_eq!(&buf[..3], b);
+ assert_eq!(reader.read(&mut buf).unwrap(), 0);
+ }
+
+ #[test]
+ fn test_slice_reader_vectored() {
+ let in_buf = vec![0, 1, 2, 3, 4, 5, 6, 7];
+ let reader = &mut &in_buf[..];
+ let mut buf = [];
+ assert_eq!(reader.read_vectored(&mut [IoVecMut::new(&mut buf)]).unwrap(), 0);
+ let mut buf = [0];
+ assert_eq!(
+ reader.read_vectored(&mut [IoVecMut::new(&mut []), IoVecMut::new(&mut buf)]).unwrap(),
+ 1,
+ );
+ assert_eq!(reader.len(), 7);
+ let b: &[_] = &[0];
+ assert_eq!(buf, b);
+ let mut buf1 = [0; 4];
+ let mut buf2 = [0; 4];
+ assert_eq!(
+ reader.read_vectored(
+ &mut [IoVecMut::new(&mut buf1), IoVecMut::new(&mut buf2)],
+ ).unwrap(),
+ 7,
+ );
+ let b1: &[_] = &[1, 2, 3, 4];
+ let b2: &[_] = &[5, 6, 7];
+ assert_eq!(buf1, b1);
+ assert_eq!(&buf2[..3], b2);
+ assert_eq!(reader.read(&mut buf).unwrap(), 0);
+ }
+
+ #[test]
+ fn test_read_exact() {
+ let in_buf = vec![0, 1, 2, 3, 4, 5, 6, 7];
+ let reader = &mut &in_buf[..];
+ let mut buf = [];
+ assert!(reader.read_exact(&mut buf).is_ok());
+ let mut buf = [8];
+ assert!(reader.read_exact(&mut buf).is_ok());
+ assert_eq!(buf[0], 0);
+ assert_eq!(reader.len(), 7);
+ let mut buf = [0, 0, 0, 0, 0, 0, 0];
+ assert!(reader.read_exact(&mut buf).is_ok());
+ assert_eq!(buf, [1, 2, 3, 4, 5, 6, 7]);
+ assert_eq!(reader.len(), 0);
+ let mut buf = [0];
+ assert!(reader.read_exact(&mut buf).is_err());
+ }
+
+ #[test]
+ fn test_buf_reader() {
+ let in_buf = vec![0, 1, 2, 3, 4, 5, 6, 7];
+ let mut reader = Cursor::new(&in_buf[..]);
+ let mut buf = [];
+ assert_eq!(reader.read(&mut buf).unwrap(), 0);
+ assert_eq!(reader.position(), 0);
+ let mut buf = [0];
+ assert_eq!(reader.read(&mut buf).unwrap(), 1);
+ assert_eq!(reader.position(), 1);
+ let b: &[_] = &[0];
+ assert_eq!(buf, b);
+ let mut buf = [0; 4];
+ assert_eq!(reader.read(&mut buf).unwrap(), 4);
+ assert_eq!(reader.position(), 5);
+ let b: &[_] = &[1, 2, 3, 4];
+ assert_eq!(buf, b);
+ assert_eq!(reader.read(&mut buf).unwrap(), 3);
+ let b: &[_] = &[5, 6, 7];
+ assert_eq!(&buf[..3], b);
+ assert_eq!(reader.read(&mut buf).unwrap(), 0);
+ }
+
+ #[test]
+ fn seek_past_end() {
+ let buf = [0xff];
+ let mut r = Cursor::new(&buf[..]);
+ assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10);
+ assert_eq!(r.read(&mut [0]).unwrap(), 0);
+
+ let mut r = Cursor::new(vec![10]);
+ assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10);
+ assert_eq!(r.read(&mut [0]).unwrap(), 0);
+
+ let mut buf = [0];
+ let mut r = Cursor::new(&mut buf[..]);
+ assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10);
+ assert_eq!(r.write(&[3]).unwrap(), 0);
+
+ let mut r = Cursor::new(vec![10].into_boxed_slice());
+ assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10);
+ assert_eq!(r.write(&[3]).unwrap(), 0);
+ }
+
+ #[test]
+ fn seek_past_i64() {
+ let buf = [0xff];
+ let mut r = Cursor::new(&buf[..]);
+ assert_eq!(r.seek(SeekFrom::Start(6)).unwrap(), 6);
+ assert_eq!(r.seek(SeekFrom::Current(0x7ffffffffffffff0)).unwrap(), 0x7ffffffffffffff6);
+ assert_eq!(r.seek(SeekFrom::Current(0x10)).unwrap(), 0x8000000000000006);
+ assert_eq!(r.seek(SeekFrom::Current(0)).unwrap(), 0x8000000000000006);
+ assert!(r.seek(SeekFrom::Current(0x7ffffffffffffffd)).is_err());
+ assert_eq!(r.seek(SeekFrom::Current(-0x8000000000000000)).unwrap(), 6);
+
+ let mut r = Cursor::new(vec![10]);
+ assert_eq!(r.seek(SeekFrom::Start(6)).unwrap(), 6);
+ assert_eq!(r.seek(SeekFrom::Current(0x7ffffffffffffff0)).unwrap(), 0x7ffffffffffffff6);
+ assert_eq!(r.seek(SeekFrom::Current(0x10)).unwrap(), 0x8000000000000006);
+ assert_eq!(r.seek(SeekFrom::Current(0)).unwrap(), 0x8000000000000006);
+ assert!(r.seek(SeekFrom::Current(0x7ffffffffffffffd)).is_err());
+ assert_eq!(r.seek(SeekFrom::Current(-0x8000000000000000)).unwrap(), 6);
+
+ let mut buf = [0];
+ let mut r = Cursor::new(&mut buf[..]);
+ assert_eq!(r.seek(SeekFrom::Start(6)).unwrap(), 6);
+ assert_eq!(r.seek(SeekFrom::Current(0x7ffffffffffffff0)).unwrap(), 0x7ffffffffffffff6);
+ assert_eq!(r.seek(SeekFrom::Current(0x10)).unwrap(), 0x8000000000000006);
+ assert_eq!(r.seek(SeekFrom::Current(0)).unwrap(), 0x8000000000000006);
+ assert!(r.seek(SeekFrom::Current(0x7ffffffffffffffd)).is_err());
+ assert_eq!(r.seek(SeekFrom::Current(-0x8000000000000000)).unwrap(), 6);
+
+ let mut r = Cursor::new(vec![10].into_boxed_slice());
+ assert_eq!(r.seek(SeekFrom::Start(6)).unwrap(), 6);
+ assert_eq!(r.seek(SeekFrom::Current(0x7ffffffffffffff0)).unwrap(), 0x7ffffffffffffff6);
+ assert_eq!(r.seek(SeekFrom::Current(0x10)).unwrap(), 0x8000000000000006);
+ assert_eq!(r.seek(SeekFrom::Current(0)).unwrap(), 0x8000000000000006);
+ assert!(r.seek(SeekFrom::Current(0x7ffffffffffffffd)).is_err());
+ assert_eq!(r.seek(SeekFrom::Current(-0x8000000000000000)).unwrap(), 6);
+ }
+
+ #[test]
+ fn seek_before_0() {
+ let buf = [0xff];
+ let mut r = Cursor::new(&buf[..]);
+ assert!(r.seek(SeekFrom::End(-2)).is_err());
+
+ let mut r = Cursor::new(vec![10]);
+ assert!(r.seek(SeekFrom::End(-2)).is_err());
+
+ let mut buf = [0];
+ let mut r = Cursor::new(&mut buf[..]);
+ assert!(r.seek(SeekFrom::End(-2)).is_err());
+
+ let mut r = Cursor::new(vec![10].into_boxed_slice());
+ assert!(r.seek(SeekFrom::End(-2)).is_err());
+ }
+
+ #[test]
+ fn test_seekable_mem_writer() {
+ let mut writer = Cursor::new(Vec::<u8>::new());
+ assert_eq!(writer.position(), 0);
+ assert_eq!(writer.write(&[0]).unwrap(), 1);
+ assert_eq!(writer.position(), 1);
+ assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3);
+ assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4);
+ assert_eq!(writer.position(), 8);
+ let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7];
+ assert_eq!(&writer.get_ref()[..], b);
+
+ assert_eq!(writer.seek(SeekFrom::Start(0)).unwrap(), 0);
+ assert_eq!(writer.position(), 0);
+ assert_eq!(writer.write(&[3, 4]).unwrap(), 2);
+ let b: &[_] = &[3, 4, 2, 3, 4, 5, 6, 7];
+ assert_eq!(&writer.get_ref()[..], b);
+
+ assert_eq!(writer.seek(SeekFrom::Current(1)).unwrap(), 3);
+ assert_eq!(writer.write(&[0, 1]).unwrap(), 2);
+ let b: &[_] = &[3, 4, 2, 0, 1, 5, 6, 7];
+ assert_eq!(&writer.get_ref()[..], b);
+
+ assert_eq!(writer.seek(SeekFrom::End(-1)).unwrap(), 7);
+ assert_eq!(writer.write(&[1, 2]).unwrap(), 2);
+ let b: &[_] = &[3, 4, 2, 0, 1, 5, 6, 1, 2];
+ assert_eq!(&writer.get_ref()[..], b);
+
+ assert_eq!(writer.seek(SeekFrom::End(1)).unwrap(), 10);
+ assert_eq!(writer.write(&[1]).unwrap(), 1);
+ let b: &[_] = &[3, 4, 2, 0, 1, 5, 6, 1, 2, 0, 1];
+ assert_eq!(&writer.get_ref()[..], b);
+ }
+
+ #[test]
+ fn vec_seek_past_end() {
+ let mut r = Cursor::new(Vec::new());
+ assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10);
+ assert_eq!(r.write(&[3]).unwrap(), 1);
+ }
+
+ #[test]
+ fn vec_seek_before_0() {
+ let mut r = Cursor::new(Vec::new());
+ assert!(r.seek(SeekFrom::End(-2)).is_err());
+ }
+
+ #[test]
+ #[cfg(target_pointer_width = "32")]
+ fn vec_seek_and_write_past_usize_max() {
+ let mut c = Cursor::new(Vec::new());
+ c.set_position(<usize>::max_value() as u64 + 1);
+ assert!(c.write_all(&[1, 2, 3]).is_err());
+ }
+}
diff --git a/src/libstd/io/error.rs b/src/libstd/io/error.rs
new file mode 100644
index 0000000..c29a68e
--- /dev/null
+++ b/src/libstd/io/error.rs
@@ -0,0 +1,635 @@
+use crate::error;
+use crate::fmt;
+use crate::result;
+use crate::sys;
+use crate::convert::From;
+
+/// A specialized [`Result`](../result/enum.Result.html) type for I/O
+/// operations.
+///
+/// This type is broadly used across [`std::io`] for any operation which may
+/// produce an error.
+///
+/// This typedef is generally used to avoid writing out [`io::Error`] directly and
+/// is otherwise a direct mapping to [`Result`].
+///
+/// While usual Rust style is to import types directly, aliases of [`Result`]
+/// often are not, to make it easier to distinguish between them. [`Result`] is
+/// generally assumed to be [`std::result::Result`][`Result`], and so users of this alias
+/// will generally use `io::Result` instead of shadowing the prelude's import
+/// of [`std::result::Result`][`Result`].
+///
+/// [`std::io`]: ../io/index.html
+/// [`io::Error`]: ../io/struct.Error.html
+/// [`Result`]: ../result/enum.Result.html
+///
+/// # Examples
+///
+/// A convenience function that bubbles an `io::Result` to its caller:
+///
+/// ```
+/// use std::io;
+///
+/// fn get_string() -> io::Result<String> {
+/// let mut buffer = String::new();
+///
+/// io::stdin().read_line(&mut buffer)?;
+///
+/// Ok(buffer)
+/// }
+/// ```
+#[stable(feature = "rust1", since = "1.0.0")]
+pub type Result<T> = result::Result<T, Error>;
+
+/// The error type for I/O operations of the [`Read`], [`Write`], [`Seek`], and
+/// associated traits.
+///
+/// Errors mostly originate from the underlying OS, but custom instances of
+/// `Error` can be created with crafted error messages and a particular value of
+/// [`ErrorKind`].
+///
+/// [`Read`]: ../io/trait.Read.html
+/// [`Write`]: ../io/trait.Write.html
+/// [`Seek`]: ../io/trait.Seek.html
+/// [`ErrorKind`]: enum.ErrorKind.html
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct Error {
+ repr: Repr,
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl fmt::Debug for Error {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt::Debug::fmt(&self.repr, f)
+ }
+}
+
+enum Repr {
+ Os(i32),
+ Simple(ErrorKind),
+ Custom(Box<Custom>),
+}
+
+#[derive(Debug)]
+struct Custom {
+ kind: ErrorKind,
+ error: Box<dyn error::Error+Send+Sync>,
+}
+
+/// A list specifying general categories of I/O error.
+///
+/// This list is intended to grow over time and it is not recommended to
+/// exhaustively match against it.
+///
+/// It is used with the [`io::Error`] type.
+///
+/// [`io::Error`]: struct.Error.html
+#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
+#[stable(feature = "rust1", since = "1.0.0")]
+#[allow(deprecated)]
+#[non_exhaustive]
+pub enum ErrorKind {
+ /// An entity was not found, often a file.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ NotFound,
+ /// The operation lacked the necessary privileges to complete.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ PermissionDenied,
+ /// The connection was refused by the remote server.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ ConnectionRefused,
+ /// The connection was reset by the remote server.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ ConnectionReset,
+ /// The connection was aborted (terminated) by the remote server.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ ConnectionAborted,
+ /// The network operation failed because it was not connected yet.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ NotConnected,
+ /// A socket address could not be bound because the address is already in
+ /// use elsewhere.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ AddrInUse,
+ /// A nonexistent interface was requested or the requested address was not
+ /// local.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ AddrNotAvailable,
+ /// The operation failed because a pipe was closed.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ BrokenPipe,
+ /// An entity already exists, often a file.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ AlreadyExists,
+ /// The operation needs to block to complete, but the blocking operation was
+ /// requested to not occur.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ WouldBlock,
+ /// A parameter was incorrect.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ InvalidInput,
+ /// Data not valid for the operation were encountered.
+ ///
+ /// Unlike [`InvalidInput`], this typically means that the operation
+ /// parameters were valid, however the error was caused by malformed
+ /// input data.
+ ///
+ /// For example, a function that reads a file into a string will error with
+ /// `InvalidData` if the file's contents are not valid UTF-8.
+ ///
+ /// [`InvalidInput`]: #variant.InvalidInput
+ #[stable(feature = "io_invalid_data", since = "1.2.0")]
+ InvalidData,
+ /// The I/O operation's timeout expired, causing it to be canceled.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ TimedOut,
+ /// An error returned when an operation could not be completed because a
+ /// call to [`write`] returned [`Ok(0)`].
+ ///
+ /// This typically means that an operation could only succeed if it wrote a
+ /// particular number of bytes but only a smaller number of bytes could be
+ /// written.
+ ///
+ /// [`write`]: ../../std/io/trait.Write.html#tymethod.write
+ /// [`Ok(0)`]: ../../std/io/type.Result.html
+ #[stable(feature = "rust1", since = "1.0.0")]
+ WriteZero,
+ /// This operation was interrupted.
+ ///
+ /// Interrupted operations can typically be retried.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ Interrupted,
+ /// Any I/O error not part of this list.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ Other,
+
+ /// An error returned when an operation could not be completed because an
+ /// "end of file" was reached prematurely.
+ ///
+ /// This typically means that an operation could only succeed if it read a
+ /// particular number of bytes but only a smaller number of bytes could be
+ /// read.
+ #[stable(feature = "read_exact", since = "1.6.0")]
+ UnexpectedEof,
+}
+
+impl ErrorKind {
+ pub(crate) fn as_str(&self) -> &'static str {
+ match *self {
+ ErrorKind::NotFound => "entity not found",
+ ErrorKind::PermissionDenied => "permission denied",
+ ErrorKind::ConnectionRefused => "connection refused",
+ ErrorKind::ConnectionReset => "connection reset",
+ ErrorKind::ConnectionAborted => "connection aborted",
+ ErrorKind::NotConnected => "not connected",
+ ErrorKind::AddrInUse => "address in use",
+ ErrorKind::AddrNotAvailable => "address not available",
+ ErrorKind::BrokenPipe => "broken pipe",
+ ErrorKind::AlreadyExists => "entity already exists",
+ ErrorKind::WouldBlock => "operation would block",
+ ErrorKind::InvalidInput => "invalid input parameter",
+ ErrorKind::InvalidData => "invalid data",
+ ErrorKind::TimedOut => "timed out",
+ ErrorKind::WriteZero => "write zero",
+ ErrorKind::Interrupted => "operation interrupted",
+ ErrorKind::Other => "other os error",
+ ErrorKind::UnexpectedEof => "unexpected end of file",
+ }
+ }
+}
+
+/// Intended for use for errors not exposed to the user, where allocating onto
+/// the heap (for normal construction via Error::new) is too costly.
+#[stable(feature = "io_error_from_errorkind", since = "1.14.0")]
+impl From<ErrorKind> for Error {
+ /// Converts an [`ErrorKind`] into an [`Error`].
+ ///
+ /// This conversion allocates a new error with a simple representation of error kind.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::io::{Error, ErrorKind};
+ ///
+ /// let not_found = ErrorKind::NotFound;
+ /// let error = Error::from(not_found);
+ /// assert_eq!("entity not found", format!("{}", error));
+ /// ```
+ ///
+ /// [`ErrorKind`]: ../../std/io/enum.ErrorKind.html
+ /// [`Error`]: ../../std/io/struct.Error.html
+ #[inline]
+ fn from(kind: ErrorKind) -> Error {
+ Error {
+ repr: Repr::Simple(kind)
+ }
+ }
+}
+
+impl Error {
+ /// Creates a new I/O error from a known kind of error as well as an
+ /// arbitrary error payload.
+ ///
+ /// This function is used to generically create I/O errors which do not
+ /// originate from the OS itself. The `error` argument is an arbitrary
+ /// payload which will be contained in this `Error`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::io::{Error, ErrorKind};
+ ///
+ /// // errors can be created from strings
+ /// let custom_error = Error::new(ErrorKind::Other, "oh no!");
+ ///
+ /// // errors can also be created from other errors
+ /// let custom_error2 = Error::new(ErrorKind::Interrupted, custom_error);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn new<E>(kind: ErrorKind, error: E) -> Error
+ where E: Into<Box<dyn error::Error+Send+Sync>>
+ {
+ Self::_new(kind, error.into())
+ }
+
+ fn _new(kind: ErrorKind, error: Box<dyn error::Error+Send+Sync>) -> Error {
+ Error {
+ repr: Repr::Custom(Box::new(Custom {
+ kind,
+ error,
+ }))
+ }
+ }
+
+ /// Returns an error representing the last OS error which occurred.
+ ///
+ /// This function reads the value of `errno` for the target platform (e.g.
+ /// `GetLastError` on Windows) and will return a corresponding instance of
+ /// `Error` for the error code.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::io::Error;
+ ///
+ /// println!("last OS error: {:?}", Error::last_os_error());
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn last_os_error() -> Error {
+ Error::from_raw_os_error(sys::os::errno() as i32)
+ }
+
+ /// Creates a new instance of an `Error` from a particular OS error code.
+ ///
+ /// # Examples
+ ///
+ /// On Linux:
+ ///
+ /// ```
+ /// # if cfg!(target_os = "linux") {
+ /// use std::io;
+ ///
+ /// let error = io::Error::from_raw_os_error(22);
+ /// assert_eq!(error.kind(), io::ErrorKind::InvalidInput);
+ /// # }
+ /// ```
+ ///
+ /// On Windows:
+ ///
+ /// ```
+ /// # if cfg!(windows) {
+ /// use std::io;
+ ///
+ /// let error = io::Error::from_raw_os_error(10022);
+ /// assert_eq!(error.kind(), io::ErrorKind::InvalidInput);
+ /// # }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn from_raw_os_error(code: i32) -> Error {
+ Error { repr: Repr::Os(code) }
+ }
+
+ /// Returns the OS error that this error represents (if any).
+ ///
+ /// If this `Error` was constructed via `last_os_error` or
+ /// `from_raw_os_error`, then this function will return `Some`, otherwise
+ /// it will return `None`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::io::{Error, ErrorKind};
+ ///
+ /// fn print_os_error(err: &Error) {
+ /// if let Some(raw_os_err) = err.raw_os_error() {
+ /// println!("raw OS error: {:?}", raw_os_err);
+ /// } else {
+ /// println!("Not an OS error");
+ /// }
+ /// }
+ ///
+ /// fn main() {
+ /// // Will print "raw OS error: ...".
+ /// print_os_error(&Error::last_os_error());
+ /// // Will print "Not an OS error".
+ /// print_os_error(&Error::new(ErrorKind::Other, "oh no!"));
+ /// }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn raw_os_error(&self) -> Option<i32> {
+ match self.repr {
+ Repr::Os(i) => Some(i),
+ Repr::Custom(..) => None,
+ Repr::Simple(..) => None,
+ }
+ }
+
+ /// Returns a reference to the inner error wrapped by this error (if any).
+ ///
+ /// If this `Error` was constructed via `new` then this function will
+ /// return `Some`, otherwise it will return `None`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::io::{Error, ErrorKind};
+ ///
+ /// fn print_error(err: &Error) {
+ /// if let Some(inner_err) = err.get_ref() {
+ /// println!("Inner error: {:?}", inner_err);
+ /// } else {
+ /// println!("No inner error");
+ /// }
+ /// }
+ ///
+ /// fn main() {
+ /// // Will print "No inner error".
+ /// print_error(&Error::last_os_error());
+ /// // Will print "Inner error: ...".
+ /// print_error(&Error::new(ErrorKind::Other, "oh no!"));
+ /// }
+ /// ```
+ #[stable(feature = "io_error_inner", since = "1.3.0")]
+ pub fn get_ref(&self) -> Option<&(dyn error::Error+Send+Sync+'static)> {
+ match self.repr {
+ Repr::Os(..) => None,
+ Repr::Simple(..) => None,
+ Repr::Custom(ref c) => Some(&*c.error),
+ }
+ }
+
+ /// Returns a mutable reference to the inner error wrapped by this error
+ /// (if any).
+ ///
+ /// If this `Error` was constructed via `new` then this function will
+ /// return `Some`, otherwise it will return `None`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::io::{Error, ErrorKind};
+ /// use std::{error, fmt};
+ /// use std::fmt::Display;
+ ///
+ /// #[derive(Debug)]
+ /// struct MyError {
+ /// v: String,
+ /// }
+ ///
+ /// impl MyError {
+ /// fn new() -> MyError {
+ /// MyError {
+ /// v: "oh no!".to_string()
+ /// }
+ /// }
+ ///
+ /// fn change_message(&mut self, new_message: &str) {
+ /// self.v = new_message.to_string();
+ /// }
+ /// }
+ ///
+ /// impl error::Error for MyError {
+ /// fn description(&self) -> &str { &self.v }
+ /// }
+ ///
+ /// impl Display for MyError {
+ /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ /// write!(f, "MyError: {}", &self.v)
+ /// }
+ /// }
+ ///
+ /// fn change_error(mut err: Error) -> Error {
+ /// if let Some(inner_err) = err.get_mut() {
+ /// inner_err.downcast_mut::<MyError>().unwrap().change_message("I've been changed!");
+ /// }
+ /// err
+ /// }
+ ///
+ /// fn print_error(err: &Error) {
+ /// if let Some(inner_err) = err.get_ref() {
+ /// println!("Inner error: {}", inner_err);
+ /// } else {
+ /// println!("No inner error");
+ /// }
+ /// }
+ ///
+ /// fn main() {
+ /// // Will print "No inner error".
+ /// print_error(&change_error(Error::last_os_error()));
+ /// // Will print "Inner error: ...".
+ /// print_error(&change_error(Error::new(ErrorKind::Other, MyError::new())));
+ /// }
+ /// ```
+ #[stable(feature = "io_error_inner", since = "1.3.0")]
+ pub fn get_mut(&mut self) -> Option<&mut (dyn error::Error+Send+Sync+'static)> {
+ match self.repr {
+ Repr::Os(..) => None,
+ Repr::Simple(..) => None,
+ Repr::Custom(ref mut c) => Some(&mut *c.error),
+ }
+ }
+
+ /// Consumes the `Error`, returning its inner error (if any).
+ ///
+ /// If this `Error` was constructed via `new` then this function will
+ /// return `Some`, otherwise it will return `None`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::io::{Error, ErrorKind};
+ ///
+ /// fn print_error(err: Error) {
+ /// if let Some(inner_err) = err.into_inner() {
+ /// println!("Inner error: {}", inner_err);
+ /// } else {
+ /// println!("No inner error");
+ /// }
+ /// }
+ ///
+ /// fn main() {
+ /// // Will print "No inner error".
+ /// print_error(Error::last_os_error());
+ /// // Will print "Inner error: ...".
+ /// print_error(Error::new(ErrorKind::Other, "oh no!"));
+ /// }
+ /// ```
+ #[stable(feature = "io_error_inner", since = "1.3.0")]
+ pub fn into_inner(self) -> Option<Box<dyn error::Error+Send+Sync>> {
+ match self.repr {
+ Repr::Os(..) => None,
+ Repr::Simple(..) => None,
+ Repr::Custom(c) => Some(c.error)
+ }
+ }
+
+ /// Returns the corresponding `ErrorKind` for this error.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::io::{Error, ErrorKind};
+ ///
+ /// fn print_error(err: Error) {
+ /// println!("{:?}", err.kind());
+ /// }
+ ///
+ /// fn main() {
+ /// // Will print "No inner error".
+ /// print_error(Error::last_os_error());
+ /// // Will print "Inner error: ...".
+ /// print_error(Error::new(ErrorKind::AddrInUse, "oh no!"));
+ /// }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn kind(&self) -> ErrorKind {
+ match self.repr {
+ Repr::Os(code) => sys::decode_error_kind(code),
+ Repr::Custom(ref c) => c.kind,
+ Repr::Simple(kind) => kind,
+ }
+ }
+}
+
+impl fmt::Debug for Repr {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match *self {
+ Repr::Os(code) =>
+ fmt.debug_struct("Os")
+ .field("code", &code)
+ .field("kind", &sys::decode_error_kind(code))
+ .field("message", &sys::os::error_string(code)).finish(),
+ Repr::Custom(ref c) => fmt::Debug::fmt(&c, fmt),
+ Repr::Simple(kind) => fmt.debug_tuple("Kind").field(&kind).finish(),
+ }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl fmt::Display for Error {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self.repr {
+ Repr::Os(code) => {
+ let detail = sys::os::error_string(code);
+ write!(fmt, "{} (os error {})", detail, code)
+ }
+ Repr::Custom(ref c) => c.error.fmt(fmt),
+ Repr::Simple(kind) => write!(fmt, "{}", kind.as_str()),
+ }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl error::Error for Error {
+ fn description(&self) -> &str {
+ match self.repr {
+ Repr::Os(..) | Repr::Simple(..) => self.kind().as_str(),
+ Repr::Custom(ref c) => c.error.description(),
+ }
+ }
+
+ #[allow(deprecated)]
+ fn cause(&self) -> Option<&dyn error::Error> {
+ match self.repr {
+ Repr::Os(..) => None,
+ Repr::Simple(..) => None,
+ Repr::Custom(ref c) => c.error.cause(),
+ }
+ }
+
+ fn source(&self) -> Option<&(dyn error::Error + 'static)> {
+ match self.repr {
+ Repr::Os(..) => None,
+ Repr::Simple(..) => None,
+ Repr::Custom(ref c) => c.error.source(),
+ }
+ }
+}
+
+fn _assert_error_is_sync_send() {
+ fn _is_sync_send<T: Sync+Send>() {}
+ _is_sync_send::<Error>();
+}
+
+#[cfg(test)]
+mod test {
+ use super::{Error, ErrorKind, Repr, Custom};
+ use crate::error;
+ use crate::fmt;
+ use crate::sys::os::error_string;
+ use crate::sys::decode_error_kind;
+
+ #[test]
+ fn test_debug_error() {
+ let code = 6;
+ let msg = error_string(code);
+ let kind = decode_error_kind(code);
+ let err = Error {
+ repr: Repr::Custom(box Custom {
+ kind: ErrorKind::InvalidInput,
+ error: box Error {
+ repr: super::Repr::Os(code)
+ },
+ })
+ };
+ let expected = format!(
+ "Custom {{ \
+ kind: InvalidInput, \
+ error: Os {{ \
+ code: {:?}, \
+ kind: {:?}, \
+ message: {:?} \
+ }} \
+ }}",
+ code, kind, msg
+ );
+ assert_eq!(format!("{:?}", err), expected);
+ }
+
+ #[test]
+ fn test_downcasting() {
+ #[derive(Debug)]
+ struct TestError;
+
+ impl fmt::Display for TestError {
+ fn fmt(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result {
+ Ok(())
+ }
+ }
+
+ impl error::Error for TestError {
+ fn description(&self) -> &str {
+ "asdf"
+ }
+ }
+
+ // we have to call all of these UFCS style right now since method
+ // resolution won't implicitly drop the Send+Sync bounds
+ let mut err = Error::new(ErrorKind::Other, TestError);
+ assert!(err.get_ref().unwrap().is::<TestError>());
+ assert_eq!("asdf", err.get_ref().unwrap().description());
+ assert!(err.get_mut().unwrap().is::<TestError>());
+ let extracted = err.into_inner().unwrap();
+ extracted.downcast::<TestError>().unwrap();
+ }
+}
diff --git a/src/libstd/io/impls.rs b/src/libstd/io/impls.rs
new file mode 100644
index 0000000..0eac96f
--- /dev/null
+++ b/src/libstd/io/impls.rs
@@ -0,0 +1,397 @@
+use crate::cmp;
+use crate::io::{self, SeekFrom, Read, Initializer, Write, Seek, BufRead, Error, ErrorKind, IoVecMut,
+ IoVec};
+use crate::fmt;
+use crate::mem;
+
+// =============================================================================
+// Forwarding implementations
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<R: Read + ?Sized> Read for &mut R {
+ #[inline]
+ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+ (**self).read(buf)
+ }
+
+ #[inline]
+ fn read_vectored(&mut self, bufs: &mut [IoVecMut<'_>]) -> io::Result<usize> {
+ (**self).read_vectored(bufs)
+ }
+
+ #[inline]
+ unsafe fn initializer(&self) -> Initializer {
+ (**self).initializer()
+ }
+
+ #[inline]
+ fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
+ (**self).read_to_end(buf)
+ }
+
+ #[inline]
+ fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
+ (**self).read_to_string(buf)
+ }
+
+ #[inline]
+ fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
+ (**self).read_exact(buf)
+ }
+}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<W: Write + ?Sized> Write for &mut W {
+ #[inline]
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> { (**self).write(buf) }
+
+ #[inline]
+ fn write_vectored(&mut self, bufs: &[IoVec<'_>]) -> io::Result<usize> {
+ (**self).write_vectored(bufs)
+ }
+
+ #[inline]
+ fn flush(&mut self) -> io::Result<()> { (**self).flush() }
+
+ #[inline]
+ fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
+ (**self).write_all(buf)
+ }
+
+ #[inline]
+ fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> io::Result<()> {
+ (**self).write_fmt(fmt)
+ }
+}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<S: Seek + ?Sized> Seek for &mut S {
+ #[inline]
+ fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> { (**self).seek(pos) }
+}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<B: BufRead + ?Sized> BufRead for &mut B {
+ #[inline]
+ fn fill_buf(&mut self) -> io::Result<&[u8]> { (**self).fill_buf() }
+
+ #[inline]
+ fn consume(&mut self, amt: usize) { (**self).consume(amt) }
+
+ #[inline]
+ fn read_until(&mut self, byte: u8, buf: &mut Vec<u8>) -> io::Result<usize> {
+ (**self).read_until(byte, buf)
+ }
+
+ #[inline]
+ fn read_line(&mut self, buf: &mut String) -> io::Result<usize> {
+ (**self).read_line(buf)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<R: Read + ?Sized> Read for Box<R> {
+ #[inline]
+ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+ (**self).read(buf)
+ }
+
+ #[inline]
+ fn read_vectored(&mut self, bufs: &mut [IoVecMut<'_>]) -> io::Result<usize> {
+ (**self).read_vectored(bufs)
+ }
+
+ #[inline]
+ unsafe fn initializer(&self) -> Initializer {
+ (**self).initializer()
+ }
+
+ #[inline]
+ fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
+ (**self).read_to_end(buf)
+ }
+
+ #[inline]
+ fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
+ (**self).read_to_string(buf)
+ }
+
+ #[inline]
+ fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
+ (**self).read_exact(buf)
+ }
+}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<W: Write + ?Sized> Write for Box<W> {
+ #[inline]
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> { (**self).write(buf) }
+
+ #[inline]
+ fn write_vectored(&mut self, bufs: &[IoVec<'_>]) -> io::Result<usize> {
+ (**self).write_vectored(bufs)
+ }
+
+ #[inline]
+ fn flush(&mut self) -> io::Result<()> { (**self).flush() }
+
+ #[inline]
+ fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
+ (**self).write_all(buf)
+ }
+
+ #[inline]
+ fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> io::Result<()> {
+ (**self).write_fmt(fmt)
+ }
+}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<S: Seek + ?Sized> Seek for Box<S> {
+ #[inline]
+ fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> { (**self).seek(pos) }
+}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<B: BufRead + ?Sized> BufRead for Box<B> {
+ #[inline]
+ fn fill_buf(&mut self) -> io::Result<&[u8]> { (**self).fill_buf() }
+
+ #[inline]
+ fn consume(&mut self, amt: usize) { (**self).consume(amt) }
+
+ #[inline]
+ fn read_until(&mut self, byte: u8, buf: &mut Vec<u8>) -> io::Result<usize> {
+ (**self).read_until(byte, buf)
+ }
+
+ #[inline]
+ fn read_line(&mut self, buf: &mut String) -> io::Result<usize> {
+ (**self).read_line(buf)
+ }
+}
+
+// Used by panicking::default_hook
+#[cfg(test)]
+/// This impl is only used by printing logic, so any error returned is always
+/// of kind `Other`, and should be ignored.
+impl Write for Box<dyn (::realstd::io::Write) + Send> {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ (**self).write(buf).map_err(|_| ErrorKind::Other.into())
+ }
+
+ fn flush(&mut self) -> io::Result<()> {
+ (**self).flush().map_err(|_| ErrorKind::Other.into())
+ }
+}
+
+// =============================================================================
+// In-memory buffer implementations
+
+/// Read is implemented for `&[u8]` by copying from the slice.
+///
+/// Note that reading updates the slice to point to the yet unread part.
+/// The slice will be empty when EOF is reached.
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Read for &[u8] {
+ #[inline]
+ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+ let amt = cmp::min(buf.len(), self.len());
+ let (a, b) = self.split_at(amt);
+
+ // First check if the amount of bytes we want to read is small:
+ // `copy_from_slice` will generally expand to a call to `memcpy`, and
+ // for a single byte the overhead is significant.
+ if amt == 1 {
+ buf[0] = a[0];
+ } else {
+ buf[..amt].copy_from_slice(a);
+ }
+
+ *self = b;
+ Ok(amt)
+ }
+
+ #[inline]
+ fn read_vectored(&mut self, bufs: &mut [IoVecMut<'_>]) -> io::Result<usize> {
+ let mut nread = 0;
+ for buf in bufs {
+ nread += self.read(buf)?;
+ if self.is_empty() {
+ break;
+ }
+ }
+
+ Ok(nread)
+ }
+
+ #[inline]
+ unsafe fn initializer(&self) -> Initializer {
+ Initializer::nop()
+ }
+
+ #[inline]
+ fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
+ if buf.len() > self.len() {
+ return Err(Error::new(ErrorKind::UnexpectedEof,
+ "failed to fill whole buffer"));
+ }
+ let (a, b) = self.split_at(buf.len());
+
+ // First check if the amount of bytes we want to read is small:
+ // `copy_from_slice` will generally expand to a call to `memcpy`, and
+ // for a single byte the overhead is significant.
+ if buf.len() == 1 {
+ buf[0] = a[0];
+ } else {
+ buf.copy_from_slice(a);
+ }
+
+ *self = b;
+ Ok(())
+ }
+
+ #[inline]
+ fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
+ buf.extend_from_slice(*self);
+ let len = self.len();
+ *self = &self[len..];
+ Ok(len)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl BufRead for &[u8] {
+ #[inline]
+ fn fill_buf(&mut self) -> io::Result<&[u8]> { Ok(*self) }
+
+ #[inline]
+ fn consume(&mut self, amt: usize) { *self = &self[amt..]; }
+}
+
+/// Write is implemented for `&mut [u8]` by copying into the slice, overwriting
+/// its data.
+///
+/// Note that writing updates the slice to point to the yet unwritten part.
+/// The slice will be empty when it has been completely overwritten.
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Write for &mut [u8] {
+ #[inline]
+ fn write(&mut self, data: &[u8]) -> io::Result<usize> {
+ let amt = cmp::min(data.len(), self.len());
+ let (a, b) = mem::replace(self, &mut []).split_at_mut(amt);
+ a.copy_from_slice(&data[..amt]);
+ *self = b;
+ Ok(amt)
+ }
+
+ #[inline]
+ fn write_vectored(&mut self, bufs: &[IoVec<'_>]) -> io::Result<usize> {
+ let mut nwritten = 0;
+ for buf in bufs {
+ nwritten += self.write(buf)?;
+ if self.is_empty() {
+ break;
+ }
+ }
+
+ Ok(nwritten)
+ }
+
+ #[inline]
+ fn write_all(&mut self, data: &[u8]) -> io::Result<()> {
+ if self.write(data)? == data.len() {
+ Ok(())
+ } else {
+ Err(Error::new(ErrorKind::WriteZero, "failed to write whole buffer"))
+ }
+ }
+
+ #[inline]
+ fn flush(&mut self) -> io::Result<()> { Ok(()) }
+}
+
+/// Write is implemented for `Vec<u8>` by appending to the vector.
+/// The vector will grow as needed.
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Write for Vec<u8> {
+ #[inline]
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ self.extend_from_slice(buf);
+ Ok(buf.len())
+ }
+
+ #[inline]
+ fn write_vectored(&mut self, bufs: &[IoVec<'_>]) -> io::Result<usize> {
+ let len = bufs.iter().map(|b| b.len()).sum();
+ self.reserve(len);
+ for buf in bufs {
+ self.extend_from_slice(buf);
+ }
+ Ok(len)
+ }
+
+ #[inline]
+ fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
+ self.extend_from_slice(buf);
+ Ok(())
+ }
+
+ #[inline]
+ fn flush(&mut self) -> io::Result<()> { Ok(()) }
+}
+
+#[cfg(test)]
+mod tests {
+ use crate::io::prelude::*;
+
+ #[bench]
+ fn bench_read_slice(b: &mut test::Bencher) {
+ let buf = [5; 1024];
+ let mut dst = [0; 128];
+
+ b.iter(|| {
+ let mut rd = &buf[..];
+ for _ in 0..8 {
+ let _ = rd.read(&mut dst);
+ test::black_box(&dst);
+ }
+ })
+ }
+
+ #[bench]
+ fn bench_write_slice(b: &mut test::Bencher) {
+ let mut buf = [0; 1024];
+ let src = [5; 128];
+
+ b.iter(|| {
+ let mut wr = &mut buf[..];
+ for _ in 0..8 {
+ let _ = wr.write_all(&src);
+ test::black_box(&wr);
+ }
+ })
+ }
+
+ #[bench]
+ fn bench_read_vec(b: &mut test::Bencher) {
+ let buf = vec![5; 1024];
+ let mut dst = [0; 128];
+
+ b.iter(|| {
+ let mut rd = &buf[..];
+ for _ in 0..8 {
+ let _ = rd.read(&mut dst);
+ test::black_box(&dst);
+ }
+ })
+ }
+
+ #[bench]
+ fn bench_write_vec(b: &mut test::Bencher) {
+ let mut buf = Vec::with_capacity(1024);
+ let src = [5; 128];
+
+ b.iter(|| {
+ let mut wr = &mut buf[..];
+ for _ in 0..8 {
+ let _ = wr.write_all(&src);
+ test::black_box(&wr);
+ }
+ })
+ }
+}
diff --git a/src/libstd/io/lazy.rs b/src/libstd/io/lazy.rs
new file mode 100644
index 0000000..e864aa2
--- /dev/null
+++ b/src/libstd/io/lazy.rs
@@ -0,0 +1,64 @@
+use crate::cell::Cell;
+use crate::ptr;
+use crate::sync::Arc;
+use crate::sys_common;
+use crate::sys_common::mutex::Mutex;
+
+pub struct Lazy<T> {
+ // We never call `lock.init()`, so it is UB to attempt to acquire this mutex reentrantly!
+ lock: Mutex,
+ ptr: Cell<*mut Arc<T>>,
+}
+
+#[inline]
+const fn done<T>() -> *mut Arc<T> { 1_usize as *mut _ }
+
+unsafe impl<T> Sync for Lazy<T> {}
+
+impl<T> Lazy<T> {
+ pub const fn new() -> Lazy<T> {
+ Lazy {
+ lock: Mutex::new(),
+ ptr: Cell::new(ptr::null_mut()),
+ }
+ }
+}
+
+impl<T: Send + Sync + 'static> Lazy<T> {
+ /// Safety: `init` must not call `get` on the variable that is being
+ /// initialized.
+ pub unsafe fn get(&'static self, init: fn() -> Arc<T>) -> Option<Arc<T>> {
+ let _guard = self.lock.lock();
+ let ptr = self.ptr.get();
+ if ptr.is_null() {
+ Some(self.init(init))
+ } else if ptr == done() {
+ None
+ } else {
+ Some((*ptr).clone())
+ }
+ }
+
+ // Must only be called with `lock` held
+ unsafe fn init(&'static self, init: fn() -> Arc<T>) -> Arc<T> {
+ // If we successfully register an at exit handler, then we cache the
+ // `Arc` allocation in our own internal box (it will get deallocated by
+ // the at exit handler). Otherwise we just return the freshly allocated
+ // `Arc`.
+ let registered = sys_common::at_exit(move || {
+ let ptr = {
+ let _guard = self.lock.lock();
+ self.ptr.replace(done())
+ };
+ drop(Box::from_raw(ptr))
+ });
+ // This could reentrantly call `init` again, which is a problem
+ // because our `lock` allows reentrancy!
+ // That's why `get` is unsafe and requires the caller to ensure no reentrancy happens.
+ let ret = init();
+ if registered.is_ok() {
+ self.ptr.set(Box::into_raw(Box::new(ret.clone())));
+ }
+ ret
+ }
+}
diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs
new file mode 100644
index 0000000..1ce66b9
--- /dev/null
+++ b/src/libstd/io/mod.rs
@@ -0,0 +1,2536 @@
+//! Traits, helpers, and type definitions for core I/O functionality.
+//!
+//! The `std::io` module contains a number of common things you'll need
+//! when doing input and output. The most core part of this module is
+//! the [`Read`] and [`Write`] traits, which provide the
+//! most general interface for reading and writing input and output.
+//!
+//! # Read and Write
+//!
+//! Because they are traits, [`Read`] and [`Write`] are implemented by a number
+//! of other types, and you can implement them for your types too. As such,
+//! you'll see a few different types of I/O throughout the documentation in
+//! this module: [`File`]s, [`TcpStream`]s, and sometimes even [`Vec<T>`]s. For
+//! example, [`Read`] adds a [`read`][`Read::read`] method, which we can use on
+//! [`File`]s:
+//!
+//! ```no_run
+//! use std::io;
+//! use std::io::prelude::*;
+//! use std::fs::File;
+//!
+//! fn main() -> io::Result<()> {
+//! let mut f = File::open("foo.txt")?;
+//! let mut buffer = [0; 10];
+//!
+//! // read up to 10 bytes
+//! let n = f.read(&mut buffer)?;
+//!
+//! println!("The bytes: {:?}", &buffer[..n]);
+//! Ok(())
+//! }
+//! ```
+//!
+//! [`Read`] and [`Write`] are so important, implementors of the two traits have a
+//! nickname: readers and writers. So you'll sometimes see 'a reader' instead
+//! of 'a type that implements the [`Read`] trait'. Much easier!
+//!
+//! ## Seek and BufRead
+//!
+//! Beyond that, there are two important traits that are provided: [`Seek`]
+//! and [`BufRead`]. Both of these build on top of a reader to control
+//! how the reading happens. [`Seek`] lets you control where the next byte is
+//! coming from:
+//!
+//! ```no_run
+//! use std::io;
+//! use std::io::prelude::*;
+//! use std::io::SeekFrom;
+//! use std::fs::File;
+//!
+//! fn main() -> io::Result<()> {
+//! let mut f = File::open("foo.txt")?;
+//! let mut buffer = [0; 10];
+//!
+//! // skip to the last 10 bytes of the file
+//! f.seek(SeekFrom::End(-10))?;
+//!
+//! // read up to 10 bytes
+//! let n = f.read(&mut buffer)?;
+//!
+//! println!("The bytes: {:?}", &buffer[..n]);
+//! Ok(())
+//! }
+//! ```
+//!
+//! [`BufRead`] uses an internal buffer to provide a number of other ways to read, but
+//! to show it off, we'll need to talk about buffers in general. Keep reading!
+//!
+//! ## BufReader and BufWriter
+//!
+//! Byte-based interfaces are unwieldy and can be inefficient, as we'd need to be
+//! making near-constant calls to the operating system. To help with this,
+//! `std::io` comes with two structs, [`BufReader`] and [`BufWriter`], which wrap
+//! readers and writers. The wrapper uses a buffer, reducing the number of
+//! calls and providing nicer methods for accessing exactly what you want.
+//!
+//! For example, [`BufReader`] works with the [`BufRead`] trait to add extra
+//! methods to any reader:
+//!
+//! ```no_run
+//! use std::io;
+//! use std::io::prelude::*;
+//! use std::io::BufReader;
+//! use std::fs::File;
+//!
+//! fn main() -> io::Result<()> {
+//! let f = File::open("foo.txt")?;
+//! let mut reader = BufReader::new(f);
+//! let mut buffer = String::new();
+//!
+//! // read a line into buffer
+//! reader.read_line(&mut buffer)?;
+//!
+//! println!("{}", buffer);
+//! Ok(())
+//! }
+//! ```
+//!
+//! [`BufWriter`] doesn't add any new ways of writing; it just buffers every call
+//! to [`write`][`Write::write`]:
+//!
+//! ```no_run
+//! use std::io;
+//! use std::io::prelude::*;
+//! use std::io::BufWriter;
+//! use std::fs::File;
+//!
+//! fn main() -> io::Result<()> {
+//! let f = File::create("foo.txt")?;
+//! {
+//! let mut writer = BufWriter::new(f);
+//!
+//! // write a byte to the buffer
+//! writer.write(&[42])?;
+//!
+//! } // the buffer is flushed once writer goes out of scope
+//!
+//! Ok(())
+//! }
+//! ```
+//!
+//! ## Standard input and output
+//!
+//! A very common source of input is standard input:
+//!
+//! ```no_run
+//! use std::io;
+//!
+//! fn main() -> io::Result<()> {
+//! let mut input = String::new();
+//!
+//! io::stdin().read_line(&mut input)?;
+//!
+//! println!("You typed: {}", input.trim());
+//! Ok(())
+//! }
+//! ```
+//!
+//! Note that you cannot use the [`?` operator] in functions that do not return
+//! a [`Result<T, E>`][`Result`]. Instead, you can call [`.unwrap()`]
+//! or `match` on the return value to catch any possible errors:
+//!
+//! ```no_run
+//! use std::io;
+//!
+//! let mut input = String::new();
+//!
+//! io::stdin().read_line(&mut input).unwrap();
+//! ```
+//!
+//! And a very common source of output is standard output:
+//!
+//! ```no_run
+//! use std::io;
+//! use std::io::prelude::*;
+//!
+//! fn main() -> io::Result<()> {
+//! io::stdout().write(&[42])?;
+//! Ok(())
+//! }
+//! ```
+//!
+//! Of course, using [`io::stdout`] directly is less common than something like
+//! [`println!`].
+//!
+//! ## Iterator types
+//!
+//! A large number of the structures provided by `std::io` are for various
+//! ways of iterating over I/O. For example, [`Lines`] is used to split over
+//! lines:
+//!
+//! ```no_run
+//! use std::io;
+//! use std::io::prelude::*;
+//! use std::io::BufReader;
+//! use std::fs::File;
+//!
+//! fn main() -> io::Result<()> {
+//! let f = File::open("foo.txt")?;
+//! let reader = BufReader::new(f);
+//!
+//! for line in reader.lines() {
+//! println!("{}", line?);
+//! }
+//! Ok(())
+//! }
+//! ```
+//!
+//! ## Functions
+//!
+//! There are a number of [functions][functions-list] that offer access to various
+//! features. For example, we can use three of these functions to copy everything
+//! from standard input to standard output:
+//!
+//! ```no_run
+//! use std::io;
+//!
+//! fn main() -> io::Result<()> {
+//! io::copy(&mut io::stdin(), &mut io::stdout())?;
+//! Ok(())
+//! }
+//! ```
+//!
+//! [functions-list]: #functions-1
+//!
+//! ## io::Result
+//!
+//! Last, but certainly not least, is [`io::Result`]. This type is used
+//! as the return type of many `std::io` functions that can cause an error, and
+//! can be returned from your own functions as well. Many of the examples in this
+//! module use the [`?` operator]:
+//!
+//! ```
+//! use std::io;
+//!
+//! fn read_input() -> io::Result<()> {
+//! let mut input = String::new();
+//!
+//! io::stdin().read_line(&mut input)?;
+//!
+//! println!("You typed: {}", input.trim());
+//!
+//! Ok(())
+//! }
+//! ```
+//!
+//! The return type of `read_input()`, [`io::Result<()>`][`io::Result`], is a very
+//! common type for functions which don't have a 'real' return value, but do want to
+//! return errors if they happen. In this case, the only purpose of this function is
+//! to read the line and print it, so we use `()`.
+//!
+//! ## Platform-specific behavior
+//!
+//! Many I/O functions throughout the standard library are documented to indicate
+//! what various library or syscalls they are delegated to. This is done to help
+//! applications both understand what's happening under the hood as well as investigate
+//! any possibly unclear semantics. Note, however, that this is informative, not a binding
+//! contract. The implementation of many of these functions are subject to change over
+//! time and may call fewer or more syscalls/library functions.
+//!
+//! [`Read`]: trait.Read.html
+//! [`Write`]: trait.Write.html
+//! [`Seek`]: trait.Seek.html
+//! [`BufRead`]: trait.BufRead.html
+//! [`File`]: ../fs/struct.File.html
+//! [`TcpStream`]: ../net/struct.TcpStream.html
+//! [`Vec<T>`]: ../vec/struct.Vec.html
+//! [`BufReader`]: struct.BufReader.html
+//! [`BufWriter`]: struct.BufWriter.html
+//! [`Write::write`]: trait.Write.html#tymethod.write
+//! [`io::stdout`]: fn.stdout.html
+//! [`println!`]: ../macro.println.html
+//! [`Lines`]: struct.Lines.html
+//! [`io::Result`]: type.Result.html
+//! [`?` operator]: ../../book/appendix-02-operators.html
+//! [`Read::read`]: trait.Read.html#tymethod.read
+//! [`Result`]: ../result/enum.Result.html
+//! [`.unwrap()`]: ../result/enum.Result.html#method.unwrap
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+use crate::cmp;
+use crate::fmt;
+use crate::slice;
+use crate::str;
+use crate::memchr;
+use crate::ops::{Deref, DerefMut};
+use crate::ptr;
+use crate::sys;
+
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use self::buffered::{BufReader, BufWriter, LineWriter};
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use self::buffered::IntoInnerError;
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use self::cursor::Cursor;
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use self::error::{Result, Error, ErrorKind};
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use self::util::{copy, sink, Sink, empty, Empty, repeat, Repeat};
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use self::stdio::{stdin, stdout, stderr, Stdin, Stdout, Stderr};
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use self::stdio::{StdoutLock, StderrLock, StdinLock};
+#[unstable(feature = "print_internals", issue = "0")]
+pub use self::stdio::{_print, _eprint};
+#[unstable(feature = "libstd_io_internals", issue = "42788")]
+#[doc(no_inline, hidden)]
+pub use self::stdio::{set_panic, set_print};
+
+pub mod prelude;
+mod buffered;
+mod cursor;
+mod error;
+mod impls;
+mod lazy;
+mod util;
+mod stdio;
+
+const DEFAULT_BUF_SIZE: usize = crate::sys_common::io::DEFAULT_BUF_SIZE;
+
+struct Guard<'a> { buf: &'a mut Vec<u8>, len: usize }
+
+impl Drop for Guard<'_> {
+ fn drop(&mut self) {
+ unsafe { self.buf.set_len(self.len); }
+ }
+}
+
+// A few methods below (read_to_string, read_line) will append data into a
+// `String` buffer, but we need to be pretty careful when doing this. The
+// implementation will just call `.as_mut_vec()` and then delegate to a
+// byte-oriented reading method, but we must ensure that when returning we never
+// leave `buf` in a state such that it contains invalid UTF-8 in its bounds.
+//
+// To this end, we use an RAII guard (to protect against panics) which updates
+// the length of the string when it is dropped. This guard initially truncates
+// the string to the prior length and only after we've validated that the
+// new contents are valid UTF-8 do we allow it to set a longer length.
+//
+// The unsafety in this function is twofold:
+//
+// 1. We're looking at the raw bytes of `buf`, so we take on the burden of UTF-8
+// checks.
+// 2. We're passing a raw buffer to the function `f`, and it is expected that
+// the function only *appends* bytes to the buffer. We'll get undefined
+// behavior if existing bytes are overwritten to have non-UTF-8 data.
+fn append_to_string<F>(buf: &mut String, f: F) -> Result<usize>
+ where F: FnOnce(&mut Vec<u8>) -> Result<usize>
+{
+ unsafe {
+ let mut g = Guard { len: buf.len(), buf: buf.as_mut_vec() };
+ let ret = f(g.buf);
+ if str::from_utf8(&g.buf[g.len..]).is_err() {
+ ret.and_then(|_| {
+ Err(Error::new(ErrorKind::InvalidData,
+ "stream did not contain valid UTF-8"))
+ })
+ } else {
+ g.len = g.buf.len();
+ ret
+ }
+ }
+}
+
+// This uses an adaptive system to extend the vector when it fills. We want to
+// avoid paying to allocate and zero a huge chunk of memory if the reader only
+// has 4 bytes while still making large reads if the reader does have a ton
+// of data to return. Simply tacking on an extra DEFAULT_BUF_SIZE space every
+// time is 4,500 times (!) slower than a default reservation size of 32 if the
+// reader has a very small amount of data to return.
+//
+// Because we're extending the buffer with uninitialized data for trusted
+// readers, we need to make sure to truncate that if any of this panics.
+fn read_to_end<R: Read + ?Sized>(r: &mut R, buf: &mut Vec<u8>) -> Result<usize> {
+ read_to_end_with_reservation(r, buf, 32)
+}
+
+fn read_to_end_with_reservation<R: Read + ?Sized>(r: &mut R,
+ buf: &mut Vec<u8>,
+ reservation_size: usize) -> Result<usize>
+{
+ let start_len = buf.len();
+ let mut g = Guard { len: buf.len(), buf: buf };
+ let ret;
+ loop {
+ if g.len == g.buf.len() {
+ unsafe {
+ g.buf.reserve(reservation_size);
+ let capacity = g.buf.capacity();
+ g.buf.set_len(capacity);
+ r.initializer().initialize(&mut g.buf[g.len..]);
+ }
+ }
+
+ match r.read(&mut g.buf[g.len..]) {
+ Ok(0) => {
+ ret = Ok(g.len - start_len);
+ break;
+ }
+ Ok(n) => g.len += n,
+ Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
+ Err(e) => {
+ ret = Err(e);
+ break;
+ }
+ }
+ }
+
+ ret
+}
+
+pub(crate) fn default_read_vectored<F>(read: F, bufs: &mut [IoVecMut<'_>]) -> Result<usize>
+where
+ F: FnOnce(&mut [u8]) -> Result<usize>
+{
+ let buf = bufs
+ .iter_mut()
+ .find(|b| !b.is_empty())
+ .map_or(&mut [][..], |b| &mut **b);
+ read(buf)
+}
+
+pub(crate) fn default_write_vectored<F>(write: F, bufs: &[IoVec<'_>]) -> Result<usize>
+where
+ F: FnOnce(&[u8]) -> Result<usize>
+{
+ let buf = bufs
+ .iter()
+ .find(|b| !b.is_empty())
+ .map_or(&[][..], |b| &**b);
+ write(buf)
+}
+
+/// The `Read` trait allows for reading bytes from a source.
+///
+/// Implementors of the `Read` trait are called 'readers'.
+///
+/// Readers are defined by one required method, [`read()`]. Each call to [`read()`]
+/// will attempt to pull bytes from this source into a provided buffer. A
+/// number of other methods are implemented in terms of [`read()`], giving
+/// implementors a number of ways to read bytes while only needing to implement
+/// a single method.
+///
+/// Readers are intended to be composable with one another. Many implementors
+/// throughout [`std::io`] take and provide types which implement the `Read`
+/// trait.
+///
+/// Please note that each call to [`read()`] may involve a system call, and
+/// therefore, using something that implements [`BufRead`], such as
+/// [`BufReader`], will be more efficient.
+///
+/// # Examples
+///
+/// [`File`]s implement `Read`:
+///
+/// ```no_run
+/// use std::io;
+/// use std::io::prelude::*;
+/// use std::fs::File;
+///
+/// fn main() -> io::Result<()> {
+/// let mut f = File::open("foo.txt")?;
+/// let mut buffer = [0; 10];
+///
+/// // read up to 10 bytes
+/// f.read(&mut buffer)?;
+///
+/// let mut buffer = Vec::new();
+/// // read the whole file
+/// f.read_to_end(&mut buffer)?;
+///
+/// // read into a String, so that you don't need to do the conversion.
+/// let mut buffer = String::new();
+/// f.read_to_string(&mut buffer)?;
+///
+/// // and more! See the other methods for more details.
+/// Ok(())
+/// }
+/// ```
+///
+/// Read from [`&str`] because [`&[u8]`][slice] implements `Read`:
+///
+/// ```no_run
+/// # use std::io;
+/// use std::io::prelude::*;
+///
+/// fn main() -> io::Result<()> {
+/// let mut b = "This string will be read".as_bytes();
+/// let mut buffer = [0; 10];
+///
+/// // read up to 10 bytes
+/// b.read(&mut buffer)?;
+///
+/// // etc... it works exactly as a File does!
+/// Ok(())
+/// }
+/// ```
+///
+/// [`read()`]: trait.Read.html#tymethod.read
+/// [`std::io`]: ../../std/io/index.html
+/// [`File`]: ../fs/struct.File.html
+/// [`BufRead`]: trait.BufRead.html
+/// [`BufReader`]: struct.BufReader.html
+/// [`&str`]: ../../std/primitive.str.html
+/// [slice]: ../../std/primitive.slice.html
+#[stable(feature = "rust1", since = "1.0.0")]
+#[doc(spotlight)]
+pub trait Read {
+ /// Pull some bytes from this source into the specified buffer, returning
+ /// how many bytes were read.
+ ///
+ /// This function does not provide any guarantees about whether it blocks
+ /// waiting for data, but if an object needs to block for a read but cannot
+ /// it will typically signal this via an [`Err`] return value.
+ ///
+ /// If the return value of this method is [`Ok(n)`], then it must be
+ /// guaranteed that `0 <= n <= buf.len()`. A nonzero `n` value indicates
+ /// that the buffer `buf` has been filled in with `n` bytes of data from this
+ /// source. If `n` is `0`, then it can indicate one of two scenarios:
+ ///
+ /// 1. This reader has reached its "end of file" and will likely no longer
+ /// be able to produce bytes. Note that this does not mean that the
+ /// reader will *always* no longer be able to produce bytes.
+ /// 2. The buffer specified was 0 bytes in length.
+ ///
+ /// No guarantees are provided about the contents of `buf` when this
+ /// function is called, implementations cannot rely on any property of the
+ /// contents of `buf` being true. It is recommended that implementations
+ /// only write data to `buf` instead of reading its contents.
+ ///
+ /// # Errors
+ ///
+ /// If this function encounters any form of I/O or other error, an error
+ /// variant will be returned. If an error is returned then it must be
+ /// guaranteed that no bytes were read.
+ ///
+ /// An error of the [`ErrorKind::Interrupted`] kind is non-fatal and the read
+ /// operation should be retried if there is nothing else to do.
+ ///
+ /// # Examples
+ ///
+ /// [`File`]s implement `Read`:
+ ///
+ /// [`Err`]: ../../std/result/enum.Result.html#variant.Err
+ /// [`Ok(n)`]: ../../std/result/enum.Result.html#variant.Ok
+ /// [`ErrorKind::Interrupted`]: ../../std/io/enum.ErrorKind.html#variant.Interrupted
+ /// [`File`]: ../fs/struct.File.html
+ ///
+ /// ```no_run
+ /// use std::io;
+ /// use std::io::prelude::*;
+ /// use std::fs::File;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let mut f = File::open("foo.txt")?;
+ /// let mut buffer = [0; 10];
+ ///
+ /// // read up to 10 bytes
+ /// let n = f.read(&mut buffer[..])?;
+ ///
+ /// println!("The bytes: {:?}", &buffer[..n]);
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ fn read(&mut self, buf: &mut [u8]) -> Result<usize>;
+
+ /// Like `read`, except that it reads into a slice of buffers.
+ ///
+ /// Data is copied to fill each buffer in order, with the final buffer
+ /// written to possibly being only partially filled. This method must behave
+ /// as a single call to `read` with the buffers concatenated would.
+ ///
+ /// The default implementation calls `read` with either the first nonempty
+ /// buffer provided, or an empty one if none exists.
+ #[unstable(feature = "iovec", issue = "58452")]
+ fn read_vectored(&mut self, bufs: &mut [IoVecMut<'_>]) -> Result<usize> {
+ default_read_vectored(|b| self.read(b), bufs)
+ }
+
+ /// Determines if this `Read`er can work with buffers of uninitialized
+ /// memory.
+ ///
+ /// The default implementation returns an initializer which will zero
+ /// buffers.
+ ///
+ /// If a `Read`er guarantees that it can work properly with uninitialized
+ /// memory, it should call [`Initializer::nop()`]. See the documentation for
+ /// [`Initializer`] for details.
+ ///
+ /// The behavior of this method must be independent of the state of the
+ /// `Read`er - the method only takes `&self` so that it can be used through
+ /// trait objects.
+ ///
+ /// # Safety
+ ///
+ /// This method is unsafe because a `Read`er could otherwise return a
+ /// non-zeroing `Initializer` from another `Read` type without an `unsafe`
+ /// block.
+ ///
+ /// [`Initializer::nop()`]: ../../std/io/struct.Initializer.html#method.nop
+ /// [`Initializer`]: ../../std/io/struct.Initializer.html
+ #[unstable(feature = "read_initializer", issue = "42788")]
+ #[inline]
+ unsafe fn initializer(&self) -> Initializer {
+ Initializer::zeroing()
+ }
+
+ /// Read all bytes until EOF in this source, placing them into `buf`.
+ ///
+ /// All bytes read from this source will be appended to the specified buffer
+ /// `buf`. This function will continuously call [`read()`] to append more data to
+ /// `buf` until [`read()`] returns either [`Ok(0)`] or an error of
+ /// non-[`ErrorKind::Interrupted`] kind.
+ ///
+ /// If successful, this function will return the total number of bytes read.
+ ///
+ /// # Errors
+ ///
+ /// If this function encounters an error of the kind
+ /// [`ErrorKind::Interrupted`] then the error is ignored and the operation
+ /// will continue.
+ ///
+ /// If any other read error is encountered then this function immediately
+ /// returns. Any bytes which have already been read will be appended to
+ /// `buf`.
+ ///
+ /// # Examples
+ ///
+ /// [`File`]s implement `Read`:
+ ///
+ /// [`read()`]: trait.Read.html#tymethod.read
+ /// [`Ok(0)`]: ../../std/result/enum.Result.html#variant.Ok
+ /// [`ErrorKind::Interrupted`]: ../../std/io/enum.ErrorKind.html#variant.Interrupted
+ /// [`File`]: ../fs/struct.File.html
+ ///
+ /// ```no_run
+ /// use std::io;
+ /// use std::io::prelude::*;
+ /// use std::fs::File;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let mut f = File::open("foo.txt")?;
+ /// let mut buffer = Vec::new();
+ ///
+ /// // read the whole file
+ /// f.read_to_end(&mut buffer)?;
+ /// Ok(())
+ /// }
+ /// ```
+ ///
+ /// (See also the [`std::fs::read`] convenience function for reading from a
+ /// file.)
+ ///
+ /// [`std::fs::read`]: ../fs/fn.read.html
+ #[stable(feature = "rust1", since = "1.0.0")]
+ fn read_to_end(&mut self, buf: &mut Vec<u8>) -> Result<usize> {
+ read_to_end(self, buf)
+ }
+
+ /// Read all bytes until EOF in this source, appending them to `buf`.
+ ///
+ /// If successful, this function returns the number of bytes which were read
+ /// and appended to `buf`.
+ ///
+ /// # Errors
+ ///
+ /// If the data in this stream is *not* valid UTF-8 then an error is
+ /// returned and `buf` is unchanged.
+ ///
+ /// See [`read_to_end`][readtoend] for other error semantics.
+ ///
+ /// [readtoend]: #method.read_to_end
+ ///
+ /// # Examples
+ ///
+ /// [`File`][file]s implement `Read`:
+ ///
+ /// [file]: ../fs/struct.File.html
+ ///
+ /// ```no_run
+ /// use std::io;
+ /// use std::io::prelude::*;
+ /// use std::fs::File;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let mut f = File::open("foo.txt")?;
+ /// let mut buffer = String::new();
+ ///
+ /// f.read_to_string(&mut buffer)?;
+ /// Ok(())
+ /// }
+ /// ```
+ ///
+ /// (See also the [`std::fs::read_to_string`] convenience function for
+ /// reading from a file.)
+ ///
+ /// [`std::fs::read_to_string`]: ../fs/fn.read_to_string.html
+ #[stable(feature = "rust1", since = "1.0.0")]
+ fn read_to_string(&mut self, buf: &mut String) -> Result<usize> {
+ // Note that we do *not* call `.read_to_end()` here. We are passing
+ // `&mut Vec<u8>` (the raw contents of `buf`) into the `read_to_end`
+ // method to fill it up. An arbitrary implementation could overwrite the
+ // entire contents of the vector, not just append to it (which is what
+ // we are expecting).
+ //
+ // To prevent extraneously checking the UTF-8-ness of the entire buffer
+ // we pass it to our hardcoded `read_to_end` implementation which we
+ // know is guaranteed to only read data into the end of the buffer.
+ append_to_string(buf, |b| read_to_end(self, b))
+ }
+
+ /// Read the exact number of bytes required to fill `buf`.
+ ///
+ /// This function reads as many bytes as necessary to completely fill the
+ /// specified buffer `buf`.
+ ///
+ /// No guarantees are provided about the contents of `buf` when this
+ /// function is called, implementations cannot rely on any property of the
+ /// contents of `buf` being true. It is recommended that implementations
+ /// only write data to `buf` instead of reading its contents.
+ ///
+ /// # 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.
+ ///
+ /// # Examples
+ ///
+ /// [`File`]s implement `Read`:
+ ///
+ /// [`File`]: ../fs/struct.File.html
+ /// [`ErrorKind::Interrupted`]: ../../std/io/enum.ErrorKind.html#variant.Interrupted
+ /// [`ErrorKind::UnexpectedEof`]: ../../std/io/enum.ErrorKind.html#variant.UnexpectedEof
+ ///
+ /// ```no_run
+ /// use std::io;
+ /// use std::io::prelude::*;
+ /// use std::fs::File;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let mut f = File::open("foo.txt")?;
+ /// let mut buffer = [0; 10];
+ ///
+ /// // read exactly 10 bytes
+ /// f.read_exact(&mut buffer)?;
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "read_exact", since = "1.6.0")]
+ fn read_exact(&mut self, mut buf: &mut [u8]) -> Result<()> {
+ while !buf.is_empty() {
+ match self.read(buf) {
+ Ok(0) => break,
+ Ok(n) => { let tmp = buf; buf = &mut tmp[n..]; }
+ Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
+ Err(e) => return Err(e),
+ }
+ }
+ if !buf.is_empty() {
+ Err(Error::new(ErrorKind::UnexpectedEof,
+ "failed to fill whole buffer"))
+ } else {
+ Ok(())
+ }
+ }
+
+ /// Creates a "by reference" adaptor for this instance of `Read`.
+ ///
+ /// The returned adaptor also implements `Read` and will simply borrow this
+ /// current reader.
+ ///
+ /// # Examples
+ ///
+ /// [`File`][file]s implement `Read`:
+ ///
+ /// [file]: ../fs/struct.File.html
+ ///
+ /// ```no_run
+ /// use std::io;
+ /// use std::io::Read;
+ /// use std::fs::File;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let mut f = File::open("foo.txt")?;
+ /// let mut buffer = Vec::new();
+ /// let mut other_buffer = Vec::new();
+ ///
+ /// {
+ /// let reference = f.by_ref();
+ ///
+ /// // read at most 5 bytes
+ /// reference.take(5).read_to_end(&mut buffer)?;
+ ///
+ /// } // drop our &mut reference so we can use f again
+ ///
+ /// // original file still usable, read the rest
+ /// f.read_to_end(&mut other_buffer)?;
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ fn by_ref(&mut self) -> &mut Self where Self: Sized { self }
+
+ /// Transforms this `Read` instance to an [`Iterator`] over its bytes.
+ ///
+ /// The returned type implements [`Iterator`] where the `Item` is
+ /// [`Result`]`<`[`u8`]`, `[`io::Error`]`>`.
+ /// The yielded item is [`Ok`] if a byte was successfully read and [`Err`]
+ /// otherwise. EOF is mapped to returning [`None`] from this iterator.
+ ///
+ /// # Examples
+ ///
+ /// [`File`][file]s implement `Read`:
+ ///
+ /// [file]: ../fs/struct.File.html
+ /// [`Iterator`]: ../../std/iter/trait.Iterator.html
+ /// [`Result`]: ../../std/result/enum.Result.html
+ /// [`io::Error`]: ../../std/io/struct.Error.html
+ /// [`u8`]: ../../std/primitive.u8.html
+ /// [`Ok`]: ../../std/result/enum.Result.html#variant.Ok
+ /// [`Err`]: ../../std/result/enum.Result.html#variant.Err
+ /// [`None`]: ../../std/option/enum.Option.html#variant.None
+ ///
+ /// ```no_run
+ /// use std::io;
+ /// use std::io::prelude::*;
+ /// use std::fs::File;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let mut f = File::open("foo.txt")?;
+ ///
+ /// for byte in f.bytes() {
+ /// println!("{}", byte.unwrap());
+ /// }
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ fn bytes(self) -> Bytes<Self> where Self: Sized {
+ Bytes { inner: self }
+ }
+
+ /// Creates an adaptor which will chain this stream with another.
+ ///
+ /// The returned `Read` instance will first read all bytes from this object
+ /// until EOF is encountered. Afterwards the output is equivalent to the
+ /// output of `next`.
+ ///
+ /// # Examples
+ ///
+ /// [`File`][file]s implement `Read`:
+ ///
+ /// [file]: ../fs/struct.File.html
+ ///
+ /// ```no_run
+ /// use std::io;
+ /// use std::io::prelude::*;
+ /// use std::fs::File;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let mut f1 = File::open("foo.txt")?;
+ /// let mut f2 = File::open("bar.txt")?;
+ ///
+ /// let mut handle = f1.chain(f2);
+ /// let mut buffer = String::new();
+ ///
+ /// // read the value into a String. We could use any Read method here,
+ /// // this is just one example.
+ /// handle.read_to_string(&mut buffer)?;
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ fn chain<R: Read>(self, next: R) -> Chain<Self, R> where Self: Sized {
+ Chain { first: self, second: next, done_first: false }
+ }
+
+ /// Creates an adaptor which will read at most `limit` bytes from it.
+ ///
+ /// This function returns a new instance of `Read` which will read at most
+ /// `limit` bytes, after which it will always return EOF ([`Ok(0)`]). Any
+ /// read errors will not count towards the number of bytes read and future
+ /// calls to [`read()`] may succeed.
+ ///
+ /// # Examples
+ ///
+ /// [`File`]s implement `Read`:
+ ///
+ /// [`File`]: ../fs/struct.File.html
+ /// [`Ok(0)`]: ../../std/result/enum.Result.html#variant.Ok
+ /// [`read()`]: trait.Read.html#tymethod.read
+ ///
+ /// ```no_run
+ /// use std::io;
+ /// use std::io::prelude::*;
+ /// use std::fs::File;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let mut f = File::open("foo.txt")?;
+ /// let mut buffer = [0; 5];
+ ///
+ /// // read at most five bytes
+ /// let mut handle = f.take(5);
+ ///
+ /// handle.read(&mut buffer)?;
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ fn take(self, limit: u64) -> Take<Self> where Self: Sized {
+ Take { inner: self, limit: limit }
+ }
+}
+
+/// A buffer type used with `Read::read_vectored`.
+///
+/// It is semantically a wrapper around an `&mut [u8]`, but is guaranteed to be
+/// ABI compatible with the `iovec` type on Unix platforms and `WSABUF` on
+/// Windows.
+#[unstable(feature = "iovec", issue = "58452")]
+#[repr(transparent)]
+pub struct IoVecMut<'a>(sys::io::IoVecMut<'a>);
+
+#[unstable(feature = "iovec", issue = "58452")]
+impl<'a> fmt::Debug for IoVecMut<'a> {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt::Debug::fmt(self.0.as_slice(), fmt)
+ }
+}
+
+impl<'a> IoVecMut<'a> {
+ /// Creates a new `IoVecMut` wrapping a byte slice.
+ ///
+ /// # Panics
+ ///
+ /// Panics on Windows if the slice is larger than 4GB.
+ #[unstable(feature = "iovec", issue = "58452")]
+ #[inline]
+ pub fn new(buf: &'a mut [u8]) -> IoVecMut<'a> {
+ IoVecMut(sys::io::IoVecMut::new(buf))
+ }
+}
+
+#[unstable(feature = "iovec", issue = "58452")]
+impl<'a> Deref for IoVecMut<'a> {
+ type Target = [u8];
+
+ #[inline]
+ fn deref(&self) -> &[u8] {
+ self.0.as_slice()
+ }
+}
+
+#[unstable(feature = "iovec", issue = "58452")]
+impl<'a> DerefMut for IoVecMut<'a> {
+ #[inline]
+ fn deref_mut(&mut self) -> &mut [u8] {
+ self.0.as_mut_slice()
+ }
+}
+
+/// A buffer type used with `Write::write_vectored`.
+///
+/// It is semantically a wrapper around an `&[u8]`, but is guaranteed to be
+/// ABI compatible with the `iovec` type on Unix platforms and `WSABUF` on
+/// Windows.
+#[unstable(feature = "iovec", issue = "58452")]
+#[repr(transparent)]
+pub struct IoVec<'a>(sys::io::IoVec<'a>);
+
+#[unstable(feature = "iovec", issue = "58452")]
+impl<'a> fmt::Debug for IoVec<'a> {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt::Debug::fmt(self.0.as_slice(), fmt)
+ }
+}
+
+impl<'a> IoVec<'a> {
+ /// Creates a new `IoVec` wrapping a byte slice.
+ ///
+ /// # Panics
+ ///
+ /// Panics on Windows if the slice is larger than 4GB.
+ #[unstable(feature = "iovec", issue = "58452")]
+ #[inline]
+ pub fn new(buf: &'a [u8]) -> IoVec<'a> {
+ IoVec(sys::io::IoVec::new(buf))
+ }
+}
+
+#[unstable(feature = "iovec", issue = "58452")]
+impl<'a> Deref for IoVec<'a> {
+ type Target = [u8];
+
+ #[inline]
+ fn deref(&self) -> &[u8] {
+ self.0.as_slice()
+ }
+}
+
+/// A type used to conditionally initialize buffers passed to `Read` methods.
+#[unstable(feature = "read_initializer", issue = "42788")]
+#[derive(Debug)]
+pub struct Initializer(bool);
+
+impl Initializer {
+ /// Returns a new `Initializer` which will zero out buffers.
+ #[unstable(feature = "read_initializer", issue = "42788")]
+ #[inline]
+ pub fn zeroing() -> Initializer {
+ Initializer(true)
+ }
+
+ /// Returns a new `Initializer` which will not zero out buffers.
+ ///
+ /// # Safety
+ ///
+ /// This may only be called by `Read`ers which guarantee that they will not
+ /// read from buffers passed to `Read` methods, and that the return value of
+ /// the method accurately reflects the number of bytes that have been
+ /// written to the head of the buffer.
+ #[unstable(feature = "read_initializer", issue = "42788")]
+ #[inline]
+ pub unsafe fn nop() -> Initializer {
+ Initializer(false)
+ }
+
+ /// Indicates if a buffer should be initialized.
+ #[unstable(feature = "read_initializer", issue = "42788")]
+ #[inline]
+ pub fn should_initialize(&self) -> bool {
+ self.0
+ }
+
+ /// Initializes a buffer if necessary.
+ #[unstable(feature = "read_initializer", issue = "42788")]
+ #[inline]
+ pub fn initialize(&self, buf: &mut [u8]) {
+ if self.should_initialize() {
+ unsafe { ptr::write_bytes(buf.as_mut_ptr(), 0, buf.len()) }
+ }
+ }
+}
+
+/// A trait for objects which are byte-oriented sinks.
+///
+/// Implementors of the `Write` trait are sometimes called 'writers'.
+///
+/// Writers are defined by two required methods, [`write`] and [`flush`]:
+///
+/// * The [`write`] method will attempt to write some data into the object,
+/// returning how many bytes were successfully written.
+///
+/// * The [`flush`] method is useful for adaptors and explicit buffers
+/// themselves for ensuring that all buffered data has been pushed out to the
+/// 'true sink'.
+///
+/// Writers are intended to be composable with one another. Many implementors
+/// throughout [`std::io`] take and provide types which implement the `Write`
+/// trait.
+///
+/// [`write`]: #tymethod.write
+/// [`flush`]: #tymethod.flush
+/// [`std::io`]: index.html
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::io::prelude::*;
+/// use std::fs::File;
+///
+/// fn main() -> std::io::Result<()> {
+/// let data = b"some bytes";
+///
+/// let mut pos = 0;
+/// let mut buffer = File::create("foo.txt")?;
+///
+/// while pos < data.len() {
+/// let bytes_written = buffer.write(&data[pos..])?;
+/// pos += bytes_written;
+/// }
+/// Ok(())
+/// }
+/// ```
+///
+/// The trait also provides convenience methods like [`write_all`], which calls
+/// `write` in a loop until its entire input has been written.
+///
+/// [`write_all`]: #method.write_all
+#[stable(feature = "rust1", since = "1.0.0")]
+#[doc(spotlight)]
+pub trait Write {
+ /// Write a buffer into this writer, returning how many bytes were written.
+ ///
+ /// This function will attempt to write the entire contents of `buf`, but
+ /// the entire write may not succeed, or the write may also generate an
+ /// error. A call to `write` represents *at most one* attempt to write to
+ /// any wrapped object.
+ ///
+ /// Calls to `write` are not guaranteed to block waiting for data to be
+ /// written, and a write which would otherwise block can be indicated through
+ /// an [`Err`] variant.
+ ///
+ /// If the return value is [`Ok(n)`] then it must be guaranteed that
+ /// `0 <= n <= buf.len()`. A return value of `0` typically means that the
+ /// underlying object is no longer able to accept bytes and will likely not
+ /// be able to in the future as well, or that the buffer provided is empty.
+ ///
+ /// # Errors
+ ///
+ /// Each call to `write` may generate an I/O error indicating that the
+ /// operation could not be completed. If an error is returned then no bytes
+ /// in the buffer were written to this writer.
+ ///
+ /// It is **not** considered an error if the entire buffer could not be
+ /// written to this writer.
+ ///
+ /// An error of the [`ErrorKind::Interrupted`] kind is non-fatal and the
+ /// write operation should be retried if there is nothing else to do.
+ ///
+ /// [`Err`]: ../../std/result/enum.Result.html#variant.Err
+ /// [`Ok(n)`]: ../../std/result/enum.Result.html#variant.Ok
+ /// [`ErrorKind::Interrupted`]: ../../std/io/enum.ErrorKind.html#variant.Interrupted
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::io::prelude::*;
+ /// use std::fs::File;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let mut buffer = File::create("foo.txt")?;
+ ///
+ /// // Writes some prefix of the byte string, not necessarily all of it.
+ /// buffer.write(b"some bytes")?;
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ fn write(&mut self, buf: &[u8]) -> Result<usize>;
+
+ /// Like `write`, except that it writes from a slice of buffers.
+ ///
+ /// Data is copied to from each buffer in order, with the final buffer
+ /// read from possibly being only partially consumed. This method must
+ /// behave as a call to `write` with the buffers concatenated would.
+ ///
+ /// The default implementation calls `write` with either the first nonempty
+ /// buffer provided, or an empty one if none exists.
+ #[unstable(feature = "iovec", issue = "58452")]
+ fn write_vectored(&mut self, bufs: &[IoVec<'_>]) -> Result<usize> {
+ default_write_vectored(|b| self.write(b), bufs)
+ }
+
+ /// Flush this output stream, ensuring that all intermediately buffered
+ /// contents reach their destination.
+ ///
+ /// # Errors
+ ///
+ /// It is considered an error if not all bytes could be written due to
+ /// I/O errors or EOF being reached.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::io::prelude::*;
+ /// use std::io::BufWriter;
+ /// use std::fs::File;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let mut buffer = BufWriter::new(File::create("foo.txt")?);
+ ///
+ /// buffer.write_all(b"some bytes")?;
+ /// buffer.flush()?;
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ fn flush(&mut self) -> Result<()>;
+
+ /// Attempts to write an entire buffer into this writer.
+ ///
+ /// This method will continuously call [`write`] until there is no more data
+ /// to be written or an error of non-[`ErrorKind::Interrupted`] kind is
+ /// returned. This method will not return until the entire buffer has been
+ /// successfully written or such an error occurs. The first error that is
+ /// not of [`ErrorKind::Interrupted`] kind generated from this method will be
+ /// returned.
+ ///
+ /// # Errors
+ ///
+ /// This function will return the first error of
+ /// non-[`ErrorKind::Interrupted`] kind that [`write`] returns.
+ ///
+ /// [`ErrorKind::Interrupted`]: ../../std/io/enum.ErrorKind.html#variant.Interrupted
+ /// [`write`]: #tymethod.write
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::io::prelude::*;
+ /// use std::fs::File;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let mut buffer = File::create("foo.txt")?;
+ ///
+ /// buffer.write_all(b"some bytes")?;
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ fn write_all(&mut self, mut buf: &[u8]) -> Result<()> {
+ while !buf.is_empty() {
+ match self.write(buf) {
+ Ok(0) => return Err(Error::new(ErrorKind::WriteZero,
+ "failed to write whole buffer")),
+ Ok(n) => buf = &buf[n..],
+ Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
+ Err(e) => return Err(e),
+ }
+ }
+ Ok(())
+ }
+
+ /// Writes a formatted string into this writer, returning any error
+ /// encountered.
+ ///
+ /// This method is primarily used to interface with the
+ /// [`format_args!`][formatargs] macro, but it is rare that this should
+ /// explicitly be called. The [`write!`][write] macro should be favored to
+ /// invoke this method instead.
+ ///
+ /// [formatargs]: ../macro.format_args.html
+ /// [write]: ../macro.write.html
+ ///
+ /// This function internally uses the [`write_all`][writeall] method on
+ /// this trait and hence will continuously write data so long as no errors
+ /// are received. This also means that partial writes are not indicated in
+ /// this signature.
+ ///
+ /// [writeall]: #method.write_all
+ ///
+ /// # Errors
+ ///
+ /// This function will return any I/O error reported while formatting.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::io::prelude::*;
+ /// use std::fs::File;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let mut buffer = File::create("foo.txt")?;
+ ///
+ /// // this call
+ /// write!(buffer, "{:.*}", 2, 1.234567)?;
+ /// // turns into this:
+ /// buffer.write_fmt(format_args!("{:.*}", 2, 1.234567))?;
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> Result<()> {
+ // Create a shim which translates a Write to a fmt::Write and saves
+ // off I/O errors. instead of discarding them
+ struct Adaptor<'a, T: ?Sized + 'a> {
+ inner: &'a mut T,
+ error: Result<()>,
+ }
+
+ impl<T: Write + ?Sized> fmt::Write for Adaptor<'_, T> {
+ fn write_str(&mut self, s: &str) -> fmt::Result {
+ match self.inner.write_all(s.as_bytes()) {
+ Ok(()) => Ok(()),
+ Err(e) => {
+ self.error = Err(e);
+ Err(fmt::Error)
+ }
+ }
+ }
+ }
+
+ let mut output = Adaptor { inner: self, error: Ok(()) };
+ match fmt::write(&mut output, fmt) {
+ Ok(()) => Ok(()),
+ Err(..) => {
+ // check if the error came from the underlying `Write` or not
+ if output.error.is_err() {
+ output.error
+ } else {
+ Err(Error::new(ErrorKind::Other, "formatter error"))
+ }
+ }
+ }
+ }
+
+ /// Creates a "by reference" adaptor for this instance of `Write`.
+ ///
+ /// The returned adaptor also implements `Write` and will simply borrow this
+ /// current writer.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::io::Write;
+ /// use std::fs::File;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let mut buffer = File::create("foo.txt")?;
+ ///
+ /// let reference = buffer.by_ref();
+ ///
+ /// // we can use reference just like our original buffer
+ /// reference.write_all(b"some bytes")?;
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ fn by_ref(&mut self) -> &mut Self where Self: Sized { self }
+}
+
+/// The `Seek` trait provides a cursor which can be moved within a stream of
+/// bytes.
+///
+/// The stream typically has a fixed size, allowing seeking relative to either
+/// end or the current offset.
+///
+/// # Examples
+///
+/// [`File`][file]s implement `Seek`:
+///
+/// [file]: ../fs/struct.File.html
+///
+/// ```no_run
+/// use std::io;
+/// use std::io::prelude::*;
+/// use std::fs::File;
+/// use std::io::SeekFrom;
+///
+/// fn main() -> io::Result<()> {
+/// let mut f = File::open("foo.txt")?;
+///
+/// // move the cursor 42 bytes from the start of the file
+/// f.seek(SeekFrom::Start(42))?;
+/// Ok(())
+/// }
+/// ```
+#[stable(feature = "rust1", since = "1.0.0")]
+pub trait Seek {
+ /// Seek to an offset, in bytes, in a stream.
+ ///
+ /// A seek beyond the end of a stream is allowed, but behavior is defined
+ /// by the implementation.
+ ///
+ /// If the seek operation completed successfully,
+ /// this method returns the new position from the start of the stream.
+ /// That position can be used later with [`SeekFrom::Start`].
+ ///
+ /// # Errors
+ ///
+ /// Seeking to a negative offset is considered an error.
+ ///
+ /// [`SeekFrom::Start`]: enum.SeekFrom.html#variant.Start
+ #[stable(feature = "rust1", since = "1.0.0")]
+ fn seek(&mut self, pos: SeekFrom) -> Result<u64>;
+
+ /// Returns the length of this stream (in bytes).
+ ///
+ /// This method is implemented using up to three seek operations. If this
+ /// method returns successfully, the seek position is unchanged (i.e. the
+ /// position before calling this method is the same as afterwards).
+ /// However, if this method returns an error, the seek position is
+ /// unspecified.
+ ///
+ /// If you need to obtain the length of *many* streams and you don't care
+ /// about the seek position afterwards, you can reduce the number of seek
+ /// operations by simply calling `seek(SeekFrom::End(0))` and using its
+ /// return value (it is also the stream length).
+ ///
+ /// Note that length of a stream can change over time (for example, when
+ /// data is appended to a file). So calling this method multiple times does
+ /// not necessarily return the same length each time.
+ ///
+ ///
+ /// # Example
+ ///
+ /// ```no_run
+ /// #![feature(seek_convenience)]
+ /// use std::{
+ /// io::{self, Seek},
+ /// fs::File,
+ /// };
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let mut f = File::open("foo.txt")?;
+ ///
+ /// let len = f.stream_len()?;
+ /// println!("The file is currently {} bytes long", len);
+ /// Ok(())
+ /// }
+ /// ```
+ #[unstable(feature = "seek_convenience", issue = "59359")]
+ fn stream_len(&mut self) -> Result<u64> {
+ let old_pos = self.stream_position()?;
+ let len = self.seek(SeekFrom::End(0))?;
+
+ // Avoid seeking a third time when we were already at the end of the
+ // stream. The branch is usually way cheaper than a seek operation.
+ if old_pos != len {
+ self.seek(SeekFrom::Start(old_pos))?;
+ }
+
+ Ok(len)
+ }
+
+ /// Returns the current seek position from the start of the stream.
+ ///
+ /// This is equivalent to `self.seek(SeekFrom::Current(0))`.
+ ///
+ ///
+ /// # Example
+ ///
+ /// ```no_run
+ /// #![feature(seek_convenience)]
+ /// use std::{
+ /// io::{self, BufRead, BufReader, Seek},
+ /// fs::File,
+ /// };
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let mut f = BufReader::new(File::open("foo.txt")?);
+ ///
+ /// let before = f.stream_position()?;
+ /// f.read_line(&mut String::new())?;
+ /// let after = f.stream_position()?;
+ ///
+ /// println!("The first line was {} bytes long", after - before);
+ /// Ok(())
+ /// }
+ /// ```
+ #[unstable(feature = "seek_convenience", issue = "59359")]
+ fn stream_position(&mut self) -> Result<u64> {
+ self.seek(SeekFrom::Current(0))
+ }
+}
+
+/// Enumeration of possible methods to seek within an I/O object.
+///
+/// It is used by the [`Seek`] trait.
+///
+/// [`Seek`]: trait.Seek.html
+#[derive(Copy, PartialEq, Eq, Clone, Debug)]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub enum SeekFrom {
+ /// Sets the offset to the provided number of bytes.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ Start(#[stable(feature = "rust1", since = "1.0.0")] u64),
+
+ /// Sets the offset to the size of this object plus the specified number of
+ /// bytes.
+ ///
+ /// It is possible to seek beyond the end of an object, but it's an error to
+ /// seek before byte 0.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ End(#[stable(feature = "rust1", since = "1.0.0")] i64),
+
+ /// Sets the offset to the current position plus the specified number of
+ /// bytes.
+ ///
+ /// It is possible to seek beyond the end of an object, but it's an error to
+ /// seek before byte 0.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ Current(#[stable(feature = "rust1", since = "1.0.0")] i64),
+}
+
+fn read_until<R: BufRead + ?Sized>(r: &mut R, delim: u8, buf: &mut Vec<u8>)
+ -> Result<usize> {
+ let mut read = 0;
+ loop {
+ let (done, used) = {
+ let available = match r.fill_buf() {
+ Ok(n) => n,
+ Err(ref e) if e.kind() == ErrorKind::Interrupted => continue,
+ Err(e) => return Err(e)
+ };
+ match memchr::memchr(delim, available) {
+ Some(i) => {
+ buf.extend_from_slice(&available[..=i]);
+ (true, i + 1)
+ }
+ None => {
+ buf.extend_from_slice(available);
+ (false, available.len())
+ }
+ }
+ };
+ r.consume(used);
+ read += used;
+ if done || used == 0 {
+ return Ok(read);
+ }
+ }
+}
+
+/// A `BufRead` is a type of `Read`er which has an internal buffer, allowing it
+/// to perform extra ways of reading.
+///
+/// For example, reading line-by-line is inefficient without using a buffer, so
+/// if you want to read by line, you'll need `BufRead`, which includes a
+/// [`read_line`] method as well as a [`lines`] iterator.
+///
+/// # Examples
+///
+/// A locked standard input implements `BufRead`:
+///
+/// ```no_run
+/// use std::io;
+/// use std::io::prelude::*;
+///
+/// let stdin = io::stdin();
+/// for line in stdin.lock().lines() {
+/// println!("{}", line.unwrap());
+/// }
+/// ```
+///
+/// If you have something that implements [`Read`], you can use the [`BufReader`
+/// type][`BufReader`] to turn it into a `BufRead`.
+///
+/// For example, [`File`] implements [`Read`], but not `BufRead`.
+/// [`BufReader`] to the rescue!
+///
+/// [`BufReader`]: struct.BufReader.html
+/// [`File`]: ../fs/struct.File.html
+/// [`read_line`]: #method.read_line
+/// [`lines`]: #method.lines
+/// [`Read`]: trait.Read.html
+///
+/// ```no_run
+/// use std::io::{self, BufReader};
+/// use std::io::prelude::*;
+/// use std::fs::File;
+///
+/// fn main() -> io::Result<()> {
+/// let f = File::open("foo.txt")?;
+/// let f = BufReader::new(f);
+///
+/// for line in f.lines() {
+/// println!("{}", line.unwrap());
+/// }
+///
+/// Ok(())
+/// }
+/// ```
+///
+#[stable(feature = "rust1", since = "1.0.0")]
+pub trait BufRead: Read {
+ /// Returns the contents of the internal buffer, filling it with more data
+ /// from the inner reader if it is empty.
+ ///
+ /// This function is a lower-level call. It needs to be paired with the
+ /// [`consume`] method to function properly. When calling this
+ /// method, none of the contents will be "read" in the sense that later
+ /// calling `read` may return the same contents. As such, [`consume`] must
+ /// be called with the number of bytes that are consumed from this buffer to
+ /// ensure that the bytes are never returned twice.
+ ///
+ /// [`consume`]: #tymethod.consume
+ ///
+ /// An empty buffer returned indicates that the stream has reached EOF.
+ ///
+ /// # Errors
+ ///
+ /// This function will return an I/O error if the underlying reader was
+ /// read, but returned an error.
+ ///
+ /// # Examples
+ ///
+ /// A locked standard input implements `BufRead`:
+ ///
+ /// ```no_run
+ /// use std::io;
+ /// use std::io::prelude::*;
+ ///
+ /// let stdin = io::stdin();
+ /// let mut stdin = stdin.lock();
+ ///
+ /// // we can't have two `&mut` references to `stdin`, so use a block
+ /// // to end the borrow early.
+ /// let length = {
+ /// let buffer = stdin.fill_buf().unwrap();
+ ///
+ /// // work with buffer
+ /// println!("{:?}", buffer);
+ ///
+ /// buffer.len()
+ /// };
+ ///
+ /// // ensure the bytes we worked with aren't returned again later
+ /// stdin.consume(length);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ fn fill_buf(&mut self) -> Result<&[u8]>;
+
+ /// Tells this buffer that `amt` bytes have been consumed from the buffer,
+ /// so they should no longer be returned in calls to `read`.
+ ///
+ /// This function is a lower-level call. It needs to be paired with the
+ /// [`fill_buf`] method to function properly. This function does
+ /// not perform any I/O, it simply informs this object that some amount of
+ /// its buffer, returned from [`fill_buf`], has been consumed and should
+ /// no longer be returned. As such, this function may do odd things if
+ /// [`fill_buf`] isn't called before calling it.
+ ///
+ /// The `amt` must be `<=` the number of bytes in the buffer returned by
+ /// [`fill_buf`].
+ ///
+ /// # Examples
+ ///
+ /// Since `consume()` is meant to be used with [`fill_buf`],
+ /// that method's example includes an example of `consume()`.
+ ///
+ /// [`fill_buf`]: #tymethod.fill_buf
+ #[stable(feature = "rust1", since = "1.0.0")]
+ fn consume(&mut self, amt: usize);
+
+ /// Read all bytes into `buf` until the delimiter `byte` or EOF is reached.
+ ///
+ /// This function will read bytes from the underlying stream until the
+ /// delimiter or EOF is found. Once found, all bytes up to, and including,
+ /// the delimiter (if found) will be appended to `buf`.
+ ///
+ /// If successful, this function will return the total number of bytes read.
+ ///
+ /// # Errors
+ ///
+ /// This function will ignore all instances of [`ErrorKind::Interrupted`] and
+ /// will otherwise return any errors returned by [`fill_buf`].
+ ///
+ /// If an I/O error is encountered then all bytes read so far will be
+ /// present in `buf` and its length will have been adjusted appropriately.
+ ///
+ /// [`fill_buf`]: #tymethod.fill_buf
+ /// [`ErrorKind::Interrupted`]: enum.ErrorKind.html#variant.Interrupted
+ ///
+ /// # Examples
+ ///
+ /// [`std::io::Cursor`][`Cursor`] is a type that implements `BufRead`. In
+ /// this example, we use [`Cursor`] to read all the bytes in a byte slice
+ /// in hyphen delimited segments:
+ ///
+ /// [`Cursor`]: struct.Cursor.html
+ ///
+ /// ```
+ /// use std::io::{self, BufRead};
+ ///
+ /// let mut cursor = io::Cursor::new(b"lorem-ipsum");
+ /// let mut buf = vec![];
+ ///
+ /// // cursor is at 'l'
+ /// let num_bytes = cursor.read_until(b'-', &mut buf)
+ /// .expect("reading from cursor won't fail");
+ /// assert_eq!(num_bytes, 6);
+ /// assert_eq!(buf, b"lorem-");
+ /// buf.clear();
+ ///
+ /// // cursor is at 'i'
+ /// let num_bytes = cursor.read_until(b'-', &mut buf)
+ /// .expect("reading from cursor won't fail");
+ /// assert_eq!(num_bytes, 5);
+ /// assert_eq!(buf, b"ipsum");
+ /// buf.clear();
+ ///
+ /// // cursor is at EOF
+ /// let num_bytes = cursor.read_until(b'-', &mut buf)
+ /// .expect("reading from cursor won't fail");
+ /// assert_eq!(num_bytes, 0);
+ /// assert_eq!(buf, b"");
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ fn read_until(&mut self, byte: u8, buf: &mut Vec<u8>) -> Result<usize> {
+ read_until(self, byte, buf)
+ }
+
+ /// Read all bytes until a newline (the 0xA byte) is reached, and append
+ /// them to the provided buffer.
+ ///
+ /// This function will read bytes from the underlying stream until the
+ /// newline delimiter (the 0xA byte) or EOF is found. Once found, all bytes
+ /// up to, and including, the delimiter (if found) will be appended to
+ /// `buf`.
+ ///
+ /// If successful, this function will return the total number of bytes read.
+ ///
+ /// If this function returns `Ok(0)`, the stream has reached EOF.
+ ///
+ /// # Errors
+ ///
+ /// This function has the same error semantics as [`read_until`] and will
+ /// also return an error if the read bytes are not valid UTF-8. If an I/O
+ /// error is encountered then `buf` may contain some bytes already read in
+ /// the event that all data read so far was valid UTF-8.
+ ///
+ /// [`read_until`]: #method.read_until
+ ///
+ /// # Examples
+ ///
+ /// [`std::io::Cursor`][`Cursor`] is a type that implements `BufRead`. In
+ /// this example, we use [`Cursor`] to read all the lines in a byte slice:
+ ///
+ /// [`Cursor`]: struct.Cursor.html
+ ///
+ /// ```
+ /// use std::io::{self, BufRead};
+ ///
+ /// let mut cursor = io::Cursor::new(b"foo\nbar");
+ /// let mut buf = String::new();
+ ///
+ /// // cursor is at 'f'
+ /// let num_bytes = cursor.read_line(&mut buf)
+ /// .expect("reading from cursor won't fail");
+ /// assert_eq!(num_bytes, 4);
+ /// assert_eq!(buf, "foo\n");
+ /// buf.clear();
+ ///
+ /// // cursor is at 'b'
+ /// let num_bytes = cursor.read_line(&mut buf)
+ /// .expect("reading from cursor won't fail");
+ /// assert_eq!(num_bytes, 3);
+ /// assert_eq!(buf, "bar");
+ /// buf.clear();
+ ///
+ /// // cursor is at EOF
+ /// let num_bytes = cursor.read_line(&mut buf)
+ /// .expect("reading from cursor won't fail");
+ /// assert_eq!(num_bytes, 0);
+ /// assert_eq!(buf, "");
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ fn read_line(&mut self, buf: &mut String) -> Result<usize> {
+ // Note that we are not calling the `.read_until` method here, but
+ // rather our hardcoded implementation. For more details as to why, see
+ // the comments in `read_to_end`.
+ append_to_string(buf, |b| read_until(self, b'\n', b))
+ }
+
+ /// Returns an iterator over the contents of this reader split on the byte
+ /// `byte`.
+ ///
+ /// The iterator returned from this function will return instances of
+ /// [`io::Result`]`<`[`Vec<u8>`]`>`. Each vector returned will *not* have
+ /// the delimiter byte at the end.
+ ///
+ /// This function will yield errors whenever [`read_until`] would have
+ /// also yielded an error.
+ ///
+ /// [`io::Result`]: type.Result.html
+ /// [`Vec<u8>`]: ../vec/struct.Vec.html
+ /// [`read_until`]: #method.read_until
+ ///
+ /// # Examples
+ ///
+ /// [`std::io::Cursor`][`Cursor`] is a type that implements `BufRead`. In
+ /// this example, we use [`Cursor`] to iterate over all hyphen delimited
+ /// segments in a byte slice
+ ///
+ /// [`Cursor`]: struct.Cursor.html
+ ///
+ /// ```
+ /// use std::io::{self, BufRead};
+ ///
+ /// let cursor = io::Cursor::new(b"lorem-ipsum-dolor");
+ ///
+ /// let mut split_iter = cursor.split(b'-').map(|l| l.unwrap());
+ /// assert_eq!(split_iter.next(), Some(b"lorem".to_vec()));
+ /// assert_eq!(split_iter.next(), Some(b"ipsum".to_vec()));
+ /// assert_eq!(split_iter.next(), Some(b"dolor".to_vec()));
+ /// assert_eq!(split_iter.next(), None);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ fn split(self, byte: u8) -> Split<Self> where Self: Sized {
+ Split { buf: self, delim: byte }
+ }
+
+ /// Returns an iterator over the lines of this reader.
+ ///
+ /// The iterator returned from this function will yield instances of
+ /// [`io::Result`]`<`[`String`]`>`. Each string returned will *not* have a newline
+ /// byte (the 0xA byte) or CRLF (0xD, 0xA bytes) at the end.
+ ///
+ /// [`io::Result`]: type.Result.html
+ /// [`String`]: ../string/struct.String.html
+ ///
+ /// # Examples
+ ///
+ /// [`std::io::Cursor`][`Cursor`] is a type that implements `BufRead`. In
+ /// this example, we use [`Cursor`] to iterate over all the lines in a byte
+ /// slice.
+ ///
+ /// [`Cursor`]: struct.Cursor.html
+ ///
+ /// ```
+ /// use std::io::{self, BufRead};
+ ///
+ /// let cursor = io::Cursor::new(b"lorem\nipsum\r\ndolor");
+ ///
+ /// let mut lines_iter = cursor.lines().map(|l| l.unwrap());
+ /// assert_eq!(lines_iter.next(), Some(String::from("lorem")));
+ /// assert_eq!(lines_iter.next(), Some(String::from("ipsum")));
+ /// assert_eq!(lines_iter.next(), Some(String::from("dolor")));
+ /// assert_eq!(lines_iter.next(), None);
+ /// ```
+ ///
+ /// # Errors
+ ///
+ /// Each line of the iterator has the same error semantics as [`BufRead::read_line`].
+ ///
+ /// [`BufRead::read_line`]: trait.BufRead.html#method.read_line
+ #[stable(feature = "rust1", since = "1.0.0")]
+ fn lines(self) -> Lines<Self> where Self: Sized {
+ Lines { buf: self }
+ }
+}
+
+/// Adaptor to chain together two readers.
+///
+/// This struct is generally created by calling [`chain`] on a reader.
+/// Please see the documentation of [`chain`] for more details.
+///
+/// [`chain`]: trait.Read.html#method.chain
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct Chain<T, U> {
+ first: T,
+ second: U,
+ done_first: bool,
+}
+
+impl<T, U> Chain<T, U> {
+ /// Consumes the `Chain`, returning the wrapped readers.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::io;
+ /// use std::io::prelude::*;
+ /// use std::fs::File;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let mut foo_file = File::open("foo.txt")?;
+ /// let mut bar_file = File::open("bar.txt")?;
+ ///
+ /// let chain = foo_file.chain(bar_file);
+ /// let (foo_file, bar_file) = chain.into_inner();
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "more_io_inner_methods", since = "1.20.0")]
+ pub fn into_inner(self) -> (T, U) {
+ (self.first, self.second)
+ }
+
+ /// Gets references to the underlying readers in this `Chain`.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::io;
+ /// use std::io::prelude::*;
+ /// use std::fs::File;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let mut foo_file = File::open("foo.txt")?;
+ /// let mut bar_file = File::open("bar.txt")?;
+ ///
+ /// let chain = foo_file.chain(bar_file);
+ /// let (foo_file, bar_file) = chain.get_ref();
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "more_io_inner_methods", since = "1.20.0")]
+ pub fn get_ref(&self) -> (&T, &U) {
+ (&self.first, &self.second)
+ }
+
+ /// Gets mutable references to the underlying readers in this `Chain`.
+ ///
+ /// Care should be taken to avoid modifying the internal I/O state of the
+ /// underlying readers as doing so may corrupt the internal state of this
+ /// `Chain`.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::io;
+ /// use std::io::prelude::*;
+ /// use std::fs::File;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let mut foo_file = File::open("foo.txt")?;
+ /// let mut bar_file = File::open("bar.txt")?;
+ ///
+ /// let mut chain = foo_file.chain(bar_file);
+ /// let (foo_file, bar_file) = chain.get_mut();
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "more_io_inner_methods", since = "1.20.0")]
+ pub fn get_mut(&mut self) -> (&mut T, &mut U) {
+ (&mut self.first, &mut self.second)
+ }
+}
+
+#[stable(feature = "std_debug", since = "1.16.0")]
+impl<T: fmt::Debug, U: fmt::Debug> fmt::Debug for Chain<T, U> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("Chain")
+ .field("t", &self.first)
+ .field("u", &self.second)
+ .finish()
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T: Read, U: Read> Read for Chain<T, U> {
+ fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
+ if !self.done_first {
+ match self.first.read(buf)? {
+ 0 if buf.len() != 0 => self.done_first = true,
+ n => return Ok(n),
+ }
+ }
+ self.second.read(buf)
+ }
+
+ fn read_vectored(&mut self, bufs: &mut [IoVecMut<'_>]) -> Result<usize> {
+ if !self.done_first {
+ match self.first.read_vectored(bufs)? {
+ 0 if bufs.iter().any(|b| !b.is_empty()) => self.done_first = true,
+ n => return Ok(n),
+ }
+ }
+ self.second.read_vectored(bufs)
+ }
+
+ unsafe fn initializer(&self) -> Initializer {
+ let initializer = self.first.initializer();
+ if initializer.should_initialize() {
+ initializer
+ } else {
+ self.second.initializer()
+ }
+ }
+}
+
+#[stable(feature = "chain_bufread", since = "1.9.0")]
+impl<T: BufRead, U: BufRead> BufRead for Chain<T, U> {
+ fn fill_buf(&mut self) -> Result<&[u8]> {
+ if !self.done_first {
+ match self.first.fill_buf()? {
+ buf if buf.len() == 0 => { self.done_first = true; }
+ buf => return Ok(buf),
+ }
+ }
+ self.second.fill_buf()
+ }
+
+ fn consume(&mut self, amt: usize) {
+ if !self.done_first {
+ self.first.consume(amt)
+ } else {
+ self.second.consume(amt)
+ }
+ }
+}
+
+/// Reader adaptor which limits the bytes read from an underlying reader.
+///
+/// This struct is generally created by calling [`take`] on a reader.
+/// Please see the documentation of [`take`] for more details.
+///
+/// [`take`]: trait.Read.html#method.take
+#[stable(feature = "rust1", since = "1.0.0")]
+#[derive(Debug)]
+pub struct Take<T> {
+ inner: T,
+ limit: u64,
+}
+
+impl<T> Take<T> {
+ /// Returns the number of bytes that can be read before this instance will
+ /// return EOF.
+ ///
+ /// # Note
+ ///
+ /// This instance may reach `EOF` after reading fewer bytes than indicated by
+ /// this method if the underlying [`Read`] instance reaches EOF.
+ ///
+ /// [`Read`]: ../../std/io/trait.Read.html
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::io;
+ /// use std::io::prelude::*;
+ /// use std::fs::File;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let f = File::open("foo.txt")?;
+ ///
+ /// // read at most five bytes
+ /// let handle = f.take(5);
+ ///
+ /// println!("limit: {}", handle.limit());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn limit(&self) -> u64 { self.limit }
+
+ /// Sets the number of bytes that can be read before this instance will
+ /// return EOF. This is the same as constructing a new `Take` instance, so
+ /// the amount of bytes read and the previous limit value don't matter when
+ /// calling this method.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::io;
+ /// use std::io::prelude::*;
+ /// use std::fs::File;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let f = File::open("foo.txt")?;
+ ///
+ /// // read at most five bytes
+ /// let mut handle = f.take(5);
+ /// handle.set_limit(10);
+ ///
+ /// assert_eq!(handle.limit(), 10);
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "take_set_limit", since = "1.27.0")]
+ pub fn set_limit(&mut self, limit: u64) {
+ self.limit = limit;
+ }
+
+ /// Consumes the `Take`, returning the wrapped reader.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::io;
+ /// use std::io::prelude::*;
+ /// use std::fs::File;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let mut file = File::open("foo.txt")?;
+ ///
+ /// let mut buffer = [0; 5];
+ /// let mut handle = file.take(5);
+ /// handle.read(&mut buffer)?;
+ ///
+ /// let file = handle.into_inner();
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "io_take_into_inner", since = "1.15.0")]
+ pub fn into_inner(self) -> T {
+ self.inner
+ }
+
+ /// Gets a reference to the underlying reader.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::io;
+ /// use std::io::prelude::*;
+ /// use std::fs::File;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let mut file = File::open("foo.txt")?;
+ ///
+ /// let mut buffer = [0; 5];
+ /// let mut handle = file.take(5);
+ /// handle.read(&mut buffer)?;
+ ///
+ /// let file = handle.get_ref();
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "more_io_inner_methods", since = "1.20.0")]
+ pub fn get_ref(&self) -> &T {
+ &self.inner
+ }
+
+ /// Gets a mutable reference to the underlying reader.
+ ///
+ /// Care should be taken to avoid modifying the internal I/O state of the
+ /// underlying reader as doing so may corrupt the internal limit of this
+ /// `Take`.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::io;
+ /// use std::io::prelude::*;
+ /// use std::fs::File;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let mut file = File::open("foo.txt")?;
+ ///
+ /// let mut buffer = [0; 5];
+ /// let mut handle = file.take(5);
+ /// handle.read(&mut buffer)?;
+ ///
+ /// let file = handle.get_mut();
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "more_io_inner_methods", since = "1.20.0")]
+ pub fn get_mut(&mut self) -> &mut T {
+ &mut self.inner
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T: Read> Read for Take<T> {
+ fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
+ // Don't call into inner reader at all at EOF because it may still block
+ if self.limit == 0 {
+ return Ok(0);
+ }
+
+ let max = cmp::min(buf.len() as u64, self.limit) as usize;
+ let n = self.inner.read(&mut buf[..max])?;
+ self.limit -= n as u64;
+ Ok(n)
+ }
+
+ unsafe fn initializer(&self) -> Initializer {
+ self.inner.initializer()
+ }
+
+ fn read_to_end(&mut self, buf: &mut Vec<u8>) -> Result<usize> {
+ let reservation_size = cmp::min(self.limit, 32) as usize;
+
+ read_to_end_with_reservation(self, buf, reservation_size)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T: BufRead> BufRead for Take<T> {
+ fn fill_buf(&mut self) -> Result<&[u8]> {
+ // Don't call into inner reader at all at EOF because it may still block
+ if self.limit == 0 {
+ return Ok(&[]);
+ }
+
+ let buf = self.inner.fill_buf()?;
+ let cap = cmp::min(buf.len() as u64, self.limit) as usize;
+ Ok(&buf[..cap])
+ }
+
+ fn consume(&mut self, amt: usize) {
+ // Don't let callers reset the limit by passing an overlarge value
+ let amt = cmp::min(amt as u64, self.limit) as usize;
+ self.limit -= amt as u64;
+ self.inner.consume(amt);
+ }
+}
+
+/// An iterator over `u8` values of a reader.
+///
+/// This struct is generally created by calling [`bytes`] on a reader.
+/// Please see the documentation of [`bytes`] for more details.
+///
+/// [`bytes`]: trait.Read.html#method.bytes
+#[stable(feature = "rust1", since = "1.0.0")]
+#[derive(Debug)]
+pub struct Bytes<R> {
+ inner: R,
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<R: Read> Iterator for Bytes<R> {
+ type Item = Result<u8>;
+
+ fn next(&mut self) -> Option<Result<u8>> {
+ let mut byte = 0;
+ loop {
+ return match self.inner.read(slice::from_mut(&mut byte)) {
+ Ok(0) => None,
+ Ok(..) => Some(Ok(byte)),
+ Err(ref e) if e.kind() == ErrorKind::Interrupted => continue,
+ Err(e) => Some(Err(e)),
+ };
+ }
+ }
+}
+
+/// An iterator over the contents of an instance of `BufRead` split on a
+/// particular byte.
+///
+/// This struct is generally created by calling [`split`][split] on a
+/// `BufRead`. Please see the documentation of `split()` for more details.
+///
+/// [split]: trait.BufRead.html#method.split
+#[stable(feature = "rust1", since = "1.0.0")]
+#[derive(Debug)]
+pub struct Split<B> {
+ buf: B,
+ delim: u8,
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<B: BufRead> Iterator for Split<B> {
+ type Item = Result<Vec<u8>>;
+
+ fn next(&mut self) -> Option<Result<Vec<u8>>> {
+ let mut buf = Vec::new();
+ match self.buf.read_until(self.delim, &mut buf) {
+ Ok(0) => None,
+ Ok(_n) => {
+ if buf[buf.len() - 1] == self.delim {
+ buf.pop();
+ }
+ Some(Ok(buf))
+ }
+ Err(e) => Some(Err(e))
+ }
+ }
+}
+
+/// An iterator over the lines of an instance of `BufRead`.
+///
+/// This struct is generally created by calling [`lines`][lines] on a
+/// `BufRead`. Please see the documentation of `lines()` for more details.
+///
+/// [lines]: trait.BufRead.html#method.lines
+#[stable(feature = "rust1", since = "1.0.0")]
+#[derive(Debug)]
+pub struct Lines<B> {
+ buf: B,
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<B: BufRead> Iterator for Lines<B> {
+ type Item = Result<String>;
+
+ fn next(&mut self) -> Option<Result<String>> {
+ let mut buf = String::new();
+ match self.buf.read_line(&mut buf) {
+ Ok(0) => None,
+ Ok(_n) => {
+ if buf.ends_with("\n") {
+ buf.pop();
+ if buf.ends_with("\r") {
+ buf.pop();
+ }
+ }
+ Some(Ok(buf))
+ }
+ Err(e) => Some(Err(e))
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use crate::io::prelude::*;
+ use crate::io;
+ use super::{Cursor, SeekFrom, repeat};
+
+ #[test]
+ #[cfg_attr(target_os = "emscripten", ignore)]
+ fn read_until() {
+ let mut buf = Cursor::new(&b"12"[..]);
+ let mut v = Vec::new();
+ assert_eq!(buf.read_until(b'3', &mut v).unwrap(), 2);
+ assert_eq!(v, b"12");
+
+ let mut buf = Cursor::new(&b"1233"[..]);
+ let mut v = Vec::new();
+ assert_eq!(buf.read_until(b'3', &mut v).unwrap(), 3);
+ assert_eq!(v, b"123");
+ v.truncate(0);
+ assert_eq!(buf.read_until(b'3', &mut v).unwrap(), 1);
+ assert_eq!(v, b"3");
+ v.truncate(0);
+ assert_eq!(buf.read_until(b'3', &mut v).unwrap(), 0);
+ assert_eq!(v, []);
+ }
+
+ #[test]
+ fn split() {
+ let buf = Cursor::new(&b"12"[..]);
+ let mut s = buf.split(b'3');
+ assert_eq!(s.next().unwrap().unwrap(), vec![b'1', b'2']);
+ assert!(s.next().is_none());
+
+ let buf = Cursor::new(&b"1233"[..]);
+ let mut s = buf.split(b'3');
+ assert_eq!(s.next().unwrap().unwrap(), vec![b'1', b'2']);
+ assert_eq!(s.next().unwrap().unwrap(), vec![]);
+ assert!(s.next().is_none());
+ }
+
+ #[test]
+ fn read_line() {
+ let mut buf = Cursor::new(&b"12"[..]);
+ let mut v = String::new();
+ assert_eq!(buf.read_line(&mut v).unwrap(), 2);
+ assert_eq!(v, "12");
+
+ let mut buf = Cursor::new(&b"12\n\n"[..]);
+ let mut v = String::new();
+ assert_eq!(buf.read_line(&mut v).unwrap(), 3);
+ assert_eq!(v, "12\n");
+ v.truncate(0);
+ assert_eq!(buf.read_line(&mut v).unwrap(), 1);
+ assert_eq!(v, "\n");
+ v.truncate(0);
+ assert_eq!(buf.read_line(&mut v).unwrap(), 0);
+ assert_eq!(v, "");
+ }
+
+ #[test]
+ fn lines() {
+ let buf = Cursor::new(&b"12\r"[..]);
+ let mut s = buf.lines();
+ assert_eq!(s.next().unwrap().unwrap(), "12\r".to_string());
+ assert!(s.next().is_none());
+
+ let buf = Cursor::new(&b"12\r\n\n"[..]);
+ let mut s = buf.lines();
+ assert_eq!(s.next().unwrap().unwrap(), "12".to_string());
+ assert_eq!(s.next().unwrap().unwrap(), "".to_string());
+ assert!(s.next().is_none());
+ }
+
+ #[test]
+ fn read_to_end() {
+ let mut c = Cursor::new(&b""[..]);
+ let mut v = Vec::new();
+ assert_eq!(c.read_to_end(&mut v).unwrap(), 0);
+ assert_eq!(v, []);
+
+ let mut c = Cursor::new(&b"1"[..]);
+ let mut v = Vec::new();
+ assert_eq!(c.read_to_end(&mut v).unwrap(), 1);
+ assert_eq!(v, b"1");
+
+ let cap = 1024 * 1024;
+ let data = (0..cap).map(|i| (i / 3) as u8).collect::<Vec<_>>();
+ let mut v = Vec::new();
+ let (a, b) = data.split_at(data.len() / 2);
+ assert_eq!(Cursor::new(a).read_to_end(&mut v).unwrap(), a.len());
+ assert_eq!(Cursor::new(b).read_to_end(&mut v).unwrap(), b.len());
+ assert_eq!(v, data);
+ }
+
+ #[test]
+ fn read_to_string() {
+ let mut c = Cursor::new(&b""[..]);
+ let mut v = String::new();
+ assert_eq!(c.read_to_string(&mut v).unwrap(), 0);
+ assert_eq!(v, "");
+
+ let mut c = Cursor::new(&b"1"[..]);
+ let mut v = String::new();
+ assert_eq!(c.read_to_string(&mut v).unwrap(), 1);
+ assert_eq!(v, "1");
+
+ let mut c = Cursor::new(&b"\xff"[..]);
+ let mut v = String::new();
+ assert!(c.read_to_string(&mut v).is_err());
+ }
+
+ #[test]
+ fn read_exact() {
+ let mut buf = [0; 4];
+
+ let mut c = Cursor::new(&b""[..]);
+ assert_eq!(c.read_exact(&mut buf).unwrap_err().kind(),
+ io::ErrorKind::UnexpectedEof);
+
+ let mut c = Cursor::new(&b"123"[..]).chain(Cursor::new(&b"456789"[..]));
+ c.read_exact(&mut buf).unwrap();
+ assert_eq!(&buf, b"1234");
+ c.read_exact(&mut buf).unwrap();
+ assert_eq!(&buf, b"5678");
+ assert_eq!(c.read_exact(&mut buf).unwrap_err().kind(),
+ io::ErrorKind::UnexpectedEof);
+ }
+
+ #[test]
+ fn read_exact_slice() {
+ let mut buf = [0; 4];
+
+ let mut c = &b""[..];
+ assert_eq!(c.read_exact(&mut buf).unwrap_err().kind(),
+ io::ErrorKind::UnexpectedEof);
+
+ let mut c = &b"123"[..];
+ assert_eq!(c.read_exact(&mut buf).unwrap_err().kind(),
+ io::ErrorKind::UnexpectedEof);
+ // make sure the optimized (early returning) method is being used
+ assert_eq!(&buf, &[0; 4]);
+
+ let mut c = &b"1234"[..];
+ c.read_exact(&mut buf).unwrap();
+ assert_eq!(&buf, b"1234");
+
+ let mut c = &b"56789"[..];
+ c.read_exact(&mut buf).unwrap();
+ assert_eq!(&buf, b"5678");
+ assert_eq!(c, b"9");
+ }
+
+ #[test]
+ fn take_eof() {
+ struct R;
+
+ impl Read for R {
+ fn read(&mut self, _: &mut [u8]) -> io::Result<usize> {
+ Err(io::Error::new(io::ErrorKind::Other, ""))
+ }
+ }
+ impl BufRead for R {
+ fn fill_buf(&mut self) -> io::Result<&[u8]> {
+ Err(io::Error::new(io::ErrorKind::Other, ""))
+ }
+ fn consume(&mut self, _amt: usize) { }
+ }
+
+ let mut buf = [0; 1];
+ assert_eq!(0, R.take(0).read(&mut buf).unwrap());
+ assert_eq!(b"", R.take(0).fill_buf().unwrap());
+ }
+
+ fn cmp_bufread<Br1: BufRead, Br2: BufRead>(mut br1: Br1, mut br2: Br2, exp: &[u8]) {
+ let mut cat = Vec::new();
+ loop {
+ let consume = {
+ let buf1 = br1.fill_buf().unwrap();
+ let buf2 = br2.fill_buf().unwrap();
+ let minlen = if buf1.len() < buf2.len() { buf1.len() } else { buf2.len() };
+ assert_eq!(buf1[..minlen], buf2[..minlen]);
+ cat.extend_from_slice(&buf1[..minlen]);
+ minlen
+ };
+ if consume == 0 {
+ break;
+ }
+ br1.consume(consume);
+ br2.consume(consume);
+ }
+ assert_eq!(br1.fill_buf().unwrap().len(), 0);
+ assert_eq!(br2.fill_buf().unwrap().len(), 0);
+ assert_eq!(&cat[..], &exp[..])
+ }
+
+ #[test]
+ fn chain_bufread() {
+ let testdata = b"ABCDEFGHIJKL";
+ let chain1 = (&testdata[..3]).chain(&testdata[3..6])
+ .chain(&testdata[6..9])
+ .chain(&testdata[9..]);
+ let chain2 = (&testdata[..4]).chain(&testdata[4..8])
+ .chain(&testdata[8..]);
+ cmp_bufread(chain1, chain2, &testdata[..]);
+ }
+
+ #[test]
+ fn chain_zero_length_read_is_not_eof() {
+ let a = b"A";
+ let b = b"B";
+ let mut s = String::new();
+ let mut chain = (&a[..]).chain(&b[..]);
+ chain.read(&mut []).unwrap();
+ chain.read_to_string(&mut s).unwrap();
+ assert_eq!("AB", s);
+ }
+
+ #[bench]
+ #[cfg_attr(target_os = "emscripten", ignore)]
+ fn bench_read_to_end(b: &mut test::Bencher) {
+ b.iter(|| {
+ let mut lr = repeat(1).take(10000000);
+ let mut vec = Vec::with_capacity(1024);
+ super::read_to_end(&mut lr, &mut vec)
+ });
+ }
+
+ #[test]
+ fn seek_len() -> io::Result<()> {
+ let mut c = Cursor::new(vec![0; 15]);
+ assert_eq!(c.stream_len()?, 15);
+
+ c.seek(SeekFrom::End(0))?;
+ let old_pos = c.stream_position()?;
+ assert_eq!(c.stream_len()?, 15);
+ assert_eq!(c.stream_position()?, old_pos);
+
+ c.seek(SeekFrom::Start(7))?;
+ c.seek(SeekFrom::Current(2))?;
+ let old_pos = c.stream_position()?;
+ assert_eq!(c.stream_len()?, 15);
+ assert_eq!(c.stream_position()?, old_pos);
+
+ Ok(())
+ }
+
+ #[test]
+ fn seek_position() -> io::Result<()> {
+ // All `asserts` are duplicated here to make sure the method does not
+ // change anything about the seek state.
+ let mut c = Cursor::new(vec![0; 15]);
+ assert_eq!(c.stream_position()?, 0);
+ assert_eq!(c.stream_position()?, 0);
+
+ c.seek(SeekFrom::End(0))?;
+ assert_eq!(c.stream_position()?, 15);
+ assert_eq!(c.stream_position()?, 15);
+
+
+ c.seek(SeekFrom::Start(7))?;
+ c.seek(SeekFrom::Current(2))?;
+ assert_eq!(c.stream_position()?, 9);
+ assert_eq!(c.stream_position()?, 9);
+
+ c.seek(SeekFrom::End(-3))?;
+ c.seek(SeekFrom::Current(1))?;
+ c.seek(SeekFrom::Current(-5))?;
+ assert_eq!(c.stream_position()?, 8);
+ assert_eq!(c.stream_position()?, 8);
+
+ Ok(())
+ }
+}
diff --git a/src/libstd/io/prelude.rs b/src/libstd/io/prelude.rs
new file mode 100644
index 0000000..2e19edf
--- /dev/null
+++ b/src/libstd/io/prelude.rs
@@ -0,0 +1,14 @@
+//! The I/O Prelude
+//!
+//! The purpose of this module is to alleviate imports of many common I/O traits
+//! by adding a glob import to the top of I/O heavy modules:
+//!
+//! ```
+//! # #![allow(unused_imports)]
+//! use std::io::prelude::*;
+//! ```
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use super::{Read, Write, BufRead, Seek};
diff --git a/src/libstd/io/stdio.rs b/src/libstd/io/stdio.rs
new file mode 100644
index 0000000..0bbff57
--- /dev/null
+++ b/src/libstd/io/stdio.rs
@@ -0,0 +1,815 @@
+#![cfg_attr(test, allow(unused))]
+
+use crate::io::prelude::*;
+
+use crate::cell::RefCell;
+use crate::fmt;
+use crate::io::lazy::Lazy;
+use crate::io::{self, Initializer, BufReader, LineWriter};
+use crate::sync::{Arc, Mutex, MutexGuard};
+use crate::sys::stdio;
+use crate::sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard};
+use crate::thread::LocalKey;
+
+thread_local! {
+ /// Stdout used by print! and println! macros
+ static LOCAL_STDOUT: RefCell<Option<Box<dyn Write + Send>>> = {
+ RefCell::new(None)
+ }
+}
+
+thread_local! {
+ /// Stderr used by eprint! and eprintln! macros, and panics
+ static LOCAL_STDERR: RefCell<Option<Box<dyn Write + Send>>> = {
+ RefCell::new(None)
+ }
+}
+
+/// A handle to a raw instance of the standard input stream of this process.
+///
+/// This handle is not synchronized or buffered in any fashion. Constructed via
+/// the `std::io::stdio::stdin_raw` function.
+struct StdinRaw(stdio::Stdin);
+
+/// A handle to a raw instance of the standard output stream of this process.
+///
+/// This handle is not synchronized or buffered in any fashion. Constructed via
+/// the `std::io::stdio::stdout_raw` function.
+struct StdoutRaw(stdio::Stdout);
+
+/// A handle to a raw instance of the standard output stream of this process.
+///
+/// This handle is not synchronized or buffered in any fashion. Constructed via
+/// the `std::io::stdio::stderr_raw` function.
+struct StderrRaw(stdio::Stderr);
+
+/// Constructs a new raw handle to the standard input of this process.
+///
+/// The returned handle does not interact with any other handles created nor
+/// handles returned by `std::io::stdin`. Data buffered by the `std::io::stdin`
+/// handles is **not** available to raw handles returned from this function.
+///
+/// The returned handle has no external synchronization or buffering.
+fn stdin_raw() -> io::Result<StdinRaw> { stdio::Stdin::new().map(StdinRaw) }
+
+/// Constructs a new raw handle to the standard output stream of this process.
+///
+/// The returned handle does not interact with any other handles created nor
+/// handles returned by `std::io::stdout`. Note that data is buffered by the
+/// `std::io::stdout` handles so writes which happen via this raw handle may
+/// appear before previous writes.
+///
+/// The returned handle has no external synchronization or buffering layered on
+/// top.
+fn stdout_raw() -> io::Result<StdoutRaw> { stdio::Stdout::new().map(StdoutRaw) }
+
+/// Constructs a new raw handle to the standard error stream of this process.
+///
+/// The returned handle does not interact with any other handles created nor
+/// handles returned by `std::io::stderr`.
+///
+/// The returned handle has no external synchronization or buffering layered on
+/// top.
+fn stderr_raw() -> io::Result<StderrRaw> { stdio::Stderr::new().map(StderrRaw) }
+
+impl Read for StdinRaw {
+ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { self.0.read(buf) }
+
+ #[inline]
+ unsafe fn initializer(&self) -> Initializer {
+ Initializer::nop()
+ }
+}
+impl Write for StdoutRaw {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> { self.0.write(buf) }
+ fn flush(&mut self) -> io::Result<()> { self.0.flush() }
+}
+impl Write for StderrRaw {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> { self.0.write(buf) }
+ fn flush(&mut self) -> io::Result<()> { self.0.flush() }
+}
+
+enum Maybe<T> {
+ Real(T),
+ Fake,
+}
+
+impl<W: io::Write> io::Write for Maybe<W> {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ match *self {
+ Maybe::Real(ref mut w) => handle_ebadf(w.write(buf), buf.len()),
+ Maybe::Fake => Ok(buf.len())
+ }
+ }
+
+ fn flush(&mut self) -> io::Result<()> {
+ match *self {
+ Maybe::Real(ref mut w) => handle_ebadf(w.flush(), ()),
+ Maybe::Fake => Ok(())
+ }
+ }
+}
+
+impl<R: io::Read> io::Read for Maybe<R> {
+ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+ match *self {
+ Maybe::Real(ref mut r) => handle_ebadf(r.read(buf), 0),
+ Maybe::Fake => Ok(0)
+ }
+ }
+}
+
+fn handle_ebadf<T>(r: io::Result<T>, default: T) -> io::Result<T> {
+ match r {
+ Err(ref e) if stdio::is_ebadf(e) => Ok(default),
+ r => r
+ }
+}
+
+/// A handle to the standard input stream of a process.
+///
+/// Each handle is a shared reference to a global buffer of input data to this
+/// process. A handle can be `lock`'d to gain full access to [`BufRead`] methods
+/// (e.g., `.lines()`). Reads to this handle are otherwise locked with respect
+/// to other reads.
+///
+/// This handle implements the `Read` trait, but beware that concurrent reads
+/// of `Stdin` must be executed with care.
+///
+/// Created by the [`io::stdin`] method.
+///
+/// [`io::stdin`]: fn.stdin.html
+/// [`BufRead`]: trait.BufRead.html
+///
+/// ### Note: Windows Portability Consideration
+/// When operating in a console, the Windows implementation of this stream does not support
+/// non-UTF-8 byte sequences. Attempting to read bytes that are not valid UTF-8 will return
+/// an error.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct Stdin {
+ inner: Arc<Mutex<BufReader<Maybe<StdinRaw>>>>,
+}
+
+/// A locked reference to the `Stdin` handle.
+///
+/// This handle implements both the [`Read`] and [`BufRead`] traits, and
+/// is constructed via the [`Stdin::lock`] method.
+///
+/// [`Read`]: trait.Read.html
+/// [`BufRead`]: trait.BufRead.html
+/// [`Stdin::lock`]: struct.Stdin.html#method.lock
+///
+/// ### Note: Windows Portability Consideration
+/// When operating in a console, the Windows implementation of this stream does not support
+/// non-UTF-8 byte sequences. Attempting to read bytes that are not valid UTF-8 will return
+/// an error.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct StdinLock<'a> {
+ inner: MutexGuard<'a, BufReader<Maybe<StdinRaw>>>,
+}
+
+/// Constructs a new handle to the standard input of the current process.
+///
+/// Each handle returned is a reference to a shared global buffer whose access
+/// is synchronized via a mutex. If you need more explicit control over
+/// locking, see the [`lock() method`][lock].
+///
+/// [lock]: struct.Stdin.html#method.lock
+///
+/// ### Note: Windows Portability Consideration
+/// When operating in a console, the Windows implementation of this stream does not support
+/// non-UTF-8 byte sequences. Attempting to read bytes that are not valid UTF-8 will return
+/// an error.
+///
+/// # Examples
+///
+/// Using implicit synchronization:
+///
+/// ```no_run
+/// use std::io::{self, Read};
+///
+/// fn main() -> io::Result<()> {
+/// let mut buffer = String::new();
+/// io::stdin().read_to_string(&mut buffer)?;
+/// Ok(())
+/// }
+/// ```
+///
+/// Using explicit synchronization:
+///
+/// ```no_run
+/// use std::io::{self, Read};
+///
+/// fn main() -> io::Result<()> {
+/// let mut buffer = String::new();
+/// let stdin = io::stdin();
+/// let mut handle = stdin.lock();
+///
+/// handle.read_to_string(&mut buffer)?;
+/// Ok(())
+/// }
+/// ```
+#[stable(feature = "rust1", since = "1.0.0")]
+pub fn stdin() -> Stdin {
+ static INSTANCE: Lazy<Mutex<BufReader<Maybe<StdinRaw>>>> = Lazy::new();
+ return Stdin {
+ inner: unsafe {
+ INSTANCE.get(stdin_init).expect("cannot access stdin during shutdown")
+ },
+ };
+
+ fn stdin_init() -> Arc<Mutex<BufReader<Maybe<StdinRaw>>>> {
+ // This must not reentrantly access `INSTANCE`
+ let stdin = match stdin_raw() {
+ Ok(stdin) => Maybe::Real(stdin),
+ _ => Maybe::Fake
+ };
+
+ Arc::new(Mutex::new(BufReader::with_capacity(stdio::STDIN_BUF_SIZE, stdin)))
+ }
+}
+
+impl Stdin {
+ /// Locks this handle to the standard input stream, returning a readable
+ /// guard.
+ ///
+ /// The lock is released when the returned lock goes out of scope. The
+ /// returned guard also implements the [`Read`] and [`BufRead`] traits for
+ /// accessing the underlying data.
+ ///
+ /// [`Read`]: trait.Read.html
+ /// [`BufRead`]: trait.BufRead.html
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::io::{self, Read};
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let mut buffer = String::new();
+ /// let stdin = io::stdin();
+ /// let mut handle = stdin.lock();
+ ///
+ /// handle.read_to_string(&mut buffer)?;
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn lock(&self) -> StdinLock<'_> {
+ StdinLock { inner: self.inner.lock().unwrap_or_else(|e| e.into_inner()) }
+ }
+
+ /// Locks this handle and reads a line of input into the specified buffer.
+ ///
+ /// For detailed semantics of this method, see the documentation on
+ /// [`BufRead::read_line`].
+ ///
+ /// [`BufRead::read_line`]: trait.BufRead.html#method.read_line
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::io;
+ ///
+ /// let mut input = String::new();
+ /// match io::stdin().read_line(&mut input) {
+ /// Ok(n) => {
+ /// println!("{} bytes read", n);
+ /// println!("{}", input);
+ /// }
+ /// Err(error) => println!("error: {}", error),
+ /// }
+ /// ```
+ ///
+ /// You can run the example one of two ways:
+ ///
+ /// - Pipe some text to it, e.g., `printf foo | path/to/executable`
+ /// - Give it text interactively by running the executable directly,
+ /// in which case it will wait for the Enter key to be pressed before
+ /// continuing
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn read_line(&self, buf: &mut String) -> io::Result<usize> {
+ self.lock().read_line(buf)
+ }
+}
+
+#[stable(feature = "std_debug", since = "1.16.0")]
+impl fmt::Debug for Stdin {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.pad("Stdin { .. }")
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Read for Stdin {
+ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+ self.lock().read(buf)
+ }
+ #[inline]
+ unsafe fn initializer(&self) -> Initializer {
+ Initializer::nop()
+ }
+ fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
+ self.lock().read_to_end(buf)
+ }
+ fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
+ self.lock().read_to_string(buf)
+ }
+ fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
+ self.lock().read_exact(buf)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Read for StdinLock<'_> {
+ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+ self.inner.read(buf)
+ }
+ #[inline]
+ unsafe fn initializer(&self) -> Initializer {
+ Initializer::nop()
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl BufRead for StdinLock<'_> {
+ fn fill_buf(&mut self) -> io::Result<&[u8]> { self.inner.fill_buf() }
+ fn consume(&mut self, n: usize) { self.inner.consume(n) }
+}
+
+#[stable(feature = "std_debug", since = "1.16.0")]
+impl fmt::Debug for StdinLock<'_> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.pad("StdinLock { .. }")
+ }
+}
+
+/// A handle to the global standard output stream of the current process.
+///
+/// Each handle shares a global buffer of data to be written to the standard
+/// output stream. Access is also synchronized via a lock and explicit control
+/// over locking is available via the [`lock`] method.
+///
+/// Created by the [`io::stdout`] method.
+///
+/// ### Note: Windows Portability Consideration
+/// When operating in a console, the Windows implementation of this stream does not support
+/// non-UTF-8 byte sequences. Attempting to write bytes that are not valid UTF-8 will return
+/// an error.
+///
+/// [`lock`]: #method.lock
+/// [`io::stdout`]: fn.stdout.html
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct Stdout {
+ // FIXME: this should be LineWriter or BufWriter depending on the state of
+ // stdout (tty or not). Note that if this is not line buffered it
+ // should also flush-on-panic or some form of flush-on-abort.
+ inner: Arc<ReentrantMutex<RefCell<LineWriter<Maybe<StdoutRaw>>>>>,
+}
+
+/// A locked reference to the `Stdout` handle.
+///
+/// This handle implements the [`Write`] trait, and is constructed via
+/// the [`Stdout::lock`] method.
+///
+/// ### Note: Windows Portability Consideration
+/// When operating in a console, the Windows implementation of this stream does not support
+/// non-UTF-8 byte sequences. Attempting to write bytes that are not valid UTF-8 will return
+/// an error.
+///
+/// [`Write`]: trait.Write.html
+/// [`Stdout::lock`]: struct.Stdout.html#method.lock
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct StdoutLock<'a> {
+ inner: ReentrantMutexGuard<'a, RefCell<LineWriter<Maybe<StdoutRaw>>>>,
+}
+
+/// Constructs a new handle to the standard output of the current process.
+///
+/// Each handle returned is a reference to a shared global buffer whose access
+/// is synchronized via a mutex. If you need more explicit control over
+/// locking, see the [Stdout::lock] method.
+///
+/// [Stdout::lock]: struct.Stdout.html#method.lock
+///
+/// ### Note: Windows Portability Consideration
+/// When operating in a console, the Windows implementation of this stream does not support
+/// non-UTF-8 byte sequences. Attempting to write bytes that are not valid UTF-8 will return
+/// an error.
+///
+/// # Examples
+///
+/// Using implicit synchronization:
+///
+/// ```no_run
+/// use std::io::{self, Write};
+///
+/// fn main() -> io::Result<()> {
+/// io::stdout().write_all(b"hello world")?;
+///
+/// Ok(())
+/// }
+/// ```
+///
+/// Using explicit synchronization:
+///
+/// ```no_run
+/// use std::io::{self, Write};
+///
+/// fn main() -> io::Result<()> {
+/// let stdout = io::stdout();
+/// let mut handle = stdout.lock();
+///
+/// handle.write_all(b"hello world")?;
+///
+/// Ok(())
+/// }
+/// ```
+#[stable(feature = "rust1", since = "1.0.0")]
+pub fn stdout() -> Stdout {
+ static INSTANCE: Lazy<ReentrantMutex<RefCell<LineWriter<Maybe<StdoutRaw>>>>> = Lazy::new();
+ return Stdout {
+ inner: unsafe {
+ INSTANCE.get(stdout_init).expect("cannot access stdout during shutdown")
+ },
+ };
+
+ fn stdout_init() -> Arc<ReentrantMutex<RefCell<LineWriter<Maybe<StdoutRaw>>>>> {
+ // This must not reentrantly access `INSTANCE`
+ let stdout = match stdout_raw() {
+ Ok(stdout) => Maybe::Real(stdout),
+ _ => Maybe::Fake,
+ };
+ Arc::new(ReentrantMutex::new(RefCell::new(LineWriter::new(stdout))))
+ }
+}
+
+impl Stdout {
+ /// Locks this handle to the standard output stream, returning a writable
+ /// guard.
+ ///
+ /// The lock is released when the returned lock goes out of scope. The
+ /// returned guard also implements the `Write` trait for writing data.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::io::{self, Write};
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let stdout = io::stdout();
+ /// let mut handle = stdout.lock();
+ ///
+ /// handle.write_all(b"hello world")?;
+ ///
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn lock(&self) -> StdoutLock<'_> {
+ StdoutLock { inner: self.inner.lock().unwrap_or_else(|e| e.into_inner()) }
+ }
+}
+
+#[stable(feature = "std_debug", since = "1.16.0")]
+impl fmt::Debug for Stdout {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.pad("Stdout { .. }")
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Write for Stdout {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ self.lock().write(buf)
+ }
+ fn flush(&mut self) -> io::Result<()> {
+ self.lock().flush()
+ }
+ fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
+ self.lock().write_all(buf)
+ }
+ fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> io::Result<()> {
+ self.lock().write_fmt(args)
+ }
+}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Write for StdoutLock<'_> {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ self.inner.borrow_mut().write(buf)
+ }
+ fn flush(&mut self) -> io::Result<()> {
+ self.inner.borrow_mut().flush()
+ }
+}
+
+#[stable(feature = "std_debug", since = "1.16.0")]
+impl fmt::Debug for StdoutLock<'_> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.pad("StdoutLock { .. }")
+ }
+}
+
+/// A handle to the standard error stream of a process.
+///
+/// For more information, see the [`io::stderr`] method.
+///
+/// [`io::stderr`]: fn.stderr.html
+///
+/// ### Note: Windows Portability Consideration
+/// When operating in a console, the Windows implementation of this stream does not support
+/// non-UTF-8 byte sequences. Attempting to write bytes that are not valid UTF-8 will return
+/// an error.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct Stderr {
+ inner: Arc<ReentrantMutex<RefCell<Maybe<StderrRaw>>>>,
+}
+
+/// A locked reference to the `Stderr` handle.
+///
+/// This handle implements the `Write` trait and is constructed via
+/// the [`Stderr::lock`] method.
+///
+/// [`Stderr::lock`]: struct.Stderr.html#method.lock
+///
+/// ### Note: Windows Portability Consideration
+/// When operating in a console, the Windows implementation of this stream does not support
+/// non-UTF-8 byte sequences. Attempting to write bytes that are not valid UTF-8 will return
+/// an error.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct StderrLock<'a> {
+ inner: ReentrantMutexGuard<'a, RefCell<Maybe<StderrRaw>>>,
+}
+
+/// Constructs a new handle to the standard error of the current process.
+///
+/// This handle is not buffered.
+///
+/// ### Note: Windows Portability Consideration
+/// When operating in a console, the Windows implementation of this stream does not support
+/// non-UTF-8 byte sequences. Attempting to write bytes that are not valid UTF-8 will return
+/// an error.
+///
+/// # Examples
+///
+/// Using implicit synchronization:
+///
+/// ```no_run
+/// use std::io::{self, Write};
+///
+/// fn main() -> io::Result<()> {
+/// io::stderr().write_all(b"hello world")?;
+///
+/// Ok(())
+/// }
+/// ```
+///
+/// Using explicit synchronization:
+///
+/// ```no_run
+/// use std::io::{self, Write};
+///
+/// fn main() -> io::Result<()> {
+/// let stderr = io::stderr();
+/// let mut handle = stderr.lock();
+///
+/// handle.write_all(b"hello world")?;
+///
+/// Ok(())
+/// }
+/// ```
+#[stable(feature = "rust1", since = "1.0.0")]
+pub fn stderr() -> Stderr {
+ static INSTANCE: Lazy<ReentrantMutex<RefCell<Maybe<StderrRaw>>>> = Lazy::new();
+ return Stderr {
+ inner: unsafe {
+ INSTANCE.get(stderr_init).expect("cannot access stderr during shutdown")
+ },
+ };
+
+ fn stderr_init() -> Arc<ReentrantMutex<RefCell<Maybe<StderrRaw>>>> {
+ // This must not reentrantly access `INSTANCE`
+ let stderr = match stderr_raw() {
+ Ok(stderr) => Maybe::Real(stderr),
+ _ => Maybe::Fake,
+ };
+ Arc::new(ReentrantMutex::new(RefCell::new(stderr)))
+ }
+}
+
+impl Stderr {
+ /// Locks this handle to the standard error stream, returning a writable
+ /// guard.
+ ///
+ /// The lock is released when the returned lock goes out of scope. The
+ /// returned guard also implements the `Write` trait for writing data.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::io::{self, Write};
+ ///
+ /// fn foo() -> io::Result<()> {
+ /// let stderr = io::stderr();
+ /// let mut handle = stderr.lock();
+ ///
+ /// handle.write_all(b"hello world")?;
+ ///
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn lock(&self) -> StderrLock<'_> {
+ StderrLock { inner: self.inner.lock().unwrap_or_else(|e| e.into_inner()) }
+ }
+}
+
+#[stable(feature = "std_debug", since = "1.16.0")]
+impl fmt::Debug for Stderr {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.pad("Stderr { .. }")
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Write for Stderr {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ self.lock().write(buf)
+ }
+ fn flush(&mut self) -> io::Result<()> {
+ self.lock().flush()
+ }
+ fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
+ self.lock().write_all(buf)
+ }
+ fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> io::Result<()> {
+ self.lock().write_fmt(args)
+ }
+}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Write for StderrLock<'_> {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ self.inner.borrow_mut().write(buf)
+ }
+ fn flush(&mut self) -> io::Result<()> {
+ self.inner.borrow_mut().flush()
+ }
+}
+
+#[stable(feature = "std_debug", since = "1.16.0")]
+impl fmt::Debug for StderrLock<'_> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.pad("StderrLock { .. }")
+ }
+}
+
+/// Resets the thread-local stderr handle to the specified writer
+///
+/// This will replace the current thread's stderr handle, returning the old
+/// handle. All future calls to `panic!` and friends will emit their output to
+/// this specified handle.
+///
+/// Note that this does not need to be called for all new threads; the default
+/// output handle is to the process's stderr stream.
+#[unstable(feature = "set_stdio",
+ reason = "this function may disappear completely or be replaced \
+ with a more general mechanism",
+ issue = "0")]
+#[doc(hidden)]
+pub fn set_panic(sink: Option<Box<dyn Write + Send>>) -> Option<Box<dyn Write + Send>> {
+ use crate::mem;
+ LOCAL_STDERR.with(move |slot| {
+ mem::replace(&mut *slot.borrow_mut(), sink)
+ }).and_then(|mut s| {
+ let _ = s.flush();
+ Some(s)
+ })
+}
+
+/// Resets the thread-local stdout handle to the specified writer
+///
+/// This will replace the current thread's stdout handle, returning the old
+/// handle. All future calls to `print!` and friends will emit their output to
+/// this specified handle.
+///
+/// Note that this does not need to be called for all new threads; the default
+/// output handle is to the process's stdout stream.
+#[unstable(feature = "set_stdio",
+ reason = "this function may disappear completely or be replaced \
+ with a more general mechanism",
+ issue = "0")]
+#[doc(hidden)]
+pub fn set_print(sink: Option<Box<dyn Write + Send>>) -> Option<Box<dyn Write + Send>> {
+ use crate::mem;
+ LOCAL_STDOUT.with(move |slot| {
+ mem::replace(&mut *slot.borrow_mut(), sink)
+ }).and_then(|mut s| {
+ let _ = s.flush();
+ Some(s)
+ })
+}
+
+/// Write `args` to output stream `local_s` if possible, `global_s`
+/// otherwise. `label` identifies the stream in a panic message.
+///
+/// This function is used to print error messages, so it takes extra
+/// care to avoid causing a panic when `local_stream` is unusable.
+/// For instance, if the TLS key for the local stream is
+/// already destroyed, or if the local stream is locked by another
+/// thread, it will just fall back to the global stream.
+///
+/// However, if the actual I/O causes an error, this function does panic.
+fn print_to<T>(
+ args: fmt::Arguments<'_>,
+ local_s: &'static LocalKey<RefCell<Option<Box<dyn Write+Send>>>>,
+ global_s: fn() -> T,
+ label: &str,
+)
+where
+ T: Write,
+{
+ let result = local_s.try_with(|s| {
+ if let Ok(mut borrowed) = s.try_borrow_mut() {
+ if let Some(w) = borrowed.as_mut() {
+ return w.write_fmt(args);
+ }
+ }
+ global_s().write_fmt(args)
+ }).unwrap_or_else(|_| {
+ global_s().write_fmt(args)
+ });
+
+ if let Err(e) = result {
+ panic!("failed printing to {}: {}", label, e);
+ }
+}
+
+#[unstable(feature = "print_internals",
+ reason = "implementation detail which may disappear or be replaced at any time",
+ issue = "0")]
+#[doc(hidden)]
+#[cfg(not(test))]
+pub fn _print(args: fmt::Arguments<'_>) {
+ print_to(args, &LOCAL_STDOUT, stdout, "stdout");
+}
+
+#[unstable(feature = "print_internals",
+ reason = "implementation detail which may disappear or be replaced at any time",
+ issue = "0")]
+#[doc(hidden)]
+#[cfg(not(test))]
+pub fn _eprint(args: fmt::Arguments<'_>) {
+ print_to(args, &LOCAL_STDERR, stderr, "stderr");
+}
+
+#[cfg(test)]
+pub use realstd::io::{_eprint, _print};
+
+#[cfg(test)]
+mod tests {
+ use crate::panic::{UnwindSafe, RefUnwindSafe};
+ use crate::thread;
+ use super::*;
+
+ #[test]
+ fn stdout_unwind_safe() {
+ assert_unwind_safe::<Stdout>();
+ }
+ #[test]
+ fn stdoutlock_unwind_safe() {
+ assert_unwind_safe::<StdoutLock<'_>>();
+ assert_unwind_safe::<StdoutLock<'static>>();
+ }
+ #[test]
+ fn stderr_unwind_safe() {
+ assert_unwind_safe::<Stderr>();
+ }
+ #[test]
+ fn stderrlock_unwind_safe() {
+ assert_unwind_safe::<StderrLock<'_>>();
+ assert_unwind_safe::<StderrLock<'static>>();
+ }
+
+ fn assert_unwind_safe<T: UnwindSafe + RefUnwindSafe>() {}
+
+ #[test]
+ #[cfg_attr(target_os = "emscripten", ignore)]
+ fn panic_doesnt_poison() {
+ thread::spawn(|| {
+ let _a = stdin();
+ let _a = _a.lock();
+ let _a = stdout();
+ let _a = _a.lock();
+ let _a = stderr();
+ let _a = _a.lock();
+ panic!();
+ }).join().unwrap_err();
+
+ let _a = stdin();
+ let _a = _a.lock();
+ let _a = stdout();
+ let _a = _a.lock();
+ let _a = stderr();
+ let _a = _a.lock();
+ }
+}
diff --git a/src/libstd/io/util.rs b/src/libstd/io/util.rs
new file mode 100644
index 0000000..d2638be
--- /dev/null
+++ b/src/libstd/io/util.rs
@@ -0,0 +1,272 @@
+#![allow(missing_copy_implementations)]
+
+use crate::fmt;
+use crate::io::{self, Read, Initializer, Write, ErrorKind, BufRead, IoVec, IoVecMut};
+use crate::mem;
+
+/// Copies the entire contents of a reader into a writer.
+///
+/// This function will continuously read data from `reader` and then
+/// write it into `writer` in a streaming fashion until `reader`
+/// returns EOF.
+///
+/// On success, the total number of bytes that were copied from
+/// `reader` to `writer` is returned.
+///
+/// If you’re wanting to copy the contents of one file to another and you’re
+/// working with filesystem paths, see the [`fs::copy`] function.
+///
+/// [`fs::copy`]: ../fs/fn.copy.html
+///
+/// # Errors
+///
+/// This function will return an error immediately if any call to `read` or
+/// `write` returns an error. All instances of `ErrorKind::Interrupted` are
+/// handled by this function and the underlying operation is retried.
+///
+/// # Examples
+///
+/// ```
+/// use std::io;
+///
+/// fn main() -> io::Result<()> {
+/// let mut reader: &[u8] = b"hello";
+/// let mut writer: Vec<u8> = vec![];
+///
+/// io::copy(&mut reader, &mut writer)?;
+///
+/// assert_eq!(&b"hello"[..], &writer[..]);
+/// Ok(())
+/// }
+/// ```
+#[stable(feature = "rust1", since = "1.0.0")]
+pub fn copy<R: ?Sized, W: ?Sized>(reader: &mut R, writer: &mut W) -> io::Result<u64>
+ where R: Read, W: Write
+{
+ let mut buf = unsafe {
+ let mut buf: [u8; super::DEFAULT_BUF_SIZE] = mem::uninitialized();
+ reader.initializer().initialize(&mut buf);
+ buf
+ };
+
+ let mut written = 0;
+ loop {
+ let len = match reader.read(&mut buf) {
+ Ok(0) => return Ok(written),
+ Ok(len) => len,
+ Err(ref e) if e.kind() == ErrorKind::Interrupted => continue,
+ Err(e) => return Err(e),
+ };
+ writer.write_all(&buf[..len])?;
+ written += len as u64;
+ }
+}
+
+/// A reader which is always at EOF.
+///
+/// This struct is generally created by calling [`empty`]. Please see
+/// the documentation of [`empty()`][`empty`] for more details.
+///
+/// [`empty`]: fn.empty.html
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct Empty { _priv: () }
+
+/// Constructs a new handle to an empty reader.
+///
+/// All reads from the returned reader will return [`Ok`]`(0)`.
+///
+/// [`Ok`]: ../result/enum.Result.html#variant.Ok
+///
+/// # Examples
+///
+/// A slightly sad example of not reading anything into a buffer:
+///
+/// ```
+/// use std::io::{self, Read};
+///
+/// let mut buffer = String::new();
+/// io::empty().read_to_string(&mut buffer).unwrap();
+/// assert!(buffer.is_empty());
+/// ```
+#[stable(feature = "rust1", since = "1.0.0")]
+pub fn empty() -> Empty { Empty { _priv: () } }
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Read for Empty {
+ #[inline]
+ fn read(&mut self, _buf: &mut [u8]) -> io::Result<usize> { Ok(0) }
+
+ #[inline]
+ unsafe fn initializer(&self) -> Initializer {
+ Initializer::nop()
+ }
+}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl BufRead for Empty {
+ #[inline]
+ fn fill_buf(&mut self) -> io::Result<&[u8]> { Ok(&[]) }
+ #[inline]
+ fn consume(&mut self, _n: usize) {}
+}
+
+#[stable(feature = "std_debug", since = "1.16.0")]
+impl fmt::Debug for Empty {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.pad("Empty { .. }")
+ }
+}
+
+/// A reader which yields one byte over and over and over and over and over and...
+///
+/// This struct is generally created by calling [`repeat`][repeat]. Please
+/// see the documentation of `repeat()` for more details.
+///
+/// [repeat]: fn.repeat.html
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct Repeat { byte: u8 }
+
+/// Creates an instance of a reader that infinitely repeats one byte.
+///
+/// All reads from this reader will succeed by filling the specified buffer with
+/// the given byte.
+///
+/// # Examples
+///
+/// ```
+/// use std::io::{self, Read};
+///
+/// let mut buffer = [0; 3];
+/// io::repeat(0b101).read_exact(&mut buffer).unwrap();
+/// assert_eq!(buffer, [0b101, 0b101, 0b101]);
+/// ```
+#[stable(feature = "rust1", since = "1.0.0")]
+pub fn repeat(byte: u8) -> Repeat { Repeat { byte } }
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Read for Repeat {
+ #[inline]
+ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+ for slot in &mut *buf {
+ *slot = self.byte;
+ }
+ Ok(buf.len())
+ }
+
+ #[inline]
+ fn read_vectored(&mut self, bufs: &mut [IoVecMut<'_>]) -> io::Result<usize> {
+ let mut nwritten = 0;
+ for buf in bufs {
+ nwritten += self.read(buf)?;
+ }
+ Ok(nwritten)
+ }
+
+ #[inline]
+ unsafe fn initializer(&self) -> Initializer {
+ Initializer::nop()
+ }
+}
+
+#[stable(feature = "std_debug", since = "1.16.0")]
+impl fmt::Debug for Repeat {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.pad("Repeat { .. }")
+ }
+}
+
+/// A writer which will move data into the void.
+///
+/// This struct is generally created by calling [`sink`][sink]. Please
+/// see the documentation of `sink()` for more details.
+///
+/// [sink]: fn.sink.html
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct Sink { _priv: () }
+
+/// Creates an instance of a writer which will successfully consume all data.
+///
+/// All calls to `write` on the returned instance will return `Ok(buf.len())`
+/// and the contents of the buffer will not be inspected.
+///
+/// # Examples
+///
+/// ```rust
+/// use std::io::{self, Write};
+///
+/// let buffer = vec![1, 2, 3, 5, 8];
+/// let num_bytes = io::sink().write(&buffer).unwrap();
+/// assert_eq!(num_bytes, 5);
+/// ```
+#[stable(feature = "rust1", since = "1.0.0")]
+pub fn sink() -> Sink { Sink { _priv: () } }
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Write for Sink {
+ #[inline]
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> { Ok(buf.len()) }
+
+ #[inline]
+ fn write_vectored(&mut self, bufs: &[IoVec<'_>]) -> io::Result<usize> {
+ let total_len = bufs.iter().map(|b| b.len()).sum();
+ Ok(total_len)
+ }
+
+ #[inline]
+ fn flush(&mut self) -> io::Result<()> { Ok(()) }
+}
+
+#[stable(feature = "std_debug", since = "1.16.0")]
+impl fmt::Debug for Sink {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.pad("Sink { .. }")
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use crate::io::prelude::*;
+ use crate::io::{copy, sink, empty, repeat};
+
+ #[test]
+ fn copy_copies() {
+ let mut r = repeat(0).take(4);
+ let mut w = sink();
+ assert_eq!(copy(&mut r, &mut w).unwrap(), 4);
+
+ let mut r = repeat(0).take(1 << 17);
+ assert_eq!(copy(&mut r as &mut dyn Read, &mut w as &mut dyn Write).unwrap(), 1 << 17);
+ }
+
+ #[test]
+ fn sink_sinks() {
+ let mut s = sink();
+ assert_eq!(s.write(&[]).unwrap(), 0);
+ assert_eq!(s.write(&[0]).unwrap(), 1);
+ assert_eq!(s.write(&[0; 1024]).unwrap(), 1024);
+ assert_eq!(s.by_ref().write(&[0; 1024]).unwrap(), 1024);
+ }
+
+ #[test]
+ fn empty_reads() {
+ let mut e = empty();
+ assert_eq!(e.read(&mut []).unwrap(), 0);
+ assert_eq!(e.read(&mut [0]).unwrap(), 0);
+ assert_eq!(e.read(&mut [0; 1024]).unwrap(), 0);
+ assert_eq!(e.by_ref().read(&mut [0; 1024]).unwrap(), 0);
+ }
+
+ #[test]
+ fn repeat_repeats() {
+ let mut r = repeat(4);
+ let mut b = [0; 1024];
+ assert_eq!(r.read(&mut b).unwrap(), 1024);
+ assert!(b.iter().all(|b| *b == 4));
+ }
+
+ #[test]
+ fn take_some_bytes() {
+ assert_eq!(repeat(4).take(100).bytes().count(), 100);
+ assert_eq!(repeat(4).take(100).bytes().next().unwrap().unwrap(), 4);
+ assert_eq!(repeat(1).take(10).chain(repeat(2).take(10)).bytes().count(), 20);
+ }
+}
diff --git a/src/libstd/keyword_docs.rs b/src/libstd/keyword_docs.rs
new file mode 100644
index 0000000..7b0d154
--- /dev/null
+++ b/src/libstd/keyword_docs.rs
@@ -0,0 +1,717 @@
+#[doc(keyword = "as")]
+//
+/// The keyword for casting a value to a type.
+///
+/// `as` is most commonly used to turn primitive types into other primitive types, but it has other
+/// uses that include turning pointers into addresses, addresses into pointers, and pointers into
+/// other pointers.
+///
+/// ```rust
+/// let thing1: u8 = 89.0 as u8;
+/// assert_eq!('B' as u32, 66);
+/// assert_eq!(thing1 as char, 'Y');
+/// let thing2: f32 = thing1 as f32 + 10.5;
+/// assert_eq!(true as u8 + thing2 as u8, 100);
+/// ```
+///
+/// In general, any cast that can be performed via ascribing the type can also be done using `as`,
+/// so instead of writing `let x: u32 = 123`, you can write `let x = 123 as u32` (Note: `let x: u32
+/// = 123` would be best in that situation). The same is not true in the other direction, however,
+/// explicitly using `as` allows a few more coercions that aren't allowed implicitly, such as
+/// changing the type of a raw pointer or turning closures into raw pointers.
+///
+/// Other places `as` is used include as extra syntax for [`crate`] and `use`, to change the name
+/// something is imported as.
+///
+/// For more information on what `as` is capable of, see the [Reference]
+///
+/// [Reference]:
+/// https://doc.rust-lang.org/reference/expressions/operator-expr.html#type-cast-expressions
+/// [`crate`]: keyword.crate.html
+mod as_keyword { }
+
+#[doc(keyword = "const")]
+//
+/// The keyword for defining constants.
+///
+/// Sometimes a certain value is used many times throughout a program, and it can become
+/// inconvenient to copy it over and over. What's more, it's not always possible or desirable to
+/// make it a variable that gets carried around to each function that needs it. In these cases, the
+/// `const` keyword provides a convenient alternative to code duplication.
+///
+/// ```rust
+/// const THING: u32 = 0xABAD1DEA;
+///
+/// let foo = 123 + THING;
+/// ```
+///
+/// Constants must be explicitly typed, unlike with `let` you can't ignore its type and let the
+/// compiler figure it out. Any constant value can be defined in a const, which in practice happens
+/// to be most things that would be reasonable to have a constant (barring `const fn`s). For
+/// example, you can't have a File as a `const`.
+///
+/// The only lifetime allowed in a constant is `'static`, which is the lifetime that encompasses
+/// all others in a Rust program. For example, if you wanted to define a constant string, it would
+/// look like this:
+///
+/// ```rust
+/// const WORDS: &str = "hello rust!";
+/// ```
+///
+/// Thanks to static lifetime elision, you usually don't have to explicitly use 'static:
+///
+/// ```rust
+/// const WORDS: &str = "hello convenience!";
+/// ```
+///
+/// `const` items looks remarkably similar to `static` items, which introduces some confusion as
+/// to which one should be used at which times. To put it simply, constants are inlined wherever
+/// they're used, making using them identical to simply replacing the name of the const with its
+/// value. Static variables on the other hand point to a single location in memory, which all
+/// accesses share. This means that, unlike with constants, they can't have destructors, and act as
+/// a single value across the entire codebase.
+///
+/// Constants, as with statics, should always be in SCREAMING_SNAKE_CASE.
+///
+/// The `const` keyword is also used in raw pointers in combination with `mut`, as seen in `*const
+/// T` and `*mut T`. More about that can be read at the [pointer] primitive part of the Rust docs.
+///
+/// For more detail on `const`, see the [Rust Book] or the [Reference]
+///
+/// [pointer]: primitive.pointer.html
+/// [Rust Book]:
+/// https://doc.rust-lang.org/stable/book/2018-edition/ch03-01-variables-and-mutability.html#differences-between-variables-and-constants
+/// [Reference]: https://doc.rust-lang.org/reference/items/constant-items.html
+mod const_keyword { }
+
+#[doc(keyword = "crate")]
+//
+/// The `crate` keyword.
+///
+/// The primary use of the `crate` keyword is as a part of `extern crate` declarations, which are
+/// used to specify a dependency on a crate external to the one it's declared in. Crates are the
+/// fundamental compilation unit of Rust code, and can be seen as libraries or projects. More can
+/// be read about crates in the [Reference].
+///
+/// ```rust ignore
+/// extern crate rand;
+/// extern crate my_crate as thing;
+/// extern crate std; // implicitly added to the root of every Rust project
+/// ```
+///
+/// The `as` keyword can be used to change what the crate is referred to as in your project. If a
+/// crate name includes a dash, it is implicitly imported with the dashes replaced by underscores.
+///
+/// `crate` is also used as in conjunction with `pub` to signify that the item it's attached to
+/// is public only to other members of the same crate it's in.
+///
+/// ```rust
+/// # #[allow(unused_imports)]
+/// pub(crate) use std::io::Error as IoError;
+/// pub(crate) enum CoolMarkerType { }
+/// pub struct PublicThing {
+/// pub(crate) semi_secret_thing: bool,
+/// }
+/// ```
+///
+/// [Reference]: https://doc.rust-lang.org/reference/items/extern-crates.html
+mod crate_keyword { }
+
+#[doc(keyword = "enum")]
+//
+/// For defining enumerations.
+///
+/// Enums in Rust are similar to those of other compiled languages like C, but have important
+/// differences that make them considerably more powerful. What Rust calls enums are more commonly
+/// known as [Algebraic Data Types] if you're coming from a functional programming background. The
+/// important detail is that each enum variant can have data to go along with it.
+///
+/// ```rust
+/// # struct Coord;
+/// enum SimpleEnum {
+/// FirstVariant,
+/// SecondVariant,
+/// ThirdVariant,
+/// }
+///
+/// enum Location {
+/// Unknown,
+/// Anonymous,
+/// Known(Coord),
+/// }
+///
+/// enum ComplexEnum {
+/// Nothing,
+/// Something(u32),
+/// LotsOfThings {
+/// usual_struct_stuff: bool,
+/// blah: String,
+/// }
+/// }
+///
+/// enum EmptyEnum { }
+/// ```
+///
+/// The first enum shown is the usual kind of enum you'd find in a C-style language. The second
+/// shows off a hypothetical example of something storing location data, with `Coord` being any
+/// other type that's needed, for example a struct. The third example demonstrates the kind of
+/// data a variant can store, ranging from nothing, to a tuple, to an anonymous struct.
+///
+/// Instantiating enum variants involves explicitly using the enum's name as its namespace,
+/// followed by one of its variants. `SimpleEnum::SecondVariant` would be an example from above.
+/// When data follows along with a variant, such as with rust's built-in [`Option`] type, the data
+/// is added as the type describes, for example `Option::Some(123)`. The same follows with
+/// struct-like variants, with things looking like `ComplexEnum::LotsOfThings { usual_struct_stuff:
+/// true, blah: "hello!".to_string(), }`. Empty Enums are similar to () in that they cannot be
+/// instantiated at all, and are used mainly to mess with the type system in interesting ways.
+///
+/// For more information, take a look at the [Rust Book] or the [Reference]
+///
+/// [Algebraic Data Types]: https://en.wikipedia.org/wiki/Algebraic_data_type
+/// [`Option`]: option/enum.Option.html
+/// [Rust Book]: https://doc.rust-lang.org/book/ch06-01-defining-an-enum.html
+/// [Reference]: https://doc.rust-lang.org/reference/items/enumerations.html
+mod enum_keyword { }
+
+#[doc(keyword = "extern")]
+//
+/// For external connections in Rust code.
+///
+/// The `extern` keyword is used in two places in Rust. One is in conjunction with the [`crate`]
+/// keyword to make your Rust code aware of other Rust crates in your project, i.e., `extern crate
+/// lazy_static;`. The other use is in foreign function interfaces (FFI).
+///
+/// `extern` is used in two different contexts within FFI. The first is in the form of external
+/// blocks, for declaring function interfaces that Rust code can call foreign code by.
+///
+/// ```rust ignore
+/// #[link(name = "my_c_library")]
+/// extern "C" {
+/// fn my_c_function(x: i32) -> bool;
+/// }
+/// ```
+///
+/// This code would attempt to link with `libmy_c_library.so` on unix-like systems and
+/// `my_c_library.dll` on Windows at runtime, and panic if it can't find something to link to. Rust
+/// code could then use `my_c_function` as if it were any other unsafe Rust function. Working with
+/// non-Rust languages and FFI is inherently unsafe, so wrappers are usually built around C APIs.
+///
+/// The mirror use case of FFI is also done via the `extern` keyword:
+///
+/// ```rust
+/// #[no_mangle]
+/// pub extern fn callable_from_c(x: i32) -> bool {
+/// x % 3 == 0
+/// }
+/// ```
+///
+/// If compiled as a dylib, the resulting .so could then be linked to from a C library, and the
+/// function could be used as if it was from any other library.
+///
+/// For more information on FFI, check the [Rust book] or the [Reference].
+///
+/// [Rust book]:
+/// https://doc.rust-lang.org/book/ch19-01-unsafe-rust.html#using-extern-functions-to-call-external-code
+/// [Reference]: https://doc.rust-lang.org/reference/items/external-blocks.html
+mod extern_keyword { }
+
+#[doc(keyword = "fn")]
+//
+/// The keyword for defining functions.
+///
+/// Functions are the primary way code is executed within Rust. Function blocks, usually just
+/// called functions, can be defined in a variety of different places and be assigned many
+/// different attributes and modifiers.
+///
+/// Standalone functions that just sit within a module not attached to anything else are common,
+/// but most functions will end up being inside [`impl`] blocks, either on another type itself, or
+/// as a trait impl for that type.
+///
+/// ```rust
+/// fn standalone_function() {
+/// // code
+/// }
+///
+/// pub fn public_thing(argument: bool) -> String {
+/// // code
+/// # "".to_string()
+/// }
+///
+/// struct Thing {
+/// foo: i32,
+/// }
+///
+/// impl Thing {
+/// pub fn new() -> Self {
+/// Self {
+/// foo: 42,
+/// }
+/// }
+/// }
+/// ```
+///
+/// In addition to presenting fixed types in the form of `fn name(arg: type, ..) -> return_type`,
+/// functions can also declare a list of type parameters along with trait bounds that they fall
+/// into.
+///
+/// ```rust
+/// fn generic_function<T: Clone>(x: T) -> (T, T, T) {
+/// (x.clone(), x.clone(), x.clone())
+/// }
+///
+/// fn generic_where<T>(x: T) -> T
+/// where T: std::ops::Add<Output = T> + Copy
+/// {
+/// x + x + x
+/// }
+/// ```
+///
+/// Declaring trait bounds in the angle brackets is functionally identical to using a `where`
+/// clause. It's up to the programmer to decide which works better in each situation, but `where`
+/// tends to be better when things get longer than one line.
+///
+/// Along with being made public via `pub`, `fn` can also have an [`extern`] added for use in
+/// FFI.
+///
+/// For more information on the various types of functions and how they're used, consult the [Rust
+/// book] or the [Reference].
+///
+/// [`impl`]: keyword.impl.html
+/// [`extern`]: keyword.extern.html
+/// [Rust book]: https://doc.rust-lang.org/book/ch03-03-how-functions-work.html
+/// [Reference]: https://doc.rust-lang.org/reference/items/functions.html
+mod fn_keyword { }
+
+#[doc(keyword = "for")]
+//
+/// The `for` keyword.
+///
+/// The `for` keyword is used in many syntactic locations:
+///
+/// * `for` is used in for-in-loops (see below).
+/// * `for` is used when implementing traits as in `impl Trait for Type` (see [`impl`] for more info
+/// on that).
+/// * `for` is also used for [higher-ranked trait bounds] as in `for<'a> &'a T: PartialEq<i32>`.
+///
+/// for-in-loops, or to be more precise, iterator loops, are a simple syntactic sugar over a common
+/// practice within Rust, which is to loop over an iterator until that iterator returns `None` (or
+/// `break` is called).
+///
+/// ```rust
+/// for i in 0..5 {
+/// println!("{}", i * 2);
+/// }
+///
+/// for i in std::iter::repeat(5) {
+/// println!("turns out {} never stops being 5", i);
+/// break; // would loop forever otherwise
+/// }
+///
+/// 'outer: for x in 5..50 {
+/// for y in 0..10 {
+/// if x == y {
+/// break 'outer;
+/// }
+/// }
+/// }
+/// ```
+///
+/// As shown in the example above, `for` loops (along with all other loops) can be tagged, using
+/// similar syntax to lifetimes (only visually similar, entirely distinct in practice). Giving the
+/// same tag to `break` breaks the tagged loop, which is useful for inner loops. It is definitely
+/// not a goto.
+///
+/// A `for` loop expands as shown:
+///
+/// ```rust
+/// # fn code() { }
+/// # let iterator = 0..2;
+/// for loop_variable in iterator {
+/// code()
+/// }
+/// ```
+///
+/// ```rust
+/// # fn code() { }
+/// # let iterator = 0..2;
+/// {
+/// let mut _iter = std::iter::IntoIterator::into_iter(iterator);
+/// loop {
+/// match _iter.next() {
+/// Some(loop_variable) => {
+/// code()
+/// },
+/// None => break,
+/// }
+/// }
+/// }
+/// ```
+///
+/// More details on the functionality shown can be seen at the [`IntoIterator`] docs.
+///
+/// For more information on for-loops, see the [Rust book] or the [Reference].
+///
+/// [`impl`]: keyword.impl.html
+/// [higher-ranked trait bounds]:
+/// https://doc.rust-lang.org/nightly/reference/trait-bounds.html#higher-ranked-trait-bounds
+/// [`IntoIterator`]: iter/trait.IntoIterator.html
+/// [Rust book]:
+/// https://doc.rust-lang.org/book/2018-edition/ch03-05-control-flow.html#looping-through-a-collection-with-for
+/// [Reference]: https://doc.rust-lang.org/reference/expressions/loop-expr.html#iterator-loops
+mod for_keyword { }
+
+#[doc(keyword = "if")]
+//
+/// If statements and expressions.
+///
+/// `if` is a familiar construct to most programmers, and is the main way you'll often do logic in
+/// your code. However, unlike in most languages, `if` blocks can also act as expressions.
+///
+/// ```rust
+/// # let rude = true;
+/// if 1 == 2 {
+/// println!("whoops, mathematics broke");
+/// } else {
+/// println!("everything's fine!");
+/// }
+///
+/// let greeting = if rude {
+/// "sup nerd."
+/// } else {
+/// "hello, friend!"
+/// };
+///
+/// if let Ok(x) = "123".parse::<i32>() {
+/// println!("{} double that and you get {}!", greeting, x * 2);
+/// }
+/// ```
+///
+/// Shown above are the three typical forms an `if` block comes in. First is the usual kind of
+/// thing you'd see in many languages, with an optional `else` block. Second uses `if` as an
+/// expression, which is only possible if all branches return the same type. An `if` expression can
+/// be used everywhere you'd expect. The third kind of `if` block is an `if let` block, which
+/// behaves similarly to using a `match` expression:
+///
+/// ```rust
+/// if let Some(x) = Some(123) {
+/// // code
+/// # let _ = x;
+/// } else {
+/// // something else
+/// }
+///
+/// match Some(123) {
+/// Some(x) => {
+/// // code
+/// # let _ = x;
+/// },
+/// _ => {
+/// // something else
+/// },
+/// }
+/// ```
+///
+/// Each kind of `if` expression can be mixed and matched as needed.
+///
+/// ```rust
+/// if true == false {
+/// println!("oh no");
+/// } else if "something" == "other thing" {
+/// println!("oh dear");
+/// } else if let Some(200) = "blarg".parse::<i32>().ok() {
+/// println!("uh oh");
+/// } else {
+/// println!("phew, nothing's broken");
+/// }
+/// ```
+///
+/// The `if` keyword is used in one other place in Rust, namely as a part of pattern matching
+/// itself, allowing patterns such as `Some(x) if x > 200` to be used.
+///
+/// For more information on `if` expressions, see the [Rust book] or the [Reference].
+///
+/// [Rust book]:
+/// https://doc.rust-lang.org/stable/book/2018-edition/ch03-05-control-flow.html#if-expressions
+/// [Reference]: https://doc.rust-lang.org/reference/expressions/if-expr.html
+mod if_keyword { }
+
+#[doc(keyword = "impl")]
+//
+/// The implementation-defining keyword.
+///
+/// The `impl` keyword is primarily used to define implementations on types. Inherent
+/// implementations are standalone, while trait implementations are used to implement traits for
+/// types, or other traits.
+///
+/// Functions and consts can both be defined in an implementation. A function defined in an
+/// `impl` block can be standalone, meaning it would be called like `Foo::bar()`. If the function
+/// takes `self`, `&self`, or `&mut self` as its first argument, it can also be called using
+/// method-call syntax, a familiar feature to any object oriented programmer, like `foo.bar()`.
+///
+/// ```rust
+/// struct Example {
+/// number: i32,
+/// }
+///
+/// impl Example {
+/// fn boo() {
+/// println!("boo! Example::boo() was called!");
+/// }
+///
+/// fn answer(&mut self) {
+/// self.number += 42;
+/// }
+///
+/// fn get_number(&self) -> i32 {
+/// self.number
+/// }
+/// }
+///
+/// trait Thingy {
+/// fn do_thingy(&self);
+/// }
+///
+/// impl Thingy for Example {
+/// fn do_thingy(&self) {
+/// println!("doing a thing! also, number is {}!", self.number);
+/// }
+/// }
+/// ```
+///
+/// For more information on implementations, see the [Rust book][book1] or the [Reference].
+///
+/// The other use of the `impl` keyword is in `impl Trait` syntax, which can be seen as a shorthand
+/// for "a concrete type that implements this trait". Its primary use is working with closures,
+/// which have type definitions generated at compile time that can't be simply typed out.
+///
+/// ```rust
+/// fn thing_returning_closure() -> impl Fn(i32) -> bool {
+/// println!("here's a closure for you!");
+/// |x: i32| x % 3 == 0
+/// }
+/// ```
+///
+/// For more information on `impl Trait` syntax, see the [Rust book][book2].
+///
+/// [book1]: https://doc.rust-lang.org/stable/book/2018-edition/ch05-03-method-syntax.html
+/// [Reference]: https://doc.rust-lang.org/reference/items/implementations.html
+/// [book2]:
+/// https://doc.rust-lang.org/stable/book/2018-edition/ch10-02-traits.html#returning-traits
+mod impl_keyword { }
+
+#[doc(keyword = "let")]
+//
+/// The variable binding keyword.
+///
+/// The primary use for the `let` keyword is in `let` statements, which are used to introduce a new
+/// set of variables into the current scope, as given by a pattern.
+///
+/// ```rust
+/// # #![allow(unused_assignments)]
+/// let thing1: i32 = 100;
+/// let thing2 = 200 + thing1;
+///
+/// let mut changing_thing = true;
+/// changing_thing = false;
+///
+/// let (part1, part2) = ("first", "second");
+///
+/// struct Example {
+/// a: bool,
+/// b: u64,
+/// }
+///
+/// let Example { a, b: _ } = Example {
+/// a: true,
+/// b: 10004,
+/// };
+/// assert!(a);
+/// ```
+///
+/// The pattern is most commonly a single variable, which means no pattern matching is done and
+/// the expression given is bound to the variable. Apart from that, patterns used in `let` bindings
+/// can be as complicated as needed, given that the pattern is exhaustive. See the [Rust
+/// book][book1] for more information on pattern matching. The type of the pattern is optionally
+/// given afterwards, but if left blank is automatically inferred by the compiler if possible.
+///
+/// Variables in Rust are immutable by default, and require the `mut` keyword to be made mutable.
+///
+/// Multiple variables can be defined with the same name, known as shadowing. This doesn't affect
+/// the original variable in any way beyond being unable to directly access it beyond the point of
+/// shadowing. It continues to remain in scope, getting dropped only when it falls out of scope.
+/// Shadowed variables don't need to have the same type as the variables shadowing them.
+///
+/// ```rust
+/// let shadowing_example = true;
+/// let shadowing_example = 123.4;
+/// let shadowing_example = shadowing_example as u32;
+/// let mut shadowing_example = format!("cool! {}", shadowing_example);
+/// shadowing_example += " something else!"; // not shadowing
+/// ```
+///
+/// Other places the `let` keyword is used include along with [`if`], in the form of `if let`
+/// expressions. They're useful if the pattern being matched isn't exhaustive, such as with
+/// enumerations. `while let` also exists, which runs a loop with a pattern matched value until
+/// that pattern can't be matched.
+///
+/// For more information on the `let` keyword, see the [Rust book] or the [Reference]
+///
+/// [book1]: https://doc.rust-lang.org/stable/book/2018-edition/ch06-02-match.html
+/// [`if`]: keyword.if.html
+/// [book2]:
+/// https://doc.rust-lang.org/stable/book/2018-edition/ch18-01-all-the-places-for-patterns.html#let-statements
+/// [Reference]: https://doc.rust-lang.org/reference/statements.html#let-statements
+mod let_keyword { }
+
+#[doc(keyword = "loop")]
+//
+/// The loop-defining keyword.
+///
+/// `loop` is used to define the simplest kind of loop supported in Rust. It runs the code inside
+/// it until the code uses `break` or the program exits.
+///
+/// ```rust
+/// loop {
+/// println!("hello world forever!");
+/// # break;
+/// }
+///
+/// let mut i = 0;
+/// loop {
+/// println!("i is {}", i);
+/// if i > 10 {
+/// break;
+/// }
+/// i += 1;
+/// }
+/// ```
+///
+/// Unlike the other kinds of loops in Rust (`while`, `while let`, and `for`), loops can be used as
+/// expressions that return values via `break`.
+///
+/// ```rust
+/// let mut i = 1;
+/// let something = loop {
+/// i *= 2;
+/// if i > 100 {
+/// break i;
+/// }
+/// };
+/// assert_eq!(something, 128);
+/// ```
+///
+/// Every `break` in a loop has to have the same type. When it's not explicitly giving something,
+/// `break;` returns `()`.
+///
+/// For more information on `loop` and loops in general, see the [Reference].
+///
+/// [Reference]: https://doc.rust-lang.org/reference/expressions/loop-expr.html
+mod loop_keyword { }
+
+#[doc(keyword = "struct")]
+//
+/// The keyword used to define structs.
+///
+/// Structs in Rust come in three flavors: Structs with named fields, tuple structs, and unit
+/// structs.
+///
+/// ```rust
+/// struct Regular {
+/// field1: f32,
+/// field2: String,
+/// pub field3: bool
+/// }
+///
+/// struct Tuple(u32, String);
+///
+/// struct Unit;
+/// ```
+///
+/// Regular structs are the most commonly used. Each field defined within them has a name and a
+/// type, and once defined can be accessed using `example_struct.field` syntax. The fields of a
+/// struct share its mutability, so `foo.bar = 2;` would only be valid if `foo` was mutable. Adding
+/// `pub` to a field makes it visible to code in other modules, as well as allowing it to be
+/// directly accessed and modified.
+///
+/// Tuple structs are similar to regular structs, but its fields have no names. They are used like
+/// tuples, with deconstruction possible via `let TupleStruct(x, y) = foo;` syntax. For accessing
+/// individual variables, the same syntax is used as with regular tuples, namely `foo.0`, `foo.1`,
+/// etc, starting at zero.
+///
+/// Unit structs are most commonly used as marker. They have a size of zero bytes, but unlike empty
+/// enums they can be instantiated, making them isomorphic to the unit type `()`. Unit structs are
+/// useful when you need to implement a trait on something, but don't need to store any data inside
+/// it.
+///
+/// # Instantiation
+///
+/// Structs can be instantiated in different ways, all of which can be mixed and
+/// matched as needed. The most common way to make a new struct is via a constructor method such as
+/// `new()`, but when that isn't available (or you're writing the constructor itself), struct
+/// literal syntax is used:
+///
+/// ```rust
+/// # struct Foo { field1: f32, field2: String, etc: bool }
+/// let example = Foo {
+/// field1: 42.0,
+/// field2: "blah".to_string(),
+/// etc: true,
+/// };
+/// ```
+///
+/// It's only possible to directly instantiate a struct using struct literal syntax when all of its
+/// fields are visible to you.
+///
+/// There are a handful of shortcuts provided to make writing constructors more convenient, most
+/// common of which is the Field Init shorthand. When there is a variable and a field of the same
+/// name, the assignment can be simplified from `field: field` into simply `field`. The following
+/// example of a hypothetical constructor demonstrates this:
+///
+/// ```rust
+/// struct User {
+/// name: String,
+/// admin: bool,
+/// }
+///
+/// impl User {
+/// pub fn new(name: String) -> Self {
+/// Self {
+/// name,
+/// admin: false,
+/// }
+/// }
+/// }
+/// ```
+///
+/// Another shortcut for struct instantiation is available, used when you need to make a new
+/// struct that has the same values as most of a previous struct of the same type, called struct
+/// update syntax:
+///
+/// ```rust
+/// # struct Foo { field1: String, field2: () }
+/// # let thing = Foo { field1: "".to_string(), field2: () };
+/// let updated_thing = Foo {
+/// field1: "a new value".to_string(),
+/// ..thing
+/// };
+/// ```
+///
+/// Tuple structs are instantiated in the same way as tuples themselves, except with the struct's
+/// name as a prefix: `Foo(123, false, 0.1)`.
+///
+/// Empty structs are instantiated with just their name, and don't need anything else. `let thing =
+/// EmptyStruct;`
+///
+/// # Style conventions
+///
+/// Structs are always written in CamelCase, with few exceptions. While the trailing comma on a
+/// struct's list of fields can be omitted, it's usually kept for convenience in adding and
+/// removing fields down the line.
+///
+/// For more information on structs, take a look at the [Rust Book][book] or the
+/// [Reference][reference].
+///
+/// [`PhantomData`]: marker/struct.PhantomData.html
+/// [book]: https://doc.rust-lang.org/book/ch05-01-defining-structs.html
+/// [reference]: https://doc.rust-lang.org/reference/items/structs.html
+mod struct_keyword { }
diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs
new file mode 100644
index 0000000..8935245
--- /dev/null
+++ b/src/libstd/lib.rs
@@ -0,0 +1,516 @@
+//! # The Rust Standard Library
+//!
+//! The Rust Standard Library is the foundation of portable Rust software, a
+//! set of minimal and battle-tested shared abstractions for the [broader Rust
+//! ecosystem][crates.io]. It offers core types, like [`Vec<T>`] and
+//! [`Option<T>`], library-defined [operations on language
+//! primitives](#primitives), [standard macros](#macros), [I/O] and
+//! [multithreading], among [many other things][other].
+//!
+//! `std` is available to all Rust crates by default. Therefore, the
+//! standard library can be accessed in [`use`] statements through the path
+//! `std`, as in [`use std::env`].
+//!
+//! # How to read this documentation
+//!
+//! If you already know the name of what you are looking for, the fastest way to
+//! find it is to use the <a href="#" onclick="focusSearchBar();">search
+//! bar</a> at the top of the page.
+//!
+//! Otherwise, you may want to jump to one of these useful sections:
+//!
+//! * [`std::*` modules](#modules)
+//! * [Primitive types](#primitives)
+//! * [Standard macros](#macros)
+//! * [The Rust Prelude](prelude/index.html)
+//!
+//! If this is your first time, the documentation for the standard library is
+//! written to be casually perused. Clicking on interesting things should
+//! generally lead you to interesting places. Still, there are important bits
+//! you don't want to miss, so read on for a tour of the standard library and
+//! its documentation!
+//!
+//! Once you are familiar with the contents of the standard library you may
+//! begin to find the verbosity of the prose distracting. At this stage in your
+//! development you may want to press the `[-]` button near the top of the
+//! page to collapse it into a more skimmable view.
+//!
+//! While you are looking at that `[-]` button also notice the `[src]`
+//! button. Rust's API documentation comes with the source code and you are
+//! encouraged to read it. The standard library source is generally high
+//! quality and a peek behind the curtains is often enlightening.
+//!
+//! # What is in the standard library documentation?
+//!
+//! First of all, The Rust Standard Library is divided into a number of focused
+//! modules, [all listed further down this page](#modules). These modules are
+//! the bedrock upon which all of Rust is forged, and they have mighty names
+//! like [`std::slice`] and [`std::cmp`]. Modules' documentation typically
+//! includes an overview of the module along with examples, and are a smart
+//! place to start familiarizing yourself with the library.
+//!
+//! Second, implicit methods on [primitive types] are documented here. This can
+//! be a source of confusion for two reasons:
+//!
+//! 1. While primitives are implemented by the compiler, the standard library
+//! implements methods directly on the primitive types (and it is the only
+//! library that does so), which are [documented in the section on
+//! primitives](#primitives).
+//! 2. The standard library exports many modules *with the same name as
+//! primitive types*. These define additional items related to the primitive
+//! type, but not the all-important methods.
+//!
+//! So for example there is a [page for the primitive type
+//! `i32`](primitive.i32.html) that lists all the methods that can be called on
+//! 32-bit integers (very useful), and there is a [page for the module
+//! `std::i32`](i32/index.html) that documents the constant values [`MIN`] and
+//! [`MAX`](i32/constant.MAX.html) (rarely useful).
+//!
+//! Note the documentation for the primitives [`str`] and [`[T]`][slice] (also
+//! called 'slice'). Many method calls on [`String`] and [`Vec<T>`] are actually
+//! calls to methods on [`str`] and [`[T]`][slice] respectively, via [deref
+//! coercions][deref-coercions].
+//!
+//! Third, the standard library defines [The Rust Prelude], a small collection
+//! of items - mostly traits - that are imported into every module of every
+//! crate. The traits in the prelude are pervasive, making the prelude
+//! documentation a good entry point to learning about the library.
+//!
+//! And finally, the standard library exports a number of standard macros, and
+//! [lists them on this page](#macros) (technically, not all of the standard
+//! macros are defined by the standard library - some are defined by the
+//! compiler - but they are documented here the same). Like the prelude, the
+//! standard macros are imported by default into all crates.
+//!
+//! # Contributing changes to the documentation
+//!
+//! Check out the rust contribution guidelines [here](
+//! https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.md).
+//! The source for this documentation can be found on [Github](https://github.com/rust-lang).
+//! To contribute changes, make sure you read the guidelines first, then submit
+//! pull-requests for your suggested changes.
+//!
+//! Contributions are appreciated! If you see a part of the docs that can be
+//! improved, submit a PR, or chat with us first on irc.mozilla.org #rust-docs.
+//!
+//! # A Tour of The Rust Standard Library
+//!
+//! The rest of this crate documentation is dedicated to pointing out notable
+//! features of The Rust Standard Library.
+//!
+//! ## Containers and collections
+//!
+//! The [`option`] and [`result`] modules define optional and error-handling
+//! types, [`Option<T>`] and [`Result<T, E>`]. The [`iter`] module defines
+//! Rust's iterator trait, [`Iterator`], which works with the [`for`] loop to
+//! access collections.
+//!
+//! The standard library exposes three common ways to deal with contiguous
+//! regions of memory:
+//!
+//! * [`Vec<T>`] - A heap-allocated *vector* that is resizable at runtime.
+//! * [`[T; n]`][array] - An inline *array* with a fixed size at compile time.
+//! * [`[T]`][slice] - A dynamically sized *slice* into any other kind of contiguous
+//! storage, whether heap-allocated or not.
+//!
+//! Slices can only be handled through some kind of *pointer*, and as such come
+//! in many flavors such as:
+//!
+//! * `&[T]` - *shared slice*
+//! * `&mut [T]` - *mutable slice*
+//! * [`Box<[T]>`][owned slice] - *owned slice*
+//!
+//! [`str`], a UTF-8 string slice, is a primitive type, and the standard library
+//! defines many methods for it. Rust [`str`]s are typically accessed as
+//! immutable references: `&str`. Use the owned [`String`] for building and
+//! mutating strings.
+//!
+//! For converting to strings use the [`format!`] macro, and for converting from
+//! strings use the [`FromStr`] trait.
+//!
+//! Data may be shared by placing it in a reference-counted box or the [`Rc`]
+//! type, and if further contained in a [`Cell`] or [`RefCell`], may be mutated
+//! as well as shared. Likewise, in a concurrent setting it is common to pair an
+//! atomically-reference-counted box, [`Arc`], with a [`Mutex`] to get the same
+//! effect.
+//!
+//! The [`collections`] module defines maps, sets, linked lists and other
+//! typical collection types, including the common [`HashMap<K, V>`].
+//!
+//! ## Platform abstractions and I/O
+//!
+//! Besides basic data types, the standard library is largely concerned with
+//! abstracting over differences in common platforms, most notably Windows and
+//! Unix derivatives.
+//!
+//! Common types of I/O, including [files], [TCP], [UDP], are defined in the
+//! [`io`], [`fs`], and [`net`] modules.
+//!
+//! The [`thread`] module contains Rust's threading abstractions. [`sync`]
+//! contains further primitive shared memory types, including [`atomic`] and
+//! [`mpsc`], which contains the channel types for message passing.
+//!
+//! [I/O]: io/index.html
+//! [`MIN`]: i32/constant.MIN.html
+//! [TCP]: net/struct.TcpStream.html
+//! [The Rust Prelude]: prelude/index.html
+//! [UDP]: net/struct.UdpSocket.html
+//! [`Arc`]: sync/struct.Arc.html
+//! [owned slice]: boxed/index.html
+//! [`Cell`]: cell/struct.Cell.html
+//! [`FromStr`]: str/trait.FromStr.html
+//! [`HashMap<K, V>`]: collections/struct.HashMap.html
+//! [`Iterator`]: iter/trait.Iterator.html
+//! [`Mutex`]: sync/struct.Mutex.html
+//! [`Option<T>`]: option/enum.Option.html
+//! [`Rc`]: rc/index.html
+//! [`RefCell`]: cell/struct.RefCell.html
+//! [`Result<T, E>`]: result/enum.Result.html
+//! [`String`]: string/struct.String.html
+//! [`Vec<T>`]: vec/index.html
+//! [array]: primitive.array.html
+//! [slice]: primitive.slice.html
+//! [`atomic`]: sync/atomic/index.html
+//! [`collections`]: collections/index.html
+//! [`for`]: ../book/ch03-05-control-flow.html#looping-through-a-collection-with-for
+//! [`format!`]: macro.format.html
+//! [`fs`]: fs/index.html
+//! [`io`]: io/index.html
+//! [`iter`]: iter/index.html
+//! [`mpsc`]: sync/mpsc/index.html
+//! [`net`]: net/index.html
+//! [`option`]: option/index.html
+//! [`result`]: result/index.html
+//! [`std::cmp`]: cmp/index.html
+//! [`std::slice`]: slice/index.html
+//! [`str`]: primitive.str.html
+//! [`sync`]: sync/index.html
+//! [`thread`]: thread/index.html
+//! [`use std::env`]: env/index.html
+//! [`use`]: ../book/ch07-02-defining-modules-to-control-scope-and-privacy.html
+//! [crates.io]: https://crates.io
+//! [deref-coercions]: ../book/ch15-02-deref.html#implicit-deref-coercions-with-functions-and-methods
+//! [files]: fs/struct.File.html
+//! [multithreading]: thread/index.html
+//! [other]: #what-is-in-the-standard-library-documentation
+//! [primitive types]: ../book/ch03-02-data-types.html
+
+#![stable(feature = "rust1", since = "1.0.0")]
+#![doc(html_root_url = "https://doc.rust-lang.org/nightly/",
+ html_playground_url = "https://play.rust-lang.org/",
+ issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/",
+ test(no_crate_inject, attr(deny(warnings))),
+ test(attr(allow(dead_code, deprecated, unused_variables, unused_mut))))]
+
+// Don't link to std. We are std.
+#![no_std]
+
+#![deny(missing_docs)]
+#![deny(intra_doc_link_resolution_failure)]
+#![deny(missing_debug_implementations)]
+
+#![deny(rust_2018_idioms)]
+#![allow(explicit_outlives_requirements)]
+
+// Tell the compiler to link to either panic_abort or panic_unwind
+#![needs_panic_runtime]
+
+// std may use features in a platform-specific way
+#![allow(unused_features)]
+
+#![cfg_attr(test, feature(print_internals, set_stdio, test, update_panic_count))]
+#![cfg_attr(all(target_vendor = "fortanix", target_env = "sgx"),
+ feature(global_asm, slice_index_methods,
+ decl_macro, coerce_unsized, sgx_platform, ptr_wrapping_offset_from))]
+
+// std is implemented with unstable features, many of which are internal
+// compiler details that will never be stable
+// NB: the following list is sorted to minimize merge conflicts.
+#![feature(align_offset)]
+#![feature(alloc_error_handler)]
+#![feature(alloc_layout_extra)]
+#![feature(alloc)]
+#![feature(allocator_api)]
+#![feature(allocator_internals)]
+#![feature(allow_internal_unsafe)]
+#![feature(allow_internal_unstable)]
+#![feature(arbitrary_self_types)]
+#![feature(array_error_internals)]
+#![feature(asm)]
+#![feature(bind_by_move_pattern_guards)]
+#![feature(box_syntax)]
+#![feature(c_variadic)]
+#![feature(cfg_target_has_atomic)]
+#![feature(cfg_target_thread_local)]
+#![feature(char_error_internals)]
+#![feature(checked_duration_since)]
+#![feature(clamp)]
+#![feature(compiler_builtins_lib)]
+#![feature(concat_idents)]
+#![feature(const_cstr_unchecked)]
+#![feature(const_raw_ptr_deref)]
+#![feature(core_intrinsics)]
+#![feature(doc_alias)]
+#![feature(doc_cfg)]
+#![feature(doc_keyword)]
+#![feature(doc_masked)]
+#![feature(doc_spotlight)]
+#![feature(dropck_eyepatch)]
+#![feature(duration_constants)]
+#![feature(exact_size_is_empty)]
+#![feature(exhaustive_patterns)]
+#![feature(external_doc)]
+#![feature(fn_traits)]
+#![feature(fnbox)]
+#![feature(futures_api)]
+#![feature(generator_trait)]
+#![feature(hash_raw_entry)]
+#![feature(hashmap_internals)]
+#![feature(int_error_internals)]
+#![feature(integer_atomics)]
+#![feature(lang_items)]
+#![feature(libc)]
+#![feature(link_args)]
+#![feature(linkage)]
+#![feature(maybe_uninit)]
+#![feature(needs_panic_runtime)]
+#![feature(never_type)]
+#![feature(nll)]
+#![feature(non_exhaustive)]
+#![feature(on_unimplemented)]
+#![feature(optin_builtin_traits)]
+#![feature(panic_info_message)]
+#![feature(panic_internals)]
+#![feature(panic_unwind)]
+#![feature(prelude_import)]
+#![feature(ptr_internals)]
+#![feature(raw)]
+#![feature(renamed_spin_loop)]
+#![feature(rustc_attrs)]
+#![feature(rustc_const_unstable)]
+#![feature(rustc_private)]
+#![feature(shrink_to)]
+#![feature(slice_concat_ext)]
+#![feature(slice_internals)]
+#![feature(slice_patterns)]
+#![feature(staged_api)]
+#![feature(std_internals)]
+#![feature(stdsimd)]
+#![feature(stmt_expr_attributes)]
+#![feature(str_internals)]
+#![feature(thread_local)]
+#![feature(todo_macro)]
+#![feature(toowned_clone_into)]
+#![feature(try_reserve)]
+#![feature(unboxed_closures)]
+#![feature(untagged_unions)]
+#![feature(unwind_attributes)]
+// NB: the above list is sorted to minimize merge conflicts.
+
+#![default_lib_allocator]
+
+// Explicitly import the prelude. The compiler uses this same unstable attribute
+// to import the prelude implicitly when building crates that depend on std.
+#[prelude_import]
+#[allow(unused)]
+use prelude::v1::*;
+
+// Access to Bencher, etc.
+#[cfg(test)] extern crate test;
+
+// Re-export a few macros from core
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use core::{assert_eq, assert_ne, debug_assert, debug_assert_eq, debug_assert_ne};
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use core::{unreachable, unimplemented, write, writeln, r#try, todo};
+
+#[allow(unused_imports)] // macros from `alloc` are not used on all platforms
+#[macro_use]
+extern crate alloc as alloc_crate;
+#[doc(masked)]
+#[allow(unused_extern_crates)]
+extern crate libc;
+
+// We always need an unwinder currently for backtraces
+#[doc(masked)]
+#[allow(unused_extern_crates)]
+extern crate unwind;
+
+// During testing, this crate is not actually the "real" std library, but rather
+// it links to the real std library, which was compiled from this same source
+// code. So any lang items std defines are conditionally excluded (or else they
+// would generate duplicate lang item errors), and any globals it defines are
+// _not_ the globals used by "real" std. So this import, defined only during
+// testing gives test-std access to real-std lang items and globals. See #2912
+#[cfg(test)] extern crate std as realstd;
+
+// The standard macros that are not built-in to the compiler.
+#[macro_use]
+mod macros;
+
+// The Rust prelude
+pub mod prelude;
+
+// Public module declarations and re-exports
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use core::any;
+#[stable(feature = "simd_arch", since = "1.27.0")]
+#[doc(no_inline)]
+pub use core::arch;
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use core::cell;
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use core::clone;
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use core::cmp;
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use core::convert;
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use core::default;
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use core::hash;
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use core::intrinsics;
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use core::iter;
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use core::marker;
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use core::mem;
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use core::ops;
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use core::ptr;
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use core::raw;
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use core::result;
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use core::option;
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use core::isize;
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use core::i8;
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use core::i16;
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use core::i32;
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use core::i64;
+#[stable(feature = "i128", since = "1.26.0")]
+pub use core::i128;
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use core::usize;
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use core::u8;
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use core::u16;
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use core::u32;
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use core::u64;
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use alloc_crate::boxed;
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use alloc_crate::rc;
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use alloc_crate::borrow;
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use alloc_crate::fmt;
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use alloc_crate::format;
+#[stable(feature = "pin", since = "1.33.0")]
+pub use core::pin;
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use alloc_crate::slice;
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use alloc_crate::str;
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use alloc_crate::string;
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use alloc_crate::vec;
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use core::char;
+#[stable(feature = "i128", since = "1.26.0")]
+pub use core::u128;
+#[stable(feature = "core_hint", since = "1.27.0")]
+pub use core::hint;
+#[stable(feature = "core_array", since = "1.36.0")]
+pub use core::array;
+
+pub mod f32;
+pub mod f64;
+
+#[macro_use]
+pub mod thread;
+pub mod ascii;
+pub mod collections;
+pub mod env;
+pub mod error;
+pub mod ffi;
+pub mod fs;
+pub mod io;
+pub mod net;
+pub mod num;
+pub mod os;
+pub mod panic;
+pub mod path;
+pub mod process;
+pub mod sync;
+pub mod time;
+
+#[unstable(feature = "futures_api",
+ reason = "futures in libcore are unstable",
+ issue = "50547")]
+pub mod task {
+ //! Types and Traits for working with asynchronous tasks.
+ #[doc(inline)]
+ pub use core::task::*;
+}
+
+#[unstable(feature = "futures_api",
+ reason = "futures in libcore are unstable",
+ issue = "50547")]
+pub mod future;
+
+// Platform-abstraction modules
+#[macro_use]
+mod sys_common;
+mod sys;
+
+pub mod alloc;
+
+// Private support modules
+mod panicking;
+mod memchr;
+
+// The runtime entry point and a few unstable public functions used by the
+// compiler
+pub mod rt;
+
+// Pull in the `std_detect` crate directly into libstd. The contents of
+// `std_detect` are in a different repository: rust-lang-nursery/stdsimd.
+//
+// `std_detect` depends on libstd, but the contents of this module are
+// set up in such a way that directly pulling it here works such that the
+// crate uses the this crate as its libstd.
+#[path = "../stdsimd/crates/std_detect/src/mod.rs"]
+#[allow(missing_debug_implementations, missing_docs, dead_code)]
+#[unstable(feature = "stdsimd", issue = "48556")]
+#[cfg(not(test))]
+mod std_detect;
+
+#[doc(hidden)]
+#[unstable(feature = "stdsimd", issue = "48556")]
+#[cfg(not(test))]
+pub use std_detect::detect;
+
+// Include a number of private modules that exist solely to provide
+// the rustdoc documentation for primitive types. Using `include!`
+// because rustdoc only looks for these modules at the crate level.
+include!("primitive_docs.rs");
+
+// Include a number of private modules that exist solely to provide
+// the rustdoc documentation for the existing keywords. Using `include!`
+// because rustdoc only looks for these modules at the crate level.
+include!("keyword_docs.rs");
diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs
new file mode 100644
index 0000000..14b266a
--- /dev/null
+++ b/src/libstd/macros.rs
@@ -0,0 +1,991 @@
+//! Standard library macros
+//!
+//! This modules contains a set of macros which are exported from the standard
+//! library. Each macro is available for use when linking against the standard
+//! library.
+
+/// Panics the current thread.
+///
+/// This allows a program to terminate immediately and provide feedback
+/// to the caller of the program. `panic!` should be used when a program reaches
+/// an unrecoverable state.
+///
+/// This macro is the perfect way to assert conditions in example code and in
+/// tests. `panic!` is closely tied with the `unwrap` method of both [`Option`]
+/// and [`Result`][runwrap] enums. Both implementations call `panic!` when they are set
+/// to None or Err variants.
+///
+/// This macro is used to inject panic into a Rust thread, causing the thread to
+/// panic entirely. Each thread's panic can be reaped as the `Box<Any>` type,
+/// and the single-argument form of the `panic!` macro will be the value which
+/// is transmitted.
+///
+/// [`Result`] enum is often a better solution for recovering from errors than
+/// using the `panic!` macro. This macro should be used to avoid proceeding using
+/// incorrect values, such as from external sources. Detailed information about
+/// error handling is found in the [book].
+///
+/// The multi-argument form of this macro panics with a string and has the
+/// [`format!`] syntax for building a string.
+///
+/// See also the macro [`compile_error!`], for raising errors during compilation.
+///
+/// [runwrap]: ../std/result/enum.Result.html#method.unwrap
+/// [`Option`]: ../std/option/enum.Option.html#method.unwrap
+/// [`Result`]: ../std/result/enum.Result.html
+/// [`format!`]: ../std/macro.format.html
+/// [`compile_error!`]: ../std/macro.compile_error.html
+/// [book]: ../book/ch09-00-error-handling.html
+///
+/// # Current implementation
+///
+/// If the main thread panics it will terminate all your threads and end your
+/// program with code `101`.
+///
+/// # Examples
+///
+/// ```should_panic
+/// # #![allow(unreachable_code)]
+/// panic!();
+/// panic!("this is a terrible mistake!");
+/// panic!(4); // panic with the value of 4 to be collected elsewhere
+/// panic!("this is a {} {message}", "fancy", message = "message");
+/// ```
+#[macro_export]
+#[stable(feature = "rust1", since = "1.0.0")]
+#[allow_internal_unstable(__rust_unstable_column, libstd_sys_internals)]
+macro_rules! panic {
+ () => ({
+ panic!("explicit panic")
+ });
+ ($msg:expr) => ({
+ $crate::rt::begin_panic($msg, &(file!(), line!(), __rust_unstable_column!()))
+ });
+ ($msg:expr,) => ({
+ panic!($msg)
+ });
+ ($fmt:expr, $($arg:tt)+) => ({
+ $crate::rt::begin_panic_fmt(&format_args!($fmt, $($arg)+),
+ &(file!(), line!(), __rust_unstable_column!()))
+ });
+}
+
+/// Prints to the standard output.
+///
+/// Equivalent to the [`println!`] macro except that a newline is not printed at
+/// the end of the message.
+///
+/// Note that stdout is frequently line-buffered by default so it may be
+/// necessary to use [`io::stdout().flush()`][flush] to ensure the output is emitted
+/// immediately.
+///
+/// Use `print!` only for the primary output of your program. Use
+/// [`eprint!`] instead to print error and progress messages.
+///
+/// [`println!`]: ../std/macro.println.html
+/// [flush]: ../std/io/trait.Write.html#tymethod.flush
+/// [`eprint!`]: ../std/macro.eprint.html
+///
+/// # Panics
+///
+/// Panics if writing to `io::stdout()` fails.
+///
+/// # Examples
+///
+/// ```
+/// use std::io::{self, Write};
+///
+/// print!("this ");
+/// print!("will ");
+/// print!("be ");
+/// print!("on ");
+/// print!("the ");
+/// print!("same ");
+/// print!("line ");
+///
+/// io::stdout().flush().unwrap();
+///
+/// print!("this string has a newline, why not choose println! instead?\n");
+///
+/// io::stdout().flush().unwrap();
+/// ```
+#[macro_export]
+#[stable(feature = "rust1", since = "1.0.0")]
+#[allow_internal_unstable(print_internals)]
+macro_rules! print {
+ ($($arg:tt)*) => ($crate::io::_print(format_args!($($arg)*)));
+}
+
+/// Prints to the standard output, with a newline.
+///
+/// On all platforms, the newline is the LINE FEED character (`\n`/`U+000A`) alone
+/// (no additional CARRIAGE RETURN (`\r`/`U+000D`).
+///
+/// Use the [`format!`] syntax to write data to the standard output.
+/// See [`std::fmt`] for more information.
+///
+/// Use `println!` only for the primary output of your program. Use
+/// [`eprintln!`] instead to print error and progress messages.
+///
+/// [`format!`]: ../std/macro.format.html
+/// [`std::fmt`]: ../std/fmt/index.html
+/// [`eprintln!`]: ../std/macro.eprintln.html
+/// # Panics
+///
+/// Panics if writing to `io::stdout` fails.
+///
+/// # Examples
+///
+/// ```
+/// println!(); // prints just a newline
+/// println!("hello there!");
+/// println!("format {} arguments", "some");
+/// ```
+#[macro_export]
+#[stable(feature = "rust1", since = "1.0.0")]
+#[allow_internal_unstable(print_internals, format_args_nl)]
+macro_rules! println {
+ () => (print!("\n"));
+ ($($arg:tt)*) => ({
+ $crate::io::_print(format_args_nl!($($arg)*));
+ })
+}
+
+/// Prints to the standard error.
+///
+/// Equivalent to the [`print!`] macro, except that output goes to
+/// [`io::stderr`] instead of `io::stdout`. See [`print!`] for
+/// example usage.
+///
+/// Use `eprint!` only for error and progress messages. Use `print!`
+/// instead for the primary output of your program.
+///
+/// [`io::stderr`]: ../std/io/struct.Stderr.html
+/// [`print!`]: ../std/macro.print.html
+///
+/// # Panics
+///
+/// Panics if writing to `io::stderr` fails.
+///
+/// # Examples
+///
+/// ```
+/// eprint!("Error: Could not complete task");
+/// ```
+#[macro_export]
+#[stable(feature = "eprint", since = "1.19.0")]
+#[allow_internal_unstable(print_internals)]
+macro_rules! eprint {
+ ($($arg:tt)*) => ($crate::io::_eprint(format_args!($($arg)*)));
+}
+
+/// Prints to the standard error, with a newline.
+///
+/// Equivalent to the [`println!`] macro, except that output goes to
+/// [`io::stderr`] instead of `io::stdout`. See [`println!`] for
+/// example usage.
+///
+/// Use `eprintln!` only for error and progress messages. Use `println!`
+/// instead for the primary output of your program.
+///
+/// [`io::stderr`]: ../std/io/struct.Stderr.html
+/// [`println!`]: ../std/macro.println.html
+///
+/// # Panics
+///
+/// Panics if writing to `io::stderr` fails.
+///
+/// # Examples
+///
+/// ```
+/// eprintln!("Error: Could not complete task");
+/// ```
+#[macro_export]
+#[stable(feature = "eprint", since = "1.19.0")]
+#[allow_internal_unstable(print_internals, format_args_nl)]
+macro_rules! eprintln {
+ () => (eprint!("\n"));
+ ($($arg:tt)*) => ({
+ $crate::io::_eprint(format_args_nl!($($arg)*));
+ })
+}
+
+/// Prints and returns the value of a given expression for quick and dirty
+/// debugging.
+///
+/// An example:
+///
+/// ```rust
+/// let a = 2;
+/// let b = dbg!(a * 2) + 1;
+/// // ^-- prints: [src/main.rs:2] a * 2 = 4
+/// assert_eq!(b, 5);
+/// ```
+///
+/// The macro works by using the `Debug` implementation of the type of
+/// the given expression to print the value to [stderr] along with the
+/// source location of the macro invocation as well as the source code
+/// of the expression.
+///
+/// Invoking the macro on an expression moves and takes ownership of it
+/// before returning the evaluated expression unchanged. If the type
+/// of the expression does not implement `Copy` and you don't want
+/// to give up ownership, you can instead borrow with `dbg!(&expr)`
+/// for some expression `expr`.
+///
+/// The `dbg!` macro works exactly the same in release builds.
+/// This is useful when debugging issues that only occur in release
+/// builds or when debugging in release mode is significantly faster.
+///
+/// Note that the macro is intended as a debugging tool and therefore you
+/// should avoid having uses of it in version control for longer periods.
+/// Use cases involving debug output that should be added to version control
+/// are better served by macros such as [`debug!`] from the [`log`] crate.
+///
+/// # Stability
+///
+/// The exact output printed by this macro should not be relied upon
+/// and is subject to future changes.
+///
+/// # Panics
+///
+/// Panics if writing to `io::stderr` fails.
+///
+/// # Further examples
+///
+/// With a method call:
+///
+/// ```rust
+/// fn foo(n: usize) {
+/// if let Some(_) = dbg!(n.checked_sub(4)) {
+/// // ...
+/// }
+/// }
+///
+/// foo(3)
+/// ```
+///
+/// This prints to [stderr]:
+///
+/// ```text,ignore
+/// [src/main.rs:4] n.checked_sub(4) = None
+/// ```
+///
+/// Naive factorial implementation:
+///
+/// ```rust
+/// fn factorial(n: u32) -> u32 {
+/// if dbg!(n <= 1) {
+/// dbg!(1)
+/// } else {
+/// dbg!(n * factorial(n - 1))
+/// }
+/// }
+///
+/// dbg!(factorial(4));
+/// ```
+///
+/// This prints to [stderr]:
+///
+/// ```text,ignore
+/// [src/main.rs:3] n <= 1 = false
+/// [src/main.rs:3] n <= 1 = false
+/// [src/main.rs:3] n <= 1 = false
+/// [src/main.rs:3] n <= 1 = true
+/// [src/main.rs:4] 1 = 1
+/// [src/main.rs:5] n * factorial(n - 1) = 2
+/// [src/main.rs:5] n * factorial(n - 1) = 6
+/// [src/main.rs:5] n * factorial(n - 1) = 24
+/// [src/main.rs:11] factorial(4) = 24
+/// ```
+///
+/// The `dbg!(..)` macro moves the input:
+///
+/// ```compile_fail
+/// /// A wrapper around `usize` which importantly is not Copyable.
+/// #[derive(Debug)]
+/// struct NoCopy(usize);
+///
+/// let a = NoCopy(42);
+/// let _ = dbg!(a); // <-- `a` is moved here.
+/// let _ = dbg!(a); // <-- `a` is moved again; error!
+/// ```
+///
+/// You can also use `dbg!()` without a value to just print the
+/// file and line whenever it's reached.
+///
+/// [stderr]: https://en.wikipedia.org/wiki/Standard_streams#Standard_error_(stderr)
+/// [`debug!`]: https://docs.rs/log/*/log/macro.debug.html
+/// [`log`]: https://crates.io/crates/log
+#[macro_export]
+#[stable(feature = "dbg_macro", since = "1.32.0")]
+macro_rules! dbg {
+ () => {
+ eprintln!("[{}:{}]", file!(), line!());
+ };
+ ($val:expr) => {
+ // Use of `match` here is intentional because it affects the lifetimes
+ // of temporaries - https://stackoverflow.com/a/48732525/1063961
+ match $val {
+ tmp => {
+ eprintln!("[{}:{}] {} = {:#?}",
+ file!(), line!(), stringify!($val), &tmp);
+ tmp
+ }
+ }
+ }
+}
+
+/// Awaits the completion of an async call.
+#[macro_export]
+#[unstable(feature = "await_macro", issue = "50547")]
+#[allow_internal_unstable(gen_future, generators)]
+#[allow_internal_unsafe]
+macro_rules! r#await {
+ ($e:expr) => { {
+ let mut pinned = $e;
+ loop {
+ if let $crate::task::Poll::Ready(x) =
+ $crate::future::poll_with_tls_context(unsafe {
+ $crate::pin::Pin::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
+ }
+ } }
+}
+
+/// Selects the first successful receive event from a number of receivers.
+///
+/// This macro is used to wait for the first event to occur on a number of
+/// receivers. It places no restrictions on the types of receivers given to
+/// this macro, this can be viewed as a heterogeneous select.
+///
+/// # Examples
+///
+/// ```
+/// #![feature(mpsc_select)]
+///
+/// use std::thread;
+/// use std::sync::mpsc;
+///
+/// // two placeholder functions for now
+/// fn long_running_thread() {}
+/// fn calculate_the_answer() -> u32 { 42 }
+///
+/// let (tx1, rx1) = mpsc::channel();
+/// let (tx2, rx2) = mpsc::channel();
+///
+/// thread::spawn(move|| { long_running_thread(); tx1.send(()).unwrap(); });
+/// thread::spawn(move|| { tx2.send(calculate_the_answer()).unwrap(); });
+///
+/// select! {
+/// _ = rx1.recv() => println!("the long running thread finished first"),
+/// answer = rx2.recv() => {
+/// println!("the answer was: {}", answer.unwrap());
+/// }
+/// }
+/// # drop(rx1.recv());
+/// # drop(rx2.recv());
+/// ```
+///
+/// For more information about select, see the `std::sync::mpsc::Select` structure.
+#[macro_export]
+#[unstable(feature = "mpsc_select", issue = "27800")]
+#[rustc_deprecated(since = "1.32.0",
+ reason = "channel selection will be removed in a future release")]
+macro_rules! select {
+ (
+ $($name:pat = $rx:ident.$meth:ident() => $code:expr),+
+ ) => ({
+ use $crate::sync::mpsc::Select;
+ let sel = Select::new();
+ $( let mut $rx = sel.handle(&$rx); )+
+ unsafe {
+ $( $rx.add(); )+
+ }
+ let ret = sel.wait();
+ $( if ret == $rx.id() { let $name = $rx.$meth(); $code } else )+
+ { unreachable!() }
+ })
+}
+
+#[cfg(test)]
+macro_rules! assert_approx_eq {
+ ($a:expr, $b:expr) => ({
+ let (a, b) = (&$a, &$b);
+ assert!((*a - *b).abs() < 1.0e-6,
+ "{} is not approximately equal to {}", *a, *b);
+ })
+}
+
+/// Built-in macros to the compiler itself.
+///
+/// These macros do not have any corresponding definition with a `macro_rules!`
+/// macro, but are documented here. Their implementations can be found hardcoded
+/// into libsyntax itself.
+#[cfg(rustdoc)]
+mod builtin {
+
+ /// Causes compilation to fail with the given error message when encountered.
+ ///
+ /// This macro should be used when a crate uses a conditional compilation strategy to provide
+ /// better error messages for erroneous conditions. It's the compiler-level form of [`panic!`],
+ /// which emits an error at *runtime*, rather than during compilation.
+ ///
+ /// # Examples
+ ///
+ /// Two such examples are macros and `#[cfg]` environments.
+ ///
+ /// Emit better compiler error if a macro is passed invalid values. Without the final branch,
+ /// the compiler would still emit an error, but the error's message would not mention the two
+ /// valid values.
+ ///
+ /// ```compile_fail
+ /// macro_rules! give_me_foo_or_bar {
+ /// (foo) => {};
+ /// (bar) => {};
+ /// ($x:ident) => {
+ /// compile_error!("This macro only accepts `foo` or `bar`");
+ /// }
+ /// }
+ ///
+ /// give_me_foo_or_bar!(neither);
+ /// // ^ will fail at compile time with message "This macro only accepts `foo` or `bar`"
+ /// ```
+ ///
+ /// Emit compiler error if one of a number of features isn't available.
+ ///
+ /// ```compile_fail
+ /// #[cfg(not(any(feature = "foo", feature = "bar")))]
+ /// compile_error!("Either feature \"foo\" or \"bar\" must be enabled for this crate.")
+ /// ```
+ ///
+ /// [`panic!`]: ../std/macro.panic.html
+ #[stable(feature = "compile_error_macro", since = "1.20.0")]
+ #[rustc_doc_only_macro]
+ macro_rules! compile_error {
+ ($msg:expr) => ({ /* compiler built-in */ });
+ ($msg:expr,) => ({ /* compiler built-in */ });
+ }
+
+ /// Constructs parameters for the other string-formatting macros.
+ ///
+ /// This macro functions by taking a formatting string literal containing
+ /// `{}` for each additional argument passed. `format_args!` prepares the
+ /// additional parameters to ensure the output can be interpreted as a string
+ /// and canonicalizes the arguments into a single type. Any value that implements
+ /// the [`Display`] trait can be passed to `format_args!`, as can any
+ /// [`Debug`] implementation be passed to a `{:?}` within the formatting string.
+ ///
+ /// This macro produces a value of type [`fmt::Arguments`]. This value can be
+ /// passed to the macros within [`std::fmt`] for performing useful redirection.
+ /// All other formatting macros ([`format!`], [`write!`], [`println!`], etc) are
+ /// proxied through this one. `format_args!`, unlike its derived macros, avoids
+ /// heap allocations.
+ ///
+ /// You can use the [`fmt::Arguments`] value that `format_args!` returns
+ /// in `Debug` and `Display` contexts as seen below. The example also shows
+ /// that `Debug` and `Display` format to the same thing: the interpolated
+ /// format string in `format_args!`.
+ ///
+ /// ```rust
+ /// let debug = format!("{:?}", format_args!("{} foo {:?}", 1, 2));
+ /// let display = format!("{}", format_args!("{} foo {:?}", 1, 2));
+ /// assert_eq!("1 foo 2", display);
+ /// assert_eq!(display, debug);
+ /// ```
+ ///
+ /// For more information, see the documentation in [`std::fmt`].
+ ///
+ /// [`Display`]: ../std/fmt/trait.Display.html
+ /// [`Debug`]: ../std/fmt/trait.Debug.html
+ /// [`fmt::Arguments`]: ../std/fmt/struct.Arguments.html
+ /// [`std::fmt`]: ../std/fmt/index.html
+ /// [`format!`]: ../std/macro.format.html
+ /// [`write!`]: ../std/macro.write.html
+ /// [`println!`]: ../std/macro.println.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::fmt;
+ ///
+ /// let s = fmt::format(format_args!("hello {}", "world"));
+ /// assert_eq!(s, format!("hello {}", "world"));
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_doc_only_macro]
+ macro_rules! format_args {
+ ($fmt:expr) => ({ /* compiler built-in */ });
+ ($fmt:expr, $($args:tt)*) => ({ /* compiler built-in */ });
+ }
+
+ /// Inspects an environment variable at compile time.
+ ///
+ /// This macro will expand to the value of the named environment variable at
+ /// compile time, yielding an expression of type `&'static str`.
+ ///
+ /// If the environment variable is not defined, then a compilation error
+ /// will be emitted. To not emit a compile error, use the [`option_env!`]
+ /// macro instead.
+ ///
+ /// [`option_env!`]: ../std/macro.option_env.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let path: &'static str = env!("PATH");
+ /// println!("the $PATH variable at the time of compiling was: {}", path);
+ /// ```
+ ///
+ /// You can customize the error message by passing a string as the second
+ /// parameter:
+ ///
+ /// ```compile_fail
+ /// let doc: &'static str = env!("documentation", "what's that?!");
+ /// ```
+ ///
+ /// If the `documentation` environment variable is not defined, you'll get
+ /// the following error:
+ ///
+ /// ```text
+ /// error: what's that?!
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_doc_only_macro]
+ macro_rules! env {
+ ($name:expr) => ({ /* compiler built-in */ });
+ ($name:expr,) => ({ /* compiler built-in */ });
+ }
+
+ /// Optionally inspects an environment variable at compile time.
+ ///
+ /// If the named environment variable is present at compile time, this will
+ /// expand into an expression of type `Option<&'static str>` whose value is
+ /// `Some` of the value of the environment variable. If the environment
+ /// variable is not present, then this will expand to `None`. See
+ /// [`Option<T>`][option] for more information on this type.
+ ///
+ /// A compile time error is never emitted when using this macro regardless
+ /// of whether the environment variable is present or not.
+ ///
+ /// [option]: ../std/option/enum.Option.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let key: Option<&'static str> = option_env!("SECRET_KEY");
+ /// println!("the secret key might be: {:?}", key);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_doc_only_macro]
+ macro_rules! option_env {
+ ($name:expr) => ({ /* compiler built-in */ });
+ ($name:expr,) => ({ /* compiler built-in */ });
+ }
+
+ /// Concatenates identifiers into one identifier.
+ ///
+ /// This macro takes any number of comma-separated identifiers, and
+ /// concatenates them all into one, yielding an expression which is a new
+ /// identifier. Note that hygiene makes it such that this macro cannot
+ /// capture local variables. Also, as a general rule, macros are only
+ /// allowed in item, statement or expression position. That means while
+ /// you may use this macro for referring to existing variables, functions or
+ /// modules etc, you cannot define a new one with it.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(concat_idents)]
+ ///
+ /// # fn main() {
+ /// fn foobar() -> u32 { 23 }
+ ///
+ /// let f = concat_idents!(foo, bar);
+ /// println!("{}", f());
+ ///
+ /// // fn concat_idents!(new, fun, name) { } // not usable in this way!
+ /// # }
+ /// ```
+ #[unstable(feature = "concat_idents_macro", issue = "29599")]
+ #[rustc_doc_only_macro]
+ macro_rules! concat_idents {
+ ($($e:ident),+) => ({ /* compiler built-in */ });
+ ($($e:ident,)+) => ({ /* compiler built-in */ });
+ }
+
+ /// Concatenates literals into a static string slice.
+ ///
+ /// This macro takes any number of comma-separated literals, yielding an
+ /// expression of type `&'static str` which represents all of the literals
+ /// concatenated left-to-right.
+ ///
+ /// Integer and floating point literals are stringified in order to be
+ /// concatenated.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let s = concat!("test", 10, 'b', true);
+ /// assert_eq!(s, "test10btrue");
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_doc_only_macro]
+ macro_rules! concat {
+ ($($e:expr),*) => ({ /* compiler built-in */ });
+ ($($e:expr,)*) => ({ /* compiler built-in */ });
+ }
+
+ /// Expands to the line number on which it was invoked.
+ ///
+ /// With [`column!`] and [`file!`], these macros provide debugging information for
+ /// developers about the location within the source.
+ ///
+ /// The expanded expression has type `u32` and is 1-based, so the first line
+ /// in each file evaluates to 1, the second to 2, etc. This is consistent
+ /// with error messages by common compilers or popular editors.
+ /// The returned line is *not necessarily* the line of the `line!` invocation itself,
+ /// but rather the first macro invocation leading up to the invocation
+ /// of the `line!` macro.
+ ///
+ /// [`column!`]: macro.column.html
+ /// [`file!`]: macro.file.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let current_line = line!();
+ /// println!("defined on line: {}", current_line);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_doc_only_macro]
+ macro_rules! line { () => ({ /* compiler built-in */ }) }
+
+ /// Expands to the column number at which it was invoked.
+ ///
+ /// With [`line!`] and [`file!`], these macros provide debugging information for
+ /// developers about the location within the source.
+ ///
+ /// The expanded expression has type `u32` and is 1-based, so the first column
+ /// in each line evaluates to 1, the second to 2, etc. This is consistent
+ /// with error messages by common compilers or popular editors.
+ /// The returned column is *not necessarily* the line of the `column!` invocation itself,
+ /// but rather the first macro invocation leading up to the invocation
+ /// of the `column!` macro.
+ ///
+ /// [`line!`]: macro.line.html
+ /// [`file!`]: macro.file.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let current_col = column!();
+ /// println!("defined on column: {}", current_col);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_doc_only_macro]
+ macro_rules! column { () => ({ /* compiler built-in */ }) }
+
+ /// Expands to the file name in which it was invoked.
+ ///
+ /// With [`line!`] and [`column!`], these macros provide debugging information for
+ /// developers about the location within the source.
+ ///
+ ///
+ /// The expanded expression has type `&'static str`, and the returned file
+ /// is not the invocation of the `file!` macro itself, but rather the
+ /// first macro invocation leading up to the invocation of the `file!`
+ /// macro.
+ ///
+ /// [`line!`]: macro.line.html
+ /// [`column!`]: macro.column.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let this_file = file!();
+ /// println!("defined in file: {}", this_file);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_doc_only_macro]
+ macro_rules! file { () => ({ /* compiler built-in */ }) }
+
+ /// Stringifies its arguments.
+ ///
+ /// This macro will yield an expression of type `&'static str` which is the
+ /// stringification of all the tokens passed to the macro. No restrictions
+ /// are placed on the syntax of the macro invocation itself.
+ ///
+ /// Note that the expanded results of the input tokens may change in the
+ /// future. You should be careful if you rely on the output.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let one_plus_one = stringify!(1 + 1);
+ /// assert_eq!(one_plus_one, "1 + 1");
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_doc_only_macro]
+ macro_rules! stringify { ($($t:tt)*) => ({ /* compiler built-in */ }) }
+
+ /// Includes a utf8-encoded file as a string.
+ ///
+ /// The file is located relative to the current file. (similarly to how
+ /// modules are found)
+ ///
+ /// This macro will yield an expression of type `&'static str` which is the
+ /// contents of the file.
+ ///
+ /// # Examples
+ ///
+ /// Assume there are two files in the same directory with the following
+ /// contents:
+ ///
+ /// File 'spanish.in':
+ ///
+ /// ```text
+ /// adiós
+ /// ```
+ ///
+ /// File 'main.rs':
+ ///
+ /// ```ignore (cannot-doctest-external-file-dependency)
+ /// fn main() {
+ /// let my_str = include_str!("spanish.in");
+ /// assert_eq!(my_str, "adiós\n");
+ /// print!("{}", my_str);
+ /// }
+ /// ```
+ ///
+ /// Compiling 'main.rs' and running the resulting binary will print "adiós".
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_doc_only_macro]
+ macro_rules! include_str {
+ ($file:expr) => ({ /* compiler built-in */ });
+ ($file:expr,) => ({ /* compiler built-in */ });
+ }
+
+ /// Includes a file as a reference to a byte array.
+ ///
+ /// The file is located relative to the current file. (similarly to how
+ /// modules are found)
+ ///
+ /// This macro will yield an expression of type `&'static [u8; N]` which is
+ /// the contents of the file.
+ ///
+ /// # Examples
+ ///
+ /// Assume there are two files in the same directory with the following
+ /// contents:
+ ///
+ /// File 'spanish.in':
+ ///
+ /// ```text
+ /// adiós
+ /// ```
+ ///
+ /// File 'main.rs':
+ ///
+ /// ```ignore (cannot-doctest-external-file-dependency)
+ /// fn main() {
+ /// let bytes = include_bytes!("spanish.in");
+ /// assert_eq!(bytes, b"adi\xc3\xb3s\n");
+ /// print!("{}", String::from_utf8_lossy(bytes));
+ /// }
+ /// ```
+ ///
+ /// Compiling 'main.rs' and running the resulting binary will print "adiós".
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_doc_only_macro]
+ macro_rules! include_bytes {
+ ($file:expr) => ({ /* compiler built-in */ });
+ ($file:expr,) => ({ /* compiler built-in */ });
+ }
+
+ /// Expands to a string that represents the current module path.
+ ///
+ /// The current module path can be thought of as the hierarchy of modules
+ /// leading back up to the crate root. The first component of the path
+ /// returned is the name of the crate currently being compiled.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// mod test {
+ /// pub fn foo() {
+ /// assert!(module_path!().ends_with("test"));
+ /// }
+ /// }
+ ///
+ /// test::foo();
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_doc_only_macro]
+ macro_rules! module_path { () => ({ /* compiler built-in */ }) }
+
+ /// Evaluates boolean combinations of configuration flags at compile-time.
+ ///
+ /// In addition to the `#[cfg]` attribute, this macro is provided to allow
+ /// boolean expression evaluation of configuration flags. This frequently
+ /// leads to less duplicated code.
+ ///
+ /// The syntax given to this macro is the same syntax as the [`cfg`]
+ /// attribute.
+ ///
+ /// [`cfg`]: ../reference/conditional-compilation.html#the-cfg-attribute
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let my_directory = if cfg!(windows) {
+ /// "windows-specific-directory"
+ /// } else {
+ /// "unix-directory"
+ /// };
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_doc_only_macro]
+ macro_rules! cfg { ($($cfg:tt)*) => ({ /* compiler built-in */ }) }
+
+ /// Parses a file as an expression or an item according to the context.
+ ///
+ /// The file is located relative to the current file (similarly to how
+ /// modules are found).
+ ///
+ /// Using this macro is often a bad idea, because if the file is
+ /// parsed as an expression, it is going to be placed in the
+ /// surrounding code unhygienically. This could result in variables
+ /// or functions being different from what the file expected if
+ /// there are variables or functions that have the same name in
+ /// the current file.
+ ///
+ /// # Examples
+ ///
+ /// Assume there are two files in the same directory with the following
+ /// contents:
+ ///
+ /// File 'monkeys.in':
+ ///
+ /// ```ignore (only-for-syntax-highlight)
+ /// ['🙈', '🙊', '🙉']
+ /// .iter()
+ /// .cycle()
+ /// .take(6)
+ /// .collect::<String>()
+ /// ```
+ ///
+ /// File 'main.rs':
+ ///
+ /// ```ignore (cannot-doctest-external-file-dependency)
+ /// fn main() {
+ /// let my_string = include!("monkeys.in");
+ /// assert_eq!("🙈🙊🙉🙈🙊🙉", my_string);
+ /// println!("{}", my_string);
+ /// }
+ /// ```
+ ///
+ /// Compiling 'main.rs' and running the resulting binary will print
+ /// "🙈🙊🙉🙈🙊🙉".
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_doc_only_macro]
+ macro_rules! include {
+ ($file:expr) => ({ /* compiler built-in */ });
+ ($file:expr,) => ({ /* compiler built-in */ });
+ }
+
+ /// Asserts that a boolean expression is `true` at runtime.
+ ///
+ /// This will invoke the [`panic!`] macro if the provided expression cannot be
+ /// evaluated to `true` at runtime.
+ ///
+ /// # Uses
+ ///
+ /// Assertions are always checked in both debug and release builds, and cannot
+ /// be disabled. See [`debug_assert!`] for assertions that are not enabled in
+ /// release builds by default.
+ ///
+ /// Unsafe code relies on `assert!` to enforce run-time invariants that, if
+ /// violated could lead to unsafety.
+ ///
+ /// Other use-cases of `assert!` include testing and enforcing run-time
+ /// invariants in safe code (whose violation cannot result in unsafety).
+ ///
+ /// # Custom Messages
+ ///
+ /// This macro has a second form, where a custom panic message can
+ /// be provided with or without arguments for formatting. See [`std::fmt`]
+ /// for syntax for this form.
+ ///
+ /// [`panic!`]: macro.panic.html
+ /// [`debug_assert!`]: macro.debug_assert.html
+ /// [`std::fmt`]: ../std/fmt/index.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// // the panic message for these assertions is the stringified value of the
+ /// // expression given.
+ /// assert!(true);
+ ///
+ /// fn some_computation() -> bool { true } // a very simple function
+ ///
+ /// assert!(some_computation());
+ ///
+ /// // assert with a custom message
+ /// let x = true;
+ /// assert!(x, "x wasn't true!");
+ ///
+ /// let a = 3; let b = 27;
+ /// assert!(a + b == 30, "a = {}, b = {}", a, b);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_doc_only_macro]
+ macro_rules! assert {
+ ($cond:expr) => ({ /* compiler built-in */ });
+ ($cond:expr,) => ({ /* compiler built-in */ });
+ ($cond:expr, $($arg:tt)+) => ({ /* compiler built-in */ });
+ }
+}
+
+/// Defines `#[cfg]` if-else statements.
+///
+/// This is similar to the `if/elif` C preprocessor macro by allowing definition
+/// of a cascade of `#[cfg]` cases, emitting the implementation which matches
+/// first.
+///
+/// This allows you to conveniently provide a long list `#[cfg]`'d blocks of code
+/// without having to rewrite each clause multiple times.
+macro_rules! cfg_if {
+ ($(
+ if #[cfg($($meta:meta),*)] { $($it:item)* }
+ ) else * else {
+ $($it2:item)*
+ }) => {
+ __cfg_if_items! {
+ () ;
+ $( ( ($($meta),*) ($($it)*) ), )*
+ ( () ($($it2)*) ),
+ }
+ }
+}
+
+macro_rules! __cfg_if_items {
+ (($($not:meta,)*) ; ) => {};
+ (($($not:meta,)*) ; ( ($($m:meta),*) ($($it:item)*) ), $($rest:tt)*) => {
+ __cfg_if_apply! { cfg(all(not(any($($not),*)), $($m,)*)), $($it)* }
+ __cfg_if_items! { ($($not,)* $($m,)*) ; $($rest)* }
+ }
+}
+
+macro_rules! __cfg_if_apply {
+ ($m:meta, $($it:item)*) => {
+ $(#[$m] $it)*
+ }
+}
diff --git a/src/libstd/memchr.rs b/src/libstd/memchr.rs
new file mode 100644
index 0000000..d69294b
--- /dev/null
+++ b/src/libstd/memchr.rs
@@ -0,0 +1,133 @@
+// Original implementation taken from rust-memchr.
+// Copyright 2015 Andrew Gallant, bluss and Nicolas Koch
+
+/// A safe interface to `memchr`.
+///
+/// Returns the index corresponding to the first occurrence of `needle` in
+/// `haystack`, or `None` if one is not found.
+///
+/// memchr reduces to super-optimized machine code at around an order of
+/// magnitude faster than `haystack.iter().position(|&b| b == needle)`.
+/// (See benchmarks.)
+///
+/// # Examples
+///
+/// This shows how to find the first position of a byte in a byte string.
+///
+/// ```ignore (cannot-doctest-private-modules)
+/// use memchr::memchr;
+///
+/// let haystack = b"the quick brown fox";
+/// assert_eq!(memchr(b'k', haystack), Some(8));
+/// ```
+#[inline]
+pub fn memchr(needle: u8, haystack: &[u8]) -> Option<usize> {
+ crate::sys::memchr::memchr(needle, haystack)
+}
+
+/// A safe interface to `memrchr`.
+///
+/// Returns the index corresponding to the last occurrence of `needle` in
+/// `haystack`, or `None` if one is not found.
+///
+/// # Examples
+///
+/// This shows how to find the last position of a byte in a byte string.
+///
+/// ```ignore (cannot-doctest-private-modules)
+/// use memchr::memrchr;
+///
+/// let haystack = b"the quick brown fox";
+/// assert_eq!(memrchr(b'o', haystack), Some(17));
+/// ```
+#[inline]
+pub fn memrchr(needle: u8, haystack: &[u8]) -> Option<usize> {
+ crate::sys::memchr::memrchr(needle, haystack)
+}
+
+#[cfg(test)]
+mod tests {
+ // test the implementations for the current platform
+ use super::{memchr, memrchr};
+
+ #[test]
+ fn matches_one() {
+ assert_eq!(Some(0), memchr(b'a', b"a"));
+ }
+
+ #[test]
+ fn matches_begin() {
+ assert_eq!(Some(0), memchr(b'a', b"aaaa"));
+ }
+
+ #[test]
+ fn matches_end() {
+ assert_eq!(Some(4), memchr(b'z', b"aaaaz"));
+ }
+
+ #[test]
+ fn matches_nul() {
+ assert_eq!(Some(4), memchr(b'\x00', b"aaaa\x00"));
+ }
+
+ #[test]
+ fn matches_past_nul() {
+ assert_eq!(Some(5), memchr(b'z', b"aaaa\x00z"));
+ }
+
+ #[test]
+ fn no_match_empty() {
+ assert_eq!(None, memchr(b'a', b""));
+ }
+
+ #[test]
+ fn no_match() {
+ assert_eq!(None, memchr(b'a', b"xyz"));
+ }
+
+ #[test]
+ fn matches_one_reversed() {
+ assert_eq!(Some(0), memrchr(b'a', b"a"));
+ }
+
+ #[test]
+ fn matches_begin_reversed() {
+ assert_eq!(Some(3), memrchr(b'a', b"aaaa"));
+ }
+
+ #[test]
+ fn matches_end_reversed() {
+ assert_eq!(Some(0), memrchr(b'z', b"zaaaa"));
+ }
+
+ #[test]
+ fn matches_nul_reversed() {
+ assert_eq!(Some(4), memrchr(b'\x00', b"aaaa\x00"));
+ }
+
+ #[test]
+ fn matches_past_nul_reversed() {
+ assert_eq!(Some(0), memrchr(b'z', b"z\x00aaaa"));
+ }
+
+ #[test]
+ fn no_match_empty_reversed() {
+ assert_eq!(None, memrchr(b'a', b""));
+ }
+
+ #[test]
+ fn no_match_reversed() {
+ assert_eq!(None, memrchr(b'a', b"xyz"));
+ }
+
+ #[test]
+ fn each_alignment() {
+ let mut data = [1u8; 64];
+ let needle = 2;
+ let pos = 40;
+ data[pos] = needle;
+ for start in 0..16 {
+ assert_eq!(Some(pos - start), memchr(needle, &data[start..]));
+ }
+ }
+}
diff --git a/src/libstd/net/addr.rs b/src/libstd/net/addr.rs
new file mode 100644
index 0000000..ec54d8a
--- /dev/null
+++ b/src/libstd/net/addr.rs
@@ -0,0 +1,1067 @@
+use crate::fmt;
+use crate::hash;
+use crate::io;
+use crate::mem;
+use crate::net::{ntoh, hton, IpAddr, Ipv4Addr, Ipv6Addr};
+use crate::option;
+use crate::sys::net::netc as c;
+use crate::sys_common::{FromInner, AsInner, IntoInner};
+use crate::sys_common::net::LookupHost;
+use crate::vec;
+use crate::iter;
+use crate::slice;
+use crate::convert::TryInto;
+
+/// An internet socket address, either IPv4 or IPv6.
+///
+/// Internet socket addresses consist of an [IP address], a 16-bit port number, as well
+/// as possibly some version-dependent additional information. See [`SocketAddrV4`]'s and
+/// [`SocketAddrV6`]'s respective documentation for more details.
+///
+/// The size of a `SocketAddr` instance may vary depending on the target operating
+/// system.
+///
+/// [IP address]: ../../std/net/enum.IpAddr.html
+/// [`SocketAddrV4`]: ../../std/net/struct.SocketAddrV4.html
+/// [`SocketAddrV6`]: ../../std/net/struct.SocketAddrV6.html
+///
+/// # Examples
+///
+/// ```
+/// use std::net::{IpAddr, Ipv4Addr, SocketAddr};
+///
+/// let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080);
+///
+/// assert_eq!("127.0.0.1:8080".parse(), Ok(socket));
+/// assert_eq!(socket.port(), 8080);
+/// assert_eq!(socket.is_ipv4(), true);
+/// ```
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub enum SocketAddr {
+ /// An IPv4 socket address.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ V4(#[stable(feature = "rust1", since = "1.0.0")] SocketAddrV4),
+ /// An IPv6 socket address.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ V6(#[stable(feature = "rust1", since = "1.0.0")] SocketAddrV6),
+}
+
+/// An IPv4 socket address.
+///
+/// IPv4 socket addresses consist of an [IPv4 address] and a 16-bit port number, as
+/// stated in [IETF RFC 793].
+///
+/// See [`SocketAddr`] for a type encompassing both IPv4 and IPv6 socket addresses.
+///
+/// The size of a `SocketAddrV4` struct may vary depending on the target operating
+/// system.
+///
+/// [IETF RFC 793]: https://tools.ietf.org/html/rfc793
+/// [IPv4 address]: ../../std/net/struct.Ipv4Addr.html
+/// [`SocketAddr`]: ../../std/net/enum.SocketAddr.html
+///
+/// # Examples
+///
+/// ```
+/// use std::net::{Ipv4Addr, SocketAddrV4};
+///
+/// let socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080);
+///
+/// assert_eq!("127.0.0.1:8080".parse(), Ok(socket));
+/// assert_eq!(socket.ip(), &Ipv4Addr::new(127, 0, 0, 1));
+/// assert_eq!(socket.port(), 8080);
+/// ```
+#[derive(Copy)]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct SocketAddrV4 { inner: c::sockaddr_in }
+
+/// An IPv6 socket address.
+///
+/// IPv6 socket addresses consist of an [Ipv6 address], a 16-bit port number, as well
+/// as fields containing the traffic class, the flow label, and a scope identifier
+/// (see [IETF RFC 2553, Section 3.3] for more details).
+///
+/// See [`SocketAddr`] for a type encompassing both IPv4 and IPv6 socket addresses.
+///
+/// The size of a `SocketAddrV6` struct may vary depending on the target operating
+/// system.
+///
+/// [IETF RFC 2553, Section 3.3]: https://tools.ietf.org/html/rfc2553#section-3.3
+/// [IPv6 address]: ../../std/net/struct.Ipv6Addr.html
+/// [`SocketAddr`]: ../../std/net/enum.SocketAddr.html
+///
+/// # Examples
+///
+/// ```
+/// use std::net::{Ipv6Addr, SocketAddrV6};
+///
+/// let socket = SocketAddrV6::new(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1), 8080, 0, 0);
+///
+/// assert_eq!("[2001:db8::1]:8080".parse(), Ok(socket));
+/// assert_eq!(socket.ip(), &Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1));
+/// assert_eq!(socket.port(), 8080);
+/// ```
+#[derive(Copy)]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct SocketAddrV6 { inner: c::sockaddr_in6 }
+
+impl SocketAddr {
+ /// Creates a new socket address from an [IP address] and a port number.
+ ///
+ /// [IP address]: ../../std/net/enum.IpAddr.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::{IpAddr, Ipv4Addr, SocketAddr};
+ ///
+ /// let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080);
+ /// assert_eq!(socket.ip(), IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)));
+ /// assert_eq!(socket.port(), 8080);
+ /// ```
+ #[stable(feature = "ip_addr", since = "1.7.0")]
+ pub fn new(ip: IpAddr, port: u16) -> SocketAddr {
+ match ip {
+ IpAddr::V4(a) => SocketAddr::V4(SocketAddrV4::new(a, port)),
+ IpAddr::V6(a) => SocketAddr::V6(SocketAddrV6::new(a, port, 0, 0)),
+ }
+ }
+
+ /// Returns the IP address associated with this socket address.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::{IpAddr, Ipv4Addr, SocketAddr};
+ ///
+ /// let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080);
+ /// assert_eq!(socket.ip(), IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)));
+ /// ```
+ #[stable(feature = "ip_addr", since = "1.7.0")]
+ pub fn ip(&self) -> IpAddr {
+ match *self {
+ SocketAddr::V4(ref a) => IpAddr::V4(*a.ip()),
+ SocketAddr::V6(ref a) => IpAddr::V6(*a.ip()),
+ }
+ }
+
+ /// Changes the IP address associated with this socket address.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::{IpAddr, Ipv4Addr, SocketAddr};
+ ///
+ /// let mut socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080);
+ /// socket.set_ip(IpAddr::V4(Ipv4Addr::new(10, 10, 0, 1)));
+ /// assert_eq!(socket.ip(), IpAddr::V4(Ipv4Addr::new(10, 10, 0, 1)));
+ /// ```
+ #[stable(feature = "sockaddr_setters", since = "1.9.0")]
+ pub fn set_ip(&mut self, new_ip: IpAddr) {
+ // `match (*self, new_ip)` would have us mutate a copy of self only to throw it away.
+ match (self, new_ip) {
+ (&mut SocketAddr::V4(ref mut a), IpAddr::V4(new_ip)) => a.set_ip(new_ip),
+ (&mut SocketAddr::V6(ref mut a), IpAddr::V6(new_ip)) => a.set_ip(new_ip),
+ (self_, new_ip) => *self_ = Self::new(new_ip, self_.port()),
+ }
+ }
+
+ /// Returns the port number associated with this socket address.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::{IpAddr, Ipv4Addr, SocketAddr};
+ ///
+ /// let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080);
+ /// assert_eq!(socket.port(), 8080);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn port(&self) -> u16 {
+ match *self {
+ SocketAddr::V4(ref a) => a.port(),
+ SocketAddr::V6(ref a) => a.port(),
+ }
+ }
+
+ /// Changes the port number associated with this socket address.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::{IpAddr, Ipv4Addr, SocketAddr};
+ ///
+ /// let mut socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080);
+ /// socket.set_port(1025);
+ /// assert_eq!(socket.port(), 1025);
+ /// ```
+ #[stable(feature = "sockaddr_setters", since = "1.9.0")]
+ pub fn set_port(&mut self, new_port: u16) {
+ match *self {
+ SocketAddr::V4(ref mut a) => a.set_port(new_port),
+ SocketAddr::V6(ref mut a) => a.set_port(new_port),
+ }
+ }
+
+ /// Returns [`true`] if the [IP address] in this `SocketAddr` is an
+ /// [IPv4 address], and [`false`] otherwise.
+ ///
+ /// [`true`]: ../../std/primitive.bool.html
+ /// [`false`]: ../../std/primitive.bool.html
+ /// [IP address]: ../../std/net/enum.IpAddr.html
+ /// [IPv4 address]: ../../std/net/enum.IpAddr.html#variant.V4
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::{IpAddr, Ipv4Addr, SocketAddr};
+ ///
+ /// fn main() {
+ /// let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080);
+ /// assert_eq!(socket.is_ipv4(), true);
+ /// assert_eq!(socket.is_ipv6(), false);
+ /// }
+ /// ```
+ #[stable(feature = "sockaddr_checker", since = "1.16.0")]
+ pub fn is_ipv4(&self) -> bool {
+ match *self {
+ SocketAddr::V4(_) => true,
+ SocketAddr::V6(_) => false,
+ }
+ }
+
+ /// Returns [`true`] if the [IP address] in this `SocketAddr` is an
+ /// [IPv6 address], and [`false`] otherwise.
+ ///
+ /// [`true`]: ../../std/primitive.bool.html
+ /// [`false`]: ../../std/primitive.bool.html
+ /// [IP address]: ../../std/net/enum.IpAddr.html
+ /// [IPv6 address]: ../../std/net/enum.IpAddr.html#variant.V6
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::{IpAddr, Ipv6Addr, SocketAddr};
+ ///
+ /// fn main() {
+ /// let socket = SocketAddr::new(
+ /// IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 65535, 0, 1)), 8080);
+ /// assert_eq!(socket.is_ipv4(), false);
+ /// assert_eq!(socket.is_ipv6(), true);
+ /// }
+ /// ```
+ #[stable(feature = "sockaddr_checker", since = "1.16.0")]
+ pub fn is_ipv6(&self) -> bool {
+ match *self {
+ SocketAddr::V4(_) => false,
+ SocketAddr::V6(_) => true,
+ }
+ }
+}
+
+impl SocketAddrV4 {
+ /// Creates a new socket address from an [IPv4 address] and a port number.
+ ///
+ /// [IPv4 address]: ../../std/net/struct.Ipv4Addr.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::{SocketAddrV4, Ipv4Addr};
+ ///
+ /// let socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn new(ip: Ipv4Addr, port: u16) -> SocketAddrV4 {
+ SocketAddrV4 {
+ inner: c::sockaddr_in {
+ sin_family: c::AF_INET as c::sa_family_t,
+ sin_port: hton(port),
+ sin_addr: *ip.as_inner(),
+ .. unsafe { mem::zeroed() }
+ },
+ }
+ }
+
+ /// Returns the IP address associated with this socket address.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::{SocketAddrV4, Ipv4Addr};
+ ///
+ /// let socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080);
+ /// assert_eq!(socket.ip(), &Ipv4Addr::new(127, 0, 0, 1));
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn ip(&self) -> &Ipv4Addr {
+ unsafe {
+ &*(&self.inner.sin_addr as *const c::in_addr as *const Ipv4Addr)
+ }
+ }
+
+ /// Changes the IP address associated with this socket address.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::{SocketAddrV4, Ipv4Addr};
+ ///
+ /// let mut socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080);
+ /// socket.set_ip(Ipv4Addr::new(192, 168, 0, 1));
+ /// assert_eq!(socket.ip(), &Ipv4Addr::new(192, 168, 0, 1));
+ /// ```
+ #[stable(feature = "sockaddr_setters", since = "1.9.0")]
+ pub fn set_ip(&mut self, new_ip: Ipv4Addr) {
+ self.inner.sin_addr = *new_ip.as_inner()
+ }
+
+ /// Returns the port number associated with this socket address.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::{SocketAddrV4, Ipv4Addr};
+ ///
+ /// let socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080);
+ /// assert_eq!(socket.port(), 8080);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn port(&self) -> u16 {
+ ntoh(self.inner.sin_port)
+ }
+
+ /// Changes the port number associated with this socket address.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::{SocketAddrV4, Ipv4Addr};
+ ///
+ /// let mut socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080);
+ /// socket.set_port(4242);
+ /// assert_eq!(socket.port(), 4242);
+ /// ```
+ #[stable(feature = "sockaddr_setters", since = "1.9.0")]
+ pub fn set_port(&mut self, new_port: u16) {
+ self.inner.sin_port = hton(new_port);
+ }
+}
+
+impl SocketAddrV6 {
+ /// Creates a new socket address from an [IPv6 address], a 16-bit port number,
+ /// and the `flowinfo` and `scope_id` fields.
+ ///
+ /// For more information on the meaning and layout of the `flowinfo` and `scope_id`
+ /// parameters, see [IETF RFC 2553, Section 3.3].
+ ///
+ /// [IETF RFC 2553, Section 3.3]: https://tools.ietf.org/html/rfc2553#section-3.3
+ /// [IPv6 address]: ../../std/net/struct.Ipv6Addr.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::{SocketAddrV6, Ipv6Addr};
+ ///
+ /// let socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 0);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn new(ip: Ipv6Addr, port: u16, flowinfo: u32, scope_id: u32)
+ -> SocketAddrV6 {
+ SocketAddrV6 {
+ inner: c::sockaddr_in6 {
+ sin6_family: c::AF_INET6 as c::sa_family_t,
+ sin6_port: hton(port),
+ sin6_addr: *ip.as_inner(),
+ sin6_flowinfo: flowinfo,
+ sin6_scope_id: scope_id,
+ .. unsafe { mem::zeroed() }
+ },
+ }
+ }
+
+ /// Returns the IP address associated with this socket address.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::{SocketAddrV6, Ipv6Addr};
+ ///
+ /// let socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 0);
+ /// assert_eq!(socket.ip(), &Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1));
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn ip(&self) -> &Ipv6Addr {
+ unsafe {
+ &*(&self.inner.sin6_addr as *const c::in6_addr as *const Ipv6Addr)
+ }
+ }
+
+ /// Changes the IP address associated with this socket address.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::{SocketAddrV6, Ipv6Addr};
+ ///
+ /// let mut socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 0);
+ /// socket.set_ip(Ipv6Addr::new(76, 45, 0, 0, 0, 0, 0, 0));
+ /// assert_eq!(socket.ip(), &Ipv6Addr::new(76, 45, 0, 0, 0, 0, 0, 0));
+ /// ```
+ #[stable(feature = "sockaddr_setters", since = "1.9.0")]
+ pub fn set_ip(&mut self, new_ip: Ipv6Addr) {
+ self.inner.sin6_addr = *new_ip.as_inner()
+ }
+
+ /// Returns the port number associated with this socket address.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::{SocketAddrV6, Ipv6Addr};
+ ///
+ /// let socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 0);
+ /// assert_eq!(socket.port(), 8080);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn port(&self) -> u16 {
+ ntoh(self.inner.sin6_port)
+ }
+
+ /// Changes the port number associated with this socket address.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::{SocketAddrV6, Ipv6Addr};
+ ///
+ /// let mut socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 0);
+ /// socket.set_port(4242);
+ /// assert_eq!(socket.port(), 4242);
+ /// ```
+ #[stable(feature = "sockaddr_setters", since = "1.9.0")]
+ pub fn set_port(&mut self, new_port: u16) {
+ self.inner.sin6_port = hton(new_port);
+ }
+
+ /// Returns the flow information associated with this address.
+ ///
+ /// This information corresponds to the `sin6_flowinfo` field in C's `netinet/in.h`,
+ /// as specified in [IETF RFC 2553, Section 3.3].
+ /// It combines information about the flow label and the traffic class as specified
+ /// in [IETF RFC 2460], respectively [Section 6] and [Section 7].
+ ///
+ /// [IETF RFC 2553, Section 3.3]: https://tools.ietf.org/html/rfc2553#section-3.3
+ /// [IETF RFC 2460]: https://tools.ietf.org/html/rfc2460
+ /// [Section 6]: https://tools.ietf.org/html/rfc2460#section-6
+ /// [Section 7]: https://tools.ietf.org/html/rfc2460#section-7
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::{SocketAddrV6, Ipv6Addr};
+ ///
+ /// let socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 10, 0);
+ /// assert_eq!(socket.flowinfo(), 10);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn flowinfo(&self) -> u32 {
+ self.inner.sin6_flowinfo
+ }
+
+ /// Changes the flow information associated with this socket address.
+ ///
+ /// See the [`flowinfo`] method's documentation for more details.
+ ///
+ /// [`flowinfo`]: #method.flowinfo
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::{SocketAddrV6, Ipv6Addr};
+ ///
+ /// let mut socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 10, 0);
+ /// socket.set_flowinfo(56);
+ /// assert_eq!(socket.flowinfo(), 56);
+ /// ```
+ #[stable(feature = "sockaddr_setters", since = "1.9.0")]
+ pub fn set_flowinfo(&mut self, new_flowinfo: u32) {
+ self.inner.sin6_flowinfo = new_flowinfo;
+ }
+
+ /// Returns the scope ID associated with this address.
+ ///
+ /// This information corresponds to the `sin6_scope_id` field in C's `netinet/in.h`,
+ /// as specified in [IETF RFC 2553, Section 3.3].
+ ///
+ /// [IETF RFC 2553, Section 3.3]: https://tools.ietf.org/html/rfc2553#section-3.3
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::{SocketAddrV6, Ipv6Addr};
+ ///
+ /// let socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 78);
+ /// assert_eq!(socket.scope_id(), 78);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn scope_id(&self) -> u32 {
+ self.inner.sin6_scope_id
+ }
+
+ /// Changes the scope ID associated with this socket address.
+ ///
+ /// See the [`scope_id`] method's documentation for more details.
+ ///
+ /// [`scope_id`]: #method.scope_id
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::{SocketAddrV6, Ipv6Addr};
+ ///
+ /// let mut socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 78);
+ /// socket.set_scope_id(42);
+ /// assert_eq!(socket.scope_id(), 42);
+ /// ```
+ #[stable(feature = "sockaddr_setters", since = "1.9.0")]
+ pub fn set_scope_id(&mut self, new_scope_id: u32) {
+ self.inner.sin6_scope_id = new_scope_id;
+ }
+}
+
+impl FromInner<c::sockaddr_in> for SocketAddrV4 {
+ fn from_inner(addr: c::sockaddr_in) -> SocketAddrV4 {
+ SocketAddrV4 { inner: addr }
+ }
+}
+
+impl FromInner<c::sockaddr_in6> for SocketAddrV6 {
+ fn from_inner(addr: c::sockaddr_in6) -> SocketAddrV6 {
+ SocketAddrV6 { inner: addr }
+ }
+}
+
+#[stable(feature = "ip_from_ip", since = "1.16.0")]
+impl From<SocketAddrV4> for SocketAddr {
+ /// Converts a [`SocketAddrV4`] into a [`SocketAddr::V4`].
+ fn from(sock4: SocketAddrV4) -> SocketAddr {
+ SocketAddr::V4(sock4)
+ }
+}
+
+#[stable(feature = "ip_from_ip", since = "1.16.0")]
+impl From<SocketAddrV6> for SocketAddr {
+ /// Converts a [`SocketAddrV6`] into a [`SocketAddr::V6`].
+ fn from(sock6: SocketAddrV6) -> SocketAddr {
+ SocketAddr::V6(sock6)
+ }
+}
+
+#[stable(feature = "addr_from_into_ip", since = "1.17.0")]
+impl<I: Into<IpAddr>> From<(I, u16)> for SocketAddr {
+ /// Converts a tuple struct (Into<[`IpAddr`]>, `u16`) into a [`SocketAddr`].
+ ///
+ /// This conversion creates a [`SocketAddr::V4`] for a [`IpAddr::V4`]
+ /// and creates a [`SocketAddr::V6`] for a [`IpAddr::V6`].
+ ///
+ /// `u16` is treated as port of the newly created [`SocketAddr`].
+ fn from(pieces: (I, u16)) -> SocketAddr {
+ SocketAddr::new(pieces.0.into(), pieces.1)
+ }
+}
+
+impl<'a> IntoInner<(*const c::sockaddr, c::socklen_t)> for &'a SocketAddr {
+ fn into_inner(self) -> (*const c::sockaddr, c::socklen_t) {
+ match *self {
+ SocketAddr::V4(ref a) => {
+ (a as *const _ as *const _, mem::size_of_val(a) as c::socklen_t)
+ }
+ SocketAddr::V6(ref a) => {
+ (a as *const _ as *const _, mem::size_of_val(a) as c::socklen_t)
+ }
+ }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl fmt::Display for SocketAddr {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match *self {
+ SocketAddr::V4(ref a) => a.fmt(f),
+ SocketAddr::V6(ref a) => a.fmt(f),
+ }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl fmt::Display for SocketAddrV4 {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "{}:{}", self.ip(), self.port())
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl fmt::Debug for SocketAddrV4 {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt::Display::fmt(self, fmt)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl fmt::Display for SocketAddrV6 {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "[{}]:{}", self.ip(), self.port())
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl fmt::Debug for SocketAddrV6 {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt::Display::fmt(self, fmt)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Clone for SocketAddrV4 {
+ fn clone(&self) -> SocketAddrV4 { *self }
+}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Clone for SocketAddrV6 {
+ fn clone(&self) -> SocketAddrV6 { *self }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl PartialEq for SocketAddrV4 {
+ fn eq(&self, other: &SocketAddrV4) -> bool {
+ self.inner.sin_port == other.inner.sin_port &&
+ self.inner.sin_addr.s_addr == other.inner.sin_addr.s_addr
+ }
+}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl PartialEq for SocketAddrV6 {
+ fn eq(&self, other: &SocketAddrV6) -> bool {
+ self.inner.sin6_port == other.inner.sin6_port &&
+ self.inner.sin6_addr.s6_addr == other.inner.sin6_addr.s6_addr &&
+ self.inner.sin6_flowinfo == other.inner.sin6_flowinfo &&
+ self.inner.sin6_scope_id == other.inner.sin6_scope_id
+ }
+}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Eq for SocketAddrV4 {}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Eq for SocketAddrV6 {}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl hash::Hash for SocketAddrV4 {
+ fn hash<H: hash::Hasher>(&self, s: &mut H) {
+ (self.inner.sin_port, self.inner.sin_addr.s_addr).hash(s)
+ }
+}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl hash::Hash for SocketAddrV6 {
+ fn hash<H: hash::Hasher>(&self, s: &mut H) {
+ (self.inner.sin6_port, &self.inner.sin6_addr.s6_addr,
+ self.inner.sin6_flowinfo, self.inner.sin6_scope_id).hash(s)
+ }
+}
+
+/// A trait for objects which can be converted or resolved to one or more
+/// [`SocketAddr`] values.
+///
+/// This trait is used for generic address resolution when constructing network
+/// objects. By default it is implemented for the following types:
+///
+/// * [`SocketAddr`]: [`to_socket_addrs`] is the identity function.
+///
+/// * [`SocketAddrV4`], [`SocketAddrV6`], `(`[`IpAddr`]`, `[`u16`]`)`,
+/// `(`[`Ipv4Addr`]`, `[`u16`]`)`, `(`[`Ipv6Addr`]`, `[`u16`]`)`:
+/// [`to_socket_addrs`] constructs a [`SocketAddr`] trivially.
+///
+/// * `(`[`&str`]`, `[`u16`]`)`: the string should be either a string representation
+/// of an [`IpAddr`] address as expected by [`FromStr`] implementation or a host
+/// name.
+///
+/// * [`&str`]: the string should be either a string representation of a
+/// [`SocketAddr`] as expected by its [`FromStr`] implementation or a string like
+/// `<host_name>:<port>` pair where `<port>` is a [`u16`] value.
+///
+/// This trait allows constructing network objects like [`TcpStream`] or
+/// [`UdpSocket`] easily with values of various types for the bind/connection
+/// address. It is needed because sometimes one type is more appropriate than
+/// the other: for simple uses a string like `"localhost:12345"` is much nicer
+/// than manual construction of the corresponding [`SocketAddr`], but sometimes
+/// [`SocketAddr`] value is *the* main source of the address, and converting it to
+/// some other type (e.g., a string) just for it to be converted back to
+/// [`SocketAddr`] in constructor methods is pointless.
+///
+/// Addresses returned by the operating system that are not IP addresses are
+/// silently ignored.
+///
+/// [`FromStr`]: ../../std/str/trait.FromStr.html
+/// [`IpAddr`]: ../../std/net/enum.IpAddr.html
+/// [`Ipv4Addr`]: ../../std/net/struct.Ipv4Addr.html
+/// [`Ipv6Addr`]: ../../std/net/struct.Ipv6Addr.html
+/// [`SocketAddr`]: ../../std/net/enum.SocketAddr.html
+/// [`SocketAddrV4`]: ../../std/net/struct.SocketAddrV4.html
+/// [`SocketAddrV6`]: ../../std/net/struct.SocketAddrV6.html
+/// [`&str`]: ../../std/primitive.str.html
+/// [`TcpStream`]: ../../std/net/struct.TcpStream.html
+/// [`to_socket_addrs`]: #tymethod.to_socket_addrs
+/// [`UdpSocket`]: ../../std/net/struct.UdpSocket.html
+/// [`u16`]: ../../std/primitive.u16.html
+///
+/// # Examples
+///
+/// Creating a [`SocketAddr`] iterator that yields one item:
+///
+/// ```
+/// use std::net::{ToSocketAddrs, SocketAddr};
+///
+/// let addr = SocketAddr::from(([127, 0, 0, 1], 443));
+/// let mut addrs_iter = addr.to_socket_addrs().unwrap();
+///
+/// assert_eq!(Some(addr), addrs_iter.next());
+/// assert!(addrs_iter.next().is_none());
+/// ```
+///
+/// Creating a [`SocketAddr`] iterator from a hostname:
+///
+/// ```no_run
+/// use std::net::{SocketAddr, ToSocketAddrs};
+///
+/// // assuming 'localhost' resolves to 127.0.0.1
+/// let mut addrs_iter = "localhost:443".to_socket_addrs().unwrap();
+/// assert_eq!(addrs_iter.next(), Some(SocketAddr::from(([127, 0, 0, 1], 443))));
+/// assert!(addrs_iter.next().is_none());
+///
+/// // assuming 'foo' does not resolve
+/// assert!("foo:443".to_socket_addrs().is_err());
+/// ```
+///
+/// Creating a [`SocketAddr`] iterator that yields multiple items:
+///
+/// ```
+/// use std::net::{SocketAddr, ToSocketAddrs};
+///
+/// let addr1 = SocketAddr::from(([0, 0, 0, 0], 80));
+/// let addr2 = SocketAddr::from(([127, 0, 0, 1], 443));
+/// let addrs = vec![addr1, addr2];
+///
+/// let mut addrs_iter = (&addrs[..]).to_socket_addrs().unwrap();
+///
+/// assert_eq!(Some(addr1), addrs_iter.next());
+/// assert_eq!(Some(addr2), addrs_iter.next());
+/// assert!(addrs_iter.next().is_none());
+/// ```
+///
+/// Attempting to create a [`SocketAddr`] iterator from an improperly formatted
+/// socket address `&str` (missing the port):
+///
+/// ```
+/// use std::io;
+/// use std::net::ToSocketAddrs;
+///
+/// let err = "127.0.0.1".to_socket_addrs().unwrap_err();
+/// assert_eq!(err.kind(), io::ErrorKind::InvalidInput);
+/// ```
+///
+/// [`TcpStream::connect`] is an example of an function that utilizes
+/// `ToSocketAddrs` as a trait bound on its parameter in order to accept
+/// different types:
+///
+/// ```no_run
+/// use std::net::{TcpStream, Ipv4Addr};
+///
+/// let stream = TcpStream::connect(("127.0.0.1", 443));
+/// // or
+/// let stream = TcpStream::connect("127.0.0.1:443");
+/// // or
+/// let stream = TcpStream::connect((Ipv4Addr::new(127, 0, 0, 1), 443));
+/// ```
+///
+/// [`TcpStream::connect`]: ../../std/net/struct.TcpStream.html#method.connect
+#[stable(feature = "rust1", since = "1.0.0")]
+pub trait ToSocketAddrs {
+ /// Returned iterator over socket addresses which this type may correspond
+ /// to.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ type Iter: Iterator<Item=SocketAddr>;
+
+ /// Converts this object to an iterator of resolved `SocketAddr`s.
+ ///
+ /// The returned iterator may not actually yield any values depending on the
+ /// outcome of any resolution performed.
+ ///
+ /// Note that this function may block the current thread while resolution is
+ /// performed.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ fn to_socket_addrs(&self) -> io::Result<Self::Iter>;
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl ToSocketAddrs for SocketAddr {
+ type Iter = option::IntoIter<SocketAddr>;
+ fn to_socket_addrs(&self) -> io::Result<option::IntoIter<SocketAddr>> {
+ Ok(Some(*self).into_iter())
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl ToSocketAddrs for SocketAddrV4 {
+ type Iter = option::IntoIter<SocketAddr>;
+ fn to_socket_addrs(&self) -> io::Result<option::IntoIter<SocketAddr>> {
+ SocketAddr::V4(*self).to_socket_addrs()
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl ToSocketAddrs for SocketAddrV6 {
+ type Iter = option::IntoIter<SocketAddr>;
+ fn to_socket_addrs(&self) -> io::Result<option::IntoIter<SocketAddr>> {
+ SocketAddr::V6(*self).to_socket_addrs()
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl ToSocketAddrs for (IpAddr, u16) {
+ type Iter = option::IntoIter<SocketAddr>;
+ fn to_socket_addrs(&self) -> io::Result<option::IntoIter<SocketAddr>> {
+ let (ip, port) = *self;
+ match ip {
+ IpAddr::V4(ref a) => (*a, port).to_socket_addrs(),
+ IpAddr::V6(ref a) => (*a, port).to_socket_addrs(),
+ }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl ToSocketAddrs for (Ipv4Addr, u16) {
+ type Iter = option::IntoIter<SocketAddr>;
+ fn to_socket_addrs(&self) -> io::Result<option::IntoIter<SocketAddr>> {
+ let (ip, port) = *self;
+ SocketAddrV4::new(ip, port).to_socket_addrs()
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl ToSocketAddrs for (Ipv6Addr, u16) {
+ type Iter = option::IntoIter<SocketAddr>;
+ fn to_socket_addrs(&self) -> io::Result<option::IntoIter<SocketAddr>> {
+ let (ip, port) = *self;
+ SocketAddrV6::new(ip, port, 0, 0).to_socket_addrs()
+ }
+}
+
+fn resolve_socket_addr(lh: LookupHost) -> io::Result<vec::IntoIter<SocketAddr>> {
+ let p = lh.port();
+ let v: Vec<_> = lh.map(|mut a| { a.set_port(p); a }).collect();
+ Ok(v.into_iter())
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl ToSocketAddrs for (&str, u16) {
+ type Iter = vec::IntoIter<SocketAddr>;
+ fn to_socket_addrs(&self) -> io::Result<vec::IntoIter<SocketAddr>> {
+ let (host, port) = *self;
+
+ // try to parse the host as a regular IP address first
+ if let Ok(addr) = host.parse::<Ipv4Addr>() {
+ let addr = SocketAddrV4::new(addr, port);
+ return Ok(vec![SocketAddr::V4(addr)].into_iter())
+ }
+ if let Ok(addr) = host.parse::<Ipv6Addr>() {
+ let addr = SocketAddrV6::new(addr, port, 0, 0);
+ return Ok(vec![SocketAddr::V6(addr)].into_iter())
+ }
+
+ resolve_socket_addr((host, port).try_into()?)
+ }
+}
+
+// accepts strings like 'localhost:12345'
+#[stable(feature = "rust1", since = "1.0.0")]
+impl ToSocketAddrs for str {
+ type Iter = vec::IntoIter<SocketAddr>;
+ fn to_socket_addrs(&self) -> io::Result<vec::IntoIter<SocketAddr>> {
+ // try to parse as a regular SocketAddr first
+ if let Some(addr) = self.parse().ok() {
+ return Ok(vec![addr].into_iter());
+ }
+
+ resolve_socket_addr(self.try_into()?)
+ }
+}
+
+#[stable(feature = "slice_to_socket_addrs", since = "1.8.0")]
+impl<'a> ToSocketAddrs for &'a [SocketAddr] {
+ type Iter = iter::Cloned<slice::Iter<'a, SocketAddr>>;
+
+ fn to_socket_addrs(&self) -> io::Result<Self::Iter> {
+ Ok(self.iter().cloned())
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T: ToSocketAddrs + ?Sized> ToSocketAddrs for &T {
+ type Iter = T::Iter;
+ fn to_socket_addrs(&self) -> io::Result<T::Iter> {
+ (**self).to_socket_addrs()
+ }
+}
+
+#[stable(feature = "string_to_socket_addrs", since = "1.16.0")]
+impl ToSocketAddrs for String {
+ type Iter = vec::IntoIter<SocketAddr>;
+ fn to_socket_addrs(&self) -> io::Result<vec::IntoIter<SocketAddr>> {
+ (&**self).to_socket_addrs()
+ }
+}
+
+#[cfg(all(test, not(target_os = "emscripten")))]
+mod tests {
+ use crate::net::*;
+ use crate::net::test::{tsa, sa6, sa4};
+
+ #[test]
+ fn to_socket_addr_ipaddr_u16() {
+ let a = Ipv4Addr::new(77, 88, 21, 11);
+ let p = 12345;
+ let e = SocketAddr::V4(SocketAddrV4::new(a, p));
+ assert_eq!(Ok(vec![e]), tsa((a, p)));
+ }
+
+ #[test]
+ fn to_socket_addr_str_u16() {
+ let a = sa4(Ipv4Addr::new(77, 88, 21, 11), 24352);
+ assert_eq!(Ok(vec![a]), tsa(("77.88.21.11", 24352)));
+
+ let a = sa6(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 53);
+ assert_eq!(Ok(vec![a]), tsa(("2a02:6b8:0:1::1", 53)));
+
+ let a = sa4(Ipv4Addr::new(127, 0, 0, 1), 23924);
+ #[cfg(not(target_env = "sgx"))]
+ assert!(tsa(("localhost", 23924)).unwrap().contains(&a));
+ #[cfg(target_env = "sgx")]
+ let _ = a;
+ }
+
+ #[test]
+ fn to_socket_addr_str() {
+ let a = sa4(Ipv4Addr::new(77, 88, 21, 11), 24352);
+ assert_eq!(Ok(vec![a]), tsa("77.88.21.11:24352"));
+
+ let a = sa6(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 53);
+ assert_eq!(Ok(vec![a]), tsa("[2a02:6b8:0:1::1]:53"));
+
+ let a = sa4(Ipv4Addr::new(127, 0, 0, 1), 23924);
+ #[cfg(not(target_env = "sgx"))]
+ assert!(tsa("localhost:23924").unwrap().contains(&a));
+ #[cfg(target_env = "sgx")]
+ let _ = a;
+ }
+
+ #[test]
+ fn to_socket_addr_string() {
+ let a = sa4(Ipv4Addr::new(77, 88, 21, 11), 24352);
+ assert_eq!(Ok(vec![a]), tsa(&*format!("{}:{}", "77.88.21.11", "24352")));
+ assert_eq!(Ok(vec![a]), tsa(&format!("{}:{}", "77.88.21.11", "24352")));
+ assert_eq!(Ok(vec![a]), tsa(format!("{}:{}", "77.88.21.11", "24352")));
+
+ let s = format!("{}:{}", "77.88.21.11", "24352");
+ assert_eq!(Ok(vec![a]), tsa(s));
+ // s has been moved into the tsa call
+ }
+
+ // FIXME: figure out why this fails on openbsd and bitrig and fix it
+ #[test]
+ #[cfg(not(any(windows, target_os = "openbsd", target_os = "bitrig")))]
+ fn to_socket_addr_str_bad() {
+ assert!(tsa("1200::AB00:1234::2552:7777:1313:34300").is_err());
+ }
+
+ #[test]
+ fn set_ip() {
+ fn ip4(low: u8) -> Ipv4Addr { Ipv4Addr::new(77, 88, 21, low) }
+ fn ip6(low: u16) -> Ipv6Addr { Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, low) }
+
+ let mut v4 = SocketAddrV4::new(ip4(11), 80);
+ assert_eq!(v4.ip(), &ip4(11));
+ v4.set_ip(ip4(12));
+ assert_eq!(v4.ip(), &ip4(12));
+
+ let mut addr = SocketAddr::V4(v4);
+ assert_eq!(addr.ip(), IpAddr::V4(ip4(12)));
+ addr.set_ip(IpAddr::V4(ip4(13)));
+ assert_eq!(addr.ip(), IpAddr::V4(ip4(13)));
+ addr.set_ip(IpAddr::V6(ip6(14)));
+ assert_eq!(addr.ip(), IpAddr::V6(ip6(14)));
+
+ let mut v6 = SocketAddrV6::new(ip6(1), 80, 0, 0);
+ assert_eq!(v6.ip(), &ip6(1));
+ v6.set_ip(ip6(2));
+ assert_eq!(v6.ip(), &ip6(2));
+
+ let mut addr = SocketAddr::V6(v6);
+ assert_eq!(addr.ip(), IpAddr::V6(ip6(2)));
+ addr.set_ip(IpAddr::V6(ip6(3)));
+ assert_eq!(addr.ip(), IpAddr::V6(ip6(3)));
+ addr.set_ip(IpAddr::V4(ip4(4)));
+ assert_eq!(addr.ip(), IpAddr::V4(ip4(4)));
+ }
+
+ #[test]
+ fn set_port() {
+ let mut v4 = SocketAddrV4::new(Ipv4Addr::new(77, 88, 21, 11), 80);
+ assert_eq!(v4.port(), 80);
+ v4.set_port(443);
+ assert_eq!(v4.port(), 443);
+
+ let mut addr = SocketAddr::V4(v4);
+ assert_eq!(addr.port(), 443);
+ addr.set_port(8080);
+ assert_eq!(addr.port(), 8080);
+
+ let mut v6 = SocketAddrV6::new(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 80, 0, 0);
+ assert_eq!(v6.port(), 80);
+ v6.set_port(443);
+ assert_eq!(v6.port(), 443);
+
+ let mut addr = SocketAddr::V6(v6);
+ assert_eq!(addr.port(), 443);
+ addr.set_port(8080);
+ assert_eq!(addr.port(), 8080);
+ }
+
+ #[test]
+ fn set_flowinfo() {
+ let mut v6 = SocketAddrV6::new(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 80, 10, 0);
+ assert_eq!(v6.flowinfo(), 10);
+ v6.set_flowinfo(20);
+ assert_eq!(v6.flowinfo(), 20);
+ }
+
+ #[test]
+ fn set_scope_id() {
+ let mut v6 = SocketAddrV6::new(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 80, 0, 10);
+ assert_eq!(v6.scope_id(), 10);
+ v6.set_scope_id(20);
+ assert_eq!(v6.scope_id(), 20);
+ }
+
+ #[test]
+ fn is_v4() {
+ let v4 = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(77, 88, 21, 11), 80));
+ assert!(v4.is_ipv4());
+ assert!(!v4.is_ipv6());
+ }
+
+ #[test]
+ fn is_v6() {
+ let v6 = SocketAddr::V6(SocketAddrV6::new(
+ Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 80, 10, 0));
+ assert!(!v6.is_ipv4());
+ assert!(v6.is_ipv6());
+ }
+}
diff --git a/src/libstd/net/ip.rs b/src/libstd/net/ip.rs
new file mode 100644
index 0000000..7f9f3b9
--- /dev/null
+++ b/src/libstd/net/ip.rs
@@ -0,0 +1,1945 @@
+#![unstable(feature = "ip", reason = "extra functionality has not been \
+ scrutinized to the level that it should \
+ be to be stable",
+ issue = "27709")]
+
+use crate::cmp::Ordering;
+use crate::fmt;
+use crate::hash;
+use crate::sys::net::netc as c;
+use crate::sys_common::{AsInner, FromInner};
+
+/// An IP address, either IPv4 or IPv6.
+///
+/// This enum can contain either an [`Ipv4Addr`] or an [`Ipv6Addr`], see their
+/// respective documentation for more details.
+///
+/// The size of an `IpAddr` instance may vary depending on the target operating
+/// system.
+///
+/// [`Ipv4Addr`]: ../../std/net/struct.Ipv4Addr.html
+/// [`Ipv6Addr`]: ../../std/net/struct.Ipv6Addr.html
+///
+/// # Examples
+///
+/// ```
+/// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
+///
+/// let localhost_v4 = IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1));
+/// let localhost_v6 = IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1));
+///
+/// assert_eq!("127.0.0.1".parse(), Ok(localhost_v4));
+/// assert_eq!("::1".parse(), Ok(localhost_v6));
+///
+/// assert_eq!(localhost_v4.is_ipv6(), false);
+/// assert_eq!(localhost_v4.is_ipv4(), true);
+/// ```
+#[stable(feature = "ip_addr", since = "1.7.0")]
+#[derive(Copy, Clone, Eq, PartialEq, Debug, Hash, PartialOrd, Ord)]
+pub enum IpAddr {
+ /// An IPv4 address.
+ #[stable(feature = "ip_addr", since = "1.7.0")]
+ V4(#[stable(feature = "ip_addr", since = "1.7.0")] Ipv4Addr),
+ /// An IPv6 address.
+ #[stable(feature = "ip_addr", since = "1.7.0")]
+ V6(#[stable(feature = "ip_addr", since = "1.7.0")] Ipv6Addr),
+}
+
+/// An IPv4 address.
+///
+/// IPv4 addresses are defined as 32-bit integers in [IETF RFC 791].
+/// They are usually represented as four octets.
+///
+/// See [`IpAddr`] for a type encompassing both IPv4 and IPv6 addresses.
+///
+/// The size of an `Ipv4Addr` struct may vary depending on the target operating
+/// system.
+///
+/// [IETF RFC 791]: https://tools.ietf.org/html/rfc791
+/// [`IpAddr`]: ../../std/net/enum.IpAddr.html
+///
+/// # Textual representation
+///
+/// `Ipv4Addr` provides a [`FromStr`] implementation. The four octets are in decimal
+/// notation, divided by `.` (this is called "dot-decimal notation").
+///
+/// [`FromStr`]: ../../std/str/trait.FromStr.html
+///
+/// # Examples
+///
+/// ```
+/// use std::net::Ipv4Addr;
+///
+/// let localhost = Ipv4Addr::new(127, 0, 0, 1);
+/// assert_eq!("127.0.0.1".parse(), Ok(localhost));
+/// assert_eq!(localhost.is_loopback(), true);
+/// ```
+#[derive(Copy)]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct Ipv4Addr {
+ inner: c::in_addr,
+}
+
+/// An IPv6 address.
+///
+/// IPv6 addresses are defined as 128-bit integers in [IETF RFC 4291].
+/// They are usually represented as eight 16-bit segments.
+///
+/// See [`IpAddr`] for a type encompassing both IPv4 and IPv6 addresses.
+///
+/// The size of an `Ipv6Addr` struct may vary depending on the target operating
+/// system.
+///
+/// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291
+/// [`IpAddr`]: ../../std/net/enum.IpAddr.html
+///
+/// # Textual representation
+///
+/// `Ipv6Addr` provides a [`FromStr`] implementation. There are many ways to represent
+/// an IPv6 address in text, but in general, each segments is written in hexadecimal
+/// notation, and segments are separated by `:`. For more information, see
+/// [IETF RFC 5952].
+///
+/// [`FromStr`]: ../../std/str/trait.FromStr.html
+/// [IETF RFC 5952]: https://tools.ietf.org/html/rfc5952
+///
+/// # Examples
+///
+/// ```
+/// use std::net::Ipv6Addr;
+///
+/// let localhost = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1);
+/// assert_eq!("::1".parse(), Ok(localhost));
+/// assert_eq!(localhost.is_loopback(), true);
+/// ```
+#[derive(Copy)]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct Ipv6Addr {
+ inner: c::in6_addr,
+}
+
+#[allow(missing_docs)]
+#[derive(Copy, PartialEq, Eq, Clone, Hash, Debug)]
+pub enum Ipv6MulticastScope {
+ InterfaceLocal,
+ LinkLocal,
+ RealmLocal,
+ AdminLocal,
+ SiteLocal,
+ OrganizationLocal,
+ Global
+}
+
+impl IpAddr {
+ /// Returns [`true`] for the special 'unspecified' address.
+ ///
+ /// See the documentation for [`Ipv4Addr::is_unspecified`][IPv4] and
+ /// [`Ipv6Addr::is_unspecified`][IPv6] for more details.
+ ///
+ /// [IPv4]: ../../std/net/struct.Ipv4Addr.html#method.is_unspecified
+ /// [IPv6]: ../../std/net/struct.Ipv6Addr.html#method.is_unspecified
+ /// [`true`]: ../../std/primitive.bool.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
+ ///
+ /// assert_eq!(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)).is_unspecified(), true);
+ /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)).is_unspecified(), true);
+ /// ```
+ #[stable(feature = "ip_shared", since = "1.12.0")]
+ pub fn is_unspecified(&self) -> bool {
+ match self {
+ IpAddr::V4(ip) => ip.is_unspecified(),
+ IpAddr::V6(ip) => ip.is_unspecified(),
+ }
+ }
+
+ /// Returns [`true`] if this is a loopback address.
+ ///
+ /// See the documentation for [`Ipv4Addr::is_loopback`][IPv4] and
+ /// [`Ipv6Addr::is_loopback`][IPv6] for more details.
+ ///
+ /// [IPv4]: ../../std/net/struct.Ipv4Addr.html#method.is_loopback
+ /// [IPv6]: ../../std/net/struct.Ipv6Addr.html#method.is_loopback
+ /// [`true`]: ../../std/primitive.bool.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
+ ///
+ /// assert_eq!(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)).is_loopback(), true);
+ /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0x1)).is_loopback(), true);
+ /// ```
+ #[stable(feature = "ip_shared", since = "1.12.0")]
+ pub fn is_loopback(&self) -> bool {
+ match self {
+ IpAddr::V4(ip) => ip.is_loopback(),
+ IpAddr::V6(ip) => ip.is_loopback(),
+ }
+ }
+
+ /// Returns [`true`] if the address appears to be globally routable.
+ ///
+ /// See the documentation for [`Ipv4Addr::is_global`][IPv4] and
+ /// [`Ipv6Addr::is_global`][IPv6] for more details.
+ ///
+ /// [IPv4]: ../../std/net/struct.Ipv4Addr.html#method.is_global
+ /// [IPv6]: ../../std/net/struct.Ipv6Addr.html#method.is_global
+ /// [`true`]: ../../std/primitive.bool.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(ip)]
+ ///
+ /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
+ ///
+ /// fn main() {
+ /// assert_eq!(IpAddr::V4(Ipv4Addr::new(80, 9, 12, 3)).is_global(), true);
+ /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0x1c9, 0, 0, 0xafc8, 0, 0x1)).is_global(),
+ /// true);
+ /// }
+ /// ```
+ pub fn is_global(&self) -> bool {
+ match self {
+ IpAddr::V4(ip) => ip.is_global(),
+ IpAddr::V6(ip) => ip.is_global(),
+ }
+ }
+
+ /// Returns [`true`] if this is a multicast address.
+ ///
+ /// See the documentation for [`Ipv4Addr::is_multicast`][IPv4] and
+ /// [`Ipv6Addr::is_multicast`][IPv6] for more details.
+ ///
+ /// [IPv4]: ../../std/net/struct.Ipv4Addr.html#method.is_multicast
+ /// [IPv6]: ../../std/net/struct.Ipv6Addr.html#method.is_multicast
+ /// [`true`]: ../../std/primitive.bool.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
+ ///
+ /// assert_eq!(IpAddr::V4(Ipv4Addr::new(224, 254, 0, 0)).is_multicast(), true);
+ /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0)).is_multicast(), true);
+ /// ```
+ #[stable(feature = "ip_shared", since = "1.12.0")]
+ pub fn is_multicast(&self) -> bool {
+ match self {
+ IpAddr::V4(ip) => ip.is_multicast(),
+ IpAddr::V6(ip) => ip.is_multicast(),
+ }
+ }
+
+ /// Returns [`true`] if this address is in a range designated for documentation.
+ ///
+ /// See the documentation for [`Ipv4Addr::is_documentation`][IPv4] and
+ /// [`Ipv6Addr::is_documentation`][IPv6] for more details.
+ ///
+ /// [IPv4]: ../../std/net/struct.Ipv4Addr.html#method.is_documentation
+ /// [IPv6]: ../../std/net/struct.Ipv6Addr.html#method.is_documentation
+ /// [`true`]: ../../std/primitive.bool.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(ip)]
+ ///
+ /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
+ ///
+ /// fn main() {
+ /// assert_eq!(IpAddr::V4(Ipv4Addr::new(203, 0, 113, 6)).is_documentation(), true);
+ /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0))
+ /// .is_documentation(), true);
+ /// }
+ /// ```
+ pub fn is_documentation(&self) -> bool {
+ match self {
+ IpAddr::V4(ip) => ip.is_documentation(),
+ IpAddr::V6(ip) => ip.is_documentation(),
+ }
+ }
+
+ /// Returns [`true`] if this address is an [IPv4 address], and [`false`] otherwise.
+ ///
+ /// [`true`]: ../../std/primitive.bool.html
+ /// [`false`]: ../../std/primitive.bool.html
+ /// [IPv4 address]: #variant.V4
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
+ ///
+ /// fn main() {
+ /// assert_eq!(IpAddr::V4(Ipv4Addr::new(203, 0, 113, 6)).is_ipv4(), true);
+ /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0)).is_ipv4(),
+ /// false);
+ /// }
+ /// ```
+ #[stable(feature = "ipaddr_checker", since = "1.16.0")]
+ pub fn is_ipv4(&self) -> bool {
+ match self {
+ IpAddr::V4(_) => true,
+ IpAddr::V6(_) => false,
+ }
+ }
+
+ /// Returns [`true`] if this address is an [IPv6 address], and [`false`] otherwise.
+ ///
+ /// [`true`]: ../../std/primitive.bool.html
+ /// [`false`]: ../../std/primitive.bool.html
+ /// [IPv6 address]: #variant.V6
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
+ ///
+ /// fn main() {
+ /// assert_eq!(IpAddr::V4(Ipv4Addr::new(203, 0, 113, 6)).is_ipv6(), false);
+ /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0)).is_ipv6(),
+ /// true);
+ /// }
+ /// ```
+ #[stable(feature = "ipaddr_checker", since = "1.16.0")]
+ pub fn is_ipv6(&self) -> bool {
+ match self {
+ IpAddr::V4(_) => false,
+ IpAddr::V6(_) => true,
+ }
+ }
+}
+
+impl Ipv4Addr {
+ /// Creates a new IPv4 address from four eight-bit octets.
+ ///
+ /// The result will represent the IP address `a`.`b`.`c`.`d`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::Ipv4Addr;
+ ///
+ /// let addr = Ipv4Addr::new(127, 0, 0, 1);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub const fn new(a: u8, b: u8, c: u8, d: u8) -> Ipv4Addr {
+ // FIXME: should just be u32::from_be_bytes([a, b, c, d]),
+ // once that method is no longer rustc_const_unstable
+ Ipv4Addr {
+ inner: c::in_addr {
+ s_addr: u32::to_be(
+ ((a as u32) << 24) |
+ ((b as u32) << 16) |
+ ((c as u32) << 8) |
+ (d as u32)
+ ),
+ }
+ }
+ }
+
+ /// An IPv4 address with the address pointing to localhost: 127.0.0.1.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::Ipv4Addr;
+ ///
+ /// let addr = Ipv4Addr::LOCALHOST;
+ /// assert_eq!(addr, Ipv4Addr::new(127, 0, 0, 1));
+ /// ```
+ #[stable(feature = "ip_constructors", since = "1.30.0")]
+ pub const LOCALHOST: Self = Ipv4Addr::new(127, 0, 0, 1);
+
+ /// An IPv4 address representing an unspecified address: 0.0.0.0
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::Ipv4Addr;
+ ///
+ /// let addr = Ipv4Addr::UNSPECIFIED;
+ /// assert_eq!(addr, Ipv4Addr::new(0, 0, 0, 0));
+ /// ```
+ #[stable(feature = "ip_constructors", since = "1.30.0")]
+ pub const UNSPECIFIED: Self = Ipv4Addr::new(0, 0, 0, 0);
+
+ /// An IPv4 address representing the broadcast address: 255.255.255.255
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::Ipv4Addr;
+ ///
+ /// let addr = Ipv4Addr::BROADCAST;
+ /// assert_eq!(addr, Ipv4Addr::new(255, 255, 255, 255));
+ /// ```
+ #[stable(feature = "ip_constructors", since = "1.30.0")]
+ pub const BROADCAST: Self = Ipv4Addr::new(255, 255, 255, 255);
+
+ /// Returns the four eight-bit integers that make up this address.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::Ipv4Addr;
+ ///
+ /// let addr = Ipv4Addr::new(127, 0, 0, 1);
+ /// assert_eq!(addr.octets(), [127, 0, 0, 1]);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn octets(&self) -> [u8; 4] {
+ // This returns the order we want because s_addr is stored in big-endian.
+ self.inner.s_addr.to_ne_bytes()
+ }
+
+ /// Returns [`true`] for the special 'unspecified' address (0.0.0.0).
+ ///
+ /// This property is defined in _UNIX Network Programming, Second Edition_,
+ /// W. Richard Stevens, p. 891; see also [ip7].
+ ///
+ /// [ip7]: http://man7.org/linux/man-pages/man7/ip.7.html
+ /// [`true`]: ../../std/primitive.bool.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::Ipv4Addr;
+ ///
+ /// assert_eq!(Ipv4Addr::new(0, 0, 0, 0).is_unspecified(), true);
+ /// assert_eq!(Ipv4Addr::new(45, 22, 13, 197).is_unspecified(), false);
+ /// ```
+ #[stable(feature = "ip_shared", since = "1.12.0")]
+ pub const fn is_unspecified(&self) -> bool {
+ self.inner.s_addr == 0
+ }
+
+ /// Returns [`true`] if this is a loopback address (127.0.0.0/8).
+ ///
+ /// This property is defined by [IETF RFC 1122].
+ ///
+ /// [IETF RFC 1122]: https://tools.ietf.org/html/rfc1122
+ /// [`true`]: ../../std/primitive.bool.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::Ipv4Addr;
+ ///
+ /// assert_eq!(Ipv4Addr::new(127, 0, 0, 1).is_loopback(), true);
+ /// assert_eq!(Ipv4Addr::new(45, 22, 13, 197).is_loopback(), false);
+ /// ```
+ #[stable(since = "1.7.0", feature = "ip_17")]
+ pub fn is_loopback(&self) -> bool {
+ self.octets()[0] == 127
+ }
+
+ /// Returns [`true`] if this is a private address.
+ ///
+ /// The private address ranges are defined in [IETF RFC 1918] and include:
+ ///
+ /// - 10.0.0.0/8
+ /// - 172.16.0.0/12
+ /// - 192.168.0.0/16
+ ///
+ /// [IETF RFC 1918]: https://tools.ietf.org/html/rfc1918
+ /// [`true`]: ../../std/primitive.bool.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::Ipv4Addr;
+ ///
+ /// assert_eq!(Ipv4Addr::new(10, 0, 0, 1).is_private(), true);
+ /// assert_eq!(Ipv4Addr::new(10, 10, 10, 10).is_private(), true);
+ /// assert_eq!(Ipv4Addr::new(172, 16, 10, 10).is_private(), true);
+ /// assert_eq!(Ipv4Addr::new(172, 29, 45, 14).is_private(), true);
+ /// assert_eq!(Ipv4Addr::new(172, 32, 0, 2).is_private(), false);
+ /// assert_eq!(Ipv4Addr::new(192, 168, 0, 2).is_private(), true);
+ /// assert_eq!(Ipv4Addr::new(192, 169, 0, 2).is_private(), false);
+ /// ```
+ #[stable(since = "1.7.0", feature = "ip_17")]
+ pub fn is_private(&self) -> bool {
+ match self.octets() {
+ [10, ..] => true,
+ [172, b, ..] if b >= 16 && b <= 31 => true,
+ [192, 168, ..] => true,
+ _ => false,
+ }
+ }
+
+ /// Returns [`true`] if the address is link-local (169.254.0.0/16).
+ ///
+ /// This property is defined by [IETF RFC 3927].
+ ///
+ /// [IETF RFC 3927]: https://tools.ietf.org/html/rfc3927
+ /// [`true`]: ../../std/primitive.bool.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::Ipv4Addr;
+ ///
+ /// assert_eq!(Ipv4Addr::new(169, 254, 0, 0).is_link_local(), true);
+ /// assert_eq!(Ipv4Addr::new(169, 254, 10, 65).is_link_local(), true);
+ /// assert_eq!(Ipv4Addr::new(16, 89, 10, 65).is_link_local(), false);
+ /// ```
+ #[stable(since = "1.7.0", feature = "ip_17")]
+ pub fn is_link_local(&self) -> bool {
+ match self.octets() {
+ [169, 254, ..] => true,
+ _ => false,
+ }
+ }
+
+ /// Returns [`true`] if the address appears to be globally routable.
+ /// See [iana-ipv4-special-registry][ipv4-sr].
+ ///
+ /// The following return false:
+ ///
+ /// - private address (10.0.0.0/8, 172.16.0.0/12 and 192.168.0.0/16)
+ /// - the loopback address (127.0.0.0/8)
+ /// - the link-local address (169.254.0.0/16)
+ /// - the broadcast address (255.255.255.255/32)
+ /// - test addresses used for documentation (192.0.2.0/24, 198.51.100.0/24 and 203.0.113.0/24)
+ /// - the unspecified address (0.0.0.0)
+ ///
+ /// [ipv4-sr]: https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml
+ /// [`true`]: ../../std/primitive.bool.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(ip)]
+ ///
+ /// use std::net::Ipv4Addr;
+ ///
+ /// fn main() {
+ /// assert_eq!(Ipv4Addr::new(10, 254, 0, 0).is_global(), false);
+ /// assert_eq!(Ipv4Addr::new(192, 168, 10, 65).is_global(), false);
+ /// assert_eq!(Ipv4Addr::new(172, 16, 10, 65).is_global(), false);
+ /// assert_eq!(Ipv4Addr::new(0, 0, 0, 0).is_global(), false);
+ /// assert_eq!(Ipv4Addr::new(80, 9, 12, 3).is_global(), true);
+ /// }
+ /// ```
+ pub fn is_global(&self) -> bool {
+ !self.is_private() && !self.is_loopback() && !self.is_link_local() &&
+ !self.is_broadcast() && !self.is_documentation() && !self.is_unspecified()
+ }
+
+ /// Returns [`true`] if this is a multicast address (224.0.0.0/4).
+ ///
+ /// Multicast addresses have a most significant octet between 224 and 239,
+ /// and is defined by [IETF RFC 5771].
+ ///
+ /// [IETF RFC 5771]: https://tools.ietf.org/html/rfc5771
+ /// [`true`]: ../../std/primitive.bool.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::Ipv4Addr;
+ ///
+ /// assert_eq!(Ipv4Addr::new(224, 254, 0, 0).is_multicast(), true);
+ /// assert_eq!(Ipv4Addr::new(236, 168, 10, 65).is_multicast(), true);
+ /// assert_eq!(Ipv4Addr::new(172, 16, 10, 65).is_multicast(), false);
+ /// ```
+ #[stable(since = "1.7.0", feature = "ip_17")]
+ pub fn is_multicast(&self) -> bool {
+ self.octets()[0] >= 224 && self.octets()[0] <= 239
+ }
+
+ /// Returns [`true`] if this is a broadcast address (255.255.255.255).
+ ///
+ /// A broadcast address has all octets set to 255 as defined in [IETF RFC 919].
+ ///
+ /// [IETF RFC 919]: https://tools.ietf.org/html/rfc919
+ /// [`true`]: ../../std/primitive.bool.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::Ipv4Addr;
+ ///
+ /// assert_eq!(Ipv4Addr::new(255, 255, 255, 255).is_broadcast(), true);
+ /// assert_eq!(Ipv4Addr::new(236, 168, 10, 65).is_broadcast(), false);
+ /// ```
+ #[stable(since = "1.7.0", feature = "ip_17")]
+ pub fn is_broadcast(&self) -> bool {
+ self == &Self::BROADCAST
+ }
+
+ /// Returns [`true`] if this address is in a range designated for documentation.
+ ///
+ /// This is defined in [IETF RFC 5737]:
+ ///
+ /// - 192.0.2.0/24 (TEST-NET-1)
+ /// - 198.51.100.0/24 (TEST-NET-2)
+ /// - 203.0.113.0/24 (TEST-NET-3)
+ ///
+ /// [IETF RFC 5737]: https://tools.ietf.org/html/rfc5737
+ /// [`true`]: ../../std/primitive.bool.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::Ipv4Addr;
+ ///
+ /// assert_eq!(Ipv4Addr::new(192, 0, 2, 255).is_documentation(), true);
+ /// assert_eq!(Ipv4Addr::new(198, 51, 100, 65).is_documentation(), true);
+ /// assert_eq!(Ipv4Addr::new(203, 0, 113, 6).is_documentation(), true);
+ /// assert_eq!(Ipv4Addr::new(193, 34, 17, 19).is_documentation(), false);
+ /// ```
+ #[stable(since = "1.7.0", feature = "ip_17")]
+ pub fn is_documentation(&self) -> bool {
+ match self.octets() {
+ [192, 0, 2, _] => true,
+ [198, 51, 100, _] => true,
+ [203, 0, 113, _] => true,
+ _ => false,
+ }
+ }
+
+ /// Converts this address to an IPv4-compatible [IPv6 address].
+ ///
+ /// a.b.c.d becomes ::a.b.c.d
+ ///
+ /// [IPv6 address]: ../../std/net/struct.Ipv6Addr.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::{Ipv4Addr, Ipv6Addr};
+ ///
+ /// assert_eq!(Ipv4Addr::new(192, 0, 2, 255).to_ipv6_compatible(),
+ /// Ipv6Addr::new(0, 0, 0, 0, 0, 0, 49152, 767));
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn to_ipv6_compatible(&self) -> Ipv6Addr {
+ let octets = self.octets();
+ Ipv6Addr::from([
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ octets[0], octets[1], octets[2], octets[3],
+ ])
+ }
+
+ /// Converts this address to an IPv4-mapped [IPv6 address].
+ ///
+ /// a.b.c.d becomes ::ffff:a.b.c.d
+ ///
+ /// [IPv6 address]: ../../std/net/struct.Ipv6Addr.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::{Ipv4Addr, Ipv6Addr};
+ ///
+ /// assert_eq!(Ipv4Addr::new(192, 0, 2, 255).to_ipv6_mapped(),
+ /// Ipv6Addr::new(0, 0, 0, 0, 0, 65535, 49152, 767));
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn to_ipv6_mapped(&self) -> Ipv6Addr {
+ let octets = self.octets();
+ Ipv6Addr::from([
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0xFF, 0xFF,
+ octets[0], octets[1], octets[2], octets[3],
+ ])
+ }
+}
+
+#[stable(feature = "ip_addr", since = "1.7.0")]
+impl fmt::Display for IpAddr {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self {
+ IpAddr::V4(ip) => ip.fmt(fmt),
+ IpAddr::V6(ip) => ip.fmt(fmt),
+ }
+ }
+}
+
+#[stable(feature = "ip_from_ip", since = "1.16.0")]
+impl From<Ipv4Addr> for IpAddr {
+ fn from(ipv4: Ipv4Addr) -> IpAddr {
+ IpAddr::V4(ipv4)
+ }
+}
+
+#[stable(feature = "ip_from_ip", since = "1.16.0")]
+impl From<Ipv6Addr> for IpAddr {
+ fn from(ipv6: Ipv6Addr) -> IpAddr {
+ IpAddr::V6(ipv6)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl fmt::Display for Ipv4Addr {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ let octets = self.octets();
+ write!(fmt, "{}.{}.{}.{}", octets[0], octets[1], octets[2], octets[3])
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl fmt::Debug for Ipv4Addr {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt::Display::fmt(self, fmt)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Clone for Ipv4Addr {
+ fn clone(&self) -> Ipv4Addr { *self }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl PartialEq for Ipv4Addr {
+ fn eq(&self, other: &Ipv4Addr) -> bool {
+ self.inner.s_addr == other.inner.s_addr
+ }
+}
+
+#[stable(feature = "ip_cmp", since = "1.16.0")]
+impl PartialEq<Ipv4Addr> for IpAddr {
+ fn eq(&self, other: &Ipv4Addr) -> bool {
+ match self {
+ IpAddr::V4(v4) => v4 == other,
+ IpAddr::V6(_) => false,
+ }
+ }
+}
+
+#[stable(feature = "ip_cmp", since = "1.16.0")]
+impl PartialEq<IpAddr> for Ipv4Addr {
+ fn eq(&self, other: &IpAddr) -> bool {
+ match other {
+ IpAddr::V4(v4) => self == v4,
+ IpAddr::V6(_) => false,
+ }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Eq for Ipv4Addr {}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl hash::Hash for Ipv4Addr {
+ fn hash<H: hash::Hasher>(&self, s: &mut H) {
+ // `inner` is #[repr(packed)], so we need to copy `s_addr`.
+ {self.inner.s_addr}.hash(s)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl PartialOrd for Ipv4Addr {
+ fn partial_cmp(&self, other: &Ipv4Addr) -> Option<Ordering> {
+ Some(self.cmp(other))
+ }
+}
+
+#[stable(feature = "ip_cmp", since = "1.16.0")]
+impl PartialOrd<Ipv4Addr> for IpAddr {
+ fn partial_cmp(&self, other: &Ipv4Addr) -> Option<Ordering> {
+ match self {
+ IpAddr::V4(v4) => v4.partial_cmp(other),
+ IpAddr::V6(_) => Some(Ordering::Greater),
+ }
+ }
+}
+
+#[stable(feature = "ip_cmp", since = "1.16.0")]
+impl PartialOrd<IpAddr> for Ipv4Addr {
+ fn partial_cmp(&self, other: &IpAddr) -> Option<Ordering> {
+ match other {
+ IpAddr::V4(v4) => self.partial_cmp(v4),
+ IpAddr::V6(_) => Some(Ordering::Less),
+ }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Ord for Ipv4Addr {
+ fn cmp(&self, other: &Ipv4Addr) -> Ordering {
+ u32::from_be(self.inner.s_addr).cmp(&u32::from_be(other.inner.s_addr))
+ }
+}
+
+impl AsInner<c::in_addr> for Ipv4Addr {
+ fn as_inner(&self) -> &c::in_addr { &self.inner }
+}
+impl FromInner<c::in_addr> for Ipv4Addr {
+ fn from_inner(addr: c::in_addr) -> Ipv4Addr {
+ Ipv4Addr { inner: addr }
+ }
+}
+
+#[stable(feature = "ip_u32", since = "1.1.0")]
+impl From<Ipv4Addr> for u32 {
+ /// Converts an `Ipv4Addr` into a host byte order `u32`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::Ipv4Addr;
+ ///
+ /// let addr = Ipv4Addr::new(13, 12, 11, 10);
+ /// assert_eq!(0x0d0c0b0au32, u32::from(addr));
+ /// ```
+ fn from(ip: Ipv4Addr) -> u32 {
+ let ip = ip.octets();
+ u32::from_be_bytes(ip)
+ }
+}
+
+#[stable(feature = "ip_u32", since = "1.1.0")]
+impl From<u32> for Ipv4Addr {
+ /// Converts a host byte order `u32` into an `Ipv4Addr`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::Ipv4Addr;
+ ///
+ /// let addr = Ipv4Addr::from(0x0d0c0b0au32);
+ /// assert_eq!(Ipv4Addr::new(13, 12, 11, 10), addr);
+ /// ```
+ fn from(ip: u32) -> Ipv4Addr {
+ Ipv4Addr::from(ip.to_be_bytes())
+ }
+}
+
+#[stable(feature = "from_slice_v4", since = "1.9.0")]
+impl From<[u8; 4]> for Ipv4Addr {
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::Ipv4Addr;
+ ///
+ /// let addr = Ipv4Addr::from([13u8, 12u8, 11u8, 10u8]);
+ /// assert_eq!(Ipv4Addr::new(13, 12, 11, 10), addr);
+ /// ```
+ fn from(octets: [u8; 4]) -> Ipv4Addr {
+ Ipv4Addr::new(octets[0], octets[1], octets[2], octets[3])
+ }
+}
+
+#[stable(feature = "ip_from_slice", since = "1.17.0")]
+impl From<[u8; 4]> for IpAddr {
+ /// Creates an `IpAddr::V4` from a four element byte array.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::{IpAddr, Ipv4Addr};
+ ///
+ /// let addr = IpAddr::from([13u8, 12u8, 11u8, 10u8]);
+ /// assert_eq!(IpAddr::V4(Ipv4Addr::new(13, 12, 11, 10)), addr);
+ /// ```
+ fn from(octets: [u8; 4]) -> IpAddr {
+ IpAddr::V4(Ipv4Addr::from(octets))
+ }
+}
+
+impl Ipv6Addr {
+ /// Creates a new IPv6 address from eight 16-bit segments.
+ ///
+ /// The result will represent the IP address `a:b:c:d:e:f:g:h`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::Ipv6Addr;
+ ///
+ /// let addr = Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub const fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16,
+ g: u16, h: u16) -> Ipv6Addr {
+ Ipv6Addr {
+ inner: c::in6_addr {
+ s6_addr: [
+ (a >> 8) as u8, a as u8,
+ (b >> 8) as u8, b as u8,
+ (c >> 8) as u8, c as u8,
+ (d >> 8) as u8, d as u8,
+ (e >> 8) as u8, e as u8,
+ (f >> 8) as u8, f as u8,
+ (g >> 8) as u8, g as u8,
+ (h >> 8) as u8, h as u8
+ ],
+ }
+ }
+
+ }
+
+ /// An IPv6 address representing localhost: `::1`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::Ipv6Addr;
+ ///
+ /// let addr = Ipv6Addr::LOCALHOST;
+ /// assert_eq!(addr, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1));
+ /// ```
+ #[stable(feature = "ip_constructors", since = "1.30.0")]
+ pub const LOCALHOST: Self = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1);
+
+ /// An IPv6 address representing the unspecified address: `::`
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::Ipv6Addr;
+ ///
+ /// let addr = Ipv6Addr::UNSPECIFIED;
+ /// assert_eq!(addr, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0));
+ /// ```
+ #[stable(feature = "ip_constructors", since = "1.30.0")]
+ pub const UNSPECIFIED: Self = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0);
+
+ /// Returns the eight 16-bit segments that make up this address.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::Ipv6Addr;
+ ///
+ /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).segments(),
+ /// [0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff]);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn segments(&self) -> [u16; 8] {
+ let arr = &self.inner.s6_addr;
+ [
+ u16::from_be_bytes([arr[0], arr[1]]),
+ u16::from_be_bytes([arr[2], arr[3]]),
+ u16::from_be_bytes([arr[4], arr[5]]),
+ u16::from_be_bytes([arr[6], arr[7]]),
+ u16::from_be_bytes([arr[8], arr[9]]),
+ u16::from_be_bytes([arr[10], arr[11]]),
+ u16::from_be_bytes([arr[12], arr[13]]),
+ u16::from_be_bytes([arr[14], arr[15]]),
+ ]
+ }
+
+ /// Returns [`true`] for the special 'unspecified' address (::).
+ ///
+ /// This property is defined in [IETF RFC 4291].
+ ///
+ /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291
+ /// [`true`]: ../../std/primitive.bool.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::Ipv6Addr;
+ ///
+ /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unspecified(), false);
+ /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0).is_unspecified(), true);
+ /// ```
+ #[stable(since = "1.7.0", feature = "ip_17")]
+ pub fn is_unspecified(&self) -> bool {
+ self.segments() == [0, 0, 0, 0, 0, 0, 0, 0]
+ }
+
+ /// Returns [`true`] if this is a loopback address (::1).
+ ///
+ /// This property is defined in [IETF RFC 4291].
+ ///
+ /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291
+ /// [`true`]: ../../std/primitive.bool.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::Ipv6Addr;
+ ///
+ /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_loopback(), false);
+ /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0x1).is_loopback(), true);
+ /// ```
+ #[stable(since = "1.7.0", feature = "ip_17")]
+ pub fn is_loopback(&self) -> bool {
+ self.segments() == [0, 0, 0, 0, 0, 0, 0, 1]
+ }
+
+ /// Returns [`true`] if the address appears to be globally routable.
+ ///
+ /// The following return [`false`]:
+ ///
+ /// - the loopback address
+ /// - link-local, site-local, and unique local unicast addresses
+ /// - interface-, link-, realm-, admin- and site-local multicast addresses
+ ///
+ /// [`true`]: ../../std/primitive.bool.html
+ /// [`false`]: ../../std/primitive.bool.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(ip)]
+ ///
+ /// use std::net::Ipv6Addr;
+ ///
+ /// fn main() {
+ /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_global(), true);
+ /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0x1).is_global(), false);
+ /// assert_eq!(Ipv6Addr::new(0, 0, 0x1c9, 0, 0, 0xafc8, 0, 0x1).is_global(), true);
+ /// }
+ /// ```
+ pub fn is_global(&self) -> bool {
+ match self.multicast_scope() {
+ Some(Ipv6MulticastScope::Global) => true,
+ None => self.is_unicast_global(),
+ _ => false
+ }
+ }
+
+ /// Returns [`true`] if this is a unique local address (fc00::/7).
+ ///
+ /// This property is defined in [IETF RFC 4193].
+ ///
+ /// [IETF RFC 4193]: https://tools.ietf.org/html/rfc4193
+ /// [`true`]: ../../std/primitive.bool.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(ip)]
+ ///
+ /// use std::net::Ipv6Addr;
+ ///
+ /// fn main() {
+ /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unique_local(),
+ /// false);
+ /// assert_eq!(Ipv6Addr::new(0xfc02, 0, 0, 0, 0, 0, 0, 0).is_unique_local(), true);
+ /// }
+ /// ```
+ pub fn is_unique_local(&self) -> bool {
+ (self.segments()[0] & 0xfe00) == 0xfc00
+ }
+
+ /// Returns [`true`] if the address is unicast and link-local (fe80::/10).
+ ///
+ /// This property is defined in [IETF RFC 4291].
+ ///
+ /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291
+ /// [`true`]: ../../std/primitive.bool.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(ip)]
+ ///
+ /// use std::net::Ipv6Addr;
+ ///
+ /// fn main() {
+ /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unicast_link_local(),
+ /// false);
+ /// assert_eq!(Ipv6Addr::new(0xfe8a, 0, 0, 0, 0, 0, 0, 0).is_unicast_link_local(), true);
+ /// }
+ /// ```
+ pub fn is_unicast_link_local(&self) -> bool {
+ (self.segments()[0] & 0xffc0) == 0xfe80
+ }
+
+ /// Returns [`true`] if this is a deprecated unicast site-local address
+ /// (fec0::/10).
+ ///
+ /// [`true`]: ../../std/primitive.bool.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(ip)]
+ ///
+ /// use std::net::Ipv6Addr;
+ ///
+ /// fn main() {
+ /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unicast_site_local(),
+ /// false);
+ /// assert_eq!(Ipv6Addr::new(0xfec2, 0, 0, 0, 0, 0, 0, 0).is_unicast_site_local(), true);
+ /// }
+ /// ```
+ pub fn is_unicast_site_local(&self) -> bool {
+ (self.segments()[0] & 0xffc0) == 0xfec0
+ }
+
+ /// Returns [`true`] if this is an address reserved for documentation
+ /// (2001:db8::/32).
+ ///
+ /// This property is defined in [IETF RFC 3849].
+ ///
+ /// [IETF RFC 3849]: https://tools.ietf.org/html/rfc3849
+ /// [`true`]: ../../std/primitive.bool.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(ip)]
+ ///
+ /// use std::net::Ipv6Addr;
+ ///
+ /// fn main() {
+ /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_documentation(),
+ /// false);
+ /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_documentation(), true);
+ /// }
+ /// ```
+ pub fn is_documentation(&self) -> bool {
+ (self.segments()[0] == 0x2001) && (self.segments()[1] == 0xdb8)
+ }
+
+ /// Returns [`true`] if the address is a globally routable unicast address.
+ ///
+ /// The following return false:
+ ///
+ /// - the loopback address
+ /// - the link-local addresses
+ /// - the (deprecated) site-local addresses
+ /// - unique local addresses
+ /// - the unspecified address
+ /// - the address range reserved for documentation
+ ///
+ /// [`true`]: ../../std/primitive.bool.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(ip)]
+ ///
+ /// use std::net::Ipv6Addr;
+ ///
+ /// fn main() {
+ /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_unicast_global(), false);
+ /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unicast_global(),
+ /// true);
+ /// }
+ /// ```
+ pub fn is_unicast_global(&self) -> bool {
+ !self.is_multicast()
+ && !self.is_loopback() && !self.is_unicast_link_local()
+ && !self.is_unicast_site_local() && !self.is_unique_local()
+ && !self.is_unspecified() && !self.is_documentation()
+ }
+
+ /// Returns the address's multicast scope if the address is multicast.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(ip)]
+ ///
+ /// use std::net::{Ipv6Addr, Ipv6MulticastScope};
+ ///
+ /// fn main() {
+ /// assert_eq!(Ipv6Addr::new(0xff0e, 0, 0, 0, 0, 0, 0, 0).multicast_scope(),
+ /// Some(Ipv6MulticastScope::Global));
+ /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).multicast_scope(), None);
+ /// }
+ /// ```
+ pub fn multicast_scope(&self) -> Option<Ipv6MulticastScope> {
+ if self.is_multicast() {
+ match self.segments()[0] & 0x000f {
+ 1 => Some(Ipv6MulticastScope::InterfaceLocal),
+ 2 => Some(Ipv6MulticastScope::LinkLocal),
+ 3 => Some(Ipv6MulticastScope::RealmLocal),
+ 4 => Some(Ipv6MulticastScope::AdminLocal),
+ 5 => Some(Ipv6MulticastScope::SiteLocal),
+ 8 => Some(Ipv6MulticastScope::OrganizationLocal),
+ 14 => Some(Ipv6MulticastScope::Global),
+ _ => None
+ }
+ } else {
+ None
+ }
+ }
+
+ /// Returns [`true`] if this is a multicast address (ff00::/8).
+ ///
+ /// This property is defined by [IETF RFC 4291].
+ ///
+ /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291
+ /// [`true`]: ../../std/primitive.bool.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::Ipv6Addr;
+ ///
+ /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).is_multicast(), true);
+ /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_multicast(), false);
+ /// ```
+ #[stable(since = "1.7.0", feature = "ip_17")]
+ pub fn is_multicast(&self) -> bool {
+ (self.segments()[0] & 0xff00) == 0xff00
+ }
+
+ /// Converts this address to an [IPv4 address]. Returns [`None`] if this address is
+ /// neither IPv4-compatible or IPv4-mapped.
+ ///
+ /// ::a.b.c.d and ::ffff:a.b.c.d become a.b.c.d
+ ///
+ /// [IPv4 address]: ../../std/net/struct.Ipv4Addr.html
+ /// [`None`]: ../../std/option/enum.Option.html#variant.None
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::{Ipv4Addr, Ipv6Addr};
+ ///
+ /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).to_ipv4(), None);
+ /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).to_ipv4(),
+ /// Some(Ipv4Addr::new(192, 10, 2, 255)));
+ /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1).to_ipv4(),
+ /// Some(Ipv4Addr::new(0, 0, 0, 1)));
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn to_ipv4(&self) -> Option<Ipv4Addr> {
+ match self.segments() {
+ [0, 0, 0, 0, 0, f, g, h] if f == 0 || f == 0xffff => {
+ Some(Ipv4Addr::new((g >> 8) as u8, g as u8,
+ (h >> 8) as u8, h as u8))
+ },
+ _ => None
+ }
+ }
+
+ /// Returns the sixteen eight-bit integers the IPv6 address consists of.
+ ///
+ /// ```
+ /// use std::net::Ipv6Addr;
+ ///
+ /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).octets(),
+ /// [255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
+ /// ```
+ #[stable(feature = "ipv6_to_octets", since = "1.12.0")]
+ pub const fn octets(&self) -> [u8; 16] {
+ self.inner.s6_addr
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl fmt::Display for Ipv6Addr {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self.segments() {
+ // We need special cases for :: and ::1, otherwise they're formatted
+ // as ::0.0.0.[01]
+ [0, 0, 0, 0, 0, 0, 0, 0] => write!(fmt, "::"),
+ [0, 0, 0, 0, 0, 0, 0, 1] => write!(fmt, "::1"),
+ // Ipv4 Compatible address
+ [0, 0, 0, 0, 0, 0, g, h] => {
+ write!(fmt, "::{}.{}.{}.{}", (g >> 8) as u8, g as u8,
+ (h >> 8) as u8, h as u8)
+ }
+ // Ipv4-Mapped address
+ [0, 0, 0, 0, 0, 0xffff, g, h] => {
+ write!(fmt, "::ffff:{}.{}.{}.{}", (g >> 8) as u8, g as u8,
+ (h >> 8) as u8, h as u8)
+ },
+ _ => {
+ fn find_zero_slice(segments: &[u16; 8]) -> (usize, usize) {
+ let mut longest_span_len = 0;
+ let mut longest_span_at = 0;
+ let mut cur_span_len = 0;
+ let mut cur_span_at = 0;
+
+ for i in 0..8 {
+ if segments[i] == 0 {
+ if cur_span_len == 0 {
+ cur_span_at = i;
+ }
+
+ cur_span_len += 1;
+
+ if cur_span_len > longest_span_len {
+ longest_span_len = cur_span_len;
+ longest_span_at = cur_span_at;
+ }
+ } else {
+ cur_span_len = 0;
+ cur_span_at = 0;
+ }
+ }
+
+ (longest_span_at, longest_span_len)
+ }
+
+ let (zeros_at, zeros_len) = find_zero_slice(&self.segments());
+
+ if zeros_len > 1 {
+ fn fmt_subslice(segments: &[u16], fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ if !segments.is_empty() {
+ write!(fmt, "{:x}", segments[0])?;
+ for &seg in &segments[1..] {
+ write!(fmt, ":{:x}", seg)?;
+ }
+ }
+ Ok(())
+ }
+
+ fmt_subslice(&self.segments()[..zeros_at], fmt)?;
+ fmt.write_str("::")?;
+ fmt_subslice(&self.segments()[zeros_at + zeros_len..], fmt)
+ } else {
+ let &[a, b, c, d, e, f, g, h] = &self.segments();
+ write!(fmt, "{:x}:{:x}:{:x}:{:x}:{:x}:{:x}:{:x}:{:x}",
+ a, b, c, d, e, f, g, h)
+ }
+ }
+ }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl fmt::Debug for Ipv6Addr {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt::Display::fmt(self, fmt)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Clone for Ipv6Addr {
+ fn clone(&self) -> Ipv6Addr { *self }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl PartialEq for Ipv6Addr {
+ fn eq(&self, other: &Ipv6Addr) -> bool {
+ self.inner.s6_addr == other.inner.s6_addr
+ }
+}
+
+#[stable(feature = "ip_cmp", since = "1.16.0")]
+impl PartialEq<IpAddr> for Ipv6Addr {
+ fn eq(&self, other: &IpAddr) -> bool {
+ match other {
+ IpAddr::V4(_) => false,
+ IpAddr::V6(v6) => self == v6,
+ }
+ }
+}
+
+#[stable(feature = "ip_cmp", since = "1.16.0")]
+impl PartialEq<Ipv6Addr> for IpAddr {
+ fn eq(&self, other: &Ipv6Addr) -> bool {
+ match self {
+ IpAddr::V4(_) => false,
+ IpAddr::V6(v6) => v6 == other,
+ }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Eq for Ipv6Addr {}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl hash::Hash for Ipv6Addr {
+ fn hash<H: hash::Hasher>(&self, s: &mut H) {
+ self.inner.s6_addr.hash(s)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl PartialOrd for Ipv6Addr {
+ fn partial_cmp(&self, other: &Ipv6Addr) -> Option<Ordering> {
+ Some(self.cmp(other))
+ }
+}
+
+#[stable(feature = "ip_cmp", since = "1.16.0")]
+impl PartialOrd<Ipv6Addr> for IpAddr {
+ fn partial_cmp(&self, other: &Ipv6Addr) -> Option<Ordering> {
+ match self {
+ IpAddr::V4(_) => Some(Ordering::Less),
+ IpAddr::V6(v6) => v6.partial_cmp(other),
+ }
+ }
+}
+
+#[stable(feature = "ip_cmp", since = "1.16.0")]
+impl PartialOrd<IpAddr> for Ipv6Addr {
+ fn partial_cmp(&self, other: &IpAddr) -> Option<Ordering> {
+ match other {
+ IpAddr::V4(_) => Some(Ordering::Greater),
+ IpAddr::V6(v6) => self.partial_cmp(v6),
+ }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Ord for Ipv6Addr {
+ fn cmp(&self, other: &Ipv6Addr) -> Ordering {
+ self.segments().cmp(&other.segments())
+ }
+}
+
+impl AsInner<c::in6_addr> for Ipv6Addr {
+ fn as_inner(&self) -> &c::in6_addr { &self.inner }
+}
+impl FromInner<c::in6_addr> for Ipv6Addr {
+ fn from_inner(addr: c::in6_addr) -> Ipv6Addr {
+ Ipv6Addr { inner: addr }
+ }
+}
+
+#[stable(feature = "i128", since = "1.26.0")]
+impl From<Ipv6Addr> for u128 {
+ /// Convert an `Ipv6Addr` into a host byte order `u128`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::Ipv6Addr;
+ ///
+ /// let addr = Ipv6Addr::new(
+ /// 0x1020, 0x3040, 0x5060, 0x7080,
+ /// 0x90A0, 0xB0C0, 0xD0E0, 0xF00D,
+ /// );
+ /// assert_eq!(0x102030405060708090A0B0C0D0E0F00D_u128, u128::from(addr));
+ /// ```
+ fn from(ip: Ipv6Addr) -> u128 {
+ let ip = ip.octets();
+ u128::from_be_bytes(ip)
+ }
+}
+#[stable(feature = "i128", since = "1.26.0")]
+impl From<u128> for Ipv6Addr {
+ /// Convert a host byte order `u128` into an `Ipv6Addr`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::Ipv6Addr;
+ ///
+ /// let addr = Ipv6Addr::from(0x102030405060708090A0B0C0D0E0F00D_u128);
+ /// assert_eq!(
+ /// Ipv6Addr::new(
+ /// 0x1020, 0x3040, 0x5060, 0x7080,
+ /// 0x90A0, 0xB0C0, 0xD0E0, 0xF00D,
+ /// ),
+ /// addr);
+ /// ```
+ fn from(ip: u128) -> Ipv6Addr {
+ Ipv6Addr::from(ip.to_be_bytes())
+ }
+}
+
+#[stable(feature = "ipv6_from_octets", since = "1.9.0")]
+impl From<[u8; 16]> for Ipv6Addr {
+ fn from(octets: [u8; 16]) -> Ipv6Addr {
+ let inner = c::in6_addr { s6_addr: octets };
+ Ipv6Addr::from_inner(inner)
+ }
+}
+
+#[stable(feature = "ipv6_from_segments", since = "1.16.0")]
+impl From<[u16; 8]> for Ipv6Addr {
+ fn from(segments: [u16; 8]) -> Ipv6Addr {
+ let [a, b, c, d, e, f, g, h] = segments;
+ Ipv6Addr::new(a, b, c, d, e, f, g, h)
+ }
+}
+
+
+#[stable(feature = "ip_from_slice", since = "1.17.0")]
+impl From<[u8; 16]> for IpAddr {
+ /// Creates an `IpAddr::V6` from a sixteen element byte array.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::{IpAddr, Ipv6Addr};
+ ///
+ /// let addr = IpAddr::from([
+ /// 25u8, 24u8, 23u8, 22u8, 21u8, 20u8, 19u8, 18u8,
+ /// 17u8, 16u8, 15u8, 14u8, 13u8, 12u8, 11u8, 10u8,
+ /// ]);
+ /// assert_eq!(
+ /// IpAddr::V6(Ipv6Addr::new(
+ /// 0x1918, 0x1716,
+ /// 0x1514, 0x1312,
+ /// 0x1110, 0x0f0e,
+ /// 0x0d0c, 0x0b0a
+ /// )),
+ /// addr
+ /// );
+ /// ```
+ fn from(octets: [u8; 16]) -> IpAddr {
+ IpAddr::V6(Ipv6Addr::from(octets))
+ }
+}
+
+#[stable(feature = "ip_from_slice", since = "1.17.0")]
+impl From<[u16; 8]> for IpAddr {
+ /// Creates an `IpAddr::V6` from an eight element 16-bit array.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::{IpAddr, Ipv6Addr};
+ ///
+ /// let addr = IpAddr::from([
+ /// 525u16, 524u16, 523u16, 522u16,
+ /// 521u16, 520u16, 519u16, 518u16,
+ /// ]);
+ /// assert_eq!(
+ /// IpAddr::V6(Ipv6Addr::new(
+ /// 0x20d, 0x20c,
+ /// 0x20b, 0x20a,
+ /// 0x209, 0x208,
+ /// 0x207, 0x206
+ /// )),
+ /// addr
+ /// );
+ /// ```
+ fn from(segments: [u16; 8]) -> IpAddr {
+ IpAddr::V6(Ipv6Addr::from(segments))
+ }
+}
+
+// Tests for this module
+#[cfg(all(test, not(target_os = "emscripten")))]
+mod tests {
+ use crate::net::*;
+ use crate::net::Ipv6MulticastScope::*;
+ use crate::net::test::{tsa, sa6, sa4};
+
+ #[test]
+ fn test_from_str_ipv4() {
+ assert_eq!(Ok(Ipv4Addr::new(127, 0, 0, 1)), "127.0.0.1".parse());
+ assert_eq!(Ok(Ipv4Addr::new(255, 255, 255, 255)), "255.255.255.255".parse());
+ assert_eq!(Ok(Ipv4Addr::new(0, 0, 0, 0)), "0.0.0.0".parse());
+
+ // out of range
+ let none: Option<Ipv4Addr> = "256.0.0.1".parse().ok();
+ assert_eq!(None, none);
+ // too short
+ let none: Option<Ipv4Addr> = "255.0.0".parse().ok();
+ assert_eq!(None, none);
+ // too long
+ let none: Option<Ipv4Addr> = "255.0.0.1.2".parse().ok();
+ assert_eq!(None, none);
+ // no number between dots
+ let none: Option<Ipv4Addr> = "255.0..1".parse().ok();
+ assert_eq!(None, none);
+ }
+
+ #[test]
+ fn test_from_str_ipv6() {
+ assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)), "0:0:0:0:0:0:0:0".parse());
+ assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)), "0:0:0:0:0:0:0:1".parse());
+
+ assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)), "::1".parse());
+ assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)), "::".parse());
+
+ assert_eq!(Ok(Ipv6Addr::new(0x2a02, 0x6b8, 0, 0, 0, 0, 0x11, 0x11)),
+ "2a02:6b8::11:11".parse());
+
+ // too long group
+ let none: Option<Ipv6Addr> = "::00000".parse().ok();
+ assert_eq!(None, none);
+ // too short
+ let none: Option<Ipv6Addr> = "1:2:3:4:5:6:7".parse().ok();
+ assert_eq!(None, none);
+ // too long
+ let none: Option<Ipv6Addr> = "1:2:3:4:5:6:7:8:9".parse().ok();
+ assert_eq!(None, none);
+ // triple colon
+ let none: Option<Ipv6Addr> = "1:2:::6:7:8".parse().ok();
+ assert_eq!(None, none);
+ // two double colons
+ let none: Option<Ipv6Addr> = "1:2::6::8".parse().ok();
+ assert_eq!(None, none);
+ // `::` indicating zero groups of zeros
+ let none: Option<Ipv6Addr> = "1:2:3:4::5:6:7:8".parse().ok();
+ assert_eq!(None, none);
+ }
+
+ #[test]
+ fn test_from_str_ipv4_in_ipv6() {
+ assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 49152, 545)),
+ "::192.0.2.33".parse());
+ assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0xFFFF, 49152, 545)),
+ "::FFFF:192.0.2.33".parse());
+ assert_eq!(Ok(Ipv6Addr::new(0x64, 0xff9b, 0, 0, 0, 0, 49152, 545)),
+ "64:ff9b::192.0.2.33".parse());
+ assert_eq!(Ok(Ipv6Addr::new(0x2001, 0xdb8, 0x122, 0xc000, 0x2, 0x2100, 49152, 545)),
+ "2001:db8:122:c000:2:2100:192.0.2.33".parse());
+
+ // colon after v4
+ let none: Option<Ipv4Addr> = "::127.0.0.1:".parse().ok();
+ assert_eq!(None, none);
+ // not enough groups
+ let none: Option<Ipv6Addr> = "1.2.3.4.5:127.0.0.1".parse().ok();
+ assert_eq!(None, none);
+ // too many groups
+ let none: Option<Ipv6Addr> = "1.2.3.4.5:6:7:127.0.0.1".parse().ok();
+ assert_eq!(None, none);
+ }
+
+ #[test]
+ fn test_from_str_socket_addr() {
+ assert_eq!(Ok(sa4(Ipv4Addr::new(77, 88, 21, 11), 80)),
+ "77.88.21.11:80".parse());
+ assert_eq!(Ok(SocketAddrV4::new(Ipv4Addr::new(77, 88, 21, 11), 80)),
+ "77.88.21.11:80".parse());
+ assert_eq!(Ok(sa6(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 53)),
+ "[2a02:6b8:0:1::1]:53".parse());
+ assert_eq!(Ok(SocketAddrV6::new(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1,
+ 0, 0, 0, 1), 53, 0, 0)),
+ "[2a02:6b8:0:1::1]:53".parse());
+ assert_eq!(Ok(sa6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x7F00, 1), 22)),
+ "[::127.0.0.1]:22".parse());
+ assert_eq!(Ok(SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0,
+ 0x7F00, 1), 22, 0, 0)),
+ "[::127.0.0.1]:22".parse());
+
+ // without port
+ let none: Option<SocketAddr> = "127.0.0.1".parse().ok();
+ assert_eq!(None, none);
+ // without port
+ let none: Option<SocketAddr> = "127.0.0.1:".parse().ok();
+ assert_eq!(None, none);
+ // wrong brackets around v4
+ let none: Option<SocketAddr> = "[127.0.0.1]:22".parse().ok();
+ assert_eq!(None, none);
+ // port out of range
+ let none: Option<SocketAddr> = "127.0.0.1:123456".parse().ok();
+ assert_eq!(None, none);
+ }
+
+ #[test]
+ fn ipv6_addr_to_string() {
+ // ipv4-mapped address
+ let a1 = Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc000, 0x280);
+ assert_eq!(a1.to_string(), "::ffff:192.0.2.128");
+
+ // ipv4-compatible address
+ let a1 = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0xc000, 0x280);
+ assert_eq!(a1.to_string(), "::192.0.2.128");
+
+ // v6 address with no zero segments
+ assert_eq!(Ipv6Addr::new(8, 9, 10, 11, 12, 13, 14, 15).to_string(),
+ "8:9:a:b:c:d:e:f");
+
+ // reduce a single run of zeros
+ assert_eq!("ae::ffff:102:304",
+ Ipv6Addr::new(0xae, 0, 0, 0, 0, 0xffff, 0x0102, 0x0304).to_string());
+
+ // don't reduce just a single zero segment
+ assert_eq!("1:2:3:4:5:6:0:8",
+ Ipv6Addr::new(1, 2, 3, 4, 5, 6, 0, 8).to_string());
+
+ // 'any' address
+ assert_eq!("::", Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0).to_string());
+
+ // loopback address
+ assert_eq!("::1", Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1).to_string());
+
+ // ends in zeros
+ assert_eq!("1::", Ipv6Addr::new(1, 0, 0, 0, 0, 0, 0, 0).to_string());
+
+ // two runs of zeros, second one is longer
+ assert_eq!("1:0:0:4::8", Ipv6Addr::new(1, 0, 0, 4, 0, 0, 0, 8).to_string());
+
+ // two runs of zeros, equal length
+ assert_eq!("1::4:5:0:0:8", Ipv6Addr::new(1, 0, 0, 4, 5, 0, 0, 8).to_string());
+ }
+
+ #[test]
+ fn ipv4_to_ipv6() {
+ assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678),
+ Ipv4Addr::new(0x12, 0x34, 0x56, 0x78).to_ipv6_mapped());
+ assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x1234, 0x5678),
+ Ipv4Addr::new(0x12, 0x34, 0x56, 0x78).to_ipv6_compatible());
+ }
+
+ #[test]
+ fn ipv6_to_ipv4() {
+ assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678).to_ipv4(),
+ Some(Ipv4Addr::new(0x12, 0x34, 0x56, 0x78)));
+ assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x1234, 0x5678).to_ipv4(),
+ Some(Ipv4Addr::new(0x12, 0x34, 0x56, 0x78)));
+ assert_eq!(Ipv6Addr::new(0, 0, 1, 0, 0, 0, 0x1234, 0x5678).to_ipv4(),
+ None);
+ }
+
+ #[test]
+ fn ip_properties() {
+ fn check4(octets: &[u8; 4], unspec: bool, loopback: bool,
+ global: bool, multicast: bool, documentation: bool) {
+ let ip = IpAddr::V4(Ipv4Addr::new(octets[0], octets[1], octets[2], octets[3]));
+ assert_eq!(ip.is_unspecified(), unspec);
+ assert_eq!(ip.is_loopback(), loopback);
+ assert_eq!(ip.is_global(), global);
+ assert_eq!(ip.is_multicast(), multicast);
+ assert_eq!(ip.is_documentation(), documentation);
+ }
+
+ fn check6(str_addr: &str, unspec: bool, loopback: bool,
+ global: bool, u_doc: bool, mcast: bool) {
+ let ip = IpAddr::V6(str_addr.parse().unwrap());
+ assert_eq!(ip.is_unspecified(), unspec);
+ assert_eq!(ip.is_loopback(), loopback);
+ assert_eq!(ip.is_global(), global);
+ assert_eq!(ip.is_documentation(), u_doc);
+ assert_eq!(ip.is_multicast(), mcast);
+ }
+
+ // address unspec loopbk global multicast doc
+ check4(&[0, 0, 0, 0], true, false, false, false, false);
+ check4(&[0, 0, 0, 1], false, false, true, false, false);
+ check4(&[0, 1, 0, 0], false, false, true, false, false);
+ check4(&[10, 9, 8, 7], false, false, false, false, false);
+ check4(&[127, 1, 2, 3], false, true, false, false, false);
+ check4(&[172, 31, 254, 253], false, false, false, false, false);
+ check4(&[169, 254, 253, 242], false, false, false, false, false);
+ check4(&[192, 0, 2, 183], false, false, false, false, true);
+ check4(&[192, 1, 2, 183], false, false, true, false, false);
+ check4(&[192, 168, 254, 253], false, false, false, false, false);
+ check4(&[198, 51, 100, 0], false, false, false, false, true);
+ check4(&[203, 0, 113, 0], false, false, false, false, true);
+ check4(&[203, 2, 113, 0], false, false, true, false, false);
+ check4(&[224, 0, 0, 0], false, false, true, true, false);
+ check4(&[239, 255, 255, 255], false, false, true, true, false);
+ check4(&[255, 255, 255, 255], false, false, false, false, false);
+
+ // address unspec loopbk global doc mcast
+ check6("::", true, false, false, false, false);
+ check6("::1", false, true, false, false, false);
+ check6("::0.0.0.2", false, false, true, false, false);
+ check6("1::", false, false, true, false, false);
+ check6("fc00::", false, false, false, false, false);
+ check6("fdff:ffff::", false, false, false, false, false);
+ check6("fe80:ffff::", false, false, false, false, false);
+ check6("febf:ffff::", false, false, false, false, false);
+ check6("fec0::", false, false, false, false, false);
+ check6("ff01::", false, false, false, false, true);
+ check6("ff02::", false, false, false, false, true);
+ check6("ff03::", false, false, false, false, true);
+ check6("ff04::", false, false, false, false, true);
+ check6("ff05::", false, false, false, false, true);
+ check6("ff08::", false, false, false, false, true);
+ check6("ff0e::", false, false, true, false, true);
+ check6("2001:db8:85a3::8a2e:370:7334", false, false, false, true, false);
+ check6("102:304:506:708:90a:b0c:d0e:f10", false, false, true, false, false);
+ }
+
+ #[test]
+ fn ipv4_properties() {
+ fn check(octets: &[u8; 4], unspec: bool, loopback: bool,
+ private: bool, link_local: bool, global: bool,
+ multicast: bool, broadcast: bool, documentation: bool) {
+ let ip = Ipv4Addr::new(octets[0], octets[1], octets[2], octets[3]);
+ assert_eq!(octets, &ip.octets());
+
+ assert_eq!(ip.is_unspecified(), unspec);
+ assert_eq!(ip.is_loopback(), loopback);
+ assert_eq!(ip.is_private(), private);
+ assert_eq!(ip.is_link_local(), link_local);
+ assert_eq!(ip.is_global(), global);
+ assert_eq!(ip.is_multicast(), multicast);
+ assert_eq!(ip.is_broadcast(), broadcast);
+ assert_eq!(ip.is_documentation(), documentation);
+ }
+
+ // address unspec loopbk privt linloc global multicast brdcast doc
+ check(&[0, 0, 0, 0], true, false, false, false, false, false, false, false);
+ check(&[0, 0, 0, 1], false, false, false, false, true, false, false, false);
+ check(&[0, 1, 0, 0], false, false, false, false, true, false, false, false);
+ check(&[10, 9, 8, 7], false, false, true, false, false, false, false, false);
+ check(&[127, 1, 2, 3], false, true, false, false, false, false, false, false);
+ check(&[172, 31, 254, 253], false, false, true, false, false, false, false, false);
+ check(&[169, 254, 253, 242], false, false, false, true, false, false, false, false);
+ check(&[192, 0, 2, 183], false, false, false, false, false, false, false, true);
+ check(&[192, 1, 2, 183], false, false, false, false, true, false, false, false);
+ check(&[192, 168, 254, 253], false, false, true, false, false, false, false, false);
+ check(&[198, 51, 100, 0], false, false, false, false, false, false, false, true);
+ check(&[203, 0, 113, 0], false, false, false, false, false, false, false, true);
+ check(&[203, 2, 113, 0], false, false, false, false, true, false, false, false);
+ check(&[224, 0, 0, 0], false, false, false, false, true, true, false, false);
+ check(&[239, 255, 255, 255], false, false, false, false, true, true, false, false);
+ check(&[255, 255, 255, 255], false, false, false, false, false, false, true, false);
+ }
+
+ #[test]
+ fn ipv6_properties() {
+ fn check(str_addr: &str, octets: &[u8; 16], unspec: bool, loopback: bool,
+ unique_local: bool, global: bool,
+ u_link_local: bool, u_site_local: bool, u_global: bool, u_doc: bool,
+ m_scope: Option<Ipv6MulticastScope>) {
+ let ip: Ipv6Addr = str_addr.parse().unwrap();
+ assert_eq!(str_addr, ip.to_string());
+ assert_eq!(&ip.octets(), octets);
+ assert_eq!(Ipv6Addr::from(*octets), ip);
+
+ assert_eq!(ip.is_unspecified(), unspec);
+ assert_eq!(ip.is_loopback(), loopback);
+ assert_eq!(ip.is_unique_local(), unique_local);
+ assert_eq!(ip.is_global(), global);
+ assert_eq!(ip.is_unicast_link_local(), u_link_local);
+ assert_eq!(ip.is_unicast_site_local(), u_site_local);
+ assert_eq!(ip.is_unicast_global(), u_global);
+ assert_eq!(ip.is_documentation(), u_doc);
+ assert_eq!(ip.multicast_scope(), m_scope);
+ assert_eq!(ip.is_multicast(), m_scope.is_some());
+ }
+
+ // unspec loopbk uniqlo global unill unisl uniglo doc mscope
+ check("::", &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ true, false, false, false, false, false, false, false, None);
+ check("::1", &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
+ false, true, false, false, false, false, false, false, None);
+ check("::0.0.0.2", &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2],
+ false, false, false, true, false, false, true, false, None);
+ check("1::", &[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ false, false, false, true, false, false, true, false, None);
+ check("fc00::", &[0xfc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ false, false, true, false, false, false, false, false, None);
+ check("fdff:ffff::", &[0xfd, 0xff, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ false, false, true, false, false, false, false, false, None);
+ check("fe80:ffff::", &[0xfe, 0x80, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ false, false, false, false, true, false, false, false, None);
+ check("febf:ffff::", &[0xfe, 0xbf, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ false, false, false, false, true, false, false, false, None);
+ check("fec0::", &[0xfe, 0xc0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ false, false, false, false, false, true, false, false, None);
+ check("ff01::", &[0xff, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ false, false, false, false, false, false, false, false, Some(InterfaceLocal));
+ check("ff02::", &[0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ false, false, false, false, false, false, false, false, Some(LinkLocal));
+ check("ff03::", &[0xff, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ false, false, false, false, false, false, false, false, Some(RealmLocal));
+ check("ff04::", &[0xff, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ false, false, false, false, false, false, false, false, Some(AdminLocal));
+ check("ff05::", &[0xff, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ false, false, false, false, false, false, false, false, Some(SiteLocal));
+ check("ff08::", &[0xff, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ false, false, false, false, false, false, false, false, Some(OrganizationLocal));
+ check("ff0e::", &[0xff, 0xe, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ false, false, false, true, false, false, false, false, Some(Global));
+ check("2001:db8:85a3::8a2e:370:7334",
+ &[0x20, 1, 0xd, 0xb8, 0x85, 0xa3, 0, 0, 0, 0, 0x8a, 0x2e, 3, 0x70, 0x73, 0x34],
+ false, false, false, false, false, false, false, true, None);
+ check("102:304:506:708:90a:b0c:d0e:f10",
+ &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
+ false, false, false, true, false, false, true, false, None);
+ }
+
+ #[test]
+ fn to_socket_addr_socketaddr() {
+ let a = sa4(Ipv4Addr::new(77, 88, 21, 11), 12345);
+ assert_eq!(Ok(vec![a]), tsa(a));
+ }
+
+ #[test]
+ fn test_ipv4_to_int() {
+ let a = Ipv4Addr::new(0x11, 0x22, 0x33, 0x44);
+ assert_eq!(u32::from(a), 0x11223344);
+ }
+
+ #[test]
+ fn test_int_to_ipv4() {
+ let a = Ipv4Addr::new(0x11, 0x22, 0x33, 0x44);
+ assert_eq!(Ipv4Addr::from(0x11223344), a);
+ }
+
+ #[test]
+ fn test_ipv6_to_int() {
+ let a = Ipv6Addr::new(0x1122, 0x3344, 0x5566, 0x7788, 0x99aa, 0xbbcc, 0xddee, 0xff11);
+ assert_eq!(u128::from(a), 0x112233445566778899aabbccddeeff11u128);
+ }
+
+ #[test]
+ fn test_int_to_ipv6() {
+ let a = Ipv6Addr::new(0x1122, 0x3344, 0x5566, 0x7788, 0x99aa, 0xbbcc, 0xddee, 0xff11);
+ assert_eq!(Ipv6Addr::from(0x112233445566778899aabbccddeeff11u128), a);
+ }
+
+ #[test]
+ fn ipv4_from_constructors() {
+ assert_eq!(Ipv4Addr::LOCALHOST, Ipv4Addr::new(127, 0, 0, 1));
+ assert!(Ipv4Addr::LOCALHOST.is_loopback());
+ assert_eq!(Ipv4Addr::UNSPECIFIED, Ipv4Addr::new(0, 0, 0, 0));
+ assert!(Ipv4Addr::UNSPECIFIED.is_unspecified());
+ assert_eq!(Ipv4Addr::BROADCAST, Ipv4Addr::new(255, 255, 255, 255));
+ assert!(Ipv4Addr::BROADCAST.is_broadcast());
+ }
+
+ #[test]
+ fn ipv6_from_contructors() {
+ assert_eq!(Ipv6Addr::LOCALHOST, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1));
+ assert!(Ipv6Addr::LOCALHOST.is_loopback());
+ assert_eq!(Ipv6Addr::UNSPECIFIED, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0));
+ assert!(Ipv6Addr::UNSPECIFIED.is_unspecified());
+ }
+
+ #[test]
+ fn ipv4_from_octets() {
+ assert_eq!(Ipv4Addr::from([127, 0, 0, 1]), Ipv4Addr::new(127, 0, 0, 1))
+ }
+
+ #[test]
+ fn ipv6_from_segments() {
+ let from_u16s = Ipv6Addr::from([0x0011, 0x2233, 0x4455, 0x6677,
+ 0x8899, 0xaabb, 0xccdd, 0xeeff]);
+ let new = Ipv6Addr::new(0x0011, 0x2233, 0x4455, 0x6677,
+ 0x8899, 0xaabb, 0xccdd, 0xeeff);
+ assert_eq!(new, from_u16s);
+ }
+
+ #[test]
+ fn ipv6_from_octets() {
+ let from_u16s = Ipv6Addr::from([0x0011, 0x2233, 0x4455, 0x6677,
+ 0x8899, 0xaabb, 0xccdd, 0xeeff]);
+ let from_u8s = Ipv6Addr::from([0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+ 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff]);
+ assert_eq!(from_u16s, from_u8s);
+ }
+
+ #[test]
+ fn cmp() {
+ let v41 = Ipv4Addr::new(100, 64, 3, 3);
+ let v42 = Ipv4Addr::new(192, 0, 2, 2);
+ let v61 = "2001:db8:f00::1002".parse::<Ipv6Addr>().unwrap();
+ let v62 = "2001:db8:f00::2001".parse::<Ipv6Addr>().unwrap();
+ assert!(v41 < v42);
+ assert!(v61 < v62);
+
+ assert_eq!(v41, IpAddr::V4(v41));
+ assert_eq!(v61, IpAddr::V6(v61));
+ assert!(v41 != IpAddr::V4(v42));
+ assert!(v61 != IpAddr::V6(v62));
+
+ assert!(v41 < IpAddr::V4(v42));
+ assert!(v61 < IpAddr::V6(v62));
+ assert!(IpAddr::V4(v41) < v42);
+ assert!(IpAddr::V6(v61) < v62);
+
+ assert!(v41 < IpAddr::V6(v61));
+ assert!(IpAddr::V4(v41) < v61);
+ }
+
+ #[test]
+ fn is_v4() {
+ let ip = IpAddr::V4(Ipv4Addr::new(100, 64, 3, 3));
+ assert!(ip.is_ipv4());
+ assert!(!ip.is_ipv6());
+ }
+
+ #[test]
+ fn is_v6() {
+ let ip = IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678));
+ assert!(!ip.is_ipv4());
+ assert!(ip.is_ipv6());
+ }
+}
diff --git a/src/libstd/net/mod.rs b/src/libstd/net/mod.rs
new file mode 100644
index 0000000..b681469
--- /dev/null
+++ b/src/libstd/net/mod.rs
@@ -0,0 +1,122 @@
+//! Networking primitives for TCP/UDP communication.
+//!
+//! This module provides networking functionality for the Transmission Control and User
+//! Datagram Protocols, as well as types for IP and socket addresses.
+//!
+//! # Organization
+//!
+//! * [`TcpListener`] and [`TcpStream`] provide functionality for communication over TCP
+//! * [`UdpSocket`] provides functionality for communication over UDP
+//! * [`IpAddr`] represents IP addresses of either IPv4 or IPv6; [`Ipv4Addr`] and
+//! [`Ipv6Addr`] are respectively IPv4 and IPv6 addresses
+//! * [`SocketAddr`] represents socket addresses of either IPv4 or IPv6; [`SocketAddrV4`]
+//! and [`SocketAddrV6`] are respectively IPv4 and IPv6 socket addresses
+//! * [`ToSocketAddrs`] is a trait that used for generic address resolution when interacting
+//! with networking objects like [`TcpListener`], [`TcpStream`] or [`UdpSocket`]
+//! * Other types are return or parameter types for various methods in this module
+//!
+//! [`IpAddr`]: ../../std/net/enum.IpAddr.html
+//! [`Ipv4Addr`]: ../../std/net/struct.Ipv4Addr.html
+//! [`Ipv6Addr`]: ../../std/net/struct.Ipv6Addr.html
+//! [`SocketAddr`]: ../../std/net/enum.SocketAddr.html
+//! [`SocketAddrV4`]: ../../std/net/struct.SocketAddrV4.html
+//! [`SocketAddrV6`]: ../../std/net/struct.SocketAddrV6.html
+//! [`TcpListener`]: ../../std/net/struct.TcpListener.html
+//! [`TcpStream`]: ../../std/net/struct.TcpStream.html
+//! [`ToSocketAddrs`]: ../../std/net/trait.ToSocketAddrs.html
+//! [`UdpSocket`]: ../../std/net/struct.UdpSocket.html
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+use crate::io::{self, Error, ErrorKind};
+
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use self::ip::{IpAddr, Ipv4Addr, Ipv6Addr, Ipv6MulticastScope};
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use self::addr::{SocketAddr, SocketAddrV4, SocketAddrV6, ToSocketAddrs};
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use self::tcp::{TcpStream, TcpListener, Incoming};
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use self::udp::UdpSocket;
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use self::parser::AddrParseError;
+
+mod ip;
+mod addr;
+mod tcp;
+mod udp;
+mod parser;
+#[cfg(test)]
+mod test;
+
+/// Possible values which can be passed to the [`shutdown`] method of
+/// [`TcpStream`].
+///
+/// [`shutdown`]: struct.TcpStream.html#method.shutdown
+/// [`TcpStream`]: struct.TcpStream.html
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub enum Shutdown {
+ /// The reading portion of the [`TcpStream`] should be shut down.
+ ///
+ /// All currently blocked and future [reads] will return [`Ok(0)`].
+ ///
+ /// [`TcpStream`]: ../../std/net/struct.TcpStream.html
+ /// [reads]: ../../std/io/trait.Read.html
+ /// [`Ok(0)`]: ../../std/result/enum.Result.html#variant.Ok
+ #[stable(feature = "rust1", since = "1.0.0")]
+ Read,
+ /// The writing portion of the [`TcpStream`] should be shut down.
+ ///
+ /// All currently blocked and future [writes] will return an error.
+ ///
+ /// [`TcpStream`]: ../../std/net/struct.TcpStream.html
+ /// [writes]: ../../std/io/trait.Write.html
+ #[stable(feature = "rust1", since = "1.0.0")]
+ Write,
+ /// Both the reading and the writing portions of the [`TcpStream`] should be shut down.
+ ///
+ /// See [`Shutdown::Read`] and [`Shutdown::Write`] for more information.
+ ///
+ /// [`TcpStream`]: ../../std/net/struct.TcpStream.html
+ /// [`Shutdown::Read`]: #variant.Read
+ /// [`Shutdown::Write`]: #variant.Write
+ #[stable(feature = "rust1", since = "1.0.0")]
+ Both,
+}
+
+#[doc(hidden)]
+trait NetInt {
+ fn from_be(i: Self) -> Self;
+ fn to_be(&self) -> Self;
+}
+macro_rules! doit {
+ ($($t:ident)*) => ($(impl NetInt for $t {
+ fn from_be(i: Self) -> Self { <$t>::from_be(i) }
+ fn to_be(&self) -> Self { <$t>::to_be(*self) }
+ })*)
+}
+doit! { i8 i16 i32 i64 isize u8 u16 u32 u64 usize }
+
+fn hton<I: NetInt>(i: I) -> I { i.to_be() }
+fn ntoh<I: NetInt>(i: I) -> I { I::from_be(i) }
+
+fn each_addr<A: ToSocketAddrs, F, T>(addr: A, mut f: F) -> io::Result<T>
+ where F: FnMut(io::Result<&SocketAddr>) -> io::Result<T>
+{
+ let addrs = match addr.to_socket_addrs() {
+ Ok(addrs) => addrs,
+ Err(e) => return f(Err(e))
+ };
+ let mut last_err = None;
+ for addr in addrs {
+ match f(Ok(&addr)) {
+ Ok(l) => return Ok(l),
+ Err(e) => last_err = Some(e),
+ }
+ }
+ Err(last_err.unwrap_or_else(|| {
+ Error::new(ErrorKind::InvalidInput,
+ "could not resolve to any addresses")
+ }))
+}
diff --git a/src/libstd/net/parser.rs b/src/libstd/net/parser.rs
new file mode 100644
index 0000000..5a76139
--- /dev/null
+++ b/src/libstd/net/parser.rs
@@ -0,0 +1,404 @@
+//! A private parser implementation of IPv4, IPv6, and socket addresses.
+//!
+//! This module is "publicly exported" through the `FromStr` implementations
+//! below.
+
+use crate::error::Error;
+use crate::fmt;
+use crate::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
+use crate::str::FromStr;
+
+struct Parser<'a> {
+ // parsing as ASCII, so can use byte array
+ s: &'a [u8],
+ pos: usize,
+}
+
+impl<'a> Parser<'a> {
+ fn new(s: &'a str) -> Parser<'a> {
+ Parser {
+ s: s.as_bytes(),
+ pos: 0,
+ }
+ }
+
+ fn is_eof(&self) -> bool {
+ self.pos == self.s.len()
+ }
+
+ // Commit only if parser returns Some
+ fn read_atomically<T, F>(&mut self, cb: F) -> Option<T> where
+ F: FnOnce(&mut Parser<'_>) -> Option<T>,
+ {
+ let pos = self.pos;
+ let r = cb(self);
+ if r.is_none() {
+ self.pos = pos;
+ }
+ r
+ }
+
+ // Commit only if parser read till EOF
+ fn read_till_eof<T, F>(&mut self, cb: F) -> Option<T> where
+ F: FnOnce(&mut Parser<'_>) -> Option<T>,
+ {
+ self.read_atomically(move |p| {
+ cb(p).filter(|_| p.is_eof())
+ })
+ }
+
+ // Return result of first successful parser
+ fn read_or<T>(&mut self, parsers: &mut [Box<dyn FnMut(&mut Parser<'_>) -> Option<T> + 'static>])
+ -> Option<T> {
+ for pf in parsers {
+ if let Some(r) = self.read_atomically(|p: &mut Parser<'_>| pf(p)) {
+ return Some(r);
+ }
+ }
+ None
+ }
+
+ // Apply 3 parsers sequentially
+ fn read_seq_3<A, B, C, PA, PB, PC>(&mut self,
+ pa: PA,
+ pb: PB,
+ pc: PC)
+ -> Option<(A, B, C)> where
+ PA: FnOnce(&mut Parser<'_>) -> Option<A>,
+ PB: FnOnce(&mut Parser<'_>) -> Option<B>,
+ PC: FnOnce(&mut Parser<'_>) -> Option<C>,
+ {
+ self.read_atomically(move |p| {
+ let a = pa(p);
+ let b = if a.is_some() { pb(p) } else { None };
+ let c = if b.is_some() { pc(p) } else { None };
+ match (a, b, c) {
+ (Some(a), Some(b), Some(c)) => Some((a, b, c)),
+ _ => None
+ }
+ })
+ }
+
+ // Read next char
+ fn read_char(&mut self) -> Option<char> {
+ if self.is_eof() {
+ None
+ } else {
+ let r = self.s[self.pos] as char;
+ self.pos += 1;
+ Some(r)
+ }
+ }
+
+ // Return char and advance iff next char is equal to requested
+ fn read_given_char(&mut self, c: char) -> Option<char> {
+ self.read_atomically(|p| {
+ match p.read_char() {
+ Some(next) if next == c => Some(next),
+ _ => None,
+ }
+ })
+ }
+
+ // Read digit
+ fn read_digit(&mut self, radix: u8) -> Option<u8> {
+ fn parse_digit(c: char, radix: u8) -> Option<u8> {
+ let c = c as u8;
+ // assuming radix is either 10 or 16
+ if c >= b'0' && c <= b'9' {
+ Some(c - b'0')
+ } else if radix > 10 && c >= b'a' && c < b'a' + (radix - 10) {
+ Some(c - b'a' + 10)
+ } else if radix > 10 && c >= b'A' && c < b'A' + (radix - 10) {
+ Some(c - b'A' + 10)
+ } else {
+ None
+ }
+ }
+
+ self.read_atomically(|p| {
+ p.read_char().and_then(|c| parse_digit(c, radix))
+ })
+ }
+
+ fn read_number_impl(&mut self, radix: u8, max_digits: u32, upto: u32) -> Option<u32> {
+ let mut r = 0;
+ let mut digit_count = 0;
+ loop {
+ match self.read_digit(radix) {
+ Some(d) => {
+ r = r * (radix as u32) + (d as u32);
+ digit_count += 1;
+ if digit_count > max_digits || r >= upto {
+ return None
+ }
+ }
+ None => {
+ if digit_count == 0 {
+ return None
+ } else {
+ return Some(r)
+ }
+ }
+ };
+ }
+ }
+
+ // Read number, failing if max_digits of number value exceeded
+ fn read_number(&mut self, radix: u8, max_digits: u32, upto: u32) -> Option<u32> {
+ self.read_atomically(|p| p.read_number_impl(radix, max_digits, upto))
+ }
+
+ fn read_ipv4_addr_impl(&mut self) -> Option<Ipv4Addr> {
+ let mut bs = [0; 4];
+ let mut i = 0;
+ while i < 4 {
+ if i != 0 && self.read_given_char('.').is_none() {
+ return None;
+ }
+
+ bs[i] = self.read_number(10, 3, 0x100).map(|n| n as u8)?;
+ i += 1;
+ }
+ Some(Ipv4Addr::new(bs[0], bs[1], bs[2], bs[3]))
+ }
+
+ // Read IPv4 address
+ fn read_ipv4_addr(&mut self) -> Option<Ipv4Addr> {
+ self.read_atomically(|p| p.read_ipv4_addr_impl())
+ }
+
+ fn read_ipv6_addr_impl(&mut self) -> Option<Ipv6Addr> {
+ fn ipv6_addr_from_head_tail(head: &[u16], tail: &[u16]) -> Ipv6Addr {
+ assert!(head.len() + tail.len() <= 8);
+ let mut gs = [0; 8];
+ gs[..head.len()].copy_from_slice(head);
+ gs[(8 - tail.len()) .. 8].copy_from_slice(tail);
+ Ipv6Addr::new(gs[0], gs[1], gs[2], gs[3], gs[4], gs[5], gs[6], gs[7])
+ }
+
+ fn read_groups(p: &mut Parser<'_>, groups: &mut [u16; 8], limit: usize)
+ -> (usize, bool) {
+ let mut i = 0;
+ while i < limit {
+ if i < limit - 1 {
+ let ipv4 = p.read_atomically(|p| {
+ if i == 0 || p.read_given_char(':').is_some() {
+ p.read_ipv4_addr()
+ } else {
+ None
+ }
+ });
+ if let Some(v4_addr) = ipv4 {
+ let octets = v4_addr.octets();
+ groups[i + 0] = ((octets[0] as u16) << 8) | (octets[1] as u16);
+ groups[i + 1] = ((octets[2] as u16) << 8) | (octets[3] as u16);
+ return (i + 2, true);
+ }
+ }
+
+ let group = p.read_atomically(|p| {
+ if i == 0 || p.read_given_char(':').is_some() {
+ p.read_number(16, 4, 0x10000).map(|n| n as u16)
+ } else {
+ None
+ }
+ });
+ match group {
+ Some(g) => groups[i] = g,
+ None => return (i, false)
+ }
+ i += 1;
+ }
+ (i, false)
+ }
+
+ let mut head = [0; 8];
+ let (head_size, head_ipv4) = read_groups(self, &mut head, 8);
+
+ if head_size == 8 {
+ return Some(Ipv6Addr::new(
+ head[0], head[1], head[2], head[3],
+ head[4], head[5], head[6], head[7]))
+ }
+
+ // IPv4 part is not allowed before `::`
+ if head_ipv4 {
+ return None
+ }
+
+ // read `::` if previous code parsed less than 8 groups
+ if !self.read_given_char(':').is_some() || !self.read_given_char(':').is_some() {
+ return None;
+ }
+
+ let mut tail = [0; 8];
+ // `::` indicates one or more groups of 16 bits of zeros
+ let limit = 8 - (head_size + 1);
+ let (tail_size, _) = read_groups(self, &mut tail, limit);
+ Some(ipv6_addr_from_head_tail(&head[..head_size], &tail[..tail_size]))
+ }
+
+ fn read_ipv6_addr(&mut self) -> Option<Ipv6Addr> {
+ self.read_atomically(|p| p.read_ipv6_addr_impl())
+ }
+
+ fn read_ip_addr(&mut self) -> Option<IpAddr> {
+ let ipv4_addr = |p: &mut Parser<'_>| p.read_ipv4_addr().map(IpAddr::V4);
+ let ipv6_addr = |p: &mut Parser<'_>| p.read_ipv6_addr().map(IpAddr::V6);
+ self.read_or(&mut [Box::new(ipv4_addr), Box::new(ipv6_addr)])
+ }
+
+ fn read_socket_addr_v4(&mut self) -> Option<SocketAddrV4> {
+ let ip_addr = |p: &mut Parser<'_>| p.read_ipv4_addr();
+ let colon = |p: &mut Parser<'_>| p.read_given_char(':');
+ let port = |p: &mut Parser<'_>| {
+ p.read_number(10, 5, 0x10000).map(|n| n as u16)
+ };
+
+ self.read_seq_3(ip_addr, colon, port).map(|t| {
+ let (ip, _, port): (Ipv4Addr, char, u16) = t;
+ SocketAddrV4::new(ip, port)
+ })
+ }
+
+ fn read_socket_addr_v6(&mut self) -> Option<SocketAddrV6> {
+ let ip_addr = |p: &mut Parser<'_>| {
+ let open_br = |p: &mut Parser<'_>| p.read_given_char('[');
+ let ip_addr = |p: &mut Parser<'_>| p.read_ipv6_addr();
+ let clos_br = |p: &mut Parser<'_>| p.read_given_char(']');
+ p.read_seq_3(open_br, ip_addr, clos_br).map(|t| t.1)
+ };
+ let colon = |p: &mut Parser<'_>| p.read_given_char(':');
+ let port = |p: &mut Parser<'_>| {
+ p.read_number(10, 5, 0x10000).map(|n| n as u16)
+ };
+
+ self.read_seq_3(ip_addr, colon, port).map(|t| {
+ let (ip, _, port): (Ipv6Addr, char, u16) = t;
+ SocketAddrV6::new(ip, port, 0, 0)
+ })
+ }
+
+ fn read_socket_addr(&mut self) -> Option<SocketAddr> {
+ let v4 = |p: &mut Parser<'_>| p.read_socket_addr_v4().map(SocketAddr::V4);
+ let v6 = |p: &mut Parser<'_>| p.read_socket_addr_v6().map(SocketAddr::V6);
+ self.read_or(&mut [Box::new(v4), Box::new(v6)])
+ }
+}
+
+#[stable(feature = "ip_addr", since = "1.7.0")]
+impl FromStr for IpAddr {
+ type Err = AddrParseError;
+ fn from_str(s: &str) -> Result<IpAddr, AddrParseError> {
+ match Parser::new(s).read_till_eof(|p| p.read_ip_addr()) {
+ Some(s) => Ok(s),
+ None => Err(AddrParseError(()))
+ }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl FromStr for Ipv4Addr {
+ type Err = AddrParseError;
+ fn from_str(s: &str) -> Result<Ipv4Addr, AddrParseError> {
+ match Parser::new(s).read_till_eof(|p| p.read_ipv4_addr()) {
+ Some(s) => Ok(s),
+ None => Err(AddrParseError(()))
+ }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl FromStr for Ipv6Addr {
+ type Err = AddrParseError;
+ fn from_str(s: &str) -> Result<Ipv6Addr, AddrParseError> {
+ match Parser::new(s).read_till_eof(|p| p.read_ipv6_addr()) {
+ Some(s) => Ok(s),
+ None => Err(AddrParseError(()))
+ }
+ }
+}
+
+#[stable(feature = "socket_addr_from_str", since = "1.5.0")]
+impl FromStr for SocketAddrV4 {
+ type Err = AddrParseError;
+ fn from_str(s: &str) -> Result<SocketAddrV4, AddrParseError> {
+ match Parser::new(s).read_till_eof(|p| p.read_socket_addr_v4()) {
+ Some(s) => Ok(s),
+ None => Err(AddrParseError(())),
+ }
+ }
+}
+
+#[stable(feature = "socket_addr_from_str", since = "1.5.0")]
+impl FromStr for SocketAddrV6 {
+ type Err = AddrParseError;
+ fn from_str(s: &str) -> Result<SocketAddrV6, AddrParseError> {
+ match Parser::new(s).read_till_eof(|p| p.read_socket_addr_v6()) {
+ Some(s) => Ok(s),
+ None => Err(AddrParseError(())),
+ }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl FromStr for SocketAddr {
+ type Err = AddrParseError;
+ fn from_str(s: &str) -> Result<SocketAddr, AddrParseError> {
+ match Parser::new(s).read_till_eof(|p| p.read_socket_addr()) {
+ Some(s) => Ok(s),
+ None => Err(AddrParseError(())),
+ }
+ }
+}
+
+/// An error which can be returned when parsing an IP address or a socket address.
+///
+/// This error is used as the error type for the [`FromStr`] implementation for
+/// [`IpAddr`], [`Ipv4Addr`], [`Ipv6Addr`], [`SocketAddr`], [`SocketAddrV4`], and
+/// [`SocketAddrV6`].
+///
+/// # Potential causes
+///
+/// `AddrParseError` may be thrown because the provided string does not parse as the given type,
+/// often because it includes information only handled by a different address type.
+///
+/// ```should_panic
+/// use std::net::IpAddr;
+/// let _foo: IpAddr = "127.0.0.1:8080".parse().expect("Cannot handle the socket port");
+/// ```
+///
+/// [`IpAddr`] doesn't handle the port. Use [`SocketAddr`] instead.
+///
+/// ```
+/// use std::net::SocketAddr;
+///
+/// // No problem, the `panic!` message has disappeared.
+/// let _foo: SocketAddr = "127.0.0.1:8080".parse().expect("unreachable panic");
+/// ```
+///
+/// [`FromStr`]: ../../std/str/trait.FromStr.html
+/// [`IpAddr`]: ../../std/net/enum.IpAddr.html
+/// [`Ipv4Addr`]: ../../std/net/struct.Ipv4Addr.html
+/// [`Ipv6Addr`]: ../../std/net/struct.Ipv6Addr.html
+/// [`SocketAddr`]: ../../std/net/enum.SocketAddr.html
+/// [`SocketAddrV4`]: ../../std/net/struct.SocketAddrV4.html
+/// [`SocketAddrV6`]: ../../std/net/struct.SocketAddrV6.html
+#[stable(feature = "rust1", since = "1.0.0")]
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct AddrParseError(());
+
+#[stable(feature = "addr_parse_error_error", since = "1.4.0")]
+impl fmt::Display for AddrParseError {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt.write_str(self.description())
+ }
+}
+
+#[stable(feature = "addr_parse_error_error", since = "1.4.0")]
+impl Error for AddrParseError {
+ fn description(&self) -> &str {
+ "invalid IP address syntax"
+ }
+}
diff --git a/src/libstd/net/tcp.rs b/src/libstd/net/tcp.rs
new file mode 100644
index 0000000..cb89288
--- /dev/null
+++ b/src/libstd/net/tcp.rs
@@ -0,0 +1,1783 @@
+use crate::io::prelude::*;
+
+use crate::fmt;
+use crate::io::{self, Initializer, IoVec, IoVecMut};
+use crate::net::{ToSocketAddrs, SocketAddr, Shutdown};
+use crate::sys_common::net as net_imp;
+use crate::sys_common::{AsInner, FromInner, IntoInner};
+use crate::time::Duration;
+
+/// A TCP stream between a local and a remote socket.
+///
+/// After creating a `TcpStream` by either [`connect`]ing to a remote host or
+/// [`accept`]ing a connection on a [`TcpListener`], data can be transmitted
+/// by [reading] and [writing] to it.
+///
+/// The connection will be closed when the value is dropped. The reading and writing
+/// portions of the connection can also be shut down individually with the [`shutdown`]
+/// method.
+///
+/// The Transmission Control Protocol is specified in [IETF RFC 793].
+///
+/// [`accept`]: ../../std/net/struct.TcpListener.html#method.accept
+/// [`connect`]: #method.connect
+/// [IETF RFC 793]: https://tools.ietf.org/html/rfc793
+/// [reading]: ../../std/io/trait.Read.html
+/// [`shutdown`]: #method.shutdown
+/// [`TcpListener`]: ../../std/net/struct.TcpListener.html
+/// [writing]: ../../std/io/trait.Write.html
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::io::prelude::*;
+/// use std::net::TcpStream;
+///
+/// fn main() -> std::io::Result<()> {
+/// let mut stream = TcpStream::connect("127.0.0.1:34254")?;
+///
+/// stream.write(&[1])?;
+/// stream.read(&mut [0; 128])?;
+/// Ok(())
+/// } // the stream is closed here
+/// ```
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct TcpStream(net_imp::TcpStream);
+
+/// A TCP socket server, listening for connections.
+///
+/// After creating a `TcpListener` by [`bind`]ing it to a socket address, it listens
+/// for incoming TCP connections. These can be accepted by calling [`accept`] or by
+/// iterating over the [`Incoming`] iterator returned by [`incoming`][`TcpListener::incoming`].
+///
+/// The socket will be closed when the value is dropped.
+///
+/// The Transmission Control Protocol is specified in [IETF RFC 793].
+///
+/// [`accept`]: #method.accept
+/// [`bind`]: #method.bind
+/// [IETF RFC 793]: https://tools.ietf.org/html/rfc793
+/// [`Incoming`]: ../../std/net/struct.Incoming.html
+/// [`TcpListener::incoming`]: #method.incoming
+///
+/// # Examples
+///
+/// ```no_run
+/// # use std::io;
+/// use std::net::{TcpListener, TcpStream};
+///
+/// fn handle_client(stream: TcpStream) {
+/// // ...
+/// }
+///
+/// fn main() -> io::Result<()> {
+/// let listener = TcpListener::bind("127.0.0.1:80")?;
+///
+/// // accept connections and process them serially
+/// for stream in listener.incoming() {
+/// handle_client(stream?);
+/// }
+/// Ok(())
+/// }
+/// ```
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct TcpListener(net_imp::TcpListener);
+
+/// An iterator that infinitely [`accept`]s connections on a [`TcpListener`].
+///
+/// This `struct` is created by the [`incoming`] method on [`TcpListener`].
+/// See its documentation for more.
+///
+/// [`accept`]: ../../std/net/struct.TcpListener.html#method.accept
+/// [`incoming`]: ../../std/net/struct.TcpListener.html#method.incoming
+/// [`TcpListener`]: ../../std/net/struct.TcpListener.html
+#[stable(feature = "rust1", since = "1.0.0")]
+#[derive(Debug)]
+pub struct Incoming<'a> { listener: &'a TcpListener }
+
+impl TcpStream {
+ /// Opens a TCP connection to a remote host.
+ ///
+ /// `addr` is an address of the remote host. Anything which implements
+ /// [`ToSocketAddrs`] trait can be supplied for the address; see this trait
+ /// documentation for concrete examples.
+ ///
+ /// If `addr` yields multiple addresses, `connect` will be attempted with
+ /// each of the addresses until a connection is successful. If none of
+ /// the addresses result in a successful connection, the error returned from
+ /// the last connection attempt (the last address) is returned.
+ ///
+ /// [`ToSocketAddrs`]: ../../std/net/trait.ToSocketAddrs.html
+ ///
+ /// # Examples
+ ///
+ /// Open a TCP connection to `127.0.0.1:8080`:
+ ///
+ /// ```no_run
+ /// use std::net::TcpStream;
+ ///
+ /// if let Ok(stream) = TcpStream::connect("127.0.0.1:8080") {
+ /// println!("Connected to the server!");
+ /// } else {
+ /// println!("Couldn't connect to server...");
+ /// }
+ /// ```
+ ///
+ /// Open a TCP connection to `127.0.0.1:8080`. If the connection fails, open
+ /// a TCP connection to `127.0.0.1:8081`:
+ ///
+ /// ```no_run
+ /// use std::net::{SocketAddr, TcpStream};
+ ///
+ /// let addrs = [
+ /// SocketAddr::from(([127, 0, 0, 1], 8080)),
+ /// SocketAddr::from(([127, 0, 0, 1], 8081)),
+ /// ];
+ /// if let Ok(stream) = TcpStream::connect(&addrs[..]) {
+ /// println!("Connected to the server!");
+ /// } else {
+ /// println!("Couldn't connect to server...");
+ /// }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn connect<A: ToSocketAddrs>(addr: A) -> io::Result<TcpStream> {
+ super::each_addr(addr, net_imp::TcpStream::connect).map(TcpStream)
+ }
+
+ /// Opens a TCP connection to a remote host with a timeout.
+ ///
+ /// Unlike `connect`, `connect_timeout` takes a single [`SocketAddr`] since
+ /// timeout must be applied to individual addresses.
+ ///
+ /// It is an error to pass a zero `Duration` to this function.
+ ///
+ /// Unlike other methods on `TcpStream`, this does not correspond to a
+ /// single system call. It instead calls `connect` in nonblocking mode and
+ /// then uses an OS-specific mechanism to await the completion of the
+ /// connection request.
+ ///
+ /// [`SocketAddr`]: ../../std/net/enum.SocketAddr.html
+ #[stable(feature = "tcpstream_connect_timeout", since = "1.21.0")]
+ pub fn connect_timeout(addr: &SocketAddr, timeout: Duration) -> io::Result<TcpStream> {
+ net_imp::TcpStream::connect_timeout(addr, timeout).map(TcpStream)
+ }
+
+ /// Returns the socket address of the remote peer of this TCP connection.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4, TcpStream};
+ ///
+ /// let stream = TcpStream::connect("127.0.0.1:8080")
+ /// .expect("Couldn't connect to the server...");
+ /// assert_eq!(stream.peer_addr().unwrap(),
+ /// SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080)));
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn peer_addr(&self) -> io::Result<SocketAddr> {
+ self.0.peer_addr()
+ }
+
+ /// Returns the socket address of the local half of this TCP connection.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::net::{IpAddr, Ipv4Addr, TcpStream};
+ ///
+ /// let stream = TcpStream::connect("127.0.0.1:8080")
+ /// .expect("Couldn't connect to the server...");
+ /// assert_eq!(stream.local_addr().unwrap().ip(),
+ /// IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)));
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn local_addr(&self) -> io::Result<SocketAddr> {
+ self.0.socket_addr()
+ }
+
+ /// Shuts down the read, write, or both halves of this connection.
+ ///
+ /// This function will cause all pending and future I/O on the specified
+ /// portions to return immediately with an appropriate value (see the
+ /// documentation of [`Shutdown`]).
+ ///
+ /// [`Shutdown`]: ../../std/net/enum.Shutdown.html
+ ///
+ /// # Platform-specific behavior
+ ///
+ /// Calling this function multiple times may result in different behavior,
+ /// depending on the operating system. On Linux, the second call will
+ /// return `Ok(())`, but on macOS, it will return `ErrorKind::NotConnected`.
+ /// This may change in the future.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::net::{Shutdown, TcpStream};
+ ///
+ /// let stream = TcpStream::connect("127.0.0.1:8080")
+ /// .expect("Couldn't connect to the server...");
+ /// stream.shutdown(Shutdown::Both).expect("shutdown call failed");
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
+ self.0.shutdown(how)
+ }
+
+ /// Creates a new independently owned handle to the underlying socket.
+ ///
+ /// The returned `TcpStream` 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::net::TcpStream;
+ ///
+ /// let stream = TcpStream::connect("127.0.0.1:8080")
+ /// .expect("Couldn't connect to the server...");
+ /// let stream_clone = stream.try_clone().expect("clone failed...");
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn try_clone(&self) -> io::Result<TcpStream> {
+ self.0.duplicate().map(TcpStream)
+ }
+
+ /// Sets the read timeout to the timeout specified.
+ ///
+ /// If the value specified is [`None`], then [`read`] calls will block
+ /// indefinitely. An [`Err`] is returned if the zero [`Duration`] is
+ /// passed to this method.
+ ///
+ /// # Platform-specific behavior
+ ///
+ /// Platforms may return a different error code whenever a read times out as
+ /// a result of setting this option. For example Unix typically returns an
+ /// error of the kind [`WouldBlock`], but Windows may return [`TimedOut`].
+ ///
+ /// [`None`]: ../../std/option/enum.Option.html#variant.None
+ /// [`Err`]: ../../std/result/enum.Result.html#variant.Err
+ /// [`read`]: ../../std/io/trait.Read.html#tymethod.read
+ /// [`WouldBlock`]: ../../std/io/enum.ErrorKind.html#variant.WouldBlock
+ /// [`TimedOut`]: ../../std/io/enum.ErrorKind.html#variant.TimedOut
+ /// [`Duration`]: ../../std/time/struct.Duration.html
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::net::TcpStream;
+ ///
+ /// let stream = TcpStream::connect("127.0.0.1:8080")
+ /// .expect("Couldn't connect to the server...");
+ /// stream.set_read_timeout(None).expect("set_read_timeout call failed");
+ /// ```
+ ///
+ /// An [`Err`] is returned if the zero [`Duration`] is passed to this
+ /// method:
+ ///
+ /// ```no_run
+ /// use std::io;
+ /// use std::net::TcpStream;
+ /// use std::time::Duration;
+ ///
+ /// let stream = TcpStream::connect("127.0.0.1:8080").unwrap();
+ /// let result = stream.set_read_timeout(Some(Duration::new(0, 0)));
+ /// let err = result.unwrap_err();
+ /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput)
+ /// ```
+ #[stable(feature = "socket_timeout", since = "1.4.0")]
+ pub fn set_read_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
+ self.0.set_read_timeout(dur)
+ }
+
+ /// Sets the write timeout to the timeout specified.
+ ///
+ /// If the value specified is [`None`], then [`write`] calls will block
+ /// indefinitely. An [`Err`] is returned if the zero [`Duration`] is
+ /// passed to this method.
+ ///
+ /// # Platform-specific behavior
+ ///
+ /// Platforms may return a different error code whenever a write times out
+ /// as a result of setting this option. For example Unix typically returns
+ /// an error of the kind [`WouldBlock`], but Windows may return [`TimedOut`].
+ ///
+ /// [`None`]: ../../std/option/enum.Option.html#variant.None
+ /// [`Err`]: ../../std/result/enum.Result.html#variant.Err
+ /// [`write`]: ../../std/io/trait.Write.html#tymethod.write
+ /// [`Duration`]: ../../std/time/struct.Duration.html
+ /// [`WouldBlock`]: ../../std/io/enum.ErrorKind.html#variant.WouldBlock
+ /// [`TimedOut`]: ../../std/io/enum.ErrorKind.html#variant.TimedOut
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::net::TcpStream;
+ ///
+ /// let stream = TcpStream::connect("127.0.0.1:8080")
+ /// .expect("Couldn't connect to the server...");
+ /// stream.set_write_timeout(None).expect("set_write_timeout call failed");
+ /// ```
+ ///
+ /// An [`Err`] is returned if the zero [`Duration`] is passed to this
+ /// method:
+ ///
+ /// ```no_run
+ /// use std::io;
+ /// use std::net::TcpStream;
+ /// use std::time::Duration;
+ ///
+ /// let stream = TcpStream::connect("127.0.0.1:8080").unwrap();
+ /// let result = stream.set_write_timeout(Some(Duration::new(0, 0)));
+ /// let err = result.unwrap_err();
+ /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput)
+ /// ```
+ #[stable(feature = "socket_timeout", since = "1.4.0")]
+ pub fn set_write_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
+ self.0.set_write_timeout(dur)
+ }
+
+ /// Returns the read timeout of this socket.
+ ///
+ /// If the timeout is [`None`], then [`read`] calls will block indefinitely.
+ ///
+ /// # Platform-specific behavior
+ ///
+ /// Some platforms do not provide access to the current timeout.
+ ///
+ /// [`None`]: ../../std/option/enum.Option.html#variant.None
+ /// [`read`]: ../../std/io/trait.Read.html#tymethod.read
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::net::TcpStream;
+ ///
+ /// let stream = TcpStream::connect("127.0.0.1:8080")
+ /// .expect("Couldn't connect to the server...");
+ /// stream.set_read_timeout(None).expect("set_read_timeout call failed");
+ /// assert_eq!(stream.read_timeout().unwrap(), None);
+ /// ```
+ #[stable(feature = "socket_timeout", since = "1.4.0")]
+ pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
+ self.0.read_timeout()
+ }
+
+ /// Returns the write timeout of this socket.
+ ///
+ /// If the timeout is [`None`], then [`write`] calls will block indefinitely.
+ ///
+ /// # Platform-specific behavior
+ ///
+ /// Some platforms do not provide access to the current timeout.
+ ///
+ /// [`None`]: ../../std/option/enum.Option.html#variant.None
+ /// [`write`]: ../../std/io/trait.Write.html#tymethod.write
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::net::TcpStream;
+ ///
+ /// let stream = TcpStream::connect("127.0.0.1:8080")
+ /// .expect("Couldn't connect to the server...");
+ /// stream.set_write_timeout(None).expect("set_write_timeout call failed");
+ /// assert_eq!(stream.write_timeout().unwrap(), None);
+ /// ```
+ #[stable(feature = "socket_timeout", since = "1.4.0")]
+ pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
+ self.0.write_timeout()
+ }
+
+ /// Receives data on the socket from the remote address to which it is
+ /// connected, without removing that data from the queue. On success,
+ /// returns the number of bytes peeked.
+ ///
+ /// Successive calls return the same data. This is accomplished by passing
+ /// `MSG_PEEK` as a flag to the underlying `recv` system call.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::net::TcpStream;
+ ///
+ /// let stream = TcpStream::connect("127.0.0.1:8000")
+ /// .expect("couldn't bind to address");
+ /// let mut buf = [0; 10];
+ /// let len = stream.peek(&mut buf).expect("peek failed");
+ /// ```
+ #[stable(feature = "peek", since = "1.18.0")]
+ pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
+ self.0.peek(buf)
+ }
+
+ /// Sets the value of the `TCP_NODELAY` option on this socket.
+ ///
+ /// If set, this option disables the Nagle algorithm. This means that
+ /// segments are always sent as soon as possible, even if there is only a
+ /// small amount of data. When not set, data is buffered until there is a
+ /// sufficient amount to send out, thereby avoiding the frequent sending of
+ /// small packets.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::net::TcpStream;
+ ///
+ /// let stream = TcpStream::connect("127.0.0.1:8080")
+ /// .expect("Couldn't connect to the server...");
+ /// stream.set_nodelay(true).expect("set_nodelay call failed");
+ /// ```
+ #[stable(feature = "net2_mutators", since = "1.9.0")]
+ pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> {
+ self.0.set_nodelay(nodelay)
+ }
+
+ /// Gets the value of the `TCP_NODELAY` option on this socket.
+ ///
+ /// For more information about this option, see [`set_nodelay`][link].
+ ///
+ /// [link]: #method.set_nodelay
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::net::TcpStream;
+ ///
+ /// let stream = TcpStream::connect("127.0.0.1:8080")
+ /// .expect("Couldn't connect to the server...");
+ /// stream.set_nodelay(true).expect("set_nodelay call failed");
+ /// assert_eq!(stream.nodelay().unwrap_or(false), true);
+ /// ```
+ #[stable(feature = "net2_mutators", since = "1.9.0")]
+ pub fn nodelay(&self) -> io::Result<bool> {
+ self.0.nodelay()
+ }
+
+ /// Sets the value for the `IP_TTL` option on this socket.
+ ///
+ /// This value sets the time-to-live field that is used in every packet sent
+ /// from this socket.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::net::TcpStream;
+ ///
+ /// let stream = TcpStream::connect("127.0.0.1:8080")
+ /// .expect("Couldn't connect to the server...");
+ /// stream.set_ttl(100).expect("set_ttl call failed");
+ /// ```
+ #[stable(feature = "net2_mutators", since = "1.9.0")]
+ pub fn set_ttl(&self, ttl: u32) -> io::Result<()> {
+ self.0.set_ttl(ttl)
+ }
+
+ /// Gets the value of the `IP_TTL` option for this socket.
+ ///
+ /// For more information about this option, see [`set_ttl`][link].
+ ///
+ /// [link]: #method.set_ttl
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::net::TcpStream;
+ ///
+ /// let stream = TcpStream::connect("127.0.0.1:8080")
+ /// .expect("Couldn't connect to the server...");
+ /// stream.set_ttl(100).expect("set_ttl call failed");
+ /// assert_eq!(stream.ttl().unwrap_or(0), 100);
+ /// ```
+ #[stable(feature = "net2_mutators", since = "1.9.0")]
+ pub fn ttl(&self) -> io::Result<u32> {
+ self.0.ttl()
+ }
+
+ /// Gets the value of the `SO_ERROR` option on this socket.
+ ///
+ /// This will retrieve the stored error in the underlying socket, clearing
+ /// the field in the process. This can be useful for checking errors between
+ /// calls.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::net::TcpStream;
+ ///
+ /// let stream = TcpStream::connect("127.0.0.1:8080")
+ /// .expect("Couldn't connect to the server...");
+ /// stream.take_error().expect("No error was expected...");
+ /// ```
+ #[stable(feature = "net2_mutators", since = "1.9.0")]
+ pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+ self.0.take_error()
+ }
+
+ /// Moves this TCP stream into or out of nonblocking mode.
+ ///
+ /// This will result in `read`, `write`, `recv` and `send` operations
+ /// becoming nonblocking, i.e., immediately returning from their calls.
+ /// If the IO operation is successful, `Ok` is returned and no further
+ /// action is required. If the IO operation could not be completed and needs
+ /// to be retried, an error with kind [`io::ErrorKind::WouldBlock`] is
+ /// returned.
+ ///
+ /// On Unix platforms, calling this method corresponds to calling `fcntl`
+ /// `FIONBIO`. On Windows calling this method corresponds to calling
+ /// `ioctlsocket` `FIONBIO`.
+ ///
+ /// # Examples
+ ///
+ /// Reading bytes from a TCP stream in non-blocking mode:
+ ///
+ /// ```no_run
+ /// use std::io::{self, Read};
+ /// use std::net::TcpStream;
+ ///
+ /// let mut stream = TcpStream::connect("127.0.0.1:7878")
+ /// .expect("Couldn't connect to the server...");
+ /// stream.set_nonblocking(true).expect("set_nonblocking call failed");
+ ///
+ /// # fn wait_for_fd() { unimplemented!() }
+ /// let mut buf = vec![];
+ /// loop {
+ /// match stream.read_to_end(&mut buf) {
+ /// Ok(_) => break,
+ /// Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
+ /// // wait until network socket is ready, typically implemented
+ /// // via platform-specific APIs such as epoll or IOCP
+ /// wait_for_fd();
+ /// }
+ /// Err(e) => panic!("encountered IO error: {}", e),
+ /// };
+ /// };
+ /// println!("bytes: {:?}", buf);
+ /// ```
+ ///
+ /// [`io::ErrorKind::WouldBlock`]: ../io/enum.ErrorKind.html#variant.WouldBlock
+ #[stable(feature = "net2_mutators", since = "1.9.0")]
+ pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
+ self.0.set_nonblocking(nonblocking)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Read for TcpStream {
+ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { self.0.read(buf) }
+
+ fn read_vectored(&mut self, bufs: &mut [IoVecMut<'_>]) -> io::Result<usize> {
+ self.0.read_vectored(bufs)
+ }
+
+ #[inline]
+ unsafe fn initializer(&self) -> Initializer {
+ Initializer::nop()
+ }
+}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Write for TcpStream {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> { self.0.write(buf) }
+
+ fn write_vectored(&mut self, bufs: &[IoVec<'_>]) -> io::Result<usize> {
+ self.0.write_vectored(bufs)
+ }
+
+ fn flush(&mut self) -> io::Result<()> { Ok(()) }
+}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Read for &TcpStream {
+ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { self.0.read(buf) }
+
+ fn read_vectored(&mut self, bufs: &mut [IoVecMut<'_>]) -> io::Result<usize> {
+ self.0.read_vectored(bufs)
+ }
+
+ #[inline]
+ unsafe fn initializer(&self) -> Initializer {
+ Initializer::nop()
+ }
+}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Write for &TcpStream {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> { self.0.write(buf) }
+
+ fn write_vectored(&mut self, bufs: &[IoVec<'_>]) -> io::Result<usize> {
+ self.0.write_vectored(bufs)
+ }
+
+ fn flush(&mut self) -> io::Result<()> { Ok(()) }
+}
+
+impl AsInner<net_imp::TcpStream> for TcpStream {
+ fn as_inner(&self) -> &net_imp::TcpStream { &self.0 }
+}
+
+impl FromInner<net_imp::TcpStream> for TcpStream {
+ fn from_inner(inner: net_imp::TcpStream) -> TcpStream { TcpStream(inner) }
+}
+
+impl IntoInner<net_imp::TcpStream> for TcpStream {
+ fn into_inner(self) -> net_imp::TcpStream { self.0 }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl fmt::Debug for TcpStream {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ self.0.fmt(f)
+ }
+}
+
+impl TcpListener {
+ /// Creates a new `TcpListener` which will be bound to the specified
+ /// address.
+ ///
+ /// The returned listener is ready for accepting connections.
+ ///
+ /// Binding with a port number of 0 will request that the OS assigns a port
+ /// to this listener. The port allocated can be queried via the
+ /// [`local_addr`] method.
+ ///
+ /// The address type can be any implementor of [`ToSocketAddrs`] trait. See
+ /// its documentation for concrete examples.
+ ///
+ /// If `addr` yields multiple addresses, `bind` will be attempted with
+ /// each of the addresses until one succeeds and returns the listener. If
+ /// none of the addresses succeed in creating a listener, the error returned
+ /// from the last attempt (the last address) is returned.
+ ///
+ /// [`local_addr`]: #method.local_addr
+ /// [`ToSocketAddrs`]: ../../std/net/trait.ToSocketAddrs.html
+ ///
+ /// # Examples
+ ///
+ /// Creates a TCP listener bound to `127.0.0.1:80`:
+ ///
+ /// ```no_run
+ /// use std::net::TcpListener;
+ ///
+ /// let listener = TcpListener::bind("127.0.0.1:80").unwrap();
+ /// ```
+ ///
+ /// Creates a TCP listener bound to `127.0.0.1:80`. If that fails, create a
+ /// TCP listener bound to `127.0.0.1:443`:
+ ///
+ /// ```no_run
+ /// use std::net::{SocketAddr, TcpListener};
+ ///
+ /// let addrs = [
+ /// SocketAddr::from(([127, 0, 0, 1], 80)),
+ /// SocketAddr::from(([127, 0, 0, 1], 443)),
+ /// ];
+ /// let listener = TcpListener::bind(&addrs[..]).unwrap();
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn bind<A: ToSocketAddrs>(addr: A) -> io::Result<TcpListener> {
+ super::each_addr(addr, net_imp::TcpListener::bind).map(TcpListener)
+ }
+
+ /// Returns the local socket address of this listener.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4, TcpListener};
+ ///
+ /// let listener = TcpListener::bind("127.0.0.1:8080").unwrap();
+ /// assert_eq!(listener.local_addr().unwrap(),
+ /// SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080)));
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn local_addr(&self) -> io::Result<SocketAddr> {
+ self.0.socket_addr()
+ }
+
+ /// Creates a new independently owned handle to the underlying socket.
+ ///
+ /// The returned [`TcpListener`] is a reference to the same socket that this
+ /// object references. Both handles can be used to accept incoming
+ /// connections and options set on one listener will affect the other.
+ ///
+ /// [`TcpListener`]: ../../std/net/struct.TcpListener.html
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::net::TcpListener;
+ ///
+ /// let listener = TcpListener::bind("127.0.0.1:8080").unwrap();
+ /// let listener_clone = listener.try_clone().unwrap();
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn try_clone(&self) -> io::Result<TcpListener> {
+ self.0.duplicate().map(TcpListener)
+ }
+
+ /// Accept a new incoming connection from this listener.
+ ///
+ /// This function will block the calling thread until a new TCP connection
+ /// is established. When established, the corresponding [`TcpStream`] and the
+ /// remote peer's address will be returned.
+ ///
+ /// [`TcpStream`]: ../../std/net/struct.TcpStream.html
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::net::TcpListener;
+ ///
+ /// let listener = TcpListener::bind("127.0.0.1:8080").unwrap();
+ /// match listener.accept() {
+ /// Ok((_socket, addr)) => println!("new client: {:?}", addr),
+ /// Err(e) => println!("couldn't get client: {:?}", e),
+ /// }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> {
+ // On WASM, `TcpStream` is uninhabited (as it's unsupported) and so
+ // the `a` variable here is technically unused.
+ #[cfg_attr(target_arch = "wasm32", allow(unused_variables))]
+ self.0.accept().map(|(a, b)| (TcpStream(a), b))
+ }
+
+ /// Returns an iterator over the connections being received on this
+ /// listener.
+ ///
+ /// The returned iterator will never return [`None`] and will also not yield
+ /// the peer's [`SocketAddr`] structure. Iterating over it is equivalent to
+ /// calling [`accept`] in a loop.
+ ///
+ /// [`None`]: ../../std/option/enum.Option.html#variant.None
+ /// [`SocketAddr`]: ../../std/net/enum.SocketAddr.html
+ /// [`accept`]: #method.accept
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::net::TcpListener;
+ ///
+ /// let listener = TcpListener::bind("127.0.0.1:80").unwrap();
+ ///
+ /// for stream in listener.incoming() {
+ /// match stream {
+ /// Ok(stream) => {
+ /// println!("new client!");
+ /// }
+ /// Err(e) => { /* connection failed */ }
+ /// }
+ /// }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn incoming(&self) -> Incoming<'_> {
+ Incoming { listener: self }
+ }
+
+ /// Sets the value for the `IP_TTL` option on this socket.
+ ///
+ /// This value sets the time-to-live field that is used in every packet sent
+ /// from this socket.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::net::TcpListener;
+ ///
+ /// let listener = TcpListener::bind("127.0.0.1:80").unwrap();
+ /// listener.set_ttl(100).expect("could not set TTL");
+ /// ```
+ #[stable(feature = "net2_mutators", since = "1.9.0")]
+ pub fn set_ttl(&self, ttl: u32) -> io::Result<()> {
+ self.0.set_ttl(ttl)
+ }
+
+ /// Gets the value of the `IP_TTL` option for this socket.
+ ///
+ /// For more information about this option, see [`set_ttl`][link].
+ ///
+ /// [link]: #method.set_ttl
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::net::TcpListener;
+ ///
+ /// let listener = TcpListener::bind("127.0.0.1:80").unwrap();
+ /// listener.set_ttl(100).expect("could not set TTL");
+ /// assert_eq!(listener.ttl().unwrap_or(0), 100);
+ /// ```
+ #[stable(feature = "net2_mutators", since = "1.9.0")]
+ pub fn ttl(&self) -> io::Result<u32> {
+ self.0.ttl()
+ }
+
+ #[stable(feature = "net2_mutators", since = "1.9.0")]
+ #[rustc_deprecated(since = "1.16.0",
+ reason = "this option can only be set before the socket is bound")]
+ #[allow(missing_docs)]
+ pub fn set_only_v6(&self, only_v6: bool) -> io::Result<()> {
+ self.0.set_only_v6(only_v6)
+ }
+
+ #[stable(feature = "net2_mutators", since = "1.9.0")]
+ #[rustc_deprecated(since = "1.16.0",
+ reason = "this option can only be set before the socket is bound")]
+ #[allow(missing_docs)]
+ pub fn only_v6(&self) -> io::Result<bool> {
+ self.0.only_v6()
+ }
+
+ /// Gets the value of the `SO_ERROR` option on this socket.
+ ///
+ /// This will retrieve the stored error in the underlying socket, clearing
+ /// the field in the process. This can be useful for checking errors between
+ /// calls.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::net::TcpListener;
+ ///
+ /// let listener = TcpListener::bind("127.0.0.1:80").unwrap();
+ /// listener.take_error().expect("No error was expected");
+ /// ```
+ #[stable(feature = "net2_mutators", since = "1.9.0")]
+ pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+ self.0.take_error()
+ }
+
+ /// Moves this TCP stream into or out of nonblocking mode.
+ ///
+ /// This will result in the `accept` operation becoming nonblocking,
+ /// i.e., immediately returning from their calls. If the IO operation is
+ /// successful, `Ok` is returned and no further action is required. If the
+ /// IO operation could not be completed and needs to be retried, an error
+ /// with kind [`io::ErrorKind::WouldBlock`] is returned.
+ ///
+ /// On Unix platforms, calling this method corresponds to calling `fcntl`
+ /// `FIONBIO`. On Windows calling this method corresponds to calling
+ /// `ioctlsocket` `FIONBIO`.
+ ///
+ /// # Examples
+ ///
+ /// Bind a TCP listener to an address, listen for connections, and read
+ /// bytes in nonblocking mode:
+ ///
+ /// ```no_run
+ /// use std::io;
+ /// use std::net::TcpListener;
+ ///
+ /// let listener = TcpListener::bind("127.0.0.1:7878").unwrap();
+ /// listener.set_nonblocking(true).expect("Cannot set non-blocking");
+ ///
+ /// # fn wait_for_fd() { unimplemented!() }
+ /// # fn handle_connection(stream: std::net::TcpStream) { unimplemented!() }
+ /// for stream in listener.incoming() {
+ /// match stream {
+ /// Ok(s) => {
+ /// // do something with the TcpStream
+ /// handle_connection(s);
+ /// }
+ /// Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
+ /// // wait until network socket is ready, typically implemented
+ /// // via platform-specific APIs such as epoll or IOCP
+ /// wait_for_fd();
+ /// continue;
+ /// }
+ /// Err(e) => panic!("encountered IO error: {}", e),
+ /// }
+ /// }
+ /// ```
+ ///
+ /// [`io::ErrorKind::WouldBlock`]: ../io/enum.ErrorKind.html#variant.WouldBlock
+ #[stable(feature = "net2_mutators", since = "1.9.0")]
+ pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
+ self.0.set_nonblocking(nonblocking)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a> Iterator for Incoming<'a> {
+ type Item = io::Result<TcpStream>;
+ fn next(&mut self) -> Option<io::Result<TcpStream>> {
+ Some(self.listener.accept().map(|p| p.0))
+ }
+}
+
+impl AsInner<net_imp::TcpListener> for TcpListener {
+ fn as_inner(&self) -> &net_imp::TcpListener { &self.0 }
+}
+
+impl FromInner<net_imp::TcpListener> for TcpListener {
+ fn from_inner(inner: net_imp::TcpListener) -> TcpListener {
+ TcpListener(inner)
+ }
+}
+
+impl IntoInner<net_imp::TcpListener> for TcpListener {
+ fn into_inner(self) -> net_imp::TcpListener { self.0 }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl fmt::Debug for TcpListener {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ self.0.fmt(f)
+ }
+}
+
+#[cfg(all(test, not(any(target_os = "cloudabi", target_os = "emscripten"))))]
+mod tests {
+ use crate::fmt;
+ use crate::io::{ErrorKind, IoVec, IoVecMut};
+ use crate::io::prelude::*;
+ use crate::net::*;
+ use crate::net::test::{next_test_ip4, next_test_ip6};
+ use crate::sync::mpsc::channel;
+ use crate::time::{Instant, Duration};
+ use crate::thread;
+
+ fn each_ip(f: &mut dyn FnMut(SocketAddr)) {
+ f(next_test_ip4());
+ f(next_test_ip6());
+ }
+
+ macro_rules! t {
+ ($e:expr) => {
+ match $e {
+ Ok(t) => t,
+ Err(e) => panic!("received error for `{}`: {}", stringify!($e), e),
+ }
+ }
+ }
+
+ #[test]
+ fn bind_error() {
+ match TcpListener::bind("1.1.1.1:9999") {
+ Ok(..) => panic!(),
+ Err(e) =>
+ assert_eq!(e.kind(), ErrorKind::AddrNotAvailable),
+ }
+ }
+
+ #[test]
+ fn connect_error() {
+ match TcpStream::connect("0.0.0.0:1") {
+ Ok(..) => panic!(),
+ Err(e) => assert!(e.kind() == ErrorKind::ConnectionRefused ||
+ e.kind() == ErrorKind::InvalidInput ||
+ e.kind() == ErrorKind::AddrInUse ||
+ e.kind() == ErrorKind::AddrNotAvailable,
+ "bad error: {} {:?}", e, e.kind()),
+ }
+ }
+
+ #[test]
+ fn listen_localhost() {
+ let socket_addr = next_test_ip4();
+ let listener = t!(TcpListener::bind(&socket_addr));
+
+ let _t = thread::spawn(move || {
+ let mut stream = t!(TcpStream::connect(&("localhost",
+ socket_addr.port())));
+ t!(stream.write(&[144]));
+ });
+
+ let mut stream = t!(listener.accept()).0;
+ let mut buf = [0];
+ t!(stream.read(&mut buf));
+ assert!(buf[0] == 144);
+ }
+
+ #[test]
+ fn connect_loopback() {
+ each_ip(&mut |addr| {
+ let acceptor = t!(TcpListener::bind(&addr));
+
+ let _t = thread::spawn(move|| {
+ let host = match addr {
+ SocketAddr::V4(..) => "127.0.0.1",
+ SocketAddr::V6(..) => "::1",
+ };
+ let mut stream = t!(TcpStream::connect(&(host, addr.port())));
+ t!(stream.write(&[66]));
+ });
+
+ let mut stream = t!(acceptor.accept()).0;
+ let mut buf = [0];
+ t!(stream.read(&mut buf));
+ assert!(buf[0] == 66);
+ })
+ }
+
+ #[test]
+ fn smoke_test() {
+ each_ip(&mut |addr| {
+ let acceptor = t!(TcpListener::bind(&addr));
+
+ let (tx, rx) = channel();
+ let _t = thread::spawn(move|| {
+ let mut stream = t!(TcpStream::connect(&addr));
+ t!(stream.write(&[99]));
+ tx.send(t!(stream.local_addr())).unwrap();
+ });
+
+ let (mut stream, addr) = t!(acceptor.accept());
+ let mut buf = [0];
+ t!(stream.read(&mut buf));
+ assert!(buf[0] == 99);
+ assert_eq!(addr, t!(rx.recv()));
+ })
+ }
+
+ #[test]
+ fn read_eof() {
+ each_ip(&mut |addr| {
+ let acceptor = t!(TcpListener::bind(&addr));
+
+ let _t = thread::spawn(move|| {
+ let _stream = t!(TcpStream::connect(&addr));
+ // Close
+ });
+
+ let mut stream = t!(acceptor.accept()).0;
+ let mut buf = [0];
+ let nread = t!(stream.read(&mut buf));
+ assert_eq!(nread, 0);
+ let nread = t!(stream.read(&mut buf));
+ assert_eq!(nread, 0);
+ })
+ }
+
+ #[test]
+ fn write_close() {
+ each_ip(&mut |addr| {
+ let acceptor = t!(TcpListener::bind(&addr));
+
+ let (tx, rx) = channel();
+ let _t = thread::spawn(move|| {
+ drop(t!(TcpStream::connect(&addr)));
+ tx.send(()).unwrap();
+ });
+
+ let mut stream = t!(acceptor.accept()).0;
+ rx.recv().unwrap();
+ let buf = [0];
+ match stream.write(&buf) {
+ Ok(..) => {}
+ Err(e) => {
+ assert!(e.kind() == ErrorKind::ConnectionReset ||
+ e.kind() == ErrorKind::BrokenPipe ||
+ e.kind() == ErrorKind::ConnectionAborted,
+ "unknown error: {}", e);
+ }
+ }
+ })
+ }
+
+ #[test]
+ fn multiple_connect_serial() {
+ each_ip(&mut |addr| {
+ let max = 10;
+ let acceptor = t!(TcpListener::bind(&addr));
+
+ let _t = thread::spawn(move|| {
+ for _ in 0..max {
+ let mut stream = t!(TcpStream::connect(&addr));
+ t!(stream.write(&[99]));
+ }
+ });
+
+ for stream in acceptor.incoming().take(max) {
+ let mut stream = t!(stream);
+ let mut buf = [0];
+ t!(stream.read(&mut buf));
+ assert_eq!(buf[0], 99);
+ }
+ })
+ }
+
+ #[test]
+ fn multiple_connect_interleaved_greedy_schedule() {
+ const MAX: usize = 10;
+ each_ip(&mut |addr| {
+ let acceptor = t!(TcpListener::bind(&addr));
+
+ let _t = thread::spawn(move|| {
+ let acceptor = acceptor;
+ for (i, stream) in acceptor.incoming().enumerate().take(MAX) {
+ // Start another thread to handle the connection
+ let _t = thread::spawn(move|| {
+ let mut stream = t!(stream);
+ let mut buf = [0];
+ t!(stream.read(&mut buf));
+ assert!(buf[0] == i as u8);
+ });
+ }
+ });
+
+ connect(0, addr);
+ });
+
+ fn connect(i: usize, addr: SocketAddr) {
+ if i == MAX { return }
+
+ let t = thread::spawn(move|| {
+ let mut stream = t!(TcpStream::connect(&addr));
+ // Connect again before writing
+ connect(i + 1, addr);
+ t!(stream.write(&[i as u8]));
+ });
+ t.join().ok().expect("thread panicked");
+ }
+ }
+
+ #[test]
+ fn multiple_connect_interleaved_lazy_schedule() {
+ const MAX: usize = 10;
+ each_ip(&mut |addr| {
+ let acceptor = t!(TcpListener::bind(&addr));
+
+ let _t = thread::spawn(move|| {
+ for stream in acceptor.incoming().take(MAX) {
+ // Start another thread to handle the connection
+ let _t = thread::spawn(move|| {
+ let mut stream = t!(stream);
+ let mut buf = [0];
+ t!(stream.read(&mut buf));
+ assert!(buf[0] == 99);
+ });
+ }
+ });
+
+ connect(0, addr);
+ });
+
+ fn connect(i: usize, addr: SocketAddr) {
+ if i == MAX { return }
+
+ let t = thread::spawn(move|| {
+ let mut stream = t!(TcpStream::connect(&addr));
+ connect(i + 1, addr);
+ t!(stream.write(&[99]));
+ });
+ t.join().ok().expect("thread panicked");
+ }
+ }
+
+ #[test]
+ fn socket_and_peer_name() {
+ each_ip(&mut |addr| {
+ let listener = t!(TcpListener::bind(&addr));
+ let so_name = t!(listener.local_addr());
+ assert_eq!(addr, so_name);
+ let _t = thread::spawn(move|| {
+ t!(listener.accept());
+ });
+
+ let stream = t!(TcpStream::connect(&addr));
+ assert_eq!(addr, t!(stream.peer_addr()));
+ })
+ }
+
+ #[test]
+ fn partial_read() {
+ each_ip(&mut |addr| {
+ let (tx, rx) = channel();
+ let srv = t!(TcpListener::bind(&addr));
+ let _t = thread::spawn(move|| {
+ let mut cl = t!(srv.accept()).0;
+ cl.write(&[10]).unwrap();
+ let mut b = [0];
+ t!(cl.read(&mut b));
+ tx.send(()).unwrap();
+ });
+
+ let mut c = t!(TcpStream::connect(&addr));
+ let mut b = [0; 10];
+ assert_eq!(c.read(&mut b).unwrap(), 1);
+ t!(c.write(&[1]));
+ rx.recv().unwrap();
+ })
+ }
+
+ #[test]
+ fn read_vectored() {
+ each_ip(&mut |addr| {
+ let srv = t!(TcpListener::bind(&addr));
+ let mut s1 = t!(TcpStream::connect(&addr));
+ let mut s2 = t!(srv.accept()).0;
+
+ let len = s1.write(&[10, 11, 12]).unwrap();
+ assert_eq!(len, 3);
+
+ let mut a = [];
+ let mut b = [0];
+ let mut c = [0; 3];
+ let len = t!(s2.read_vectored(
+ &mut [IoVecMut::new(&mut a), IoVecMut::new(&mut b), IoVecMut::new(&mut c)],
+ ));
+ assert!(len > 0);
+ assert_eq!(b, [10]);
+ // some implementations don't support readv, so we may only fill the first buffer
+ assert!(len == 1 || c == [11, 12, 0]);
+ })
+ }
+
+ #[test]
+ fn write_vectored() {
+ each_ip(&mut |addr| {
+ let srv = t!(TcpListener::bind(&addr));
+ let mut s1 = t!(TcpStream::connect(&addr));
+ let mut s2 = t!(srv.accept()).0;
+
+ let a = [];
+ let b = [10];
+ let c = [11, 12];
+ t!(s1.write_vectored(&[IoVec::new(&a), IoVec::new(&b), IoVec::new(&c)]));
+
+ let mut buf = [0; 4];
+ let len = t!(s2.read(&mut buf));
+ // some implementations don't support writev, so we may only write the first buffer
+ if len == 1 {
+ assert_eq!(buf, [10, 0, 0, 0]);
+ } else {
+ assert_eq!(len, 3);
+ assert_eq!(buf, [10, 11, 12, 0]);
+ }
+ })
+ }
+
+ #[test]
+ fn double_bind() {
+ each_ip(&mut |addr| {
+ let listener1 = t!(TcpListener::bind(&addr));
+ match TcpListener::bind(&addr) {
+ Ok(listener2) => panic!(
+ "This system (perhaps due to options set by TcpListener::bind) \
+ permits double binding: {:?} and {:?}",
+ listener1, listener2
+ ),
+ Err(e) => {
+ assert!(e.kind() == ErrorKind::ConnectionRefused ||
+ e.kind() == ErrorKind::Other ||
+ e.kind() == ErrorKind::AddrInUse,
+ "unknown error: {} {:?}", e, e.kind());
+ }
+ }
+ })
+ }
+
+ #[test]
+ fn fast_rebind() {
+ each_ip(&mut |addr| {
+ let acceptor = t!(TcpListener::bind(&addr));
+
+ let _t = thread::spawn(move|| {
+ t!(TcpStream::connect(&addr));
+ });
+
+ t!(acceptor.accept());
+ drop(acceptor);
+ t!(TcpListener::bind(&addr));
+ });
+ }
+
+ #[test]
+ fn tcp_clone_smoke() {
+ each_ip(&mut |addr| {
+ let acceptor = t!(TcpListener::bind(&addr));
+
+ let _t = thread::spawn(move|| {
+ let mut s = t!(TcpStream::connect(&addr));
+ let mut buf = [0, 0];
+ assert_eq!(s.read(&mut buf).unwrap(), 1);
+ assert_eq!(buf[0], 1);
+ t!(s.write(&[2]));
+ });
+
+ let mut s1 = t!(acceptor.accept()).0;
+ let s2 = t!(s1.try_clone());
+
+ let (tx1, rx1) = channel();
+ let (tx2, rx2) = channel();
+ let _t = thread::spawn(move|| {
+ let mut s2 = s2;
+ rx1.recv().unwrap();
+ t!(s2.write(&[1]));
+ tx2.send(()).unwrap();
+ });
+ tx1.send(()).unwrap();
+ let mut buf = [0, 0];
+ assert_eq!(s1.read(&mut buf).unwrap(), 1);
+ rx2.recv().unwrap();
+ })
+ }
+
+ #[test]
+ fn tcp_clone_two_read() {
+ each_ip(&mut |addr| {
+ let acceptor = t!(TcpListener::bind(&addr));
+ let (tx1, rx) = channel();
+ let tx2 = tx1.clone();
+
+ let _t = thread::spawn(move|| {
+ let mut s = t!(TcpStream::connect(&addr));
+ t!(s.write(&[1]));
+ rx.recv().unwrap();
+ t!(s.write(&[2]));
+ rx.recv().unwrap();
+ });
+
+ let mut s1 = t!(acceptor.accept()).0;
+ let s2 = t!(s1.try_clone());
+
+ let (done, rx) = channel();
+ let _t = thread::spawn(move|| {
+ let mut s2 = s2;
+ let mut buf = [0, 0];
+ t!(s2.read(&mut buf));
+ tx2.send(()).unwrap();
+ done.send(()).unwrap();
+ });
+ let mut buf = [0, 0];
+ t!(s1.read(&mut buf));
+ tx1.send(()).unwrap();
+
+ rx.recv().unwrap();
+ })
+ }
+
+ #[test]
+ fn tcp_clone_two_write() {
+ each_ip(&mut |addr| {
+ let acceptor = t!(TcpListener::bind(&addr));
+
+ let _t = thread::spawn(move|| {
+ let mut s = t!(TcpStream::connect(&addr));
+ let mut buf = [0, 1];
+ t!(s.read(&mut buf));
+ t!(s.read(&mut buf));
+ });
+
+ let mut s1 = t!(acceptor.accept()).0;
+ let s2 = t!(s1.try_clone());
+
+ let (done, rx) = channel();
+ let _t = thread::spawn(move|| {
+ let mut s2 = s2;
+ t!(s2.write(&[1]));
+ done.send(()).unwrap();
+ });
+ t!(s1.write(&[2]));
+
+ rx.recv().unwrap();
+ })
+ }
+
+ #[test]
+ // FIXME: https://github.com/fortanix/rust-sgx/issues/110
+ #[cfg_attr(target_env = "sgx", ignore)]
+ fn shutdown_smoke() {
+ each_ip(&mut |addr| {
+ let a = t!(TcpListener::bind(&addr));
+ let _t = thread::spawn(move|| {
+ let mut c = t!(a.accept()).0;
+ let mut b = [0];
+ assert_eq!(c.read(&mut b).unwrap(), 0);
+ t!(c.write(&[1]));
+ });
+
+ let mut s = t!(TcpStream::connect(&addr));
+ t!(s.shutdown(Shutdown::Write));
+ assert!(s.write(&[1]).is_err());
+ let mut b = [0, 0];
+ assert_eq!(t!(s.read(&mut b)), 1);
+ assert_eq!(b[0], 1);
+ })
+ }
+
+ #[test]
+ // FIXME: https://github.com/fortanix/rust-sgx/issues/110
+ #[cfg_attr(target_env = "sgx", ignore)]
+ fn close_readwrite_smoke() {
+ each_ip(&mut |addr| {
+ let a = t!(TcpListener::bind(&addr));
+ let (tx, rx) = channel::<()>();
+ let _t = thread::spawn(move|| {
+ let _s = t!(a.accept());
+ let _ = rx.recv();
+ });
+
+ let mut b = [0];
+ let mut s = t!(TcpStream::connect(&addr));
+ let mut s2 = t!(s.try_clone());
+
+ // closing should prevent reads/writes
+ t!(s.shutdown(Shutdown::Write));
+ assert!(s.write(&[0]).is_err());
+ t!(s.shutdown(Shutdown::Read));
+ assert_eq!(s.read(&mut b).unwrap(), 0);
+
+ // closing should affect previous handles
+ assert!(s2.write(&[0]).is_err());
+ assert_eq!(s2.read(&mut b).unwrap(), 0);
+
+ // closing should affect new handles
+ let mut s3 = t!(s.try_clone());
+ assert!(s3.write(&[0]).is_err());
+ assert_eq!(s3.read(&mut b).unwrap(), 0);
+
+ // make sure these don't die
+ let _ = s2.shutdown(Shutdown::Read);
+ let _ = s2.shutdown(Shutdown::Write);
+ let _ = s3.shutdown(Shutdown::Read);
+ let _ = s3.shutdown(Shutdown::Write);
+ drop(tx);
+ })
+ }
+
+ #[test]
+ #[cfg(unix)] // test doesn't work on Windows, see #31657
+ fn close_read_wakes_up() {
+ each_ip(&mut |addr| {
+ let a = t!(TcpListener::bind(&addr));
+ let (tx1, rx) = channel::<()>();
+ let _t = thread::spawn(move|| {
+ let _s = t!(a.accept());
+ let _ = rx.recv();
+ });
+
+ let s = t!(TcpStream::connect(&addr));
+ let s2 = t!(s.try_clone());
+ let (tx, rx) = channel();
+ let _t = thread::spawn(move|| {
+ let mut s2 = s2;
+ assert_eq!(t!(s2.read(&mut [0])), 0);
+ tx.send(()).unwrap();
+ });
+ // this should wake up the child thread
+ t!(s.shutdown(Shutdown::Read));
+
+ // this test will never finish if the child doesn't wake up
+ rx.recv().unwrap();
+ drop(tx1);
+ })
+ }
+
+ #[test]
+ fn clone_while_reading() {
+ each_ip(&mut |addr| {
+ let accept = t!(TcpListener::bind(&addr));
+
+ // Enqueue a thread to write to a socket
+ let (tx, rx) = channel();
+ let (txdone, rxdone) = channel();
+ let txdone2 = txdone.clone();
+ let _t = thread::spawn(move|| {
+ let mut tcp = t!(TcpStream::connect(&addr));
+ rx.recv().unwrap();
+ t!(tcp.write(&[0]));
+ txdone2.send(()).unwrap();
+ });
+
+ // Spawn off a reading clone
+ let tcp = t!(accept.accept()).0;
+ let tcp2 = t!(tcp.try_clone());
+ let txdone3 = txdone.clone();
+ let _t = thread::spawn(move|| {
+ let mut tcp2 = tcp2;
+ t!(tcp2.read(&mut [0]));
+ txdone3.send(()).unwrap();
+ });
+
+ // Try to ensure that the reading clone is indeed reading
+ for _ in 0..50 {
+ thread::yield_now();
+ }
+
+ // clone the handle again while it's reading, then let it finish the
+ // read.
+ let _ = t!(tcp.try_clone());
+ tx.send(()).unwrap();
+ rxdone.recv().unwrap();
+ rxdone.recv().unwrap();
+ })
+ }
+
+ #[test]
+ fn clone_accept_smoke() {
+ each_ip(&mut |addr| {
+ let a = t!(TcpListener::bind(&addr));
+ let a2 = t!(a.try_clone());
+
+ let _t = thread::spawn(move|| {
+ let _ = TcpStream::connect(&addr);
+ });
+ let _t = thread::spawn(move|| {
+ let _ = TcpStream::connect(&addr);
+ });
+
+ t!(a.accept());
+ t!(a2.accept());
+ })
+ }
+
+ #[test]
+ fn clone_accept_concurrent() {
+ each_ip(&mut |addr| {
+ let a = t!(TcpListener::bind(&addr));
+ let a2 = t!(a.try_clone());
+
+ let (tx, rx) = channel();
+ let tx2 = tx.clone();
+
+ let _t = thread::spawn(move|| {
+ tx.send(t!(a.accept())).unwrap();
+ });
+ let _t = thread::spawn(move|| {
+ tx2.send(t!(a2.accept())).unwrap();
+ });
+
+ let _t = thread::spawn(move|| {
+ let _ = TcpStream::connect(&addr);
+ });
+ let _t = thread::spawn(move|| {
+ let _ = TcpStream::connect(&addr);
+ });
+
+ rx.recv().unwrap();
+ rx.recv().unwrap();
+ })
+ }
+
+ #[test]
+ fn debug() {
+ #[cfg(not(target_env = "sgx"))]
+ fn render_socket_addr<'a>(addr: &'a SocketAddr) -> impl fmt::Debug + 'a {
+ addr
+ }
+ #[cfg(target_env = "sgx")]
+ fn render_socket_addr<'a>(addr: &'a SocketAddr) -> impl fmt::Debug + 'a {
+ addr.to_string()
+ }
+
+ #[cfg(unix)]
+ use crate::os::unix::io::AsRawFd;
+ #[cfg(target_env = "sgx")]
+ use crate::os::fortanix_sgx::io::AsRawFd;
+ #[cfg(not(windows))]
+ fn render_inner(addr: &dyn AsRawFd) -> impl fmt::Debug {
+ addr.as_raw_fd()
+ }
+ #[cfg(windows)]
+ fn render_inner(addr: &dyn crate::os::windows::io::AsRawSocket) -> impl fmt::Debug {
+ addr.as_raw_socket()
+ }
+
+ let inner_name = if cfg!(windows) {"socket"} else {"fd"};
+ let socket_addr = next_test_ip4();
+
+ let listener = t!(TcpListener::bind(&socket_addr));
+ let compare = format!("TcpListener {{ addr: {:?}, {}: {:?} }}",
+ render_socket_addr(&socket_addr),
+ inner_name,
+ render_inner(&listener));
+ assert_eq!(format!("{:?}", listener), compare);
+
+ let stream = t!(TcpStream::connect(&("localhost", socket_addr.port())));
+ let compare = format!("TcpStream {{ addr: {:?}, peer: {:?}, {}: {:?} }}",
+ render_socket_addr(&stream.local_addr().unwrap()),
+ render_socket_addr(&stream.peer_addr().unwrap()),
+ inner_name,
+ render_inner(&stream));
+ assert_eq!(format!("{:?}", stream), compare);
+ }
+
+ // FIXME: re-enabled bitrig/openbsd tests once their socket timeout code
+ // no longer has rounding errors.
+ #[cfg_attr(any(target_os = "bitrig", target_os = "netbsd", target_os = "openbsd"), ignore)]
+ #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
+ #[test]
+ fn timeouts() {
+ let addr = next_test_ip4();
+ let listener = t!(TcpListener::bind(&addr));
+
+ let stream = t!(TcpStream::connect(&("localhost", addr.port())));
+ let dur = Duration::new(15410, 0);
+
+ assert_eq!(None, t!(stream.read_timeout()));
+
+ t!(stream.set_read_timeout(Some(dur)));
+ assert_eq!(Some(dur), t!(stream.read_timeout()));
+
+ assert_eq!(None, t!(stream.write_timeout()));
+
+ t!(stream.set_write_timeout(Some(dur)));
+ assert_eq!(Some(dur), t!(stream.write_timeout()));
+
+ t!(stream.set_read_timeout(None));
+ assert_eq!(None, t!(stream.read_timeout()));
+
+ t!(stream.set_write_timeout(None));
+ assert_eq!(None, t!(stream.write_timeout()));
+ drop(listener);
+ }
+
+ #[test]
+ #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
+ fn test_read_timeout() {
+ let addr = next_test_ip4();
+ let listener = t!(TcpListener::bind(&addr));
+
+ let mut stream = t!(TcpStream::connect(&("localhost", addr.port())));
+ t!(stream.set_read_timeout(Some(Duration::from_millis(1000))));
+
+ let mut buf = [0; 10];
+ let start = Instant::now();
+ let kind = stream.read_exact(&mut buf).err().expect("expected error").kind();
+ assert!(kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut,
+ "unexpected_error: {:?}", kind);
+ assert!(start.elapsed() > Duration::from_millis(400));
+ drop(listener);
+ }
+
+ #[test]
+ #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
+ fn test_read_with_timeout() {
+ let addr = next_test_ip4();
+ let listener = t!(TcpListener::bind(&addr));
+
+ let mut stream = t!(TcpStream::connect(&("localhost", addr.port())));
+ t!(stream.set_read_timeout(Some(Duration::from_millis(1000))));
+
+ let mut other_end = t!(listener.accept()).0;
+ t!(other_end.write_all(b"hello world"));
+
+ let mut buf = [0; 11];
+ t!(stream.read(&mut buf));
+ assert_eq!(b"hello world", &buf[..]);
+
+ let start = Instant::now();
+ let kind = stream.read_exact(&mut buf).err().expect("expected error").kind();
+ assert!(kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut,
+ "unexpected_error: {:?}", kind);
+ assert!(start.elapsed() > Duration::from_millis(400));
+ drop(listener);
+ }
+
+ // Ensure the `set_read_timeout` and `set_write_timeout` calls return errors
+ // when passed zero Durations
+ #[test]
+ fn test_timeout_zero_duration() {
+ let addr = next_test_ip4();
+
+ let listener = t!(TcpListener::bind(&addr));
+ let stream = t!(TcpStream::connect(&addr));
+
+ let result = stream.set_write_timeout(Some(Duration::new(0, 0)));
+ let err = result.unwrap_err();
+ assert_eq!(err.kind(), ErrorKind::InvalidInput);
+
+ let result = stream.set_read_timeout(Some(Duration::new(0, 0)));
+ let err = result.unwrap_err();
+ assert_eq!(err.kind(), ErrorKind::InvalidInput);
+
+ drop(listener);
+ }
+
+ #[test]
+ #[cfg_attr(target_env = "sgx", ignore)]
+ fn nodelay() {
+ let addr = next_test_ip4();
+ let _listener = t!(TcpListener::bind(&addr));
+
+ let stream = t!(TcpStream::connect(&("localhost", addr.port())));
+
+ assert_eq!(false, t!(stream.nodelay()));
+ t!(stream.set_nodelay(true));
+ assert_eq!(true, t!(stream.nodelay()));
+ t!(stream.set_nodelay(false));
+ assert_eq!(false, t!(stream.nodelay()));
+ }
+
+ #[test]
+ #[cfg_attr(target_env = "sgx", ignore)]
+ fn ttl() {
+ let ttl = 100;
+
+ let addr = next_test_ip4();
+ let listener = t!(TcpListener::bind(&addr));
+
+ t!(listener.set_ttl(ttl));
+ assert_eq!(ttl, t!(listener.ttl()));
+
+ let stream = t!(TcpStream::connect(&("localhost", addr.port())));
+
+ t!(stream.set_ttl(ttl));
+ assert_eq!(ttl, t!(stream.ttl()));
+ }
+
+ #[test]
+ #[cfg_attr(target_env = "sgx", ignore)]
+ fn set_nonblocking() {
+ let addr = next_test_ip4();
+ let listener = t!(TcpListener::bind(&addr));
+
+ t!(listener.set_nonblocking(true));
+ t!(listener.set_nonblocking(false));
+
+ let mut stream = t!(TcpStream::connect(&("localhost", addr.port())));
+
+ t!(stream.set_nonblocking(false));
+ t!(stream.set_nonblocking(true));
+
+ let mut buf = [0];
+ match stream.read(&mut buf) {
+ Ok(_) => panic!("expected error"),
+ Err(ref e) if e.kind() == ErrorKind::WouldBlock => {}
+ Err(e) => panic!("unexpected error {}", e),
+ }
+ }
+
+ #[test]
+ #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
+ fn peek() {
+ each_ip(&mut |addr| {
+ let (txdone, rxdone) = channel();
+
+ let srv = t!(TcpListener::bind(&addr));
+ let _t = thread::spawn(move|| {
+ let mut cl = t!(srv.accept()).0;
+ cl.write(&[1,3,3,7]).unwrap();
+ t!(rxdone.recv());
+ });
+
+ let mut c = t!(TcpStream::connect(&addr));
+ let mut b = [0; 10];
+ for _ in 1..3 {
+ let len = c.peek(&mut b).unwrap();
+ assert_eq!(len, 4);
+ }
+ let len = c.read(&mut b).unwrap();
+ assert_eq!(len, 4);
+
+ t!(c.set_nonblocking(true));
+ match c.peek(&mut b) {
+ Ok(_) => panic!("expected error"),
+ Err(ref e) if e.kind() == ErrorKind::WouldBlock => {}
+ Err(e) => panic!("unexpected error {}", e),
+ }
+ t!(txdone.send(()));
+ })
+ }
+
+ #[test]
+ #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
+ fn connect_timeout_valid() {
+ let listener = TcpListener::bind("127.0.0.1:0").unwrap();
+ let addr = listener.local_addr().unwrap();
+ TcpStream::connect_timeout(&addr, Duration::from_secs(2)).unwrap();
+ }
+}
diff --git a/src/libstd/net/test.rs b/src/libstd/net/test.rs
new file mode 100644
index 0000000..e2991cb
--- /dev/null
+++ b/src/libstd/net/test.rs
@@ -0,0 +1,51 @@
+#![allow(warnings)] // not used on emscripten
+
+use crate::env;
+use crate::net::{SocketAddr, SocketAddrV4, SocketAddrV6, Ipv4Addr, Ipv6Addr, ToSocketAddrs};
+use crate::sync::atomic::{AtomicUsize, Ordering};
+
+static PORT: AtomicUsize = AtomicUsize::new(0);
+
+pub fn next_test_ip4() -> SocketAddr {
+ let port = PORT.fetch_add(1, Ordering::SeqCst) as u16 + base_port();
+ SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), port))
+}
+
+pub fn next_test_ip6() -> SocketAddr {
+ let port = PORT.fetch_add(1, Ordering::SeqCst) as u16 + base_port();
+ SocketAddr::V6(SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1),
+ port, 0, 0))
+}
+
+pub fn sa4(a: Ipv4Addr, p: u16) -> SocketAddr {
+ SocketAddr::V4(SocketAddrV4::new(a, p))
+}
+
+pub fn sa6(a: Ipv6Addr, p: u16) -> SocketAddr {
+ SocketAddr::V6(SocketAddrV6::new(a, p, 0, 0))
+}
+
+pub fn tsa<A: ToSocketAddrs>(a: A) -> Result<Vec<SocketAddr>, String> {
+ match a.to_socket_addrs() {
+ Ok(a) => Ok(a.collect()),
+ Err(e) => Err(e.to_string()),
+ }
+}
+
+// The bots run multiple builds at the same time, and these builds
+// all want to use ports. This function figures out which workspace
+// it is running in and assigns a port range based on it.
+fn base_port() -> u16 {
+ let cwd = if cfg!(target_env = "sgx") {
+ String::from("sgx")
+ } else {
+ env::current_dir().unwrap().into_os_string().into_string().unwrap()
+ };
+ let dirs = ["32-opt", "32-nopt",
+ "musl-64-opt", "cross-opt",
+ "64-opt", "64-nopt", "64-opt-vg", "64-debug-opt",
+ "all-opt", "snap3", "dist", "sgx"];
+ dirs.iter().enumerate().find(|&(_, dir)| {
+ cwd.contains(dir)
+ }).map(|p| p.0).unwrap_or(0) as u16 * 1000 + 19600
+}
diff --git a/src/libstd/net/udp.rs b/src/libstd/net/udp.rs
new file mode 100644
index 0000000..d4187d2
--- /dev/null
+++ b/src/libstd/net/udp.rs
@@ -0,0 +1,1206 @@
+use crate::fmt;
+use crate::io::{self, Error, ErrorKind};
+use crate::net::{ToSocketAddrs, SocketAddr, Ipv4Addr, Ipv6Addr};
+use crate::sys_common::net as net_imp;
+use crate::sys_common::{AsInner, FromInner, IntoInner};
+use crate::time::Duration;
+
+/// A UDP socket.
+///
+/// After creating a `UdpSocket` by [`bind`]ing it to a socket address, data can be
+/// [sent to] and [received from] any other socket address.
+///
+/// Although UDP is a connectionless protocol, this implementation provides an interface
+/// to set an address where data should be sent and received from. After setting a remote
+/// address with [`connect`], data can be sent to and received from that address with
+/// [`send`] and [`recv`].
+///
+/// As stated in the User Datagram Protocol's specification in [IETF RFC 768], UDP is
+/// an unordered, unreliable protocol; refer to [`TcpListener`] and [`TcpStream`] for TCP
+/// primitives.
+///
+/// [`bind`]: #method.bind
+/// [`connect`]: #method.connect
+/// [IETF RFC 768]: https://tools.ietf.org/html/rfc768
+/// [`recv`]: #method.recv
+/// [received from]: #method.recv_from
+/// [`send`]: #method.send
+/// [sent to]: #method.send_to
+/// [`TcpListener`]: ../../std/net/struct.TcpListener.html
+/// [`TcpStream`]: ../../std/net/struct.TcpStream.html
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::net::UdpSocket;
+///
+/// fn main() -> std::io::Result<()> {
+/// {
+/// let mut socket = UdpSocket::bind("127.0.0.1:34254")?;
+///
+/// // Receives a single datagram message on the socket. If `buf` is too small to hold
+/// // the message, it will be cut off.
+/// let mut buf = [0; 10];
+/// let (amt, src) = socket.recv_from(&mut buf)?;
+///
+/// // Redeclare `buf` as slice of the received data and send reverse data back to origin.
+/// let buf = &mut buf[..amt];
+/// buf.reverse();
+/// socket.send_to(buf, &src)?;
+/// } // the socket is closed here
+/// Ok(())
+/// }
+/// ```
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct UdpSocket(net_imp::UdpSocket);
+
+impl UdpSocket {
+ /// Creates a UDP socket from the given address.
+ ///
+ /// The address type can be any implementor of [`ToSocketAddrs`] trait. See
+ /// its documentation for concrete examples.
+ ///
+ /// If `addr` yields multiple addresses, `bind` will be attempted with
+ /// each of the addresses until one succeeds and returns the socket. If none
+ /// of the addresses succeed in creating a socket, the error returned from
+ /// the last attempt (the last address) is returned.
+ ///
+ /// [`ToSocketAddrs`]: ../../std/net/trait.ToSocketAddrs.html
+ ///
+ /// # Examples
+ ///
+ /// Creates a UDP socket bound to `127.0.0.1:3400`:
+ ///
+ /// ```no_run
+ /// use std::net::UdpSocket;
+ ///
+ /// let socket = UdpSocket::bind("127.0.0.1:3400").expect("couldn't bind to address");
+ /// ```
+ ///
+ /// Creates a UDP socket bound to `127.0.0.1:3400`. If the socket cannot be
+ /// bound to that address, create a UDP socket bound to `127.0.0.1:3401`:
+ ///
+ /// ```no_run
+ /// use std::net::{SocketAddr, UdpSocket};
+ ///
+ /// let addrs = [
+ /// SocketAddr::from(([127, 0, 0, 1], 3400)),
+ /// SocketAddr::from(([127, 0, 0, 1], 3401)),
+ /// ];
+ /// let socket = UdpSocket::bind(&addrs[..]).expect("couldn't bind to address");
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn bind<A: ToSocketAddrs>(addr: A) -> io::Result<UdpSocket> {
+ super::each_addr(addr, net_imp::UdpSocket::bind).map(UdpSocket)
+ }
+
+ /// Receives a single datagram message on the socket. On success, returns the number
+ /// of bytes read and the origin.
+ ///
+ /// The function must be called with valid byte array `buf` of sufficient size to
+ /// hold the message bytes. If a message is too long to fit in the supplied buffer,
+ /// excess bytes may be discarded.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::net::UdpSocket;
+ ///
+ /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address");
+ /// let mut buf = [0; 10];
+ /// let (number_of_bytes, src_addr) = socket.recv_from(&mut buf)
+ /// .expect("Didn't receive data");
+ /// let filled_buf = &mut buf[..number_of_bytes];
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+ self.0.recv_from(buf)
+ }
+
+ /// Receives a single datagram message on the socket, without removing it from the
+ /// queue. On success, returns the number of bytes read and the origin.
+ ///
+ /// The function must be called with valid byte array `buf` of sufficient size to
+ /// hold the message bytes. If a message is too long to fit in the supplied buffer,
+ /// excess bytes may be discarded.
+ ///
+ /// Successive calls return the same data. This is accomplished by passing
+ /// `MSG_PEEK` as a flag to the underlying `recvfrom` system call.
+ ///
+ /// Do not use this function to implement busy waiting, instead use `libc::poll` to
+ /// synchronize IO events on one or more sockets.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::net::UdpSocket;
+ ///
+ /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address");
+ /// let mut buf = [0; 10];
+ /// let (number_of_bytes, src_addr) = socket.peek_from(&mut buf)
+ /// .expect("Didn't receive data");
+ /// let filled_buf = &mut buf[..number_of_bytes];
+ /// ```
+ #[stable(feature = "peek", since = "1.18.0")]
+ pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+ self.0.peek_from(buf)
+ }
+
+ /// Sends data on the socket to the given address. On success, returns the
+ /// number of bytes written.
+ ///
+ /// Address type can be any implementor of [`ToSocketAddrs`] trait. See its
+ /// documentation for concrete examples.
+ ///
+ /// It is possible for `addr` to yield multiple addresses, but `send_to`
+ /// will only send data to the first address yielded by `addr`.
+ ///
+ /// This will return an error when the IP version of the local socket
+ /// does not match that returned from [`ToSocketAddrs`].
+ ///
+ /// See issue #34202 for more details.
+ ///
+ /// [`ToSocketAddrs`]: ../../std/net/trait.ToSocketAddrs.html
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::net::UdpSocket;
+ ///
+ /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address");
+ /// socket.send_to(&[0; 10], "127.0.0.1:4242").expect("couldn't send data");
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn send_to<A: ToSocketAddrs>(&self, buf: &[u8], addr: A)
+ -> io::Result<usize> {
+ match addr.to_socket_addrs()?.next() {
+ Some(addr) => self.0.send_to(buf, &addr),
+ None => Err(Error::new(ErrorKind::InvalidInput,
+ "no addresses to send data to")),
+ }
+ }
+
+ /// Returns the socket address of the remote peer this socket was connected to.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// #![feature(udp_peer_addr)]
+ /// use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4, UdpSocket};
+ ///
+ /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address");
+ /// socket.connect("192.168.0.1:41203").expect("couldn't connect to address");
+ /// assert_eq!(socket.peer_addr().unwrap(),
+ /// SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(192, 168, 0, 1), 41203)));
+ /// ```
+ ///
+ /// If the socket isn't connected, it will return a [`NotConnected`] error.
+ ///
+ /// [`NotConnected`]: ../../std/io/enum.ErrorKind.html#variant.NotConnected
+ ///
+ /// ```no_run
+ /// #![feature(udp_peer_addr)]
+ /// use std::net::UdpSocket;
+ ///
+ /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address");
+ /// assert_eq!(socket.peer_addr().unwrap_err().kind(),
+ /// ::std::io::ErrorKind::NotConnected);
+ /// ```
+ #[unstable(feature = "udp_peer_addr", issue = "59127")]
+ pub fn peer_addr(&self) -> io::Result<SocketAddr> {
+ self.0.peer_addr()
+ }
+
+ /// Returns the socket address that this socket was created from.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4, UdpSocket};
+ ///
+ /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address");
+ /// assert_eq!(socket.local_addr().unwrap(),
+ /// SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 34254)));
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn local_addr(&self) -> io::Result<SocketAddr> {
+ self.0.socket_addr()
+ }
+
+ /// Creates a new independently owned handle to the underlying socket.
+ ///
+ /// The returned `UdpSocket` is a reference to the same socket that this
+ /// object references. Both handles will read and write the same port, and
+ /// options set on one socket will be propagated to the other.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::net::UdpSocket;
+ ///
+ /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address");
+ /// let socket_clone = socket.try_clone().expect("couldn't clone the socket");
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn try_clone(&self) -> io::Result<UdpSocket> {
+ self.0.duplicate().map(UdpSocket)
+ }
+
+ /// Sets the read timeout to the timeout specified.
+ ///
+ /// If the value specified is [`None`], then [`read`] calls will block
+ /// indefinitely. An [`Err`] is returned if the zero [`Duration`] is
+ /// passed to this method.
+ ///
+ /// # Platform-specific behavior
+ ///
+ /// Platforms may return a different error code whenever a read times out as
+ /// a result of setting this option. For example Unix typically returns an
+ /// error of the kind [`WouldBlock`], but Windows may return [`TimedOut`].
+ ///
+ /// [`None`]: ../../std/option/enum.Option.html#variant.None
+ /// [`Err`]: ../../std/result/enum.Result.html#variant.Err
+ /// [`read`]: ../../std/io/trait.Read.html#tymethod.read
+ /// [`Duration`]: ../../std/time/struct.Duration.html
+ /// [`WouldBlock`]: ../../std/io/enum.ErrorKind.html#variant.WouldBlock
+ /// [`TimedOut`]: ../../std/io/enum.ErrorKind.html#variant.TimedOut
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::net::UdpSocket;
+ ///
+ /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address");
+ /// socket.set_read_timeout(None).expect("set_read_timeout call failed");
+ /// ```
+ ///
+ /// An [`Err`] is returned if the zero [`Duration`] is passed to this
+ /// method:
+ ///
+ /// ```no_run
+ /// use std::io;
+ /// use std::net::UdpSocket;
+ /// use std::time::Duration;
+ ///
+ /// let socket = UdpSocket::bind("127.0.0.1:34254").unwrap();
+ /// let result = socket.set_read_timeout(Some(Duration::new(0, 0)));
+ /// let err = result.unwrap_err();
+ /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput)
+ /// ```
+ #[stable(feature = "socket_timeout", since = "1.4.0")]
+ pub fn set_read_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
+ self.0.set_read_timeout(dur)
+ }
+
+ /// Sets the write timeout to the timeout specified.
+ ///
+ /// If the value specified is [`None`], then [`write`] calls will block
+ /// indefinitely. An [`Err`] is returned if the zero [`Duration`] is
+ /// passed to this method.
+ ///
+ /// # Platform-specific behavior
+ ///
+ /// Platforms may return a different error code whenever a write times out
+ /// as a result of setting this option. For example Unix typically returns
+ /// an error of the kind [`WouldBlock`], but Windows may return [`TimedOut`].
+ ///
+ /// [`None`]: ../../std/option/enum.Option.html#variant.None
+ /// [`Err`]: ../../std/result/enum.Result.html#variant.Err
+ /// [`write`]: ../../std/io/trait.Write.html#tymethod.write
+ /// [`Duration`]: ../../std/time/struct.Duration.html
+ /// [`WouldBlock`]: ../../std/io/enum.ErrorKind.html#variant.WouldBlock
+ /// [`TimedOut`]: ../../std/io/enum.ErrorKind.html#variant.TimedOut
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::net::UdpSocket;
+ ///
+ /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address");
+ /// socket.set_write_timeout(None).expect("set_write_timeout call failed");
+ /// ```
+ ///
+ /// An [`Err`] is returned if the zero [`Duration`] is passed to this
+ /// method:
+ ///
+ /// ```no_run
+ /// use std::io;
+ /// use std::net::UdpSocket;
+ /// use std::time::Duration;
+ ///
+ /// let socket = UdpSocket::bind("127.0.0.1:34254").unwrap();
+ /// let result = socket.set_write_timeout(Some(Duration::new(0, 0)));
+ /// let err = result.unwrap_err();
+ /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput)
+ /// ```
+ #[stable(feature = "socket_timeout", since = "1.4.0")]
+ pub fn set_write_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
+ self.0.set_write_timeout(dur)
+ }
+
+ /// Returns the read timeout of this socket.
+ ///
+ /// If the timeout is [`None`], then [`read`] calls will block indefinitely.
+ ///
+ /// [`None`]: ../../std/option/enum.Option.html#variant.None
+ /// [`read`]: ../../std/io/trait.Read.html#tymethod.read
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::net::UdpSocket;
+ ///
+ /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address");
+ /// socket.set_read_timeout(None).expect("set_read_timeout call failed");
+ /// assert_eq!(socket.read_timeout().unwrap(), None);
+ /// ```
+ #[stable(feature = "socket_timeout", since = "1.4.0")]
+ pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
+ self.0.read_timeout()
+ }
+
+ /// Returns the write timeout of this socket.
+ ///
+ /// If the timeout is [`None`], then [`write`] calls will block indefinitely.
+ ///
+ /// [`None`]: ../../std/option/enum.Option.html#variant.None
+ /// [`write`]: ../../std/io/trait.Write.html#tymethod.write
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::net::UdpSocket;
+ ///
+ /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address");
+ /// socket.set_write_timeout(None).expect("set_write_timeout call failed");
+ /// assert_eq!(socket.write_timeout().unwrap(), None);
+ /// ```
+ #[stable(feature = "socket_timeout", since = "1.4.0")]
+ pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
+ self.0.write_timeout()
+ }
+
+ /// Sets the value of the `SO_BROADCAST` option for this socket.
+ ///
+ /// When enabled, this socket is allowed to send packets to a broadcast
+ /// address.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::net::UdpSocket;
+ ///
+ /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address");
+ /// socket.set_broadcast(false).expect("set_broadcast call failed");
+ /// ```
+ #[stable(feature = "net2_mutators", since = "1.9.0")]
+ pub fn set_broadcast(&self, broadcast: bool) -> io::Result<()> {
+ self.0.set_broadcast(broadcast)
+ }
+
+ /// Gets the value of the `SO_BROADCAST` option for this socket.
+ ///
+ /// For more information about this option, see
+ /// [`set_broadcast`][link].
+ ///
+ /// [link]: #method.set_broadcast
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::net::UdpSocket;
+ ///
+ /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address");
+ /// socket.set_broadcast(false).expect("set_broadcast call failed");
+ /// assert_eq!(socket.broadcast().unwrap(), false);
+ /// ```
+ #[stable(feature = "net2_mutators", since = "1.9.0")]
+ pub fn broadcast(&self) -> io::Result<bool> {
+ self.0.broadcast()
+ }
+
+ /// Sets the value of the `IP_MULTICAST_LOOP` option for this socket.
+ ///
+ /// If enabled, multicast packets will be looped back to the local socket.
+ /// Note that this may not have any affect on IPv6 sockets.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::net::UdpSocket;
+ ///
+ /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address");
+ /// socket.set_multicast_loop_v4(false).expect("set_multicast_loop_v4 call failed");
+ /// ```
+ #[stable(feature = "net2_mutators", since = "1.9.0")]
+ pub fn set_multicast_loop_v4(&self, multicast_loop_v4: bool) -> io::Result<()> {
+ self.0.set_multicast_loop_v4(multicast_loop_v4)
+ }
+
+ /// Gets the value of the `IP_MULTICAST_LOOP` option for this socket.
+ ///
+ /// For more information about this option, see
+ /// [`set_multicast_loop_v4`][link].
+ ///
+ /// [link]: #method.set_multicast_loop_v4
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::net::UdpSocket;
+ ///
+ /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address");
+ /// socket.set_multicast_loop_v4(false).expect("set_multicast_loop_v4 call failed");
+ /// assert_eq!(socket.multicast_loop_v4().unwrap(), false);
+ /// ```
+ #[stable(feature = "net2_mutators", since = "1.9.0")]
+ pub fn multicast_loop_v4(&self) -> io::Result<bool> {
+ self.0.multicast_loop_v4()
+ }
+
+ /// Sets the value of the `IP_MULTICAST_TTL` option for this socket.
+ ///
+ /// Indicates the time-to-live value of outgoing multicast packets for
+ /// this socket. The default value is 1 which means that multicast packets
+ /// don't leave the local network unless explicitly requested.
+ ///
+ /// Note that this may not have any affect on IPv6 sockets.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::net::UdpSocket;
+ ///
+ /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address");
+ /// socket.set_multicast_ttl_v4(42).expect("set_multicast_ttl_v4 call failed");
+ /// ```
+ #[stable(feature = "net2_mutators", since = "1.9.0")]
+ pub fn set_multicast_ttl_v4(&self, multicast_ttl_v4: u32) -> io::Result<()> {
+ self.0.set_multicast_ttl_v4(multicast_ttl_v4)
+ }
+
+ /// Gets the value of the `IP_MULTICAST_TTL` option for this socket.
+ ///
+ /// For more information about this option, see
+ /// [`set_multicast_ttl_v4`][link].
+ ///
+ /// [link]: #method.set_multicast_ttl_v4
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::net::UdpSocket;
+ ///
+ /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address");
+ /// socket.set_multicast_ttl_v4(42).expect("set_multicast_ttl_v4 call failed");
+ /// assert_eq!(socket.multicast_ttl_v4().unwrap(), 42);
+ /// ```
+ #[stable(feature = "net2_mutators", since = "1.9.0")]
+ pub fn multicast_ttl_v4(&self) -> io::Result<u32> {
+ self.0.multicast_ttl_v4()
+ }
+
+ /// Sets the value of the `IPV6_MULTICAST_LOOP` option for this socket.
+ ///
+ /// Controls whether this socket sees the multicast packets it sends itself.
+ /// Note that this may not have any affect on IPv4 sockets.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::net::UdpSocket;
+ ///
+ /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address");
+ /// socket.set_multicast_loop_v6(false).expect("set_multicast_loop_v6 call failed");
+ /// ```
+ #[stable(feature = "net2_mutators", since = "1.9.0")]
+ pub fn set_multicast_loop_v6(&self, multicast_loop_v6: bool) -> io::Result<()> {
+ self.0.set_multicast_loop_v6(multicast_loop_v6)
+ }
+
+ /// Gets the value of the `IPV6_MULTICAST_LOOP` option for this socket.
+ ///
+ /// For more information about this option, see
+ /// [`set_multicast_loop_v6`][link].
+ ///
+ /// [link]: #method.set_multicast_loop_v6
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::net::UdpSocket;
+ ///
+ /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address");
+ /// socket.set_multicast_loop_v6(false).expect("set_multicast_loop_v6 call failed");
+ /// assert_eq!(socket.multicast_loop_v6().unwrap(), false);
+ /// ```
+ #[stable(feature = "net2_mutators", since = "1.9.0")]
+ pub fn multicast_loop_v6(&self) -> io::Result<bool> {
+ self.0.multicast_loop_v6()
+ }
+
+ /// Sets the value for the `IP_TTL` option on this socket.
+ ///
+ /// This value sets the time-to-live field that is used in every packet sent
+ /// from this socket.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::net::UdpSocket;
+ ///
+ /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address");
+ /// socket.set_ttl(42).expect("set_ttl call failed");
+ /// ```
+ #[stable(feature = "net2_mutators", since = "1.9.0")]
+ pub fn set_ttl(&self, ttl: u32) -> io::Result<()> {
+ self.0.set_ttl(ttl)
+ }
+
+ /// Gets the value of the `IP_TTL` option for this socket.
+ ///
+ /// For more information about this option, see [`set_ttl`][link].
+ ///
+ /// [link]: #method.set_ttl
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::net::UdpSocket;
+ ///
+ /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address");
+ /// socket.set_ttl(42).expect("set_ttl call failed");
+ /// assert_eq!(socket.ttl().unwrap(), 42);
+ /// ```
+ #[stable(feature = "net2_mutators", since = "1.9.0")]
+ pub fn ttl(&self) -> io::Result<u32> {
+ self.0.ttl()
+ }
+
+ /// Executes an operation of the `IP_ADD_MEMBERSHIP` type.
+ ///
+ /// This function specifies a new multicast group for this socket to join.
+ /// The address must be a valid multicast address, and `interface` is the
+ /// address of the local interface with which the system should join the
+ /// multicast group. If it's equal to `INADDR_ANY` then an appropriate
+ /// interface is chosen by the system.
+ #[stable(feature = "net2_mutators", since = "1.9.0")]
+ pub fn join_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> io::Result<()> {
+ self.0.join_multicast_v4(multiaddr, interface)
+ }
+
+ /// Executes an operation of the `IPV6_ADD_MEMBERSHIP` type.
+ ///
+ /// This function specifies a new multicast group for this socket to join.
+ /// The address must be a valid multicast address, and `interface` is the
+ /// index of the interface to join/leave (or 0 to indicate any interface).
+ #[stable(feature = "net2_mutators", since = "1.9.0")]
+ pub fn join_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> {
+ self.0.join_multicast_v6(multiaddr, interface)
+ }
+
+ /// Executes an operation of the `IP_DROP_MEMBERSHIP` type.
+ ///
+ /// For more information about this option, see
+ /// [`join_multicast_v4`][link].
+ ///
+ /// [link]: #method.join_multicast_v4
+ #[stable(feature = "net2_mutators", since = "1.9.0")]
+ pub fn leave_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> io::Result<()> {
+ self.0.leave_multicast_v4(multiaddr, interface)
+ }
+
+ /// Executes an operation of the `IPV6_DROP_MEMBERSHIP` type.
+ ///
+ /// For more information about this option, see
+ /// [`join_multicast_v6`][link].
+ ///
+ /// [link]: #method.join_multicast_v6
+ #[stable(feature = "net2_mutators", since = "1.9.0")]
+ pub fn leave_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> {
+ self.0.leave_multicast_v6(multiaddr, interface)
+ }
+
+ /// Gets the value of the `SO_ERROR` option on this socket.
+ ///
+ /// This will retrieve the stored error in the underlying socket, clearing
+ /// the field in the process. This can be useful for checking errors between
+ /// calls.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::net::UdpSocket;
+ ///
+ /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address");
+ /// match socket.take_error() {
+ /// Ok(Some(error)) => println!("UdpSocket error: {:?}", error),
+ /// Ok(None) => println!("No error"),
+ /// Err(error) => println!("UdpSocket.take_error failed: {:?}", error),
+ /// }
+ /// ```
+ #[stable(feature = "net2_mutators", since = "1.9.0")]
+ pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+ self.0.take_error()
+ }
+
+ /// Connects this UDP socket to a remote address, allowing the `send` and
+ /// `recv` syscalls to be used to send data and also applies filters to only
+ /// receive data from the specified address.
+ ///
+ /// If `addr` yields multiple addresses, `connect` will be attempted with
+ /// each of the addresses until the underlying OS function returns no
+ /// error. Note that usually, a successful `connect` call does not specify
+ /// that there is a remote server listening on the port, rather, such an
+ /// error would only be detected after the first send. If the OS returns an
+ /// error for each of the specified addresses, the error returned from the
+ /// last connection attempt (the last address) is returned.
+ ///
+ /// # Examples
+ ///
+ /// Creates a UDP socket bound to `127.0.0.1:3400` and connect the socket to
+ /// `127.0.0.1:8080`:
+ ///
+ /// ```no_run
+ /// use std::net::UdpSocket;
+ ///
+ /// let socket = UdpSocket::bind("127.0.0.1:3400").expect("couldn't bind to address");
+ /// socket.connect("127.0.0.1:8080").expect("connect function failed");
+ /// ```
+ ///
+ /// Unlike in the TCP case, passing an array of addresses to the `connect`
+ /// function of a UDP socket is not a useful thing to do: The OS will be
+ /// unable to determine whether something is listening on the remote
+ /// address without the application sending data.
+ #[stable(feature = "net2_mutators", since = "1.9.0")]
+ pub fn connect<A: ToSocketAddrs>(&self, addr: A) -> io::Result<()> {
+ super::each_addr(addr, |addr| self.0.connect(addr))
+ }
+
+ /// Sends data on the socket to the remote address to which it is connected.
+ ///
+ /// The [`connect`] method will connect this socket to a remote address. This
+ /// method will fail if the socket is not connected.
+ ///
+ /// [`connect`]: #method.connect
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::net::UdpSocket;
+ ///
+ /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address");
+ /// socket.connect("127.0.0.1:8080").expect("connect function failed");
+ /// socket.send(&[0, 1, 2]).expect("couldn't send message");
+ /// ```
+ #[stable(feature = "net2_mutators", since = "1.9.0")]
+ pub fn send(&self, buf: &[u8]) -> io::Result<usize> {
+ self.0.send(buf)
+ }
+
+ /// Receives a single datagram message on the socket from the remote address to
+ /// which it is connected. On success, returns the number of bytes read.
+ ///
+ /// The function must be called with valid byte array `buf` of sufficient size to
+ /// hold the message bytes. If a message is too long to fit in the supplied buffer,
+ /// excess bytes may be discarded.
+ ///
+ /// The [`connect`] method will connect this socket to a remote address. This
+ /// method will fail if the socket is not connected.
+ ///
+ /// [`connect`]: #method.connect
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::net::UdpSocket;
+ ///
+ /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address");
+ /// socket.connect("127.0.0.1:8080").expect("connect function failed");
+ /// let mut buf = [0; 10];
+ /// match socket.recv(&mut buf) {
+ /// Ok(received) => println!("received {} bytes {:?}", received, &buf[..received]),
+ /// Err(e) => println!("recv function failed: {:?}", e),
+ /// }
+ /// ```
+ #[stable(feature = "net2_mutators", since = "1.9.0")]
+ pub fn recv(&self, buf: &mut [u8]) -> io::Result<usize> {
+ self.0.recv(buf)
+ }
+
+ /// Receives single datagram on the socket from the remote address to which it is
+ /// connected, without removing the message from input queue. On success, returns
+ /// the number of bytes peeked.
+ ///
+ /// The function must be called with valid byte array `buf` of sufficient size to
+ /// hold the message bytes. If a message is too long to fit in the supplied buffer,
+ /// excess bytes may be discarded.
+ ///
+ /// Successive calls return the same data. This is accomplished by passing
+ /// `MSG_PEEK` as a flag to the underlying `recv` system call.
+ ///
+ /// Do not use this function to implement busy waiting, instead use `libc::poll` to
+ /// synchronize IO events on one or more sockets.
+ ///
+ /// The [`connect`] method will connect this socket to a remote address. This
+ /// method will fail if the socket is not connected.
+ ///
+ /// [`connect`]: #method.connect
+ ///
+ /// # Errors
+ ///
+ /// This method will fail if the socket is not connected. The `connect` method
+ /// will connect this socket to a remote address.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::net::UdpSocket;
+ ///
+ /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address");
+ /// socket.connect("127.0.0.1:8080").expect("connect function failed");
+ /// let mut buf = [0; 10];
+ /// match socket.peek(&mut buf) {
+ /// Ok(received) => println!("received {} bytes", received),
+ /// Err(e) => println!("peek function failed: {:?}", e),
+ /// }
+ /// ```
+ #[stable(feature = "peek", since = "1.18.0")]
+ pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
+ self.0.peek(buf)
+ }
+
+ /// Moves this UDP socket into or out of nonblocking mode.
+ ///
+ /// This will result in `recv`, `recv_from`, `send`, and `send_to`
+ /// operations becoming nonblocking, i.e., immediately returning from their
+ /// calls. If the IO operation is successful, `Ok` is returned and no
+ /// further action is required. If the IO operation could not be completed
+ /// and needs to be retried, an error with kind
+ /// [`io::ErrorKind::WouldBlock`] is returned.
+ ///
+ /// On Unix platforms, calling this method corresponds to calling `fcntl`
+ /// `FIONBIO`. On Windows calling this method corresponds to calling
+ /// `ioctlsocket` `FIONBIO`.
+ ///
+ /// [`io::ErrorKind::WouldBlock`]: ../io/enum.ErrorKind.html#variant.WouldBlock
+ ///
+ /// # Examples
+ ///
+ /// Creates a UDP socket bound to `127.0.0.1:7878` and read bytes in
+ /// nonblocking mode:
+ ///
+ /// ```no_run
+ /// use std::io;
+ /// use std::net::UdpSocket;
+ ///
+ /// let socket = UdpSocket::bind("127.0.0.1:7878").unwrap();
+ /// socket.set_nonblocking(true).unwrap();
+ ///
+ /// # fn wait_for_fd() { unimplemented!() }
+ /// let mut buf = [0; 10];
+ /// let (num_bytes_read, _) = loop {
+ /// match socket.recv_from(&mut buf) {
+ /// Ok(n) => break n,
+ /// Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
+ /// // wait until network socket is ready, typically implemented
+ /// // via platform-specific APIs such as epoll or IOCP
+ /// wait_for_fd();
+ /// }
+ /// Err(e) => panic!("encountered IO error: {}", e),
+ /// }
+ /// };
+ /// println!("bytes: {:?}", &buf[..num_bytes_read]);
+ /// ```
+ #[stable(feature = "net2_mutators", since = "1.9.0")]
+ pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
+ self.0.set_nonblocking(nonblocking)
+ }
+}
+
+impl AsInner<net_imp::UdpSocket> for UdpSocket {
+ fn as_inner(&self) -> &net_imp::UdpSocket { &self.0 }
+}
+
+impl FromInner<net_imp::UdpSocket> for UdpSocket {
+ fn from_inner(inner: net_imp::UdpSocket) -> UdpSocket { UdpSocket(inner) }
+}
+
+impl IntoInner<net_imp::UdpSocket> for UdpSocket {
+ fn into_inner(self) -> net_imp::UdpSocket { self.0 }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl fmt::Debug for UdpSocket {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ self.0.fmt(f)
+ }
+}
+
+#[cfg(all(test, not(any(target_os = "cloudabi", target_os = "emscripten", target_env = "sgx"))))]
+mod tests {
+ use crate::io::ErrorKind;
+ use crate::net::*;
+ use crate::net::test::{next_test_ip4, next_test_ip6};
+ use crate::sync::mpsc::channel;
+ use crate::sys_common::AsInner;
+ use crate::time::{Instant, Duration};
+ use crate::thread;
+
+ fn each_ip(f: &mut dyn FnMut(SocketAddr, SocketAddr)) {
+ f(next_test_ip4(), next_test_ip4());
+ f(next_test_ip6(), next_test_ip6());
+ }
+
+ macro_rules! t {
+ ($e:expr) => {
+ match $e {
+ Ok(t) => t,
+ Err(e) => panic!("received error for `{}`: {}", stringify!($e), e),
+ }
+ }
+ }
+
+ #[test]
+ fn bind_error() {
+ match UdpSocket::bind("1.1.1.1:9999") {
+ Ok(..) => panic!(),
+ Err(e) => {
+ assert_eq!(e.kind(), ErrorKind::AddrNotAvailable)
+ }
+ }
+ }
+
+ #[test]
+ fn socket_smoke_test_ip4() {
+ each_ip(&mut |server_ip, client_ip| {
+ let (tx1, rx1) = channel();
+ let (tx2, rx2) = channel();
+
+ let _t = thread::spawn(move|| {
+ let client = t!(UdpSocket::bind(&client_ip));
+ rx1.recv().unwrap();
+ t!(client.send_to(&[99], &server_ip));
+ tx2.send(()).unwrap();
+ });
+
+ let server = t!(UdpSocket::bind(&server_ip));
+ tx1.send(()).unwrap();
+ let mut buf = [0];
+ let (nread, src) = t!(server.recv_from(&mut buf));
+ assert_eq!(nread, 1);
+ assert_eq!(buf[0], 99);
+ assert_eq!(src, client_ip);
+ rx2.recv().unwrap();
+ })
+ }
+
+ #[test]
+ fn socket_name() {
+ each_ip(&mut |addr, _| {
+ let server = t!(UdpSocket::bind(&addr));
+ assert_eq!(addr, t!(server.local_addr()));
+ })
+ }
+
+ #[test]
+ fn socket_peer() {
+ each_ip(&mut |addr1, addr2| {
+ let server = t!(UdpSocket::bind(&addr1));
+ assert_eq!(server.peer_addr().unwrap_err().kind(), ErrorKind::NotConnected);
+ t!(server.connect(&addr2));
+ assert_eq!(addr2, t!(server.peer_addr()));
+ })
+ }
+
+ #[test]
+ fn udp_clone_smoke() {
+ each_ip(&mut |addr1, addr2| {
+ let sock1 = t!(UdpSocket::bind(&addr1));
+ let sock2 = t!(UdpSocket::bind(&addr2));
+
+ let _t = thread::spawn(move|| {
+ let mut buf = [0, 0];
+ assert_eq!(sock2.recv_from(&mut buf).unwrap(), (1, addr1));
+ assert_eq!(buf[0], 1);
+ t!(sock2.send_to(&[2], &addr1));
+ });
+
+ let sock3 = t!(sock1.try_clone());
+
+ let (tx1, rx1) = channel();
+ let (tx2, rx2) = channel();
+ let _t = thread::spawn(move|| {
+ rx1.recv().unwrap();
+ t!(sock3.send_to(&[1], &addr2));
+ tx2.send(()).unwrap();
+ });
+ tx1.send(()).unwrap();
+ let mut buf = [0, 0];
+ assert_eq!(sock1.recv_from(&mut buf).unwrap(), (1, addr2));
+ rx2.recv().unwrap();
+ })
+ }
+
+ #[test]
+ fn udp_clone_two_read() {
+ each_ip(&mut |addr1, addr2| {
+ let sock1 = t!(UdpSocket::bind(&addr1));
+ let sock2 = t!(UdpSocket::bind(&addr2));
+ let (tx1, rx) = channel();
+ let tx2 = tx1.clone();
+
+ let _t = thread::spawn(move|| {
+ t!(sock2.send_to(&[1], &addr1));
+ rx.recv().unwrap();
+ t!(sock2.send_to(&[2], &addr1));
+ rx.recv().unwrap();
+ });
+
+ let sock3 = t!(sock1.try_clone());
+
+ let (done, rx) = channel();
+ let _t = thread::spawn(move|| {
+ let mut buf = [0, 0];
+ t!(sock3.recv_from(&mut buf));
+ tx2.send(()).unwrap();
+ done.send(()).unwrap();
+ });
+ let mut buf = [0, 0];
+ t!(sock1.recv_from(&mut buf));
+ tx1.send(()).unwrap();
+
+ rx.recv().unwrap();
+ })
+ }
+
+ #[test]
+ fn udp_clone_two_write() {
+ each_ip(&mut |addr1, addr2| {
+ let sock1 = t!(UdpSocket::bind(&addr1));
+ let sock2 = t!(UdpSocket::bind(&addr2));
+
+ let (tx, rx) = channel();
+ let (serv_tx, serv_rx) = channel();
+
+ let _t = thread::spawn(move|| {
+ let mut buf = [0, 1];
+ rx.recv().unwrap();
+ t!(sock2.recv_from(&mut buf));
+ serv_tx.send(()).unwrap();
+ });
+
+ let sock3 = t!(sock1.try_clone());
+
+ let (done, rx) = channel();
+ let tx2 = tx.clone();
+ let _t = thread::spawn(move|| {
+ match sock3.send_to(&[1], &addr2) {
+ Ok(..) => { let _ = tx2.send(()); }
+ Err(..) => {}
+ }
+ done.send(()).unwrap();
+ });
+ match sock1.send_to(&[2], &addr2) {
+ Ok(..) => { let _ = tx.send(()); }
+ Err(..) => {}
+ }
+ drop(tx);
+
+ rx.recv().unwrap();
+ serv_rx.recv().unwrap();
+ })
+ }
+
+ #[test]
+ fn debug() {
+ let name = if cfg!(windows) {"socket"} else {"fd"};
+ let socket_addr = next_test_ip4();
+
+ let udpsock = t!(UdpSocket::bind(&socket_addr));
+ let udpsock_inner = udpsock.0.socket().as_inner();
+ let compare = format!("UdpSocket {{ addr: {:?}, {}: {:?} }}",
+ socket_addr, name, udpsock_inner);
+ assert_eq!(format!("{:?}", udpsock), compare);
+ }
+
+ // FIXME: re-enabled bitrig/openbsd/netbsd tests once their socket timeout code
+ // no longer has rounding errors.
+ #[cfg_attr(any(target_os = "bitrig", target_os = "netbsd", target_os = "openbsd"), ignore)]
+ #[test]
+ fn timeouts() {
+ let addr = next_test_ip4();
+
+ let stream = t!(UdpSocket::bind(&addr));
+ let dur = Duration::new(15410, 0);
+
+ assert_eq!(None, t!(stream.read_timeout()));
+
+ t!(stream.set_read_timeout(Some(dur)));
+ assert_eq!(Some(dur), t!(stream.read_timeout()));
+
+ assert_eq!(None, t!(stream.write_timeout()));
+
+ t!(stream.set_write_timeout(Some(dur)));
+ assert_eq!(Some(dur), t!(stream.write_timeout()));
+
+ t!(stream.set_read_timeout(None));
+ assert_eq!(None, t!(stream.read_timeout()));
+
+ t!(stream.set_write_timeout(None));
+ assert_eq!(None, t!(stream.write_timeout()));
+ }
+
+ #[test]
+ fn test_read_timeout() {
+ let addr = next_test_ip4();
+
+ let stream = t!(UdpSocket::bind(&addr));
+ t!(stream.set_read_timeout(Some(Duration::from_millis(1000))));
+
+ let mut buf = [0; 10];
+
+ let start = Instant::now();
+ loop {
+ let kind = stream.recv_from(&mut buf).err().expect("expected error").kind();
+ if kind != ErrorKind::Interrupted {
+ assert!(kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut,
+ "unexpected_error: {:?}", kind);
+ break;
+ }
+ }
+ assert!(start.elapsed() > Duration::from_millis(400));
+ }
+
+ #[test]
+ fn test_read_with_timeout() {
+ let addr = next_test_ip4();
+
+ let stream = t!(UdpSocket::bind(&addr));
+ t!(stream.set_read_timeout(Some(Duration::from_millis(1000))));
+
+ t!(stream.send_to(b"hello world", &addr));
+
+ let mut buf = [0; 11];
+ t!(stream.recv_from(&mut buf));
+ assert_eq!(b"hello world", &buf[..]);
+
+ let start = Instant::now();
+ loop {
+ let kind = stream.recv_from(&mut buf).err().expect("expected error").kind();
+ if kind != ErrorKind::Interrupted {
+ assert!(kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut,
+ "unexpected_error: {:?}", kind);
+ break;
+ }
+ }
+ assert!(start.elapsed() > Duration::from_millis(400));
+ }
+
+ // Ensure the `set_read_timeout` and `set_write_timeout` calls return errors
+ // when passed zero Durations
+ #[test]
+ fn test_timeout_zero_duration() {
+ let addr = next_test_ip4();
+
+ let socket = t!(UdpSocket::bind(&addr));
+
+ let result = socket.set_write_timeout(Some(Duration::new(0, 0)));
+ let err = result.unwrap_err();
+ assert_eq!(err.kind(), ErrorKind::InvalidInput);
+
+ let result = socket.set_read_timeout(Some(Duration::new(0, 0)));
+ let err = result.unwrap_err();
+ assert_eq!(err.kind(), ErrorKind::InvalidInput);
+ }
+
+ #[test]
+ fn connect_send_recv() {
+ let addr = next_test_ip4();
+
+ let socket = t!(UdpSocket::bind(&addr));
+ t!(socket.connect(addr));
+
+ t!(socket.send(b"hello world"));
+
+ let mut buf = [0; 11];
+ t!(socket.recv(&mut buf));
+ assert_eq!(b"hello world", &buf[..]);
+ }
+
+ #[test]
+ fn connect_send_peek_recv() {
+ each_ip(&mut |addr, _| {
+ let socket = t!(UdpSocket::bind(&addr));
+ t!(socket.connect(addr));
+
+ t!(socket.send(b"hello world"));
+
+ for _ in 1..3 {
+ let mut buf = [0; 11];
+ let size = t!(socket.peek(&mut buf));
+ assert_eq!(b"hello world", &buf[..]);
+ assert_eq!(size, 11);
+ }
+
+ let mut buf = [0; 11];
+ let size = t!(socket.recv(&mut buf));
+ assert_eq!(b"hello world", &buf[..]);
+ assert_eq!(size, 11);
+ })
+ }
+
+ #[test]
+ fn peek_from() {
+ each_ip(&mut |addr, _| {
+ let socket = t!(UdpSocket::bind(&addr));
+ t!(socket.send_to(b"hello world", &addr));
+
+ for _ in 1..3 {
+ let mut buf = [0; 11];
+ let (size, _) = t!(socket.peek_from(&mut buf));
+ assert_eq!(b"hello world", &buf[..]);
+ assert_eq!(size, 11);
+ }
+
+ let mut buf = [0; 11];
+ let (size, _) = t!(socket.recv_from(&mut buf));
+ assert_eq!(b"hello world", &buf[..]);
+ assert_eq!(size, 11);
+ })
+ }
+
+ #[test]
+ fn ttl() {
+ let ttl = 100;
+
+ let addr = next_test_ip4();
+
+ let stream = t!(UdpSocket::bind(&addr));
+
+ t!(stream.set_ttl(ttl));
+ assert_eq!(ttl, t!(stream.ttl()));
+ }
+
+ #[test]
+ fn set_nonblocking() {
+ each_ip(&mut |addr, _| {
+ let socket = t!(UdpSocket::bind(&addr));
+
+ t!(socket.set_nonblocking(true));
+ t!(socket.set_nonblocking(false));
+
+ t!(socket.connect(addr));
+
+ t!(socket.set_nonblocking(false));
+ t!(socket.set_nonblocking(true));
+
+ let mut buf = [0];
+ match socket.recv(&mut buf) {
+ Ok(_) => panic!("expected error"),
+ Err(ref e) if e.kind() == ErrorKind::WouldBlock => {}
+ Err(e) => panic!("unexpected error {}", e),
+ }
+ })
+ }
+}
diff --git a/src/libstd/num.rs b/src/libstd/num.rs
new file mode 100644
index 0000000..d67d0b5
--- /dev/null
+++ b/src/libstd/num.rs
@@ -0,0 +1,287 @@
+//! Additional functionality for numerics.
+//!
+//! This module provides some extra types that are useful when doing numerical
+//! work. See the individual documentation for each piece for more information.
+
+#![stable(feature = "rust1", since = "1.0.0")]
+#![allow(missing_docs)]
+
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use core::num::{FpCategory, ParseIntError, ParseFloatError, TryFromIntError};
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use core::num::Wrapping;
+
+#[stable(feature = "nonzero", since = "1.28.0")]
+pub use core::num::{NonZeroU8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU128, NonZeroUsize};
+#[stable(feature = "signed_nonzero", since = "1.34.0")]
+pub use core::num::{NonZeroI8, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI128, NonZeroIsize};
+
+#[cfg(test)] use crate::fmt;
+#[cfg(test)] use crate::ops::{Add, Sub, Mul, Div, Rem};
+
+/// Helper function for testing numeric operations
+#[cfg(test)]
+pub fn test_num<T>(ten: T, two: T) where
+ T: PartialEq
+ + Add<Output=T> + Sub<Output=T>
+ + Mul<Output=T> + Div<Output=T>
+ + Rem<Output=T> + fmt::Debug
+ + Copy
+{
+ assert_eq!(ten.add(two), ten + two);
+ assert_eq!(ten.sub(two), ten - two);
+ assert_eq!(ten.mul(two), ten * two);
+ assert_eq!(ten.div(two), ten / two);
+ assert_eq!(ten.rem(two), ten % two);
+}
+
+#[cfg(test)]
+mod tests {
+ use crate::u8;
+ use crate::u16;
+ use crate::u32;
+ use crate::u64;
+ use crate::usize;
+ use crate::ops::Mul;
+
+ #[test]
+ fn test_saturating_add_uint() {
+ use crate::usize::MAX;
+ assert_eq!(3_usize.saturating_add(5_usize), 8_usize);
+ assert_eq!(3_usize.saturating_add(MAX-1), MAX);
+ assert_eq!(MAX.saturating_add(MAX), MAX);
+ assert_eq!((MAX-2).saturating_add(1), MAX-1);
+ }
+
+ #[test]
+ fn test_saturating_sub_uint() {
+ use crate::usize::MAX;
+ assert_eq!(5_usize.saturating_sub(3_usize), 2_usize);
+ assert_eq!(3_usize.saturating_sub(5_usize), 0_usize);
+ assert_eq!(0_usize.saturating_sub(1_usize), 0_usize);
+ assert_eq!((MAX-1).saturating_sub(MAX), 0);
+ }
+
+ #[test]
+ fn test_saturating_add_int() {
+ use crate::isize::{MIN,MAX};
+ assert_eq!(3i32.saturating_add(5), 8);
+ assert_eq!(3isize.saturating_add(MAX-1), MAX);
+ assert_eq!(MAX.saturating_add(MAX), MAX);
+ assert_eq!((MAX-2).saturating_add(1), MAX-1);
+ assert_eq!(3i32.saturating_add(-5), -2);
+ assert_eq!(MIN.saturating_add(-1), MIN);
+ assert_eq!((-2isize).saturating_add(-MAX), MIN);
+ }
+
+ #[test]
+ fn test_saturating_sub_int() {
+ use crate::isize::{MIN,MAX};
+ assert_eq!(3i32.saturating_sub(5), -2);
+ assert_eq!(MIN.saturating_sub(1), MIN);
+ assert_eq!((-2isize).saturating_sub(MAX), MIN);
+ assert_eq!(3i32.saturating_sub(-5), 8);
+ assert_eq!(3isize.saturating_sub(-(MAX-1)), MAX);
+ assert_eq!(MAX.saturating_sub(-MAX), MAX);
+ assert_eq!((MAX-2).saturating_sub(-1), MAX-1);
+ }
+
+ #[test]
+ fn test_checked_add() {
+ let five_less = usize::MAX - 5;
+ assert_eq!(five_less.checked_add(0), Some(usize::MAX - 5));
+ assert_eq!(five_less.checked_add(1), Some(usize::MAX - 4));
+ assert_eq!(five_less.checked_add(2), Some(usize::MAX - 3));
+ assert_eq!(five_less.checked_add(3), Some(usize::MAX - 2));
+ assert_eq!(five_less.checked_add(4), Some(usize::MAX - 1));
+ assert_eq!(five_less.checked_add(5), Some(usize::MAX));
+ assert_eq!(five_less.checked_add(6), None);
+ assert_eq!(five_less.checked_add(7), None);
+ }
+
+ #[test]
+ fn test_checked_sub() {
+ assert_eq!(5_usize.checked_sub(0), Some(5));
+ assert_eq!(5_usize.checked_sub(1), Some(4));
+ assert_eq!(5_usize.checked_sub(2), Some(3));
+ assert_eq!(5_usize.checked_sub(3), Some(2));
+ assert_eq!(5_usize.checked_sub(4), Some(1));
+ assert_eq!(5_usize.checked_sub(5), Some(0));
+ assert_eq!(5_usize.checked_sub(6), None);
+ assert_eq!(5_usize.checked_sub(7), None);
+ }
+
+ #[test]
+ fn test_checked_mul() {
+ let third = usize::MAX / 3;
+ assert_eq!(third.checked_mul(0), Some(0));
+ assert_eq!(third.checked_mul(1), Some(third));
+ assert_eq!(third.checked_mul(2), Some(third * 2));
+ assert_eq!(third.checked_mul(3), Some(third * 3));
+ assert_eq!(third.checked_mul(4), None);
+ }
+
+ macro_rules! test_is_power_of_two {
+ ($test_name:ident, $T:ident) => (
+ fn $test_name() {
+ #![test]
+ assert_eq!((0 as $T).is_power_of_two(), false);
+ assert_eq!((1 as $T).is_power_of_two(), true);
+ assert_eq!((2 as $T).is_power_of_two(), true);
+ assert_eq!((3 as $T).is_power_of_two(), false);
+ assert_eq!((4 as $T).is_power_of_two(), true);
+ assert_eq!((5 as $T).is_power_of_two(), false);
+ assert_eq!(($T::MAX / 2 + 1).is_power_of_two(), true);
+ }
+ )
+ }
+
+ test_is_power_of_two!{ test_is_power_of_two_u8, u8 }
+ test_is_power_of_two!{ test_is_power_of_two_u16, u16 }
+ test_is_power_of_two!{ test_is_power_of_two_u32, u32 }
+ test_is_power_of_two!{ test_is_power_of_two_u64, u64 }
+ test_is_power_of_two!{ test_is_power_of_two_uint, usize }
+
+ macro_rules! test_next_power_of_two {
+ ($test_name:ident, $T:ident) => (
+ fn $test_name() {
+ #![test]
+ assert_eq!((0 as $T).next_power_of_two(), 1);
+ let mut next_power = 1;
+ for i in 1 as $T..40 {
+ assert_eq!(i.next_power_of_two(), next_power);
+ if i == next_power { next_power *= 2 }
+ }
+ }
+ )
+ }
+
+ test_next_power_of_two! { test_next_power_of_two_u8, u8 }
+ test_next_power_of_two! { test_next_power_of_two_u16, u16 }
+ test_next_power_of_two! { test_next_power_of_two_u32, u32 }
+ test_next_power_of_two! { test_next_power_of_two_u64, u64 }
+ test_next_power_of_two! { test_next_power_of_two_uint, usize }
+
+ macro_rules! test_checked_next_power_of_two {
+ ($test_name:ident, $T:ident) => (
+ fn $test_name() {
+ #![test]
+ assert_eq!((0 as $T).checked_next_power_of_two(), Some(1));
+ let smax = $T::MAX >> 1;
+ assert_eq!(smax.checked_next_power_of_two(), Some(smax+1));
+ assert_eq!((smax + 1).checked_next_power_of_two(), Some(smax + 1));
+ assert_eq!((smax + 2).checked_next_power_of_two(), None);
+ assert_eq!(($T::MAX - 1).checked_next_power_of_two(), None);
+ assert_eq!($T::MAX.checked_next_power_of_two(), None);
+ let mut next_power = 1;
+ for i in 1 as $T..40 {
+ assert_eq!(i.checked_next_power_of_two(), Some(next_power));
+ if i == next_power { next_power *= 2 }
+ }
+ }
+ )
+ }
+
+ test_checked_next_power_of_two! { test_checked_next_power_of_two_u8, u8 }
+ test_checked_next_power_of_two! { test_checked_next_power_of_two_u16, u16 }
+ test_checked_next_power_of_two! { test_checked_next_power_of_two_u32, u32 }
+ test_checked_next_power_of_two! { test_checked_next_power_of_two_u64, u64 }
+ test_checked_next_power_of_two! { test_checked_next_power_of_two_uint, usize }
+
+ #[test]
+ fn test_pow() {
+ fn naive_pow<T: Mul<Output=T> + Copy>(one: T, base: T, exp: usize) -> T {
+ (0..exp).fold(one, |acc, _| acc * base)
+ }
+ macro_rules! assert_pow {
+ (($num:expr, $exp:expr) => $expected:expr) => {{
+ let result = $num.pow($exp);
+ assert_eq!(result, $expected);
+ assert_eq!(result, naive_pow(1, $num, $exp));
+ }}
+ }
+ assert_pow!((3u32, 0 ) => 1);
+ assert_pow!((5u32, 1 ) => 5);
+ assert_pow!((-4i32, 2 ) => 16);
+ assert_pow!((8u32, 3 ) => 512);
+ assert_pow!((2u64, 50) => 1125899906842624);
+ }
+
+ #[test]
+ fn test_uint_to_str_overflow() {
+ let mut u8_val: u8 = 255;
+ assert_eq!(u8_val.to_string(), "255");
+
+ u8_val = u8_val.wrapping_add(1);
+ assert_eq!(u8_val.to_string(), "0");
+
+ let mut u16_val: u16 = 65_535;
+ assert_eq!(u16_val.to_string(), "65535");
+
+ u16_val = u16_val.wrapping_add(1);
+ assert_eq!(u16_val.to_string(), "0");
+
+ let mut u32_val: u32 = 4_294_967_295;
+ assert_eq!(u32_val.to_string(), "4294967295");
+
+ u32_val = u32_val.wrapping_add(1);
+ assert_eq!(u32_val.to_string(), "0");
+
+ let mut u64_val: u64 = 18_446_744_073_709_551_615;
+ assert_eq!(u64_val.to_string(), "18446744073709551615");
+
+ u64_val = u64_val.wrapping_add(1);
+ assert_eq!(u64_val.to_string(), "0");
+ }
+
+ fn from_str<T: crate::str::FromStr>(t: &str) -> Option<T> {
+ crate::str::FromStr::from_str(t).ok()
+ }
+
+ #[test]
+ fn test_uint_from_str_overflow() {
+ let mut u8_val: u8 = 255;
+ assert_eq!(from_str::<u8>("255"), Some(u8_val));
+ assert_eq!(from_str::<u8>("256"), None);
+
+ u8_val = u8_val.wrapping_add(1);
+ assert_eq!(from_str::<u8>("0"), Some(u8_val));
+ assert_eq!(from_str::<u8>("-1"), None);
+
+ let mut u16_val: u16 = 65_535;
+ assert_eq!(from_str::<u16>("65535"), Some(u16_val));
+ assert_eq!(from_str::<u16>("65536"), None);
+
+ u16_val = u16_val.wrapping_add(1);
+ assert_eq!(from_str::<u16>("0"), Some(u16_val));
+ assert_eq!(from_str::<u16>("-1"), None);
+
+ let mut u32_val: u32 = 4_294_967_295;
+ assert_eq!(from_str::<u32>("4294967295"), Some(u32_val));
+ assert_eq!(from_str::<u32>("4294967296"), None);
+
+ u32_val = u32_val.wrapping_add(1);
+ assert_eq!(from_str::<u32>("0"), Some(u32_val));
+ assert_eq!(from_str::<u32>("-1"), None);
+
+ let mut u64_val: u64 = 18_446_744_073_709_551_615;
+ assert_eq!(from_str::<u64>("18446744073709551615"), Some(u64_val));
+ assert_eq!(from_str::<u64>("18446744073709551616"), None);
+
+ u64_val = u64_val.wrapping_add(1);
+ assert_eq!(from_str::<u64>("0"), Some(u64_val));
+ assert_eq!(from_str::<u64>("-1"), None);
+ }
+}
+
+
+#[cfg(test)]
+mod bench {
+ use test::Bencher;
+
+ #[bench]
+ fn bench_pow_function(b: &mut Bencher) {
+ let v = (0..1024).collect::<Vec<u32>>();
+ b.iter(|| {v.iter().fold(0u32, |old, new| old.pow(*new as u32));});
+ }
+}
diff --git a/src/libstd/os/android/fs.rs b/src/libstd/os/android/fs.rs
new file mode 100644
index 0000000..9b24f86
--- /dev/null
+++ b/src/libstd/os/android/fs.rs
@@ -0,0 +1,119 @@
+#![stable(feature = "metadata_ext", since = "1.1.0")]
+
+use crate::fs::Metadata;
+use crate::sys_common::AsInner;
+
+#[allow(deprecated)]
+use crate::os::android::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.
+ #[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;
+
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_dev(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ino(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mode(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_nlink(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_uid(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_gid(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_rdev(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_size(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_atime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_atime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mtime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mtime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ctime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ctime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_blksize(&self) -> u64;
+ #[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::stat
+ as *const raw::stat)
+ }
+ }
+ fn st_dev(&self) -> u64 {
+ self.as_inner().as_inner().st_dev as u64
+ }
+ fn st_ino(&self) -> u64 {
+ self.as_inner().as_inner().st_ino as u64
+ }
+ fn st_mode(&self) -> u32 {
+ self.as_inner().as_inner().st_mode as u32
+ }
+ fn st_nlink(&self) -> u64 {
+ self.as_inner().as_inner().st_nlink as u64
+ }
+ fn st_uid(&self) -> u32 {
+ self.as_inner().as_inner().st_uid as u32
+ }
+ fn st_gid(&self) -> u32 {
+ self.as_inner().as_inner().st_gid as u32
+ }
+ fn st_rdev(&self) -> u64 {
+ self.as_inner().as_inner().st_rdev as u64
+ }
+ fn st_size(&self) -> u64 {
+ self.as_inner().as_inner().st_size as u64
+ }
+ fn st_atime(&self) -> i64 {
+ self.as_inner().as_inner().st_atime as i64
+ }
+ fn st_atime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_atime_nsec as i64
+ }
+ fn st_mtime(&self) -> i64 {
+ self.as_inner().as_inner().st_mtime as i64
+ }
+ fn st_mtime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_mtime_nsec as i64
+ }
+ fn st_ctime(&self) -> i64 {
+ self.as_inner().as_inner().st_ctime as i64
+ }
+ fn st_ctime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_ctime_nsec as i64
+ }
+ fn st_blksize(&self) -> u64 {
+ self.as_inner().as_inner().st_blksize as u64
+ }
+ fn st_blocks(&self) -> u64 {
+ self.as_inner().as_inner().st_blocks as u64
+ }
+}
+
diff --git a/src/libstd/os/android/mod.rs b/src/libstd/os/android/mod.rs
new file mode 100644
index 0000000..ad1cd85
--- /dev/null
+++ b/src/libstd/os/android/mod.rs
@@ -0,0 +1,6 @@
+//! Android-specific definitions
+
+#![stable(feature = "raw_ext", since = "1.1.0")]
+
+pub mod raw;
+pub mod fs;
diff --git a/src/libstd/os/android/raw.rs b/src/libstd/os/android/raw.rs
new file mode 100644
index 0000000..acf5ca1
--- /dev/null
+++ b/src/libstd/os/android/raw.rs
@@ -0,0 +1,220 @@
+//! Android-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)]
+
+use crate::os::raw::c_long;
+
+#[stable(feature = "pthread_t", since = "1.8.0")]
+pub type pthread_t = c_long;
+
+#[doc(inline)]
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub use self::arch::{dev_t, mode_t, blkcnt_t, blksize_t, ino_t, nlink_t, off_t, stat, time_t};
+
+#[cfg(any(target_arch = "arm", target_arch = "x86"))]
+mod arch {
+ use crate::os::raw::{c_uint, c_uchar, c_ulonglong, c_longlong, c_ulong};
+ use crate::os::unix::raw::{uid_t, gid_t};
+
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type dev_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type mode_t = u32;
+
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type blkcnt_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type blksize_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type ino_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type nlink_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type off_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type time_t = i64;
+
+ #[repr(C)]
+ #[derive(Clone)]
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub struct stat {
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_dev: c_ulonglong,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub __pad0: [c_uchar; 4],
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub __st_ino: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mode: c_uint,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_nlink: c_uint,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_uid: uid_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_gid: gid_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_rdev: c_ulonglong,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub __pad3: [c_uchar; 4],
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_size: c_longlong,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blksize: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blocks: c_ulonglong,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime: c_ulong,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime_nsec: c_ulong,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime: c_ulong,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime_nsec: c_ulong,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime: c_ulong,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime_nsec: c_ulong,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ino: c_ulonglong,
+ }
+
+}
+
+
+#[cfg(target_arch = "aarch64")]
+mod arch {
+ use crate::os::raw::{c_uchar, c_ulong};
+ use crate::os::unix::raw::{uid_t, gid_t};
+
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type dev_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type mode_t = u32;
+
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type blkcnt_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type blksize_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type ino_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type nlink_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type off_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type time_t = i64;
+
+ #[repr(C)]
+ #[derive(Clone)]
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub struct stat {
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_dev: dev_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub __pad0: [c_uchar; 4],
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub __st_ino: ino_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mode: mode_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_nlink: nlink_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_uid: uid_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_gid: gid_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_rdev: dev_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub __pad3: [c_uchar; 4],
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_size: off_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blksize: blksize_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blocks: blkcnt_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime: time_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime_nsec: c_ulong,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime: time_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime_nsec: c_ulong,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime: time_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime_nsec: c_ulong,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ino: ino_t,
+ }
+}
+
+#[cfg(target_arch = "x86_64")]
+mod arch {
+ use crate::os::raw::{c_uint, c_long, c_ulong};
+ use crate::os::unix::raw::{uid_t, gid_t};
+
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type dev_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type mode_t = u32;
+
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type blkcnt_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type blksize_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type ino_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type nlink_t = u32;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type off_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type time_t = i64;
+
+ #[repr(C)]
+ #[derive(Clone)]
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub struct stat {
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_dev: dev_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ino: ino_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_nlink: c_ulong,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mode: c_uint,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_uid: uid_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_gid: gid_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_rdev: dev_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_size: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blksize: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blocks: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime: c_ulong,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime_nsec: c_ulong,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime: c_ulong,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime_nsec: c_ulong,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime: c_ulong,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime_nsec: c_ulong,
+ __unused: [c_long; 3],
+ }
+}
+
diff --git a/src/libstd/os/bitrig/fs.rs b/src/libstd/os/bitrig/fs.rs
new file mode 100644
index 0000000..849d4aa
--- /dev/null
+++ b/src/libstd/os/bitrig/fs.rs
@@ -0,0 +1,139 @@
+#![stable(feature = "metadata_ext", since = "1.1.0")]
+
+use crate::fs::Metadata;
+use crate::sys_common::AsInner;
+
+#[allow(deprecated)]
+use crate::os::bitrig::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.
+ #[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;
+
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_dev(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ino(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mode(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_nlink(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_uid(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_gid(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_rdev(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_size(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_atime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_atime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mtime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mtime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ctime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ctime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_birthtime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_birthtime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_blksize(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_blocks(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_flags(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_gen(&self) -> u32;
+}
+
+#[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::stat
+ 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_birthtime(&self) -> i64 {
+ self.as_inner().as_inner().st_birthtime as i64
+ }
+ fn st_birthtime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_birthtime_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
+ }
+ fn st_gen(&self) -> u32 {
+ self.as_inner().as_inner().st_gen as u32
+ }
+ fn st_flags(&self) -> u32 {
+ self.as_inner().as_inner().st_flags as u32
+ }
+}
+
diff --git a/src/libstd/os/bitrig/mod.rs b/src/libstd/os/bitrig/mod.rs
new file mode 100644
index 0000000..0bc105b
--- /dev/null
+++ b/src/libstd/os/bitrig/mod.rs
@@ -0,0 +1,6 @@
+//! Bitrig-specific definitions
+
+#![stable(feature = "raw_ext", since = "1.1.0")]
+
+pub mod raw;
+pub mod fs;
diff --git a/src/libstd/os/bitrig/raw.rs b/src/libstd/os/bitrig/raw.rs
new file mode 100644
index 0000000..c966d5a
--- /dev/null
+++ b/src/libstd/os/bitrig/raw.rs
@@ -0,0 +1,71 @@
+//! Bitrig-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)]
+
+use crate::os::raw::c_long;
+use crate::os::unix::raw::{uid_t, gid_t};
+
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type blkcnt_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type blksize_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type dev_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type fflags_t = u32;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type ino_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type mode_t = u32;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type nlink_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type off_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i64;
+
+#[stable(feature = "pthread_t", since = "1.8.0")]
+pub type pthread_t = usize;
+
+#[repr(C)]
+#[derive(Clone)]
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub struct stat {
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mode: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_dev: i32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ino: u64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_nlink: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_uid: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_gid: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_rdev: i32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime_nsec: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime: u64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime_nsec: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime_nsec: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_size: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blocks: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blksize: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_flags: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_gen: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_birthtime: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_birthtime_nsec: i64,
+}
diff --git a/src/libstd/os/dragonfly/fs.rs b/src/libstd/os/dragonfly/fs.rs
new file mode 100644
index 0000000..ba38660
--- /dev/null
+++ b/src/libstd/os/dragonfly/fs.rs
@@ -0,0 +1,134 @@
+#![stable(feature = "metadata_ext", since = "1.1.0")]
+
+use crate::fs::Metadata;
+use crate::sys_common::AsInner;
+
+#[allow(deprecated)]
+use crate::os::dragonfly::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.
+ #[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;
+
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_dev(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ino(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mode(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_nlink(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_uid(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_gid(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_rdev(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_size(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_atime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_atime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mtime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mtime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ctime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ctime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_blksize(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_blocks(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_flags(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_gen(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_lspare(&self) -> u32;
+}
+
+#[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::stat
+ 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
+ }
+ fn st_gen(&self) -> u32 {
+ self.as_inner().as_inner().st_gen as u32
+ }
+ fn st_flags(&self) -> u32 {
+ self.as_inner().as_inner().st_flags as u32
+ }
+ fn st_lspare(&self) -> u32 {
+ self.as_inner().as_inner().st_lspare as u32
+ }
+}
+
diff --git a/src/libstd/os/dragonfly/mod.rs b/src/libstd/os/dragonfly/mod.rs
new file mode 100644
index 0000000..c8df03e
--- /dev/null
+++ b/src/libstd/os/dragonfly/mod.rs
@@ -0,0 +1,6 @@
+//! Dragonfly-specific definitions
+
+#![stable(feature = "raw_ext", since = "1.1.0")]
+
+pub mod raw;
+pub mod fs;
diff --git a/src/libstd/os/dragonfly/raw.rs b/src/libstd/os/dragonfly/raw.rs
new file mode 100644
index 0000000..46ef5a1
--- /dev/null
+++ b/src/libstd/os/dragonfly/raw.rs
@@ -0,0 +1,72 @@
+//! Dragonfly-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)]
+
+use crate::os::raw::c_long;
+
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type blkcnt_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type blksize_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type dev_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type fflags_t = u32;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type ino_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type mode_t = u32;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type nlink_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type off_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i64;
+
+#[stable(feature = "pthread_t", since = "1.8.0")]
+pub type pthread_t = usize;
+
+#[repr(C)]
+#[derive(Clone)]
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub struct stat {
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_dev: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ino: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mode: u16,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_nlink: u16,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_uid: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_gid: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_rdev: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_size: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blocks: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blksize: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_flags: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_gen: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_lspare: i32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_birthtime: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_birthtime_nsec: c_long,
+}
diff --git a/src/libstd/os/emscripten/fs.rs b/src/libstd/os/emscripten/fs.rs
new file mode 100644
index 0000000..aa6aa38
--- /dev/null
+++ b/src/libstd/os/emscripten/fs.rs
@@ -0,0 +1,118 @@
+#![stable(feature = "metadata_ext", since = "1.1.0")]
+
+use crate::fs::Metadata;
+use crate::sys_common::AsInner;
+
+#[allow(deprecated)]
+use crate::os::emscripten::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.
+ #[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;
+
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_dev(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ino(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mode(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_nlink(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_uid(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_gid(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_rdev(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_size(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_atime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_atime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mtime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mtime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ctime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ctime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_blksize(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_blocks(&self) -> u64;
+}
+
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+impl MetadataExt for Metadata {
+ #[allow(deprecated)]
+ fn as_raw_stat(&self) -> &raw::stat {
+ unsafe {
+ &*(self.as_inner().as_inner() as *const libc::stat64
+ as *const raw::stat)
+ }
+ }
+ fn st_dev(&self) -> u64 {
+ self.as_inner().as_inner().st_dev as u64
+ }
+ fn st_ino(&self) -> u64 {
+ self.as_inner().as_inner().st_ino as u64
+ }
+ fn st_mode(&self) -> u32 {
+ self.as_inner().as_inner().st_mode as u32
+ }
+ fn st_nlink(&self) -> u64 {
+ self.as_inner().as_inner().st_nlink as u64
+ }
+ fn st_uid(&self) -> u32 {
+ self.as_inner().as_inner().st_uid as u32
+ }
+ fn st_gid(&self) -> u32 {
+ self.as_inner().as_inner().st_gid as u32
+ }
+ fn st_rdev(&self) -> u64 {
+ self.as_inner().as_inner().st_rdev as u64
+ }
+ fn st_size(&self) -> u64 {
+ self.as_inner().as_inner().st_size as u64
+ }
+ fn st_atime(&self) -> i64 {
+ self.as_inner().as_inner().st_atime as i64
+ }
+ fn st_atime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_atime_nsec as i64
+ }
+ fn st_mtime(&self) -> i64 {
+ self.as_inner().as_inner().st_mtime as i64
+ }
+ fn st_mtime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_mtime_nsec as i64
+ }
+ fn st_ctime(&self) -> i64 {
+ self.as_inner().as_inner().st_ctime as i64
+ }
+ fn st_ctime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_ctime_nsec as i64
+ }
+ fn st_blksize(&self) -> u64 {
+ self.as_inner().as_inner().st_blksize as u64
+ }
+ fn st_blocks(&self) -> u64 {
+ self.as_inner().as_inner().st_blocks as u64
+ }
+}
diff --git a/src/libstd/os/emscripten/mod.rs b/src/libstd/os/emscripten/mod.rs
new file mode 100644
index 0000000..3111325
--- /dev/null
+++ b/src/libstd/os/emscripten/mod.rs
@@ -0,0 +1,6 @@
+//! Linux-specific definitions
+
+#![stable(feature = "raw_ext", since = "1.1.0")]
+
+pub mod raw;
+pub mod fs;
diff --git a/src/libstd/os/emscripten/raw.rs b/src/libstd/os/emscripten/raw.rs
new file mode 100644
index 0000000..e551348
--- /dev/null
+++ b/src/libstd/os/emscripten/raw.rs
@@ -0,0 +1,71 @@
+//! Emscripten-specific raw type definitions
+//! This is basically exactly the same as the linux definitions,
+//! except using the musl-specific stat64 structure in liblibc.
+
+#![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)]
+
+use crate::os::raw::{c_long, c_short, c_uint, c_ulong};
+
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type dev_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type mode_t = u32;
+
+#[stable(feature = "pthread_t", since = "1.8.0")]
+pub type pthread_t = c_ulong;
+
+#[doc(inline)]
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type blkcnt_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type blksize_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type ino_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type nlink_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type off_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = c_long;
+
+#[repr(C)]
+#[derive(Clone)]
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub struct stat {
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_dev: u64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub __pad1: c_short,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub __st_ino: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mode: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_nlink: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_uid: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_gid: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_rdev: u64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub __pad2: c_uint,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_size: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blksize: i32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blocks: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime: time_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime: time_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime: time_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ino: u64,
+}
diff --git a/src/libstd/os/fortanix_sgx/mod.rs b/src/libstd/os/fortanix_sgx/mod.rs
new file mode 100644
index 0000000..4e30b1e
--- /dev/null
+++ b/src/libstd/os/fortanix_sgx/mod.rs
@@ -0,0 +1,50 @@
+//! Functionality specific to the `x86_64-fortanix-unknown-sgx` target.
+//!
+//! This includes functions to deal with memory isolation, usercalls, and the
+//! SGX instruction set.
+
+#![deny(missing_docs, missing_debug_implementations)]
+#![unstable(feature = "sgx_platform", issue = "56975")]
+
+/// Low-level interfaces to usercalls. See the [ABI documentation] for more
+/// information.
+///
+/// [ABI documentation]: https://docs.rs/fortanix-sgx-abi/
+pub mod usercalls {
+ pub use crate::sys::abi::usercalls::*;
+
+ /// Primitives for allocating memory in userspace as well as copying data
+ /// to and from user memory.
+ pub mod alloc {
+ pub use crate::sys::abi::usercalls::alloc::*;
+ }
+
+ /// Lowest-level interfaces to usercalls and usercall ABI type definitions.
+ pub mod raw {
+ pub use crate::sys::abi::usercalls::raw::{do_usercall, Usercalls as UsercallNrs};
+ pub use crate::sys::abi::usercalls::raw::{accept_stream, alloc, async_queues, bind_stream,
+ close, connect_stream, exit, flush, free, insecure_time,
+ launch_thread, read, read_alloc, send, wait, write};
+
+ // fortanix-sgx-abi re-exports
+ pub use crate::sys::abi::usercalls::raw::{ByteBuffer, FifoDescriptor, Return, Usercall};
+ pub use crate::sys::abi::usercalls::raw::Error;
+ pub use crate::sys::abi::usercalls::raw::{EV_RETURNQ_NOT_EMPTY, EV_UNPARK,
+ EV_USERCALLQ_NOT_FULL, FD_STDERR, FD_STDIN, FD_STDOUT,
+ RESULT_SUCCESS, USERCALL_USER_DEFINED, WAIT_INDEFINITE,
+ WAIT_NO};
+ pub use crate::sys::abi::usercalls::raw::{Fd, Result, Tcs};
+ }
+}
+
+/// Functions for querying mapping information for pointers.
+pub mod mem {
+ pub use crate::sys::abi::mem::*;
+}
+
+pub use crate::sys::ext::{io, arch, ffi};
+
+/// Functions for querying thread-related information.
+pub mod thread {
+ pub use crate::sys::abi::thread::current;
+}
diff --git a/src/libstd/os/freebsd/fs.rs b/src/libstd/os/freebsd/fs.rs
new file mode 100644
index 0000000..4cc3a4b
--- /dev/null
+++ b/src/libstd/os/freebsd/fs.rs
@@ -0,0 +1,144 @@
+#![stable(feature = "metadata_ext", since = "1.1.0")]
+
+use crate::fs::Metadata;
+use crate::sys_common::AsInner;
+
+#[allow(deprecated)]
+use crate::os::freebsd::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.
+ #[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;
+
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_dev(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ino(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mode(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_nlink(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_uid(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_gid(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_rdev(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_size(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_atime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_atime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mtime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mtime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ctime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ctime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_birthtime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_birthtime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_blksize(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_blocks(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_flags(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_gen(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_lspare(&self) -> u32;
+}
+
+#[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::stat
+ 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_birthtime(&self) -> i64 {
+ self.as_inner().as_inner().st_birthtime as i64
+ }
+ fn st_birthtime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_birthtime_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
+ }
+ fn st_gen(&self) -> u32 {
+ self.as_inner().as_inner().st_gen as u32
+ }
+ fn st_flags(&self) -> u32 {
+ self.as_inner().as_inner().st_flags as u32
+ }
+ fn st_lspare(&self) -> u32 {
+ self.as_inner().as_inner().st_lspare as u32
+ }
+}
+
diff --git a/src/libstd/os/freebsd/mod.rs b/src/libstd/os/freebsd/mod.rs
new file mode 100644
index 0000000..1d9ee54
--- /dev/null
+++ b/src/libstd/os/freebsd/mod.rs
@@ -0,0 +1,6 @@
+//! FreeBSD-specific definitions
+
+#![stable(feature = "raw_ext", since = "1.1.0")]
+
+pub mod raw;
+pub mod fs;
diff --git a/src/libstd/os/freebsd/raw.rs b/src/libstd/os/freebsd/raw.rs
new file mode 100644
index 0000000..0c58154
--- /dev/null
+++ b/src/libstd/os/freebsd/raw.rs
@@ -0,0 +1,75 @@
+//! FreeBSD-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)]
+
+use crate::os::raw::c_long;
+
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type blkcnt_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type blksize_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type dev_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type fflags_t = u32;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type ino_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type mode_t = u32;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type nlink_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type off_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i64;
+
+#[stable(feature = "pthread_t", since = "1.8.0")]
+pub type pthread_t = usize;
+
+#[repr(C)]
+#[derive(Clone)]
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub struct stat {
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_dev: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ino: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mode: u16,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_nlink: u16,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_uid: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_gid: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_rdev: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_size: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blocks: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blksize: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_flags: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_gen: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_lspare: i32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_birthtime: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_birthtime_nsec: c_long,
+ #[cfg(target_arch = "x86")]
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub __unused: [u8; 8],
+}
diff --git a/src/libstd/os/fuchsia/fs.rs b/src/libstd/os/fuchsia/fs.rs
new file mode 100644
index 0000000..1544bdf
--- /dev/null
+++ b/src/libstd/os/fuchsia/fs.rs
@@ -0,0 +1,95 @@
+#![stable(feature = "metadata_ext", since = "1.1.0")]
+
+use crate::fs::Metadata;
+use crate::sys_common::AsInner;
+
+/// OS-specific extensions to [`fs::Metadata`].
+///
+/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+pub trait MetadataExt {
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_dev(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ino(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mode(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_nlink(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_uid(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_gid(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_rdev(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_size(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_atime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_atime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mtime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mtime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ctime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ctime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_blksize(&self) -> u64;
+ #[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 {
+ fn st_dev(&self) -> u64 {
+ self.as_inner().as_inner().st_dev as u64
+ }
+ fn st_ino(&self) -> u64 {
+ self.as_inner().as_inner().st_ino as u64
+ }
+ fn st_mode(&self) -> u32 {
+ self.as_inner().as_inner().st_mode as u32
+ }
+ fn st_nlink(&self) -> u64 {
+ self.as_inner().as_inner().st_nlink as u64
+ }
+ fn st_uid(&self) -> u32 {
+ self.as_inner().as_inner().st_uid as u32
+ }
+ fn st_gid(&self) -> u32 {
+ self.as_inner().as_inner().st_gid as u32
+ }
+ fn st_rdev(&self) -> u64 {
+ self.as_inner().as_inner().st_rdev as u64
+ }
+ fn st_size(&self) -> u64 {
+ self.as_inner().as_inner().st_size as u64
+ }
+ fn st_atime(&self) -> i64 {
+ self.as_inner().as_inner().st_atime as i64
+ }
+ fn st_atime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_atime_nsec as i64
+ }
+ fn st_mtime(&self) -> i64 {
+ self.as_inner().as_inner().st_mtime as i64
+ }
+ fn st_mtime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_mtime_nsec as i64
+ }
+ fn st_ctime(&self) -> i64 {
+ self.as_inner().as_inner().st_ctime as i64
+ }
+ fn st_ctime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_ctime_nsec as i64
+ }
+ fn st_blksize(&self) -> u64 {
+ self.as_inner().as_inner().st_blksize as u64
+ }
+ fn st_blocks(&self) -> u64 {
+ self.as_inner().as_inner().st_blocks as u64
+ }
+}
diff --git a/src/libstd/os/fuchsia/mod.rs b/src/libstd/os/fuchsia/mod.rs
new file mode 100644
index 0000000..740eb01
--- /dev/null
+++ b/src/libstd/os/fuchsia/mod.rs
@@ -0,0 +1,6 @@
+//! Fuchsia-specific definitions
+
+#![stable(feature = "raw_ext", since = "1.1.0")]
+
+pub mod raw;
+pub mod fs;
diff --git a/src/libstd/os/fuchsia/raw.rs b/src/libstd/os/fuchsia/raw.rs
new file mode 100644
index 0000000..7e44a79
--- /dev/null
+++ b/src/libstd/os/fuchsia/raw.rs
@@ -0,0 +1,260 @@
+//! Fuchsia-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)]
+
+use crate::os::raw::c_ulong;
+
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type dev_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type mode_t = u32;
+
+#[stable(feature = "pthread_t", since = "1.8.0")]
+pub type pthread_t = c_ulong;
+
+#[doc(inline)]
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub use self::arch::{off_t, ino_t, nlink_t, blksize_t, blkcnt_t, stat, time_t};
+
+#[cfg(any(target_arch = "x86",
+ target_arch = "le32",
+ target_arch = "powerpc",
+ target_arch = "arm"))]
+mod arch {
+ use crate::os::raw::{c_long, c_short, c_uint};
+
+ #[stable(feature = "raw_ext", since = "1.1.0")] pub type blkcnt_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")] pub type blksize_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")] pub type ino_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")] pub type nlink_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")] pub type off_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i64;
+
+ #[repr(C)]
+ #[derive(Clone)]
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub struct stat {
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_dev: u64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub __pad1: c_short,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub __st_ino: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mode: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_nlink: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_uid: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_gid: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_rdev: u64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub __pad2: c_uint,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_size: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blksize: i32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blocks: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime: i32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime: i32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime: i32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ino: u64,
+ }
+}
+
+#[cfg(target_arch = "mips")]
+mod arch {
+ use crate::os::raw::{c_long, c_ulong};
+
+ #[cfg(target_env = "musl")]
+ #[stable(feature = "raw_ext", since = "1.1.0")] pub type blkcnt_t = i64;
+ #[cfg(not(target_env = "musl"))]
+ #[stable(feature = "raw_ext", since = "1.1.0")] pub type blkcnt_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")] pub type blksize_t = u64;
+ #[cfg(target_env = "musl")]
+ #[stable(feature = "raw_ext", since = "1.1.0")] pub type ino_t = u64;
+ #[cfg(not(target_env = "musl"))]
+ #[stable(feature = "raw_ext", since = "1.1.0")] pub type ino_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")] pub type nlink_t = u64;
+ #[cfg(target_env = "musl")]
+ #[stable(feature = "raw_ext", since = "1.1.0")] pub type off_t = u64;
+ #[cfg(not(target_env = "musl"))]
+ #[stable(feature = "raw_ext", since = "1.1.0")] pub type off_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i64;
+
+ #[repr(C)]
+ #[derive(Clone)]
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub struct stat {
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_dev: c_ulong,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_pad1: [c_long; 3],
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ino: u64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mode: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_nlink: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_uid: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_gid: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_rdev: c_ulong,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_pad2: [c_long; 2],
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_size: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime: i32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime: i32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime: i32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blksize: i32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blocks: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_pad5: [c_long; 14],
+ }
+}
+
+#[cfg(target_arch = "mips64")]
+mod arch {
+ pub use libc::{off_t, ino_t, nlink_t, blksize_t, blkcnt_t, stat, time_t};
+}
+
+#[cfg(target_arch = "aarch64")]
+mod arch {
+ use crate::os::raw::{c_long, c_int};
+
+ #[stable(feature = "raw_ext", since = "1.1.0")] pub type blkcnt_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")] pub type blksize_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")] pub type ino_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")] pub type nlink_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")] pub type off_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i64;
+
+ #[repr(C)]
+ #[derive(Clone)]
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub struct stat {
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_dev: u64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ino: u64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mode: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_nlink: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_uid: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_gid: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_rdev: u64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub __pad1: u64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_size: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blksize: i32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub __pad2: c_int,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blocks: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub __unused: [c_int; 2],
+ }
+}
+
+#[cfg(target_arch = "x86_64")]
+mod arch {
+ use crate::os::raw::{c_long, c_int};
+
+ #[stable(feature = "raw_ext", since = "1.1.0")] pub type blkcnt_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")] pub type blksize_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")] pub type ino_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")] pub type nlink_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")] pub type off_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i64;
+
+ #[repr(C)]
+ #[derive(Clone)]
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub struct stat {
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_dev: u64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ino: u64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_nlink: u64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mode: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_uid: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_gid: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub __pad0: c_int,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_rdev: u64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_size: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blksize: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blocks: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub __unused: [c_long; 3],
+ }
+}
diff --git a/src/libstd/os/haiku/fs.rs b/src/libstd/os/haiku/fs.rs
new file mode 100644
index 0000000..4097f8c
--- /dev/null
+++ b/src/libstd/os/haiku/fs.rs
@@ -0,0 +1,128 @@
+#![stable(feature = "metadata_ext", since = "1.1.0")]
+
+use crate::fs::Metadata;
+use crate::sys_common::AsInner;
+
+#[allow(deprecated)]
+use crate::os::haiku::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.
+ #[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;
+
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_dev(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ino(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mode(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_nlink(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_uid(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_gid(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_rdev(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_size(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_atime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_atime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mtime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mtime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ctime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ctime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_crtime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_crtime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_blksize(&self) -> u64;
+ #[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::stat
+ 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_crtime(&self) -> i64 {
+ self.as_inner().as_inner().st_crtime as i64
+ }
+ fn st_crtime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_crtime_nsec as i64
+ }
+ fn st_blksize(&self) -> u64 {
+ self.as_inner().as_inner().st_blksize as u64
+ }
+ fn st_blocks(&self) -> u64 {
+ self.as_inner().as_inner().st_blocks as u64
+ }
+}
diff --git a/src/libstd/os/haiku/mod.rs b/src/libstd/os/haiku/mod.rs
new file mode 100644
index 0000000..c6a43d9
--- /dev/null
+++ b/src/libstd/os/haiku/mod.rs
@@ -0,0 +1,6 @@
+//! Haiku-specific definitions
+
+#![stable(feature = "raw_ext", since = "1.1.0")]
+
+pub mod raw;
+pub mod fs;
diff --git a/src/libstd/os/haiku/raw.rs b/src/libstd/os/haiku/raw.rs
new file mode 100644
index 0000000..d86f4f3
--- /dev/null
+++ b/src/libstd/os/haiku/raw.rs
@@ -0,0 +1,64 @@
+//! Haiku-specific raw type definitions
+
+#![stable(feature = "raw_ext", since = "1.1.0")]
+
+#![allow(deprecated)]
+
+use crate::os::raw::{c_long};
+use crate::os::unix::raw::{uid_t, gid_t};
+
+// Use the direct definition of usize, instead of uintptr_t like in libc
+#[stable(feature = "pthread_t", since = "1.8.0")] pub type pthread_t = usize;
+
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type blkcnt_t = i64;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type blksize_t = i32;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type dev_t = i32;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type ino_t = i64;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type mode_t = u32;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type nlink_t = i32;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type off_t = i64;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i32;
+
+#[repr(C)]
+#[derive(Clone)]
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub struct stat {
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_dev: dev_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ino: ino_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mode: mode_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_nlink: nlink_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_uid: uid_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_gid: gid_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_size: off_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_rdev: dev_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blksize: blksize_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime: time_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime: time_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime: time_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_crtime: time_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_crtime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_type: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blocks: blkcnt_t,
+}
diff --git a/src/libstd/os/hermit/fs.rs b/src/libstd/os/hermit/fs.rs
new file mode 100644
index 0000000..eb28a83
--- /dev/null
+++ b/src/libstd/os/hermit/fs.rs
@@ -0,0 +1,377 @@
+#![stable(feature = "metadata_ext", since = "1.1.0")]
+
+use crate::fs::Metadata;
+use crate::sys_common::AsInner;
+
+#[allow(deprecated)]
+use crate::os::hermit::raw;
+
+/// OS-specific extensions to [`fs::Metadata`].
+///
+/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+pub trait MetadataExt {
+ /// Gain a reference to the underlying `stat` structure which contains
+ /// the raw information returned by the OS.
+ ///
+ /// The contents of the returned [`stat`] are **not** consistent across
+ /// Unix platforms. The `os::unix::fs::MetadataExt` trait contains the
+ /// cross-Unix abstractions contained within the raw stat.
+ ///
+ /// [`stat`]: ../../../../std/os/linux/raw/struct.stat.html
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::linux::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// let stat = meta.as_raw_stat();
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ #[rustc_deprecated(since = "1.8.0",
+ reason = "deprecated in favor of the accessor \
+ methods of this trait")]
+ #[allow(deprecated)]
+ fn as_raw_stat(&self) -> &raw::stat;
+
+ /// Returns the device ID on which this file resides.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::linux::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_dev());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_dev(&self) -> u64;
+ /// Returns the inode number.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::linux::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_ino());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ino(&self) -> u64;
+ /// Returns the file type and mode.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::linux::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_mode());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mode(&self) -> u32;
+ /// Returns the number of hard links to file.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::linux::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_nlink());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_nlink(&self) -> u64;
+ /// Returns the user ID of the file owner.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::linux::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_uid());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_uid(&self) -> u32;
+ /// Returns the group ID of the file owner.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::linux::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_gid());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_gid(&self) -> u32;
+ /// Returns the device ID that this file represents. Only relevant for special file.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::linux::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_rdev());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_rdev(&self) -> u64;
+ /// Returns the size of the file (if it is a regular file or a symbolic link) in bytes.
+ ///
+ /// The size of a symbolic link is the length of the pathname it contains,
+ /// without a terminating null byte.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::linux::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_size());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_size(&self) -> u64;
+ /// Returns the last access time.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::linux::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_atime());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_atime(&self) -> i64;
+ /// Returns the last access time, nano seconds part.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::linux::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_atime_nsec());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_atime_nsec(&self) -> i64;
+ /// Returns the last modification time.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::linux::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_mtime());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mtime(&self) -> i64;
+ /// Returns the last modification time, nano seconds part.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::linux::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_mtime_nsec());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mtime_nsec(&self) -> i64;
+ /// Returns the last status change time.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::linux::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_ctime());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ctime(&self) -> i64;
+ /// Returns the last status change time, nano seconds part.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::linux::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_ctime_nsec());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ctime_nsec(&self) -> i64;
+ /// Returns the "preferred" blocksize for efficient filesystem I/O.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::linux::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_blksize());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_blksize(&self) -> u64;
+ /// Returns the number of blocks allocated to the file, 512-byte units.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::linux::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_blocks());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_blocks(&self) -> u64;
+}
+
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+impl MetadataExt for Metadata {
+ #[allow(deprecated)]
+ fn as_raw_stat(&self) -> &raw::stat {
+ unsafe {
+ &*(self.as_inner().as_inner() as *const libc::stat64
+ as *const raw::stat)
+ }
+ }
+ fn st_dev(&self) -> u64 {
+ self.as_inner().as_inner().st_dev as u64
+ }
+ fn st_ino(&self) -> u64 {
+ self.as_inner().as_inner().st_ino as u64
+ }
+ fn st_mode(&self) -> u32 {
+ self.as_inner().as_inner().st_mode as u32
+ }
+ fn st_nlink(&self) -> u64 {
+ self.as_inner().as_inner().st_nlink as u64
+ }
+ fn st_uid(&self) -> u32 {
+ self.as_inner().as_inner().st_uid as u32
+ }
+ fn st_gid(&self) -> u32 {
+ self.as_inner().as_inner().st_gid as u32
+ }
+ fn st_rdev(&self) -> u64 {
+ self.as_inner().as_inner().st_rdev as u64
+ }
+ fn st_size(&self) -> u64 {
+ self.as_inner().as_inner().st_size as u64
+ }
+ fn st_atime(&self) -> i64 {
+ self.as_inner().as_inner().st_atime as i64
+ }
+ fn st_atime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_atime_nsec as i64
+ }
+ fn st_mtime(&self) -> i64 {
+ self.as_inner().as_inner().st_mtime as i64
+ }
+ fn st_mtime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_mtime_nsec as i64
+ }
+ fn st_ctime(&self) -> i64 {
+ self.as_inner().as_inner().st_ctime as i64
+ }
+ fn st_ctime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_ctime_nsec as i64
+ }
+ fn st_blksize(&self) -> u64 {
+ self.as_inner().as_inner().st_blksize as u64
+ }
+ fn st_blocks(&self) -> u64 {
+ self.as_inner().as_inner().st_blocks as u64
+ }
+}
diff --git a/src/libstd/os/hermit/mod.rs b/src/libstd/os/hermit/mod.rs
new file mode 100644
index 0000000..4dee2a6
--- /dev/null
+++ b/src/libstd/os/hermit/mod.rs
@@ -0,0 +1,6 @@
+//! HermitCore-specific definitions
+
+#![stable(feature = "raw_ext", since = "1.1.0")]
+
+pub mod raw;
+pub mod fs;
diff --git a/src/libstd/os/hermit/raw.rs b/src/libstd/os/hermit/raw.rs
new file mode 100644
index 0000000..0e232a8
--- /dev/null
+++ b/src/libstd/os/hermit/raw.rs
@@ -0,0 +1,17 @@
+//! HermitCore-specific raw type definitions
+
+#![stable(feature = "raw_ext", since = "1.1.0")]
+#![rustc_deprecated(since = "1.8.0",
+ reason = "these type aliases are no longer supported by \
+ the standard library, the `libc` crate on \
+ crates.io should be used instead for the correct \
+ definitions")]
+#![allow(deprecated)]
+#![allow(missing_debug_implementations)]
+
+#[stable(feature = "pthread_t", since = "1.8.0")]
+pub use libc::pthread_t;
+
+#[doc(inline)]
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub use libc::{dev_t, mode_t, off_t, ino_t, nlink_t, blksize_t, blkcnt_t, stat, time_t};
diff --git a/src/libstd/os/ios/fs.rs b/src/libstd/os/ios/fs.rs
new file mode 100644
index 0000000..7b625f5
--- /dev/null
+++ b/src/libstd/os/ios/fs.rs
@@ -0,0 +1,144 @@
+#![stable(feature = "metadata_ext", since = "1.1.0")]
+
+use crate::fs::Metadata;
+use crate::sys_common::AsInner;
+
+#[allow(deprecated)]
+use crate::os::ios::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.
+ #[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;
+
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_dev(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ino(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mode(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_nlink(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_uid(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_gid(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_rdev(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_size(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_atime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_atime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mtime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mtime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ctime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ctime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_birthtime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_birthtime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_blksize(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_blocks(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_flags(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_gen(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_lspare(&self) -> u32;
+}
+
+#[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::stat
+ 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_birthtime(&self) -> i64 {
+ self.as_inner().as_inner().st_birthtime as i64
+ }
+ fn st_birthtime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_birthtime_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
+ }
+ fn st_gen(&self) -> u32 {
+ self.as_inner().as_inner().st_gen as u32
+ }
+ fn st_flags(&self) -> u32 {
+ self.as_inner().as_inner().st_flags as u32
+ }
+ fn st_lspare(&self) -> u32 {
+ self.as_inner().as_inner().st_lspare as u32
+ }
+}
+
diff --git a/src/libstd/os/ios/mod.rs b/src/libstd/os/ios/mod.rs
new file mode 100644
index 0000000..098473c
--- /dev/null
+++ b/src/libstd/os/ios/mod.rs
@@ -0,0 +1,6 @@
+//! iOS-specific definitions
+
+#![stable(feature = "raw_ext", since = "1.1.0")]
+
+pub mod raw;
+pub mod fs;
diff --git a/src/libstd/os/ios/raw.rs b/src/libstd/os/ios/raw.rs
new file mode 100644
index 0000000..fa38bca
--- /dev/null
+++ b/src/libstd/os/ios/raw.rs
@@ -0,0 +1,73 @@
+//! iOS-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)]
+
+use crate::os::raw::c_long;
+
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type blkcnt_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type blksize_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type dev_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type ino_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type mode_t = u32;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type nlink_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type off_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i64;
+
+#[stable(feature = "pthread_t", since = "1.8.0")]
+pub type pthread_t = usize;
+
+#[repr(C)]
+#[derive(Clone)]
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub struct stat {
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_dev: i32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mode: u16,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_nlink: u16,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ino: u64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_uid: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_gid: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_rdev: i32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_birthtime: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_birthtime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_size: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blocks: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blksize: i32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_flags: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_gen: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_lspare: i32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_qspare: [i64; 2],
+}
diff --git a/src/libstd/os/linux/fs.rs b/src/libstd/os/linux/fs.rs
new file mode 100644
index 0000000..ec5e983
--- /dev/null
+++ b/src/libstd/os/linux/fs.rs
@@ -0,0 +1,383 @@
+#![stable(feature = "metadata_ext", since = "1.1.0")]
+
+use crate::fs::Metadata;
+use crate::sys_common::AsInner;
+
+#[allow(deprecated)]
+use crate::os::linux::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 of the file, in seconds since Unix Epoch.
+ ///
+ /// # 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 of the file, in nanoseconds since [`st_atime`].
+ ///
+ /// [`st_atime`]: #tymethod.st_atime
+ ///
+ /// # 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 of the file, in seconds since Unix Epoch.
+ ///
+ /// # 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 of the file, in nanoseconds since [`st_mtime`].
+ ///
+ /// [`st_mtime`]: #tymethod.st_mtime
+ ///
+ /// # 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 of the file, in seconds since Unix Epoch.
+ ///
+ /// # 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 of the file, in nanoseconds since [`st_ctime`].
+ ///
+ /// [`st_ctime`]: #tymethod.st_ctime
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::linux::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_ctime_nsec());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ctime_nsec(&self) -> i64;
+ /// Returns the "preferred" blocksize for efficient filesystem I/O.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::linux::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_blksize());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_blksize(&self) -> u64;
+ /// Returns the number of blocks allocated to the file, 512-byte units.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::linux::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_blocks());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_blocks(&self) -> u64;
+}
+
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+impl MetadataExt for Metadata {
+ #[allow(deprecated)]
+ fn as_raw_stat(&self) -> &raw::stat {
+ unsafe {
+ &*(self.as_inner().as_inner() as *const libc::stat64
+ as *const raw::stat)
+ }
+ }
+ fn st_dev(&self) -> u64 {
+ self.as_inner().as_inner().st_dev as u64
+ }
+ fn st_ino(&self) -> u64 {
+ self.as_inner().as_inner().st_ino as u64
+ }
+ fn st_mode(&self) -> u32 {
+ self.as_inner().as_inner().st_mode as u32
+ }
+ fn st_nlink(&self) -> u64 {
+ self.as_inner().as_inner().st_nlink as u64
+ }
+ fn st_uid(&self) -> u32 {
+ self.as_inner().as_inner().st_uid as u32
+ }
+ fn st_gid(&self) -> u32 {
+ self.as_inner().as_inner().st_gid as u32
+ }
+ fn st_rdev(&self) -> u64 {
+ self.as_inner().as_inner().st_rdev as u64
+ }
+ fn st_size(&self) -> u64 {
+ self.as_inner().as_inner().st_size as u64
+ }
+ fn st_atime(&self) -> i64 {
+ self.as_inner().as_inner().st_atime as i64
+ }
+ fn st_atime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_atime_nsec as i64
+ }
+ fn st_mtime(&self) -> i64 {
+ self.as_inner().as_inner().st_mtime as i64
+ }
+ fn st_mtime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_mtime_nsec as i64
+ }
+ fn st_ctime(&self) -> i64 {
+ self.as_inner().as_inner().st_ctime as i64
+ }
+ fn st_ctime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_ctime_nsec as i64
+ }
+ fn st_blksize(&self) -> u64 {
+ self.as_inner().as_inner().st_blksize as u64
+ }
+ fn st_blocks(&self) -> u64 {
+ self.as_inner().as_inner().st_blocks as u64
+ }
+}
diff --git a/src/libstd/os/linux/mod.rs b/src/libstd/os/linux/mod.rs
new file mode 100644
index 0000000..3111325
--- /dev/null
+++ b/src/libstd/os/linux/mod.rs
@@ -0,0 +1,6 @@
+//! Linux-specific definitions
+
+#![stable(feature = "raw_ext", since = "1.1.0")]
+
+pub mod raw;
+pub mod fs;
diff --git a/src/libstd/os/linux/raw.rs b/src/libstd/os/linux/raw.rs
new file mode 100644
index 0000000..77eeacb
--- /dev/null
+++ b/src/libstd/os/linux/raw.rs
@@ -0,0 +1,265 @@
+//! Linux-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)]
+
+use crate::os::raw::c_ulong;
+
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type dev_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type mode_t = u32;
+
+#[stable(feature = "pthread_t", since = "1.8.0")]
+pub type pthread_t = c_ulong;
+
+#[doc(inline)]
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub use self::arch::{off_t, ino_t, nlink_t, blksize_t, blkcnt_t, stat, time_t};
+
+#[cfg(any(target_arch = "x86",
+ target_arch = "le32",
+ target_arch = "powerpc",
+ target_arch = "arm",
+ target_arch = "asmjs",
+ target_arch = "wasm32"))]
+mod arch {
+ use crate::os::raw::{c_long, c_short, c_uint};
+
+ #[stable(feature = "raw_ext", since = "1.1.0")] pub type blkcnt_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")] pub type blksize_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")] pub type ino_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")] pub type nlink_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")] pub type off_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i64;
+
+ #[repr(C)]
+ #[derive(Clone)]
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub struct stat {
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_dev: u64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub __pad1: c_short,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub __st_ino: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mode: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_nlink: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_uid: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_gid: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_rdev: u64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub __pad2: c_uint,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_size: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blksize: i32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blocks: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime: i32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime: i32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime: i32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ino: u64,
+ }
+}
+
+#[cfg(target_arch = "mips")]
+mod arch {
+ use crate::os::raw::{c_long, c_ulong};
+
+ #[cfg(target_env = "musl")]
+ #[stable(feature = "raw_ext", since = "1.1.0")] pub type blkcnt_t = i64;
+ #[cfg(not(target_env = "musl"))]
+ #[stable(feature = "raw_ext", since = "1.1.0")] pub type blkcnt_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")] pub type blksize_t = u64;
+ #[cfg(target_env = "musl")]
+ #[stable(feature = "raw_ext", since = "1.1.0")] pub type ino_t = u64;
+ #[cfg(not(target_env = "musl"))]
+ #[stable(feature = "raw_ext", since = "1.1.0")] pub type ino_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")] pub type nlink_t = u64;
+ #[cfg(target_env = "musl")]
+ #[stable(feature = "raw_ext", since = "1.1.0")] pub type off_t = u64;
+ #[cfg(not(target_env = "musl"))]
+ #[stable(feature = "raw_ext", since = "1.1.0")] pub type off_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i64;
+
+ #[repr(C)]
+ #[derive(Clone)]
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub struct stat {
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_dev: c_ulong,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_pad1: [c_long; 3],
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ino: u64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mode: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_nlink: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_uid: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_gid: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_rdev: c_ulong,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_pad2: [c_long; 2],
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_size: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime: i32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime: i32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime: i32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blksize: i32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blocks: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_pad5: [c_long; 14],
+ }
+}
+
+#[cfg(any(target_arch = "mips64",
+ target_arch = "s390x",
+ target_arch = "sparc64"))]
+mod arch {
+ pub use libc::{off_t, ino_t, nlink_t, blksize_t, blkcnt_t, stat, time_t};
+}
+
+#[cfg(target_arch = "aarch64")]
+mod arch {
+ use crate::os::raw::{c_long, c_int};
+
+ #[stable(feature = "raw_ext", since = "1.1.0")] pub type blkcnt_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")] pub type blksize_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")] pub type ino_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")] pub type nlink_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")] pub type off_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i64;
+
+ #[repr(C)]
+ #[derive(Clone)]
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub struct stat {
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_dev: u64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ino: u64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mode: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_nlink: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_uid: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_gid: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_rdev: u64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub __pad1: u64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_size: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blksize: i32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub __pad2: c_int,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blocks: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub __unused: [c_int; 2],
+ }
+}
+
+#[cfg(any(target_arch = "x86_64", target_arch = "powerpc64"))]
+mod arch {
+ use crate::os::raw::{c_long, c_int};
+
+ #[stable(feature = "raw_ext", since = "1.1.0")] pub type blkcnt_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")] pub type blksize_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")] pub type ino_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")] pub type nlink_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")] pub type off_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i64;
+
+ #[repr(C)]
+ #[derive(Clone)]
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub struct stat {
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_dev: u64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ino: u64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_nlink: u64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mode: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_uid: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_gid: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub __pad0: c_int,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_rdev: u64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_size: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blksize: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blocks: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub __unused: [c_long; 3],
+ }
+}
diff --git a/src/libstd/os/macos/fs.rs b/src/libstd/os/macos/fs.rs
new file mode 100644
index 0000000..1bd66ad
--- /dev/null
+++ b/src/libstd/os/macos/fs.rs
@@ -0,0 +1,150 @@
+#![stable(feature = "metadata_ext", since = "1.1.0")]
+
+use crate::fs::Metadata;
+use crate::sys_common::AsInner;
+
+#[allow(deprecated)]
+use crate::os::macos::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.
+ #[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;
+
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_dev(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ino(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mode(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_nlink(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_uid(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_gid(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_rdev(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_size(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_atime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_atime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mtime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mtime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ctime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ctime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_birthtime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_birthtime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_blksize(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_blocks(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_flags(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_gen(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_lspare(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_qspare(&self) -> [u64; 2];
+}
+
+#[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::stat
+ 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_birthtime(&self) -> i64 {
+ self.as_inner().as_inner().st_birthtime as i64
+ }
+ fn st_birthtime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_birthtime_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
+ }
+ fn st_gen(&self) -> u32 {
+ self.as_inner().as_inner().st_gen as u32
+ }
+ fn st_flags(&self) -> u32 {
+ self.as_inner().as_inner().st_flags as u32
+ }
+ fn st_lspare(&self) -> u32 {
+ self.as_inner().as_inner().st_lspare as u32
+ }
+ fn st_qspare(&self) -> [u64; 2] {
+ let qspare = self.as_inner().as_inner().st_qspare;
+ [qspare[0] as u64, qspare[1] as u64]
+ }
+}
+
diff --git a/src/libstd/os/macos/mod.rs b/src/libstd/os/macos/mod.rs
new file mode 100644
index 0000000..ce48d6e
--- /dev/null
+++ b/src/libstd/os/macos/mod.rs
@@ -0,0 +1,6 @@
+//! macOS-specific definitions
+
+#![stable(feature = "raw_ext", since = "1.1.0")]
+
+pub mod raw;
+pub mod fs;
diff --git a/src/libstd/os/macos/raw.rs b/src/libstd/os/macos/raw.rs
new file mode 100644
index 0000000..5685642
--- /dev/null
+++ b/src/libstd/os/macos/raw.rs
@@ -0,0 +1,73 @@
+//! macOS-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)]
+
+use crate::os::raw::c_long;
+
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type blkcnt_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type blksize_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type dev_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type ino_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type mode_t = u32;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type nlink_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type off_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i64;
+
+#[stable(feature = "pthread_t", since = "1.8.0")]
+pub type pthread_t = usize;
+
+#[repr(C)]
+#[derive(Clone)]
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub struct stat {
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_dev: i32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mode: u16,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_nlink: u16,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ino: u64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_uid: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_gid: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_rdev: i32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_birthtime: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_birthtime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_size: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blocks: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blksize: i32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_flags: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_gen: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_lspare: i32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_qspare: [i64; 2],
+}
diff --git a/src/libstd/os/mod.rs b/src/libstd/os/mod.rs
new file mode 100644
index 0000000..d48b5ac
--- /dev/null
+++ b/src/libstd/os/mod.rs
@@ -0,0 +1,57 @@
+//! OS-specific functionality.
+
+#![stable(feature = "os", since = "1.0.0")]
+#![allow(missing_docs, nonstandard_style, missing_debug_implementations)]
+
+cfg_if! {
+ if #[cfg(rustdoc)] {
+
+ // When documenting libstd we want to show unix/windows/linux modules as
+ // these are the "main modules" that are used across platforms. This
+ // should help show platform-specific functionality in a hopefully
+ // cross-platform way in the documentation
+
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub use crate::sys::unix_ext as unix;
+
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub use crate::sys::windows_ext as windows;
+
+ #[doc(cfg(target_os = "linux"))]
+ pub mod linux;
+ } else {
+
+ // If we're not documenting libstd then we just expose the main modules
+ // as we otherwise would.
+
+ #[cfg(any(target_os = "redox", unix))]
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub use crate::sys::ext as unix;
+
+ #[cfg(windows)]
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub use crate::sys::ext as windows;
+
+ #[cfg(any(target_os = "linux", target_os = "l4re"))]
+ pub mod linux;
+
+ }
+}
+
+#[cfg(target_os = "android")] pub mod android;
+#[cfg(target_os = "bitrig")] pub mod bitrig;
+#[cfg(target_os = "dragonfly")] pub mod dragonfly;
+#[cfg(target_os = "freebsd")] pub mod freebsd;
+#[cfg(target_os = "haiku")] pub mod haiku;
+#[cfg(target_os = "ios")] pub mod ios;
+#[cfg(target_os = "macos")] pub mod macos;
+#[cfg(target_os = "netbsd")] pub mod netbsd;
+#[cfg(target_os = "openbsd")] pub mod openbsd;
+#[cfg(target_os = "solaris")] pub mod solaris;
+#[cfg(target_os = "emscripten")] pub mod emscripten;
+#[cfg(target_os = "fuchsia")] pub mod fuchsia;
+#[cfg(target_os = "hermit")] pub mod hermit;
+#[cfg(target_env = "wasi")] pub mod wasi;
+#[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] pub mod fortanix_sgx;
+
+pub mod raw;
diff --git a/src/libstd/os/netbsd/fs.rs b/src/libstd/os/netbsd/fs.rs
new file mode 100644
index 0000000..6dffb70
--- /dev/null
+++ b/src/libstd/os/netbsd/fs.rs
@@ -0,0 +1,139 @@
+#![stable(feature = "metadata_ext", since = "1.1.0")]
+
+use crate::fs::Metadata;
+use crate::sys_common::AsInner;
+
+#[allow(deprecated)]
+use crate::os::netbsd::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.
+ #[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;
+
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_dev(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ino(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mode(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_nlink(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_uid(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_gid(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_rdev(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_size(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_atime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_atime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mtime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mtime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ctime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ctime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_birthtime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_birthtime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_blksize(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_blocks(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_flags(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_gen(&self) -> u32;
+}
+
+#[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::stat
+ 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_atimensec 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_mtimensec 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_ctimensec as i64
+ }
+ fn st_birthtime(&self) -> i64 {
+ self.as_inner().as_inner().st_birthtime as i64
+ }
+ fn st_birthtime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_birthtimensec 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
+ }
+ fn st_gen(&self) -> u32 {
+ self.as_inner().as_inner().st_gen as u32
+ }
+ fn st_flags(&self) -> u32 {
+ self.as_inner().as_inner().st_flags as u32
+ }
+}
+
diff --git a/src/libstd/os/netbsd/mod.rs b/src/libstd/os/netbsd/mod.rs
new file mode 100644
index 0000000..3746363
--- /dev/null
+++ b/src/libstd/os/netbsd/mod.rs
@@ -0,0 +1,6 @@
+//! OpenBSD-specific definitions
+
+#![stable(feature = "raw_ext", since = "1.1.0")]
+
+pub mod raw;
+pub mod fs;
diff --git a/src/libstd/os/netbsd/raw.rs b/src/libstd/os/netbsd/raw.rs
new file mode 100644
index 0000000..1d5d5c6
--- /dev/null
+++ b/src/libstd/os/netbsd/raw.rs
@@ -0,0 +1,72 @@
+//! NetBSD-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)]
+
+use crate::os::raw::c_long;
+use crate::os::unix::raw::{uid_t, gid_t};
+
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type blkcnt_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type blksize_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type dev_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type fflags_t = u32;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type ino_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type mode_t = u32;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type nlink_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type off_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i64;
+
+#[stable(feature = "pthread_t", since = "1.8.0")]
+pub type pthread_t = usize;
+
+#[repr(C)]
+#[derive(Clone)]
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub struct stat {
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_dev: u64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mode: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ino: u64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_nlink: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_uid: uid_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_gid: gid_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_rdev: u64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_birthtime: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_birthtime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_size: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blocks: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blksize: i32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_flags: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_gen: u32,
+ st_spare: [u32; 2],
+}
diff --git a/src/libstd/os/openbsd/fs.rs b/src/libstd/os/openbsd/fs.rs
new file mode 100644
index 0000000..73f9757
--- /dev/null
+++ b/src/libstd/os/openbsd/fs.rs
@@ -0,0 +1,139 @@
+#![stable(feature = "metadata_ext", since = "1.1.0")]
+
+use crate::fs::Metadata;
+use crate::sys_common::AsInner;
+
+#[allow(deprecated)]
+use crate::os::openbsd::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.
+ #[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;
+
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_dev(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ino(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mode(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_nlink(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_uid(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_gid(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_rdev(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_size(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_atime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_atime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mtime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mtime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ctime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ctime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_birthtime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_birthtime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_blksize(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_blocks(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_flags(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_gen(&self) -> u32;
+}
+
+#[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::stat
+ 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_birthtime(&self) -> i64 {
+ self.as_inner().as_inner().st_birthtime as i64
+ }
+ fn st_birthtime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_birthtime_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
+ }
+ fn st_gen(&self) -> u32 {
+ self.as_inner().as_inner().st_gen as u32
+ }
+ fn st_flags(&self) -> u32 {
+ self.as_inner().as_inner().st_flags as u32
+ }
+}
+
diff --git a/src/libstd/os/openbsd/mod.rs b/src/libstd/os/openbsd/mod.rs
new file mode 100644
index 0000000..3746363
--- /dev/null
+++ b/src/libstd/os/openbsd/mod.rs
@@ -0,0 +1,6 @@
+//! OpenBSD-specific definitions
+
+#![stable(feature = "raw_ext", since = "1.1.0")]
+
+pub mod raw;
+pub mod fs;
diff --git a/src/libstd/os/openbsd/raw.rs b/src/libstd/os/openbsd/raw.rs
new file mode 100644
index 0000000..0941684
--- /dev/null
+++ b/src/libstd/os/openbsd/raw.rs
@@ -0,0 +1,70 @@
+//! OpenBSD-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)]
+
+use crate::os::raw::c_long;
+
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type blkcnt_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type blksize_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type dev_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type fflags_t = u32;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type ino_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type mode_t = u32;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type nlink_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type off_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i64;
+
+#[stable(feature = "pthread_t", since = "1.8.0")]
+pub type pthread_t = usize;
+
+#[repr(C)]
+#[derive(Clone)]
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub struct stat {
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mode: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_dev: i32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ino: u64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_nlink: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_uid: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_gid: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_rdev: i32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_size: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blocks: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blksize: i32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_flags: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_gen: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_birthtime: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_birthtime_nsec: c_long,
+}
diff --git a/src/libstd/os/raw/char.md b/src/libstd/os/raw/char.md
new file mode 100644
index 0000000..9a55767
--- /dev/null
+++ b/src/libstd/os/raw/char.md
@@ -0,0 +1,11 @@
+Equivalent to C's `char` type.
+
+[C's `char` type] is completely unlike [Rust's `char` type]; while Rust's type represents a unicode scalar value, C's `char` type is just an ordinary integer. This type will always be either [`i8`] or [`u8`], as the type is defined as being one byte long.
+
+C chars are most commonly used to make C strings. Unlike Rust, where the length of a string is included alongside the string, C strings mark the end of a string with the character `'\0'`. See [`CStr`] for more information.
+
+[C's `char` type]: https://en.wikipedia.org/wiki/C_data_types#Basic_types
+[Rust's `char` type]: ../../primitive.char.html
+[`CStr`]: ../../ffi/struct.CStr.html
+[`i8`]: ../../primitive.i8.html
+[`u8`]: ../../primitive.u8.html
diff --git a/src/libstd/os/raw/double.md b/src/libstd/os/raw/double.md
new file mode 100644
index 0000000..6818dad
--- /dev/null
+++ b/src/libstd/os/raw/double.md
@@ -0,0 +1,7 @@
+Equivalent to C's `double` type.
+
+This type will almost always be [`f64`], which is guaranteed to be an [IEEE-754 double-precision float] in Rust. That said, the standard technically only guarantees that it be a floating-point number with at least the precision of a [`float`], and it may be `f32` or something entirely different from the IEEE-754 standard.
+
+[IEEE-754 double-precision float]: https://en.wikipedia.org/wiki/IEEE_754
+[`float`]: type.c_float.html
+[`f64`]: ../../primitive.f64.html
diff --git a/src/libstd/os/raw/float.md b/src/libstd/os/raw/float.md
new file mode 100644
index 0000000..57d1071
--- /dev/null
+++ b/src/libstd/os/raw/float.md
@@ -0,0 +1,6 @@
+Equivalent to C's `float` type.
+
+This type will almost always be [`f32`], which is guaranteed to be an [IEEE-754 single-precision float] in Rust. That said, the standard technically only guarantees that it be a floating-point number, and it may have less precision than `f32` or not follow the IEEE-754 standard at all.
+
+[IEEE-754 single-precision float]: https://en.wikipedia.org/wiki/IEEE_754
+[`f32`]: ../../primitive.f32.html
diff --git a/src/libstd/os/raw/int.md b/src/libstd/os/raw/int.md
new file mode 100644
index 0000000..a0d25fd
--- /dev/null
+++ b/src/libstd/os/raw/int.md
@@ -0,0 +1,7 @@
+Equivalent to C's `signed int` (`int`) type.
+
+This type will almost always be [`i32`], but may differ on some esoteric systems. The C standard technically only requires that this type be a signed integer that is at least the size of a [`short`]; some systems define it as an [`i16`], for example.
+
+[`short`]: type.c_short.html
+[`i32`]: ../../primitive.i32.html
+[`i16`]: ../../primitive.i16.html
diff --git a/src/libstd/os/raw/long.md b/src/libstd/os/raw/long.md
new file mode 100644
index 0000000..c620b40
--- /dev/null
+++ b/src/libstd/os/raw/long.md
@@ -0,0 +1,7 @@
+Equivalent to C's `signed long` (`long`) type.
+
+This type will always be [`i32`] or [`i64`]. Most notably, many Linux-based systems assume an `i64`, but Windows assumes `i32`. The C standard technically only requires that this type be a signed integer that is at least 32 bits and at least the size of an [`int`], although in practice, no system would have a `long` that is neither an `i32` nor `i64`.
+
+[`int`]: type.c_int.html
+[`i32`]: ../../primitive.i32.html
+[`i64`]: ../../primitive.i64.html
diff --git a/src/libstd/os/raw/longlong.md b/src/libstd/os/raw/longlong.md
new file mode 100644
index 0000000..ab3d643
--- /dev/null
+++ b/src/libstd/os/raw/longlong.md
@@ -0,0 +1,7 @@
+Equivalent to C's `signed long long` (`long long`) type.
+
+This type will almost always be [`i64`], but may differ on some systems. The C standard technically only requires that this type be a signed integer that is at least 64 bits and at least the size of a [`long`], although in practice, no system would have a `long long` that is not an `i64`, as most systems do not have a standardised [`i128`] type.
+
+[`long`]: type.c_int.html
+[`i64`]: ../../primitive.i64.html
+[`i128`]: ../../primitive.i128.html
diff --git a/src/libstd/os/raw/mod.rs b/src/libstd/os/raw/mod.rs
new file mode 100644
index 0000000..e9043b4
--- /dev/null
+++ b/src/libstd/os/raw/mod.rs
@@ -0,0 +1,105 @@
+//! Platform-specific types, as defined by C.
+//!
+//! Code that interacts via FFI will almost certainly be using the
+//! base types provided by C, which aren't nearly as nicely defined
+//! as Rust's primitive types. This module provides types which will
+//! match those defined by C, so that code that interacts with C will
+//! refer to the correct types.
+
+#![stable(feature = "raw_os", since = "1.1.0")]
+
+#[doc(include = "os/raw/char.md")]
+#[cfg(any(all(target_os = "linux", any(target_arch = "aarch64",
+ target_arch = "arm",
+ target_arch = "powerpc",
+ target_arch = "powerpc64",
+ target_arch = "s390x")),
+ all(target_os = "android", any(target_arch = "aarch64",
+ target_arch = "arm")),
+ all(target_os = "l4re", target_arch = "x86_64"),
+ all(target_os = "freebsd", any(target_arch = "aarch64",
+ target_arch = "arm",
+ target_arch = "powerpc",
+ target_arch = "powerpc64")),
+ all(target_os = "netbsd", any(target_arch = "aarch64",
+ target_arch = "arm",
+ target_arch = "powerpc")),
+ all(target_os = "openbsd", target_arch = "aarch64"),
+ all(target_os = "fuchsia", target_arch = "aarch64")))]
+#[stable(feature = "raw_os", since = "1.1.0")] pub type c_char = u8;
+#[doc(include = "os/raw/char.md")]
+#[cfg(not(any(all(target_os = "linux", any(target_arch = "aarch64",
+ target_arch = "arm",
+ target_arch = "powerpc",
+ target_arch = "powerpc64",
+ target_arch = "s390x")),
+ all(target_os = "android", any(target_arch = "aarch64",
+ target_arch = "arm")),
+ all(target_os = "l4re", target_arch = "x86_64"),
+ all(target_os = "freebsd", any(target_arch = "aarch64",
+ target_arch = "arm",
+ target_arch = "powerpc",
+ target_arch = "powerpc64")),
+ all(target_os = "netbsd", any(target_arch = "aarch64",
+ target_arch = "arm",
+ target_arch = "powerpc")),
+ all(target_os = "openbsd", target_arch = "aarch64"),
+ all(target_os = "fuchsia", target_arch = "aarch64"))))]
+#[stable(feature = "raw_os", since = "1.1.0")] pub type c_char = i8;
+#[doc(include = "os/raw/schar.md")]
+#[stable(feature = "raw_os", since = "1.1.0")] pub type c_schar = i8;
+#[doc(include = "os/raw/uchar.md")]
+#[stable(feature = "raw_os", since = "1.1.0")] pub type c_uchar = u8;
+#[doc(include = "os/raw/short.md")]
+#[stable(feature = "raw_os", since = "1.1.0")] pub type c_short = i16;
+#[doc(include = "os/raw/ushort.md")]
+#[stable(feature = "raw_os", since = "1.1.0")] pub type c_ushort = u16;
+#[doc(include = "os/raw/int.md")]
+#[stable(feature = "raw_os", since = "1.1.0")] pub type c_int = i32;
+#[doc(include = "os/raw/uint.md")]
+#[stable(feature = "raw_os", since = "1.1.0")] pub type c_uint = u32;
+#[doc(include = "os/raw/long.md")]
+#[cfg(any(target_pointer_width = "32", windows))]
+#[stable(feature = "raw_os", since = "1.1.0")] pub type c_long = i32;
+#[doc(include = "os/raw/ulong.md")]
+#[cfg(any(target_pointer_width = "32", windows))]
+#[stable(feature = "raw_os", since = "1.1.0")] pub type c_ulong = u32;
+#[doc(include = "os/raw/long.md")]
+#[cfg(all(target_pointer_width = "64", not(windows)))]
+#[stable(feature = "raw_os", since = "1.1.0")] pub type c_long = i64;
+#[doc(include = "os/raw/ulong.md")]
+#[cfg(all(target_pointer_width = "64", not(windows)))]
+#[stable(feature = "raw_os", since = "1.1.0")] pub type c_ulong = u64;
+#[doc(include = "os/raw/longlong.md")]
+#[stable(feature = "raw_os", since = "1.1.0")] pub type c_longlong = i64;
+#[doc(include = "os/raw/ulonglong.md")]
+#[stable(feature = "raw_os", since = "1.1.0")] pub type c_ulonglong = u64;
+#[doc(include = "os/raw/float.md")]
+#[stable(feature = "raw_os", since = "1.1.0")] pub type c_float = f32;
+#[doc(include = "os/raw/double.md")]
+#[stable(feature = "raw_os", since = "1.1.0")] pub type c_double = f64;
+
+#[stable(feature = "raw_os", since = "1.1.0")]
+#[doc(no_inline)]
+pub use core::ffi::c_void;
+
+#[cfg(test)]
+#[allow(unused_imports)]
+mod tests {
+ use crate::any::TypeId;
+ use crate::mem;
+
+ macro_rules! ok {
+ ($($t:ident)*) => {$(
+ assert!(TypeId::of::<libc::$t>() == TypeId::of::<raw::$t>(),
+ "{} is wrong", stringify!($t));
+ )*}
+ }
+
+ #[test]
+ fn same() {
+ use crate::os::raw;
+ ok!(c_char c_schar c_uchar c_short c_ushort c_int c_uint c_long c_ulong
+ c_longlong c_ulonglong c_float c_double);
+ }
+}
diff --git a/src/libstd/os/raw/schar.md b/src/libstd/os/raw/schar.md
new file mode 100644
index 0000000..6aa8b12
--- /dev/null
+++ b/src/libstd/os/raw/schar.md
@@ -0,0 +1,6 @@
+Equivalent to C's `signed char` type.
+
+This type will always be [`i8`], but is included for completeness. It is defined as being a signed integer the same size as a C [`char`].
+
+[`char`]: type.c_char.html
+[`i8`]: ../../primitive.i8.html
diff --git a/src/libstd/os/raw/short.md b/src/libstd/os/raw/short.md
new file mode 100644
index 0000000..be92c6c
--- /dev/null
+++ b/src/libstd/os/raw/short.md
@@ -0,0 +1,6 @@
+Equivalent to C's `signed short` (`short`) type.
+
+This type will almost always be [`i16`], but may differ on some esoteric systems. The C standard technically only requires that this type be a signed integer with at least 16 bits; some systems may define it as `i32`, for example.
+
+[`char`]: type.c_char.html
+[`i16`]: ../../primitive.i16.html
diff --git a/src/libstd/os/raw/uchar.md b/src/libstd/os/raw/uchar.md
new file mode 100644
index 0000000..b6ca711
--- /dev/null
+++ b/src/libstd/os/raw/uchar.md
@@ -0,0 +1,6 @@
+Equivalent to C's `unsigned char` type.
+
+This type will always be [`u8`], but is included for completeness. It is defined as being an unsigned integer the same size as a C [`char`].
+
+[`char`]: type.c_char.html
+[`u8`]: ../../primitive.u8.html
diff --git a/src/libstd/os/raw/uint.md b/src/libstd/os/raw/uint.md
new file mode 100644
index 0000000..6f7013a
--- /dev/null
+++ b/src/libstd/os/raw/uint.md
@@ -0,0 +1,7 @@
+Equivalent to C's `unsigned int` type.
+
+This type will almost always be [`u32`], but may differ on some esoteric systems. The C standard technically only requires that this type be an unsigned integer with the same size as an [`int`]; some systems define it as a [`u16`], for example.
+
+[`int`]: type.c_int.html
+[`u32`]: ../../primitive.u32.html
+[`u16`]: ../../primitive.u16.html
diff --git a/src/libstd/os/raw/ulong.md b/src/libstd/os/raw/ulong.md
new file mode 100644
index 0000000..c350395
--- /dev/null
+++ b/src/libstd/os/raw/ulong.md
@@ -0,0 +1,7 @@
+Equivalent to C's `unsigned long` type.
+
+This type will always be [`u32`] or [`u64`]. Most notably, many Linux-based systems assume an `u64`, but Windows assumes `u32`. The C standard technically only requires that this type be an unsigned integer with the size of a [`long`], although in practice, no system would have a `ulong` that is neither a `u32` nor `u64`.
+
+[`long`]: type.c_long.html
+[`u32`]: ../../primitive.u32.html
+[`u64`]: ../../primitive.u64.html
diff --git a/src/libstd/os/raw/ulonglong.md b/src/libstd/os/raw/ulonglong.md
new file mode 100644
index 0000000..c41faf7
--- /dev/null
+++ b/src/libstd/os/raw/ulonglong.md
@@ -0,0 +1,7 @@
+Equivalent to C's `unsigned long long` type.
+
+This type will almost always be [`u64`], but may differ on some systems. The C standard technically only requires that this type be an unsigned integer with the size of a [`long long`], although in practice, no system would have a `long long` that is not a `u64`, as most systems do not have a standardised [`u128`] type.
+
+[`long long`]: type.c_longlong.html
+[`u64`]: ../../primitive.u64.html
+[`u128`]: ../../primitive.u128.html
diff --git a/src/libstd/os/raw/ushort.md b/src/libstd/os/raw/ushort.md
new file mode 100644
index 0000000..d364abb
--- /dev/null
+++ b/src/libstd/os/raw/ushort.md
@@ -0,0 +1,6 @@
+Equivalent to C's `unsigned short` type.
+
+This type will almost always be [`u16`], but may differ on some esoteric systems. The C standard technically only requires that this type be an unsigned integer with the same size as a [`short`].
+
+[`short`]: type.c_short.html
+[`u16`]: ../../primitive.u16.html
diff --git a/src/libstd/os/solaris/fs.rs b/src/libstd/os/solaris/fs.rs
new file mode 100644
index 0000000..55a8d5d
--- /dev/null
+++ b/src/libstd/os/solaris/fs.rs
@@ -0,0 +1,118 @@
+#![stable(feature = "metadata_ext", since = "1.1.0")]
+
+use crate::fs::Metadata;
+use crate::sys_common::AsInner;
+
+#[allow(deprecated)]
+use crate::os::solaris::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.
+ #[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;
+
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_dev(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ino(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mode(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_nlink(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_uid(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_gid(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_rdev(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_size(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_atime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_atime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mtime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mtime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ctime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ctime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_blksize(&self) -> u64;
+ #[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::stat
+ as *const raw::stat)
+ }
+ }
+ fn st_dev(&self) -> u64 {
+ self.as_inner().as_inner().st_dev as u64
+ }
+ fn st_ino(&self) -> u64 {
+ self.as_inner().as_inner().st_ino as u64
+ }
+ fn st_mode(&self) -> u32 {
+ self.as_inner().as_inner().st_mode as u32
+ }
+ fn st_nlink(&self) -> u64 {
+ self.as_inner().as_inner().st_nlink as u64
+ }
+ fn st_uid(&self) -> u32 {
+ self.as_inner().as_inner().st_uid as u32
+ }
+ fn st_gid(&self) -> u32 {
+ self.as_inner().as_inner().st_gid as u32
+ }
+ fn st_rdev(&self) -> u64 {
+ self.as_inner().as_inner().st_rdev as u64
+ }
+ fn st_size(&self) -> u64 {
+ self.as_inner().as_inner().st_size as u64
+ }
+ fn st_atime(&self) -> i64 {
+ self.as_inner().as_inner().st_atime as i64
+ }
+ fn st_atime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_atime_nsec as i64
+ }
+ fn st_mtime(&self) -> i64 {
+ self.as_inner().as_inner().st_mtime as i64
+ }
+ fn st_mtime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_mtime_nsec as i64
+ }
+ fn st_ctime(&self) -> i64 {
+ self.as_inner().as_inner().st_ctime as i64
+ }
+ fn st_ctime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_ctime_nsec as i64
+ }
+ fn st_blksize(&self) -> u64 {
+ self.as_inner().as_inner().st_blksize as u64
+ }
+ fn st_blocks(&self) -> u64 {
+ self.as_inner().as_inner().st_blocks as u64
+ }
+}
diff --git a/src/libstd/os/solaris/mod.rs b/src/libstd/os/solaris/mod.rs
new file mode 100644
index 0000000..7f560c9
--- /dev/null
+++ b/src/libstd/os/solaris/mod.rs
@@ -0,0 +1,6 @@
+//! Solaris-specific definitions
+
+#![stable(feature = "raw_ext", since = "1.1.0")]
+
+pub mod raw;
+pub mod fs;
diff --git a/src/libstd/os/solaris/raw.rs b/src/libstd/os/solaris/raw.rs
new file mode 100644
index 0000000..93270ef
--- /dev/null
+++ b/src/libstd/os/solaris/raw.rs
@@ -0,0 +1,65 @@
+//! Solaris-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)]
+
+use crate::os::raw::c_long;
+use crate::os::unix::raw::{uid_t, gid_t};
+
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type blkcnt_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type blksize_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type dev_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type fflags_t = u32;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type ino_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type mode_t = u32;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type nlink_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type off_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i64;
+
+#[stable(feature = "pthread_t", since = "1.8.0")]
+pub type pthread_t = u32;
+
+#[repr(C)]
+#[derive(Clone)]
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub struct stat {
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_dev: dev_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ino: ino_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mode: mode_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_nlink: nlink_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_uid: uid_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_gid: gid_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_rdev: dev_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_size: off_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime: time_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime: time_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime: time_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blksize: blksize_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blocks: blkcnt_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub __unused: [u8; 16]
+}
diff --git a/src/libstd/os/wasi.rs b/src/libstd/os/wasi.rs
new file mode 100644
index 0000000..d25b8d3
--- /dev/null
+++ b/src/libstd/os/wasi.rs
@@ -0,0 +1,6 @@
+//! WASI-specific definitions
+
+#![stable(feature = "raw_ext", since = "1.1.0")]
+
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use crate::sys::ext::*;
diff --git a/src/libstd/panic.rs b/src/libstd/panic.rs
new file mode 100644
index 0000000..5a8101e
--- /dev/null
+++ b/src/libstd/panic.rs
@@ -0,0 +1,422 @@
+//! Panic support in the standard library.
+
+#![stable(feature = "std_panic", since = "1.9.0")]
+
+use crate::any::Any;
+use crate::cell::UnsafeCell;
+use crate::fmt;
+use crate::future::Future;
+use crate::pin::Pin;
+use crate::ops::{Deref, DerefMut};
+use crate::panicking;
+use crate::ptr::{Unique, NonNull};
+use crate::rc::Rc;
+use crate::sync::{Arc, Mutex, RwLock, atomic};
+use crate::task::{Context, Poll};
+use crate::thread::Result;
+
+#[stable(feature = "panic_hooks", since = "1.10.0")]
+pub use crate::panicking::{take_hook, set_hook};
+
+#[stable(feature = "panic_hooks", since = "1.10.0")]
+pub use core::panic::{PanicInfo, Location};
+
+/// A marker trait which represents "panic safe" types in Rust.
+///
+/// This trait is implemented by default for many types and behaves similarly in
+/// terms of inference of implementation to the [`Send`] and [`Sync`] traits. The
+/// purpose of this trait is to encode what types are safe to cross a [`catch_unwind`]
+/// boundary with no fear of unwind safety.
+///
+/// [`Send`]: ../marker/trait.Send.html
+/// [`Sync`]: ../marker/trait.Sync.html
+/// [`catch_unwind`]: ./fn.catch_unwind.html
+///
+/// ## What is unwind safety?
+///
+/// In Rust a function can "return" early if it either panics or calls a
+/// function which transitively panics. This sort of control flow is not always
+/// anticipated, and has the possibility of causing subtle bugs through a
+/// combination of two critical components:
+///
+/// 1. A data structure is in a temporarily invalid state when the thread
+/// panics.
+/// 2. This broken invariant is then later observed.
+///
+/// Typically in Rust, it is difficult to perform step (2) because catching a
+/// panic involves either spawning a thread (which in turns makes it difficult
+/// to later witness broken invariants) or using the `catch_unwind` function in this
+/// module. Additionally, even if an invariant is witnessed, it typically isn't a
+/// problem in Rust because there are no uninitialized values (like in C or C++).
+///
+/// It is possible, however, for **logical** invariants to be broken in Rust,
+/// which can end up causing behavioral bugs. Another key aspect of unwind safety
+/// in Rust is that, in the absence of `unsafe` code, a panic cannot lead to
+/// memory unsafety.
+///
+/// That was a bit of a whirlwind tour of unwind safety, but for more information
+/// about unwind safety and how it applies to Rust, see an [associated RFC][rfc].
+///
+/// [rfc]: https://github.com/rust-lang/rfcs/blob/master/text/1236-stabilize-catch-panic.md
+///
+/// ## What is `UnwindSafe`?
+///
+/// Now that we've got an idea of what unwind safety is in Rust, it's also
+/// important to understand what this trait represents. As mentioned above, one
+/// way to witness broken invariants is through the `catch_unwind` function in this
+/// module as it allows catching a panic and then re-using the environment of
+/// the closure.
+///
+/// Simply put, a type `T` implements `UnwindSafe` if it cannot easily allow
+/// witnessing a broken invariant through the use of `catch_unwind` (catching a
+/// panic). This trait is an auto trait, so it is automatically implemented for
+/// many types, and it is also structurally composed (e.g., a struct is unwind
+/// safe if all of its components are unwind safe).
+///
+/// Note, however, that this is not an unsafe trait, so there is not a succinct
+/// contract that this trait is providing. Instead it is intended as more of a
+/// "speed bump" to alert users of `catch_unwind` that broken invariants may be
+/// witnessed and may need to be accounted for.
+///
+/// ## Who implements `UnwindSafe`?
+///
+/// Types such as `&mut T` and `&RefCell<T>` are examples which are **not**
+/// unwind safe. The general idea is that any mutable state which can be shared
+/// across `catch_unwind` is not unwind safe by default. This is because it is very
+/// easy to witness a broken invariant outside of `catch_unwind` as the data is
+/// simply accessed as usual.
+///
+/// Types like `&Mutex<T>`, however, are unwind safe because they implement
+/// poisoning by default. They still allow witnessing a broken invariant, but
+/// they already provide their own "speed bumps" to do so.
+///
+/// ## When should `UnwindSafe` be used?
+///
+/// It is not intended that most types or functions need to worry about this trait.
+/// It is only used as a bound on the `catch_unwind` function and as mentioned
+/// above, the lack of `unsafe` means it is mostly an advisory. The
+/// [`AssertUnwindSafe`] wrapper struct can be used to force this trait to be
+/// implemented for any closed over variables passed to `catch_unwind`.
+///
+/// [`AssertUnwindSafe`]: ./struct.AssertUnwindSafe.html
+#[stable(feature = "catch_unwind", since = "1.9.0")]
+#[rustc_on_unimplemented(
+ message="the type `{Self}` may not be safely transferred across an unwind boundary",
+ label="`{Self}` may not be safely transferred across an unwind boundary",
+)]
+pub auto trait UnwindSafe {}
+
+/// A marker trait representing types where a shared reference is considered
+/// unwind safe.
+///
+/// This trait is namely not implemented by [`UnsafeCell`], the root of all
+/// interior mutability.
+///
+/// This is a "helper marker trait" used to provide impl blocks for the
+/// [`UnwindSafe`] trait, for more information see that documentation.
+///
+/// [`UnsafeCell`]: ../cell/struct.UnsafeCell.html
+/// [`UnwindSafe`]: ./trait.UnwindSafe.html
+#[stable(feature = "catch_unwind", since = "1.9.0")]
+#[rustc_on_unimplemented(
+ message="the type `{Self}` may contain interior mutability and a reference may not be safely \
+ transferrable across a catch_unwind boundary",
+ label="`{Self}` may contain interior mutability and a reference may not be safely \
+ transferrable across a catch_unwind boundary",
+)]
+pub auto trait RefUnwindSafe {}
+
+/// A simple wrapper around a type to assert that it is unwind safe.
+///
+/// When using [`catch_unwind`] it may be the case that some of the closed over
+/// variables are not unwind safe. For example if `&mut T` is captured the
+/// compiler will generate a warning indicating that it is not unwind safe. It
+/// may not be the case, however, that this is actually a problem due to the
+/// specific usage of [`catch_unwind`] if unwind safety is specifically taken into
+/// account. This wrapper struct is useful for a quick and lightweight
+/// annotation that a variable is indeed unwind safe.
+///
+/// [`catch_unwind`]: ./fn.catch_unwind.html
+/// # Examples
+///
+/// One way to use `AssertUnwindSafe` is to assert that the entire closure
+/// itself is unwind safe, bypassing all checks for all variables:
+///
+/// ```
+/// use std::panic::{self, AssertUnwindSafe};
+///
+/// let mut variable = 4;
+///
+/// // This code will not compile because the closure captures `&mut variable`
+/// // which is not considered unwind safe by default.
+///
+/// // panic::catch_unwind(|| {
+/// // variable += 3;
+/// // });
+///
+/// // This, however, will compile due to the `AssertUnwindSafe` wrapper
+/// let result = panic::catch_unwind(AssertUnwindSafe(|| {
+/// variable += 3;
+/// }));
+/// // ...
+/// ```
+///
+/// Wrapping the entire closure amounts to a blanket assertion that all captured
+/// variables are unwind safe. This has the downside that if new captures are
+/// added in the future, they will also be considered unwind safe. Therefore,
+/// you may prefer to just wrap individual captures, as shown below. This is
+/// more annotation, but it ensures that if a new capture is added which is not
+/// unwind safe, you will get a compilation error at that time, which will
+/// allow you to consider whether that new capture in fact represent a bug or
+/// not.
+///
+/// ```
+/// use std::panic::{self, AssertUnwindSafe};
+///
+/// let mut variable = 4;
+/// let other_capture = 3;
+///
+/// let result = {
+/// let mut wrapper = AssertUnwindSafe(&mut variable);
+/// panic::catch_unwind(move || {
+/// **wrapper += other_capture;
+/// })
+/// };
+/// // ...
+/// ```
+#[stable(feature = "catch_unwind", since = "1.9.0")]
+pub struct AssertUnwindSafe<T>(
+ #[stable(feature = "catch_unwind", since = "1.9.0")]
+ pub T
+);
+
+// Implementations of the `UnwindSafe` trait:
+//
+// * By default everything is unwind safe
+// * pointers T contains mutability of some form are not unwind safe
+// * Unique, an owning pointer, lifts an implementation
+// * Types like Mutex/RwLock which are explicitly poisoned are unwind safe
+// * Our custom AssertUnwindSafe wrapper is indeed unwind safe
+
+#[stable(feature = "catch_unwind", since = "1.9.0")]
+impl<T: ?Sized> !UnwindSafe for &mut T {}
+#[stable(feature = "catch_unwind", since = "1.9.0")]
+impl<T: RefUnwindSafe + ?Sized> UnwindSafe for &T {}
+#[stable(feature = "catch_unwind", since = "1.9.0")]
+impl<T: RefUnwindSafe + ?Sized> UnwindSafe for *const T {}
+#[stable(feature = "catch_unwind", since = "1.9.0")]
+impl<T: RefUnwindSafe + ?Sized> UnwindSafe for *mut T {}
+#[unstable(feature = "ptr_internals", issue = "0")]
+impl<T: UnwindSafe + ?Sized> UnwindSafe for Unique<T> {}
+#[stable(feature = "nonnull", since = "1.25.0")]
+impl<T: RefUnwindSafe + ?Sized> UnwindSafe for NonNull<T> {}
+#[stable(feature = "catch_unwind", since = "1.9.0")]
+impl<T: ?Sized> UnwindSafe for Mutex<T> {}
+#[stable(feature = "catch_unwind", since = "1.9.0")]
+impl<T: ?Sized> UnwindSafe for RwLock<T> {}
+#[stable(feature = "catch_unwind", since = "1.9.0")]
+impl<T> UnwindSafe for AssertUnwindSafe<T> {}
+
+// not covered via the Shared impl above b/c the inner contents use
+// Cell/AtomicUsize, but the usage here is unwind safe so we can lift the
+// impl up one level to Arc/Rc itself
+#[stable(feature = "catch_unwind", since = "1.9.0")]
+impl<T: RefUnwindSafe + ?Sized> UnwindSafe for Rc<T> {}
+#[stable(feature = "catch_unwind", since = "1.9.0")]
+impl<T: RefUnwindSafe + ?Sized> UnwindSafe for Arc<T> {}
+
+// Pretty simple implementations for the `RefUnwindSafe` marker trait,
+// basically just saying that `UnsafeCell` is the
+// only thing which doesn't implement it (which then transitively applies to
+// everything else).
+#[stable(feature = "catch_unwind", since = "1.9.0")]
+impl<T: ?Sized> !RefUnwindSafe for UnsafeCell<T> {}
+#[stable(feature = "catch_unwind", since = "1.9.0")]
+impl<T> RefUnwindSafe for AssertUnwindSafe<T> {}
+
+#[stable(feature = "unwind_safe_lock_refs", since = "1.12.0")]
+impl<T: ?Sized> RefUnwindSafe for Mutex<T> {}
+#[stable(feature = "unwind_safe_lock_refs", since = "1.12.0")]
+impl<T: ?Sized> RefUnwindSafe for RwLock<T> {}
+
+#[cfg(target_has_atomic = "ptr")]
+#[stable(feature = "unwind_safe_atomic_refs", since = "1.14.0")]
+impl RefUnwindSafe for atomic::AtomicIsize {}
+#[cfg(target_has_atomic = "8")]
+#[unstable(feature = "integer_atomics", issue = "32976")]
+impl RefUnwindSafe for atomic::AtomicI8 {}
+#[cfg(target_has_atomic = "16")]
+#[unstable(feature = "integer_atomics", issue = "32976")]
+impl RefUnwindSafe for atomic::AtomicI16 {}
+#[cfg(target_has_atomic = "32")]
+#[unstable(feature = "integer_atomics", issue = "32976")]
+impl RefUnwindSafe for atomic::AtomicI32 {}
+#[cfg(target_has_atomic = "64")]
+#[unstable(feature = "integer_atomics", issue = "32976")]
+impl RefUnwindSafe for atomic::AtomicI64 {}
+#[cfg(target_has_atomic = "128")]
+#[unstable(feature = "integer_atomics", issue = "32976")]
+impl RefUnwindSafe for atomic::AtomicI128 {}
+
+#[cfg(target_has_atomic = "ptr")]
+#[stable(feature = "unwind_safe_atomic_refs", since = "1.14.0")]
+impl RefUnwindSafe for atomic::AtomicUsize {}
+#[cfg(target_has_atomic = "8")]
+#[unstable(feature = "integer_atomics", issue = "32976")]
+impl RefUnwindSafe for atomic::AtomicU8 {}
+#[cfg(target_has_atomic = "16")]
+#[unstable(feature = "integer_atomics", issue = "32976")]
+impl RefUnwindSafe for atomic::AtomicU16 {}
+#[cfg(target_has_atomic = "32")]
+#[unstable(feature = "integer_atomics", issue = "32976")]
+impl RefUnwindSafe for atomic::AtomicU32 {}
+#[cfg(target_has_atomic = "64")]
+#[unstable(feature = "integer_atomics", issue = "32976")]
+impl RefUnwindSafe for atomic::AtomicU64 {}
+#[cfg(target_has_atomic = "128")]
+#[unstable(feature = "integer_atomics", issue = "32976")]
+impl RefUnwindSafe for atomic::AtomicU128 {}
+
+#[cfg(target_has_atomic = "8")]
+#[stable(feature = "unwind_safe_atomic_refs", since = "1.14.0")]
+impl RefUnwindSafe for atomic::AtomicBool {}
+
+#[cfg(target_has_atomic = "ptr")]
+#[stable(feature = "unwind_safe_atomic_refs", since = "1.14.0")]
+impl<T> RefUnwindSafe for atomic::AtomicPtr<T> {}
+
+#[stable(feature = "catch_unwind", since = "1.9.0")]
+impl<T> Deref for AssertUnwindSafe<T> {
+ type Target = T;
+
+ fn deref(&self) -> &T {
+ &self.0
+ }
+}
+
+#[stable(feature = "catch_unwind", since = "1.9.0")]
+impl<T> DerefMut for AssertUnwindSafe<T> {
+ fn deref_mut(&mut self) -> &mut T {
+ &mut self.0
+ }
+}
+
+#[stable(feature = "catch_unwind", since = "1.9.0")]
+impl<R, F: FnOnce() -> R> FnOnce<()> for AssertUnwindSafe<F> {
+ type Output = R;
+
+ extern "rust-call" fn call_once(self, _args: ()) -> R {
+ (self.0)()
+ }
+}
+
+#[stable(feature = "std_debug", since = "1.16.0")]
+impl<T: fmt::Debug> fmt::Debug for AssertUnwindSafe<T> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_tuple("AssertUnwindSafe")
+ .field(&self.0)
+ .finish()
+ }
+}
+
+#[unstable(feature = "futures_api", issue = "50547")]
+impl<F: Future> Future for AssertUnwindSafe<F> {
+ type Output = F::Output;
+
+ fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
+ let pinned_field = unsafe { Pin::map_unchecked_mut(self, |x| &mut x.0) };
+ F::poll(pinned_field, cx)
+ }
+}
+
+/// Invokes a closure, capturing the cause of an unwinding panic if one occurs.
+///
+/// This function will return `Ok` with the closure's result if the closure
+/// does not panic, and will return `Err(cause)` if the closure panics. The
+/// `cause` returned is the object with which panic was originally invoked.
+///
+/// It is currently undefined behavior to unwind from Rust code into foreign
+/// code, so this function is particularly useful when Rust is called from
+/// another language (normally C). This can run arbitrary Rust code, capturing a
+/// panic and allowing a graceful handling of the error.
+///
+/// It is **not** recommended to use this function for a general try/catch
+/// mechanism. The [`Result`] type is more appropriate to use for functions that
+/// can fail on a regular basis. Additionally, this function is not guaranteed
+/// to catch all panics, see the "Notes" section below.
+///
+/// [`Result`]: ../result/enum.Result.html
+///
+/// The closure provided is required to adhere to the [`UnwindSafe`] trait to ensure
+/// that all captured variables are safe to cross this boundary. The purpose of
+/// this bound is to encode the concept of [exception safety][rfc] in the type
+/// system. Most usage of this function should not need to worry about this
+/// bound as programs are naturally unwind safe without `unsafe` code. If it
+/// becomes a problem the [`AssertUnwindSafe`] wrapper struct can be used to quickly
+/// assert that the usage here is indeed unwind safe.
+///
+/// [`AssertUnwindSafe`]: ./struct.AssertUnwindSafe.html
+/// [`UnwindSafe`]: ./trait.UnwindSafe.html
+///
+/// [rfc]: https://github.com/rust-lang/rfcs/blob/master/text/1236-stabilize-catch-panic.md
+///
+/// # Notes
+///
+/// Note that this function **may not catch all panics** in Rust. A panic in
+/// Rust is not always implemented via unwinding, but can be implemented by
+/// aborting the process as well. This function *only* catches unwinding panics,
+/// not those that abort the process.
+///
+/// # Examples
+///
+/// ```
+/// use std::panic;
+///
+/// let result = panic::catch_unwind(|| {
+/// println!("hello!");
+/// });
+/// assert!(result.is_ok());
+///
+/// let result = panic::catch_unwind(|| {
+/// panic!("oh no!");
+/// });
+/// assert!(result.is_err());
+/// ```
+#[stable(feature = "catch_unwind", since = "1.9.0")]
+pub fn catch_unwind<F: FnOnce() -> R + UnwindSafe, R>(f: F) -> Result<R> {
+ unsafe {
+ panicking::r#try(f)
+ }
+}
+
+/// Triggers a panic without invoking the panic hook.
+///
+/// This is designed to be used in conjunction with [`catch_unwind`] to, for
+/// example, carry a panic across a layer of C code.
+///
+/// [`catch_unwind`]: ./fn.catch_unwind.html
+///
+/// # Notes
+///
+/// Note that panics in Rust are not always implemented via unwinding, but they
+/// may be implemented by aborting the process. If this function is called when
+/// panics are implemented this way then this function will abort the process,
+/// not trigger an unwind.
+///
+/// # Examples
+///
+/// ```should_panic
+/// use std::panic;
+///
+/// let result = panic::catch_unwind(|| {
+/// panic!("oh no!");
+/// });
+///
+/// if let Err(err) = result {
+/// panic::resume_unwind(err);
+/// }
+/// ```
+#[stable(feature = "resume_unwind", since = "1.9.0")]
+pub fn resume_unwind(payload: Box<dyn Any + Send>) -> ! {
+ panicking::update_count_then_panic(payload)
+}
diff --git a/src/libstd/panicking.rs b/src/libstd/panicking.rs
new file mode 100644
index 0000000..27b8a11
--- /dev/null
+++ b/src/libstd/panicking.rs
@@ -0,0 +1,526 @@
+//! Implementation of various bits and pieces of the `panic!` macro and
+//! associated runtime pieces.
+//!
+//! Specifically, this module contains the implementation of:
+//!
+//! * Panic hooks
+//! * Executing a panic up to doing the actual implementation
+//! * Shims around "try"
+
+use core::panic::{BoxMeUp, PanicInfo, Location};
+
+use crate::any::Any;
+use crate::fmt;
+use crate::intrinsics;
+use crate::mem;
+use crate::ptr;
+use crate::raw;
+use crate::sys::stdio::panic_output;
+use crate::sys_common::rwlock::RWLock;
+use crate::sys_common::thread_info;
+use crate::sys_common::util;
+use crate::thread;
+
+#[cfg(not(test))]
+use crate::io::set_panic;
+// make sure to use the stderr output configured
+// by libtest in the real copy of std
+#[cfg(test)]
+use realstd::io::set_panic;
+
+// Binary interface to the panic runtime that the standard library depends on.
+//
+// The standard library is tagged with `#![needs_panic_runtime]` (introduced in
+// RFC 1513) to indicate that it requires some other crate tagged with
+// `#![panic_runtime]` to exist somewhere. Each panic runtime is intended to
+// implement these symbols (with the same signatures) so we can get matched up
+// to them.
+//
+// One day this may look a little less ad-hoc with the compiler helping out to
+// hook up these functions, but it is not this day!
+#[allow(improper_ctypes)]
+extern {
+ fn __rust_maybe_catch_panic(f: fn(*mut u8),
+ data: *mut u8,
+ data_ptr: *mut usize,
+ vtable_ptr: *mut usize) -> u32;
+ #[unwind(allowed)]
+ fn __rust_start_panic(payload: usize) -> u32;
+}
+
+#[derive(Copy, Clone)]
+enum Hook {
+ Default,
+ Custom(*mut (dyn Fn(&PanicInfo<'_>) + 'static + Sync + Send)),
+}
+
+static HOOK_LOCK: RWLock = RWLock::new();
+static mut HOOK: Hook = Hook::Default;
+
+/// Registers a custom panic hook, replacing any that was previously registered.
+///
+/// The panic hook is invoked when a thread panics, but before the panic runtime
+/// is invoked. As such, the hook will run with both the aborting and unwinding
+/// runtimes. The default hook prints a message to standard error and generates
+/// a backtrace if requested, but this behavior can be customized with the
+/// `set_hook` and [`take_hook`] functions.
+///
+/// [`take_hook`]: ./fn.take_hook.html
+///
+/// The hook is provided with a `PanicInfo` struct which contains information
+/// about the origin of the panic, including the payload passed to `panic!` and
+/// the source code location from which the panic originated.
+///
+/// The panic hook is a global resource.
+///
+/// # Panics
+///
+/// Panics if called from a panicking thread.
+///
+/// # Examples
+///
+/// The following will print "Custom panic hook":
+///
+/// ```should_panic
+/// use std::panic;
+///
+/// panic::set_hook(Box::new(|_| {
+/// println!("Custom panic hook");
+/// }));
+///
+/// panic!("Normal panic");
+/// ```
+#[stable(feature = "panic_hooks", since = "1.10.0")]
+pub fn set_hook(hook: Box<dyn Fn(&PanicInfo<'_>) + 'static + Sync + Send>) {
+ if thread::panicking() {
+ panic!("cannot modify the panic hook from a panicking thread");
+ }
+
+ unsafe {
+ HOOK_LOCK.write();
+ let old_hook = HOOK;
+ HOOK = Hook::Custom(Box::into_raw(hook));
+ HOOK_LOCK.write_unlock();
+
+ if let Hook::Custom(ptr) = old_hook {
+ Box::from_raw(ptr);
+ }
+ }
+}
+
+/// Unregisters the current panic hook, returning it.
+///
+/// *See also the function [`set_hook`].*
+///
+/// [`set_hook`]: ./fn.set_hook.html
+///
+/// If no custom hook is registered, the default hook will be returned.
+///
+/// # Panics
+///
+/// Panics if called from a panicking thread.
+///
+/// # Examples
+///
+/// The following will print "Normal panic":
+///
+/// ```should_panic
+/// use std::panic;
+///
+/// panic::set_hook(Box::new(|_| {
+/// println!("Custom panic hook");
+/// }));
+///
+/// let _ = panic::take_hook();
+///
+/// panic!("Normal panic");
+/// ```
+#[stable(feature = "panic_hooks", since = "1.10.0")]
+pub fn take_hook() -> Box<dyn Fn(&PanicInfo<'_>) + 'static + Sync + Send> {
+ if thread::panicking() {
+ panic!("cannot modify the panic hook from a panicking thread");
+ }
+
+ unsafe {
+ HOOK_LOCK.write();
+ let hook = HOOK;
+ HOOK = Hook::Default;
+ HOOK_LOCK.write_unlock();
+
+ match hook {
+ Hook::Default => Box::new(default_hook),
+ Hook::Custom(ptr) => Box::from_raw(ptr),
+ }
+ }
+}
+
+fn default_hook(info: &PanicInfo<'_>) {
+ #[cfg(feature = "backtrace")]
+ use crate::sys_common::backtrace;
+
+ // If this is a double panic, make sure that we print a backtrace
+ // for this panic. Otherwise only print it if logging is enabled.
+ #[cfg(feature = "backtrace")]
+ let log_backtrace = {
+ let panics = update_panic_count(0);
+
+ if panics >= 2 {
+ Some(backtrace::PrintFormat::Full)
+ } else {
+ backtrace::log_enabled()
+ }
+ };
+
+ let location = info.location().unwrap(); // The current implementation always returns Some
+
+ let msg = match info.payload().downcast_ref::<&'static str>() {
+ Some(s) => *s,
+ None => match info.payload().downcast_ref::<String>() {
+ Some(s) => &s[..],
+ None => "Box<Any>",
+ }
+ };
+ let thread = thread_info::current_thread();
+ let name = thread.as_ref().and_then(|t| t.name()).unwrap_or("<unnamed>");
+
+ let write = |err: &mut dyn crate::io::Write| {
+ let _ = writeln!(err, "thread '{}' panicked at '{}', {}",
+ name, msg, location);
+
+ #[cfg(feature = "backtrace")]
+ {
+ use crate::sync::atomic::{AtomicBool, Ordering};
+
+ static FIRST_PANIC: AtomicBool = AtomicBool::new(true);
+
+ if let Some(format) = log_backtrace {
+ let _ = backtrace::print(err, format);
+ } else if FIRST_PANIC.compare_and_swap(true, false, Ordering::SeqCst) {
+ let _ = writeln!(err, "note: Run with `RUST_BACKTRACE=1` \
+ environment variable to display a backtrace.");
+ }
+ }
+ };
+
+ if let Some(mut local) = set_panic(None) {
+ // NB. In `cfg(test)` this uses the forwarding impl
+ // for `Box<dyn (::realstd::io::Write) + Send>`.
+ write(&mut local);
+ set_panic(Some(local));
+ } else if let Some(mut out) = panic_output() {
+ write(&mut out);
+ }
+}
+
+
+#[cfg(not(test))]
+#[doc(hidden)]
+#[unstable(feature = "update_panic_count", issue = "0")]
+pub fn update_panic_count(amt: isize) -> usize {
+ use crate::cell::Cell;
+ thread_local! { static PANIC_COUNT: Cell<usize> = Cell::new(0) }
+
+ PANIC_COUNT.with(|c| {
+ let next = (c.get() as isize + amt) as usize;
+ c.set(next);
+ return next
+ })
+}
+
+#[cfg(test)]
+pub use realstd::rt::update_panic_count;
+
+/// Invoke a closure, capturing the cause of an unwinding panic if one occurs.
+pub unsafe fn r#try<R, F: FnOnce() -> R>(f: F) -> Result<R, Box<dyn Any + Send>> {
+ #[allow(unions_with_drop_fields)]
+ union Data<F, R> {
+ f: F,
+ r: R,
+ }
+
+ // We do some sketchy operations with ownership here for the sake of
+ // performance. We can only pass pointers down to
+ // `__rust_maybe_catch_panic` (can't pass objects by value), so we do all
+ // the ownership tracking here manually using a union.
+ //
+ // We go through a transition where:
+ //
+ // * First, we set the data to be the closure that we're going to call.
+ // * When we make the function call, the `do_call` function below, we take
+ // ownership of the function pointer. At this point the `Data` union is
+ // entirely uninitialized.
+ // * If the closure successfully returns, we write the return value into the
+ // data's return slot. Note that `ptr::write` is used as it's overwriting
+ // uninitialized data.
+ // * Finally, when we come back out of the `__rust_maybe_catch_panic` we're
+ // in one of two states:
+ //
+ // 1. The closure didn't panic, in which case the return value was
+ // filled in. We move it out of `data` and return it.
+ // 2. The closure panicked, in which case the return value wasn't
+ // filled in. In this case the entire `data` union is invalid, so
+ // there is no need to drop anything.
+ //
+ // Once we stack all that together we should have the "most efficient'
+ // method of calling a catch panic whilst juggling ownership.
+ let mut any_data = 0;
+ let mut any_vtable = 0;
+ let mut data = Data {
+ f,
+ };
+
+ let r = __rust_maybe_catch_panic(do_call::<F, R>,
+ &mut data as *mut _ as *mut u8,
+ &mut any_data,
+ &mut any_vtable);
+
+ return if r == 0 {
+ debug_assert!(update_panic_count(0) == 0);
+ Ok(data.r)
+ } else {
+ update_panic_count(-1);
+ debug_assert!(update_panic_count(0) == 0);
+ Err(mem::transmute(raw::TraitObject {
+ data: any_data as *mut _,
+ vtable: any_vtable as *mut _,
+ }))
+ };
+
+ fn do_call<F: FnOnce() -> R, R>(data: *mut u8) {
+ unsafe {
+ let data = data as *mut Data<F, R>;
+ let f = ptr::read(&mut (*data).f);
+ ptr::write(&mut (*data).r, f());
+ }
+ }
+}
+
+/// Determines whether the current thread is unwinding because of panic.
+pub fn panicking() -> bool {
+ update_panic_count(0) != 0
+}
+
+/// Entry point of panic from the libcore crate.
+#[cfg(not(test))]
+#[panic_handler]
+#[unwind(allowed)]
+pub fn rust_begin_panic(info: &PanicInfo<'_>) -> ! {
+ continue_panic_fmt(&info)
+}
+
+/// The entry point for panicking with a formatted message.
+///
+/// This is designed to reduce the amount of code required at the call
+/// site as much as possible (so that `panic!()` has as low an impact
+/// on (e.g.) the inlining of other functions as possible), by moving
+/// the actual formatting into this shared place.
+#[unstable(feature = "libstd_sys_internals",
+ reason = "used by the panic! macro",
+ issue = "0")]
+#[cold]
+// If panic_immediate_abort, inline the abort call,
+// otherwise avoid inlining because of it is cold path.
+#[cfg_attr(not(feature="panic_immediate_abort"),inline(never))]
+#[cfg_attr( feature="panic_immediate_abort" ,inline)]
+pub fn begin_panic_fmt(msg: &fmt::Arguments<'_>,
+ file_line_col: &(&'static str, u32, u32)) -> ! {
+ if cfg!(feature = "panic_immediate_abort") {
+ unsafe { intrinsics::abort() }
+ }
+
+ let (file, line, col) = *file_line_col;
+ let info = PanicInfo::internal_constructor(
+ Some(msg),
+ Location::internal_constructor(file, line, col),
+ );
+ continue_panic_fmt(&info)
+}
+
+fn continue_panic_fmt(info: &PanicInfo<'_>) -> ! {
+ struct PanicPayload<'a> {
+ inner: &'a fmt::Arguments<'a>,
+ string: Option<String>,
+ }
+
+ impl<'a> PanicPayload<'a> {
+ fn new(inner: &'a fmt::Arguments<'a>) -> PanicPayload<'a> {
+ PanicPayload { inner, string: None }
+ }
+
+ fn fill(&mut self) -> &mut String {
+ use crate::fmt::Write;
+
+ let inner = self.inner;
+ self.string.get_or_insert_with(|| {
+ let mut s = String::new();
+ drop(s.write_fmt(*inner));
+ s
+ })
+ }
+ }
+
+ unsafe impl<'a> BoxMeUp for PanicPayload<'a> {
+ fn box_me_up(&mut self) -> *mut (dyn Any + Send) {
+ let contents = mem::replace(self.fill(), String::new());
+ Box::into_raw(Box::new(contents))
+ }
+
+ fn get(&mut self) -> &(dyn Any + Send) {
+ self.fill()
+ }
+ }
+
+ // We do two allocations here, unfortunately. But (a) they're
+ // required with the current scheme, and (b) we don't handle
+ // panic + OOM properly anyway (see comment in begin_panic
+ // below).
+
+ let loc = info.location().unwrap(); // The current implementation always returns Some
+ let msg = info.message().unwrap(); // The current implementation always returns Some
+ let file_line_col = (loc.file(), loc.line(), loc.column());
+ rust_panic_with_hook(
+ &mut PanicPayload::new(msg),
+ info.message(),
+ &file_line_col);
+}
+
+/// This is the entry point of panicking for panic!() and assert!().
+#[unstable(feature = "libstd_sys_internals",
+ reason = "used by the panic! macro",
+ issue = "0")]
+#[cfg_attr(not(test), lang = "begin_panic")]
+// never inline unless panic_immediate_abort to avoid code
+// bloat at the call sites as much as possible
+#[cfg_attr(not(feature="panic_immediate_abort"),inline(never))]
+#[cold]
+pub fn begin_panic<M: Any + Send>(msg: M, file_line_col: &(&'static str, u32, u32)) -> ! {
+ if cfg!(feature = "panic_immediate_abort") {
+ unsafe { intrinsics::abort() }
+ }
+
+ // Note that this should be the only allocation performed in this code path.
+ // Currently this means that panic!() on OOM will invoke this code path,
+ // but then again we're not really ready for panic on OOM anyway. If
+ // we do start doing this, then we should propagate this allocation to
+ // be performed in the parent of this thread instead of the thread that's
+ // panicking.
+
+ rust_panic_with_hook(&mut PanicPayload::new(msg), None, file_line_col);
+
+ struct PanicPayload<A> {
+ inner: Option<A>,
+ }
+
+ impl<A: Send + 'static> PanicPayload<A> {
+ fn new(inner: A) -> PanicPayload<A> {
+ PanicPayload { inner: Some(inner) }
+ }
+ }
+
+ unsafe impl<A: Send + 'static> BoxMeUp for PanicPayload<A> {
+ fn box_me_up(&mut self) -> *mut (dyn Any + Send) {
+ let data = match self.inner.take() {
+ Some(a) => Box::new(a) as Box<dyn Any + Send>,
+ None => Box::new(()),
+ };
+ Box::into_raw(data)
+ }
+
+ fn get(&mut self) -> &(dyn Any + Send) {
+ match self.inner {
+ Some(ref a) => a,
+ None => &(),
+ }
+ }
+ }
+}
+
+/// Central point for dispatching panics.
+///
+/// Executes the primary logic for a panic, including checking for recursive
+/// panics, panic hooks, and finally dispatching to the panic runtime to either
+/// abort or unwind.
+fn rust_panic_with_hook(payload: &mut dyn BoxMeUp,
+ message: Option<&fmt::Arguments<'_>>,
+ file_line_col: &(&str, u32, u32)) -> ! {
+ let (file, line, col) = *file_line_col;
+
+ let panics = update_panic_count(1);
+
+ // If this is the third nested call (e.g., panics == 2, this is 0-indexed),
+ // the panic hook probably triggered the last panic, otherwise the
+ // double-panic check would have aborted the process. In this case abort the
+ // process real quickly as we don't want to try calling it again as it'll
+ // probably just panic again.
+ if panics > 2 {
+ util::dumb_print(format_args!("thread panicked while processing \
+ panic. aborting.\n"));
+ unsafe { intrinsics::abort() }
+ }
+
+ unsafe {
+ let mut info = PanicInfo::internal_constructor(
+ message,
+ Location::internal_constructor(file, line, col),
+ );
+ HOOK_LOCK.read();
+ match HOOK {
+ // Some platforms know that printing to stderr won't ever actually
+ // print anything, and if that's the case we can skip the default
+ // hook.
+ Hook::Default if panic_output().is_none() => {}
+ Hook::Default => {
+ info.set_payload(payload.get());
+ default_hook(&info);
+ }
+ Hook::Custom(ptr) => {
+ info.set_payload(payload.get());
+ (*ptr)(&info);
+ }
+ };
+ HOOK_LOCK.read_unlock();
+ }
+
+ if panics > 1 {
+ // If a thread panics while it's already unwinding then we
+ // have limited options. Currently our preference is to
+ // just abort. In the future we may consider resuming
+ // unwinding or otherwise exiting the thread cleanly.
+ util::dumb_print(format_args!("thread panicked while panicking. \
+ aborting.\n"));
+ unsafe { intrinsics::abort() }
+ }
+
+ rust_panic(payload)
+}
+
+/// Shim around rust_panic. Called by resume_unwind.
+pub fn update_count_then_panic(msg: Box<dyn Any + Send>) -> ! {
+ update_panic_count(1);
+
+ struct RewrapBox(Box<dyn Any + Send>);
+
+ unsafe impl BoxMeUp for RewrapBox {
+ fn box_me_up(&mut self) -> *mut (dyn Any + Send) {
+ Box::into_raw(mem::replace(&mut self.0, Box::new(())))
+ }
+
+ fn get(&mut self) -> &(dyn Any + Send) {
+ &*self.0
+ }
+ }
+
+ rust_panic(&mut RewrapBox(msg))
+}
+
+/// An unmangled function (through `rustc_std_internal_symbol`) on which to slap
+/// yer breakpoints.
+#[inline(never)]
+#[cfg_attr(not(test), rustc_std_internal_symbol)]
+fn rust_panic(mut msg: &mut dyn BoxMeUp) -> ! {
+ let code = unsafe {
+ let obj = &mut msg as *mut &mut dyn BoxMeUp;
+ __rust_start_panic(obj as usize)
+ };
+ rtabort!("failed to initiate panic, error {}", code)
+}
diff --git a/src/libstd/path.rs b/src/libstd/path.rs
new file mode 100644
index 0000000..1bbda9b
--- /dev/null
+++ b/src/libstd/path.rs
@@ -0,0 +1,4242 @@
+//! Cross-platform path manipulation.
+//!
+//! This module provides two types, [`PathBuf`] and [`Path`][`Path`] (akin to [`String`]
+//! and [`str`]), for working with paths abstractly. These types are thin wrappers
+//! around [`OsString`] and [`OsStr`] respectively, meaning that they work directly
+//! on strings according to the local platform's path syntax.
+//!
+//! Paths can be parsed into [`Component`]s by iterating over the structure
+//! returned by the [`components`] method on [`Path`]. [`Component`]s roughly
+//! correspond to the substrings between path separators (`/` or `\`). You can
+//! reconstruct an equivalent path from components with the [`push`] method on
+//! [`PathBuf`]; note that the paths may differ syntactically by the
+//! normalization described in the documentation for the [`components`] method.
+//!
+//! ## Simple usage
+//!
+//! Path manipulation includes both parsing components from slices and building
+//! new owned paths.
+//!
+//! To parse a path, you can create a [`Path`] slice from a [`str`]
+//! slice and start asking questions:
+//!
+//! ```
+//! use std::path::Path;
+//! use std::ffi::OsStr;
+//!
+//! let path = Path::new("/tmp/foo/bar.txt");
+//!
+//! let parent = path.parent();
+//! assert_eq!(parent, Some(Path::new("/tmp/foo")));
+//!
+//! let file_stem = path.file_stem();
+//! assert_eq!(file_stem, Some(OsStr::new("bar")));
+//!
+//! let extension = path.extension();
+//! assert_eq!(extension, Some(OsStr::new("txt")));
+//! ```
+//!
+//! To build or modify paths, use [`PathBuf`]:
+//!
+//! ```
+//! use std::path::PathBuf;
+//!
+//! // This way works...
+//! let mut path = PathBuf::from("c:\\");
+//!
+//! path.push("windows");
+//! path.push("system32");
+//!
+//! path.set_extension("dll");
+//!
+//! // ... but push is best used if you don't know everything up
+//! // front. If you do, this way is better:
+//! let path: PathBuf = ["c:\\", "windows", "system32.dll"].iter().collect();
+//! ```
+//!
+//! [`Component`]: ../../std/path/enum.Component.html
+//! [`components`]: ../../std/path/struct.Path.html#method.components
+//! [`PathBuf`]: ../../std/path/struct.PathBuf.html
+//! [`Path`]: ../../std/path/struct.Path.html
+//! [`push`]: ../../std/path/struct.PathBuf.html#method.push
+//! [`String`]: ../../std/string/struct.String.html
+//!
+//! [`str`]: ../../std/primitive.str.html
+//! [`OsString`]: ../../std/ffi/struct.OsString.html
+//! [`OsStr`]: ../../std/ffi/struct.OsStr.html
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+use crate::borrow::{Borrow, Cow};
+use crate::cmp;
+use crate::error::Error;
+use crate::fmt;
+use crate::fs;
+use crate::hash::{Hash, Hasher};
+use crate::io;
+use crate::iter::{self, FusedIterator};
+use crate::ops::{self, Deref};
+use crate::rc::Rc;
+use crate::str::FromStr;
+use crate::sync::Arc;
+
+use crate::ffi::{OsStr, OsString};
+
+use crate::sys::path::{is_sep_byte, is_verbatim_sep, MAIN_SEP_STR, parse_prefix};
+
+////////////////////////////////////////////////////////////////////////////////
+// GENERAL NOTES
+////////////////////////////////////////////////////////////////////////////////
+//
+// Parsing in this module is done by directly transmuting OsStr to [u8] slices,
+// taking advantage of the fact that OsStr always encodes ASCII characters
+// as-is. Eventually, this transmutation should be replaced by direct uses of
+// OsStr APIs for parsing, but it will take a while for those to become
+// available.
+
+////////////////////////////////////////////////////////////////////////////////
+// Windows Prefixes
+////////////////////////////////////////////////////////////////////////////////
+
+/// Windows path prefixes, e.g., `C:` or `\\server\share`.
+///
+/// Windows uses a variety of path prefix styles, including references to drive
+/// volumes (like `C:`), network shared folders (like `\\server\share`), and
+/// others. In addition, some path prefixes are "verbatim" (i.e., prefixed with
+/// `\\?\`), in which case `/` is *not* treated as a separator and essentially
+/// no normalization is performed.
+///
+/// # Examples
+///
+/// ```
+/// use std::path::{Component, Path, Prefix};
+/// use std::path::Prefix::*;
+/// use std::ffi::OsStr;
+///
+/// fn get_path_prefix(s: &str) -> Prefix {
+/// let path = Path::new(s);
+/// match path.components().next().unwrap() {
+/// Component::Prefix(prefix_component) => prefix_component.kind(),
+/// _ => panic!(),
+/// }
+/// }
+///
+/// # if cfg!(windows) {
+/// assert_eq!(Verbatim(OsStr::new("pictures")),
+/// get_path_prefix(r"\\?\pictures\kittens"));
+/// assert_eq!(VerbatimUNC(OsStr::new("server"), OsStr::new("share")),
+/// get_path_prefix(r"\\?\UNC\server\share"));
+/// assert_eq!(VerbatimDisk(b'C'), get_path_prefix(r"\\?\c:\"));
+/// assert_eq!(DeviceNS(OsStr::new("BrainInterface")),
+/// get_path_prefix(r"\\.\BrainInterface"));
+/// assert_eq!(UNC(OsStr::new("server"), OsStr::new("share")),
+/// get_path_prefix(r"\\server\share"));
+/// assert_eq!(Disk(b'C'), get_path_prefix(r"C:\Users\Rust\Pictures\Ferris"));
+/// # }
+/// ```
+#[derive(Copy, Clone, Debug, Hash, PartialOrd, Ord, PartialEq, Eq)]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub enum Prefix<'a> {
+ /// Verbatim prefix, e.g., `\\?\cat_pics`.
+ ///
+ /// Verbatim prefixes consist of `\\?\` immediately followed by the given
+ /// component.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ Verbatim(#[stable(feature = "rust1", since = "1.0.0")] &'a OsStr),
+
+ /// Verbatim prefix using Windows' _**U**niform **N**aming **C**onvention_,
+ /// e.g., `\\?\UNC\server\share`.
+ ///
+ /// Verbatim UNC prefixes consist of `\\?\UNC\` immediately followed by the
+ /// server's hostname and a share name.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ VerbatimUNC(
+ #[stable(feature = "rust1", since = "1.0.0")] &'a OsStr,
+ #[stable(feature = "rust1", since = "1.0.0")] &'a OsStr,
+ ),
+
+ /// Verbatim disk prefix, e.g., `\\?\C:\`.
+ ///
+ /// Verbatim disk prefixes consist of `\\?\` immediately followed by the
+ /// drive letter and `:\`.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ VerbatimDisk(#[stable(feature = "rust1", since = "1.0.0")] u8),
+
+ /// Device namespace prefix, e.g., `\\.\COM42`.
+ ///
+ /// Device namespace prefixes consist of `\\.\` immediately followed by the
+ /// device name.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ DeviceNS(#[stable(feature = "rust1", since = "1.0.0")] &'a OsStr),
+
+ /// Prefix using Windows' _**U**niform **N**aming **C**onvention_, e.g.
+ /// `\\server\share`.
+ ///
+ /// UNC prefixes consist of the server's hostname and a share name.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ UNC(
+ #[stable(feature = "rust1", since = "1.0.0")] &'a OsStr,
+ #[stable(feature = "rust1", since = "1.0.0")] &'a OsStr,
+ ),
+
+ /// Prefix `C:` for the given disk drive.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ Disk(#[stable(feature = "rust1", since = "1.0.0")] u8),
+}
+
+impl<'a> Prefix<'a> {
+ #[inline]
+ fn len(&self) -> usize {
+ use self::Prefix::*;
+ fn os_str_len(s: &OsStr) -> usize {
+ os_str_as_u8_slice(s).len()
+ }
+ match *self {
+ Verbatim(x) => 4 + os_str_len(x),
+ VerbatimUNC(x, y) => {
+ 8 + os_str_len(x) +
+ if os_str_len(y) > 0 {
+ 1 + os_str_len(y)
+ } else {
+ 0
+ }
+ },
+ VerbatimDisk(_) => 6,
+ UNC(x, y) => {
+ 2 + os_str_len(x) +
+ if os_str_len(y) > 0 {
+ 1 + os_str_len(y)
+ } else {
+ 0
+ }
+ },
+ DeviceNS(x) => 4 + os_str_len(x),
+ Disk(_) => 2,
+ }
+
+ }
+
+ /// Determines if the prefix is verbatim, i.e., begins with `\\?\`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::path::Prefix::*;
+ /// use std::ffi::OsStr;
+ ///
+ /// assert!(Verbatim(OsStr::new("pictures")).is_verbatim());
+ /// assert!(VerbatimUNC(OsStr::new("server"), OsStr::new("share")).is_verbatim());
+ /// assert!(VerbatimDisk(b'C').is_verbatim());
+ /// assert!(!DeviceNS(OsStr::new("BrainInterface")).is_verbatim());
+ /// assert!(!UNC(OsStr::new("server"), OsStr::new("share")).is_verbatim());
+ /// assert!(!Disk(b'C').is_verbatim());
+ /// ```
+ #[inline]
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn is_verbatim(&self) -> bool {
+ use self::Prefix::*;
+ match *self {
+ Verbatim(_) | VerbatimDisk(_) | VerbatimUNC(..) => true,
+ _ => false,
+ }
+ }
+
+ #[inline]
+ fn is_drive(&self) -> bool {
+ match *self {
+ Prefix::Disk(_) => true,
+ _ => false,
+ }
+ }
+
+ #[inline]
+ fn has_implicit_root(&self) -> bool {
+ !self.is_drive()
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Exposed parsing helpers
+////////////////////////////////////////////////////////////////////////////////
+
+/// Determines whether the character is one of the permitted path
+/// separators for the current platform.
+///
+/// # Examples
+///
+/// ```
+/// use std::path;
+///
+/// assert!(path::is_separator('/')); // '/' works for both Unix and Windows
+/// assert!(!path::is_separator('❤'));
+/// ```
+#[stable(feature = "rust1", since = "1.0.0")]
+pub fn is_separator(c: char) -> bool {
+ c.is_ascii() && is_sep_byte(c as u8)
+}
+
+/// The primary separator of path components for the current platform.
+///
+/// For example, `/` on Unix and `\` on Windows.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub const MAIN_SEPARATOR: char = crate::sys::path::MAIN_SEP;
+
+////////////////////////////////////////////////////////////////////////////////
+// Misc helpers
+////////////////////////////////////////////////////////////////////////////////
+
+// Iterate through `iter` while it matches `prefix`; return `None` if `prefix`
+// is not a prefix of `iter`, otherwise return `Some(iter_after_prefix)` giving
+// `iter` after having exhausted `prefix`.
+fn iter_after<'a, 'b, I, J>(mut iter: I, mut prefix: J) -> Option<I>
+ where I: Iterator<Item = Component<'a>> + Clone,
+ J: Iterator<Item = Component<'b>>,
+{
+ loop {
+ let mut iter_next = iter.clone();
+ match (iter_next.next(), prefix.next()) {
+ (Some(ref x), Some(ref y)) if x == y => (),
+ (Some(_), Some(_)) => return None,
+ (Some(_), None) => return Some(iter),
+ (None, None) => return Some(iter),
+ (None, Some(_)) => return None,
+ }
+ iter = iter_next;
+ }
+}
+
+// See note at the top of this module to understand why these are used:
+fn os_str_as_u8_slice(s: &OsStr) -> &[u8] {
+ unsafe { &*(s as *const OsStr as *const [u8]) }
+}
+unsafe fn u8_slice_as_os_str(s: &[u8]) -> &OsStr {
+ &*(s as *const [u8] as *const OsStr)
+}
+
+// Detect scheme on Redox
+fn has_redox_scheme(s: &[u8]) -> bool {
+ cfg!(target_os = "redox") && s.split(|b| *b == b'/').next().unwrap_or(b"").contains(&b':')
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Cross-platform, iterator-independent parsing
+////////////////////////////////////////////////////////////////////////////////
+
+/// Says whether the first byte after the prefix is a separator.
+fn has_physical_root(s: &[u8], prefix: Option<Prefix<'_>>) -> bool {
+ let path = if let Some(p) = prefix {
+ &s[p.len()..]
+ } else {
+ s
+ };
+ !path.is_empty() && is_sep_byte(path[0])
+}
+
+// basic workhorse for splitting stem and extension
+fn split_file_at_dot(file: &OsStr) -> (Option<&OsStr>, Option<&OsStr>) {
+ unsafe {
+ if os_str_as_u8_slice(file) == b".." {
+ return (Some(file), None);
+ }
+
+ // The unsafety here stems from converting between &OsStr and &[u8]
+ // and back. This is safe to do because (1) we only look at ASCII
+ // contents of the encoding and (2) new &OsStr values are produced
+ // only from ASCII-bounded slices of existing &OsStr values.
+
+ let mut iter = os_str_as_u8_slice(file).rsplitn(2, |b| *b == b'.');
+ let after = iter.next();
+ let before = iter.next();
+ if before == Some(b"") {
+ (Some(file), None)
+ } else {
+ (before.map(|s| u8_slice_as_os_str(s)),
+ after.map(|s| u8_slice_as_os_str(s)))
+ }
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// The core iterators
+////////////////////////////////////////////////////////////////////////////////
+
+/// Component parsing works by a double-ended state machine; the cursors at the
+/// front and back of the path each keep track of what parts of the path have
+/// been consumed so far.
+///
+/// Going front to back, a path is made up of a prefix, a starting
+/// directory component, and a body (of normal components)
+#[derive(Copy, Clone, PartialEq, PartialOrd, Debug)]
+enum State {
+ Prefix = 0, // c:
+ StartDir = 1, // / or . or nothing
+ Body = 2, // foo/bar/baz
+ Done = 3,
+}
+
+/// A structure wrapping a Windows path prefix as well as its unparsed string
+/// representation.
+///
+/// In addition to the parsed [`Prefix`] information returned by [`kind`],
+/// `PrefixComponent` also holds the raw and unparsed [`OsStr`] slice,
+/// returned by [`as_os_str`].
+///
+/// Instances of this `struct` can be obtained by matching against the
+/// [`Prefix` variant] on [`Component`].
+///
+/// Does not occur on Unix.
+///
+/// # Examples
+///
+/// ```
+/// # if cfg!(windows) {
+/// use std::path::{Component, Path, Prefix};
+/// use std::ffi::OsStr;
+///
+/// let path = Path::new(r"c:\you\later\");
+/// match path.components().next().unwrap() {
+/// Component::Prefix(prefix_component) => {
+/// assert_eq!(Prefix::Disk(b'C'), prefix_component.kind());
+/// assert_eq!(OsStr::new("c:"), prefix_component.as_os_str());
+/// }
+/// _ => unreachable!(),
+/// }
+/// # }
+/// ```
+///
+/// [`as_os_str`]: #method.as_os_str
+/// [`Component`]: enum.Component.html
+/// [`kind`]: #method.kind
+/// [`OsStr`]: ../../std/ffi/struct.OsStr.html
+/// [`Prefix` variant]: enum.Component.html#variant.Prefix
+/// [`Prefix`]: enum.Prefix.html
+#[stable(feature = "rust1", since = "1.0.0")]
+#[derive(Copy, Clone, Eq, Debug)]
+pub struct PrefixComponent<'a> {
+ /// The prefix as an unparsed `OsStr` slice.
+ raw: &'a OsStr,
+
+ /// The parsed prefix data.
+ parsed: Prefix<'a>,
+}
+
+impl<'a> PrefixComponent<'a> {
+ /// Returns the parsed prefix data.
+ ///
+ /// See [`Prefix`]'s documentation for more information on the different
+ /// kinds of prefixes.
+ ///
+ /// [`Prefix`]: enum.Prefix.html
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn kind(&self) -> Prefix<'a> {
+ self.parsed
+ }
+
+ /// Returns the raw [`OsStr`] slice for this prefix.
+ ///
+ /// [`OsStr`]: ../../std/ffi/struct.OsStr.html
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn as_os_str(&self) -> &'a OsStr {
+ self.raw
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a> cmp::PartialEq for PrefixComponent<'a> {
+ fn eq(&self, other: &PrefixComponent<'a>) -> bool {
+ cmp::PartialEq::eq(&self.parsed, &other.parsed)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a> cmp::PartialOrd for PrefixComponent<'a> {
+ fn partial_cmp(&self, other: &PrefixComponent<'a>) -> Option<cmp::Ordering> {
+ cmp::PartialOrd::partial_cmp(&self.parsed, &other.parsed)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl cmp::Ord for PrefixComponent<'_> {
+ fn cmp(&self, other: &Self) -> cmp::Ordering {
+ cmp::Ord::cmp(&self.parsed, &other.parsed)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Hash for PrefixComponent<'_> {
+ fn hash<H: Hasher>(&self, h: &mut H) {
+ self.parsed.hash(h);
+ }
+}
+
+/// A single component of a path.
+///
+/// A `Component` roughly corresponds to a substring between path separators
+/// (`/` or `\`).
+///
+/// This `enum` is created by iterating over [`Components`], which in turn is
+/// created by the [`components`][`Path::components`] method on [`Path`].
+///
+/// # Examples
+///
+/// ```rust
+/// use std::path::{Component, Path};
+///
+/// let path = Path::new("/tmp/foo/bar.txt");
+/// let components = path.components().collect::<Vec<_>>();
+/// assert_eq!(&components, &[
+/// Component::RootDir,
+/// Component::Normal("tmp".as_ref()),
+/// Component::Normal("foo".as_ref()),
+/// Component::Normal("bar.txt".as_ref()),
+/// ]);
+/// ```
+///
+/// [`Components`]: struct.Components.html
+/// [`Path`]: struct.Path.html
+/// [`Path::components`]: struct.Path.html#method.components
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub enum Component<'a> {
+ /// A Windows path prefix, e.g., `C:` or `\\server\share`.
+ ///
+ /// There is a large variety of prefix types, see [`Prefix`]'s documentation
+ /// for more.
+ ///
+ /// Does not occur on Unix.
+ ///
+ /// [`Prefix`]: enum.Prefix.html
+ #[stable(feature = "rust1", since = "1.0.0")]
+ Prefix(
+ #[stable(feature = "rust1", since = "1.0.0")] PrefixComponent<'a>
+ ),
+
+ /// The root directory component, appears after any prefix and before anything else.
+ ///
+ /// It represents a separator that designates that a path starts from root.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ RootDir,
+
+ /// A reference to the current directory, i.e., `.`.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ CurDir,
+
+ /// A reference to the parent directory, i.e., `..`.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ ParentDir,
+
+ /// A normal component, e.g., `a` and `b` in `a/b`.
+ ///
+ /// This variant is the most common one, it represents references to files
+ /// or directories.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ Normal(#[stable(feature = "rust1", since = "1.0.0")] &'a OsStr),
+}
+
+impl<'a> Component<'a> {
+ /// Extracts the underlying [`OsStr`] slice.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::path::Path;
+ ///
+ /// let path = Path::new("./tmp/foo/bar.txt");
+ /// let components: Vec<_> = path.components().map(|comp| comp.as_os_str()).collect();
+ /// assert_eq!(&components, &[".", "tmp", "foo", "bar.txt"]);
+ /// ```
+ ///
+ /// [`OsStr`]: ../../std/ffi/struct.OsStr.html
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn as_os_str(self) -> &'a OsStr {
+ match self {
+ Component::Prefix(p) => p.as_os_str(),
+ Component::RootDir => OsStr::new(MAIN_SEP_STR),
+ Component::CurDir => OsStr::new("."),
+ Component::ParentDir => OsStr::new(".."),
+ Component::Normal(path) => path,
+ }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRef<OsStr> for Component<'_> {
+ fn as_ref(&self) -> &OsStr {
+ self.as_os_str()
+ }
+}
+
+#[stable(feature = "path_component_asref", since = "1.25.0")]
+impl AsRef<Path> for Component<'_> {
+ fn as_ref(&self) -> &Path {
+ self.as_os_str().as_ref()
+ }
+}
+
+/// An iterator over the [`Component`]s of a [`Path`].
+///
+/// This `struct` is created by the [`components`] method on [`Path`].
+/// See its documentation for more.
+///
+/// # Examples
+///
+/// ```
+/// use std::path::Path;
+///
+/// let path = Path::new("/tmp/foo/bar.txt");
+///
+/// for component in path.components() {
+/// println!("{:?}", component);
+/// }
+/// ```
+///
+/// [`Component`]: enum.Component.html
+/// [`components`]: struct.Path.html#method.components
+/// [`Path`]: struct.Path.html
+#[derive(Clone)]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct Components<'a> {
+ // The path left to parse components from
+ path: &'a [u8],
+
+ // The prefix as it was originally parsed, if any
+ prefix: Option<Prefix<'a>>,
+
+ // true if path *physically* has a root separator; for most Windows
+ // prefixes, it may have a "logical" rootseparator for the purposes of
+ // normalization, e.g., \\server\share == \\server\share\.
+ has_physical_root: bool,
+
+ // The iterator is double-ended, and these two states keep track of what has
+ // been produced from either end
+ front: State,
+ back: State,
+}
+
+/// An iterator over the [`Component`]s of a [`Path`], as [`OsStr`] slices.
+///
+/// This `struct` is created by the [`iter`] method on [`Path`].
+/// See its documentation for more.
+///
+/// [`Component`]: enum.Component.html
+/// [`iter`]: struct.Path.html#method.iter
+/// [`OsStr`]: ../../std/ffi/struct.OsStr.html
+/// [`Path`]: struct.Path.html
+#[derive(Clone)]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct Iter<'a> {
+ inner: Components<'a>,
+}
+
+#[stable(feature = "path_components_debug", since = "1.13.0")]
+impl fmt::Debug for Components<'_> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ struct DebugHelper<'a>(&'a Path);
+
+ impl fmt::Debug for DebugHelper<'_> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_list()
+ .entries(self.0.components())
+ .finish()
+ }
+ }
+
+ f.debug_tuple("Components")
+ .field(&DebugHelper(self.as_path()))
+ .finish()
+ }
+}
+
+impl<'a> Components<'a> {
+ // how long is the prefix, if any?
+ #[inline]
+ fn prefix_len(&self) -> usize {
+ self.prefix.as_ref().map(Prefix::len).unwrap_or(0)
+ }
+
+ #[inline]
+ fn prefix_verbatim(&self) -> bool {
+ self.prefix.as_ref().map(Prefix::is_verbatim).unwrap_or(false)
+ }
+
+ /// how much of the prefix is left from the point of view of iteration?
+ #[inline]
+ fn prefix_remaining(&self) -> usize {
+ if self.front == State::Prefix {
+ self.prefix_len()
+ } else {
+ 0
+ }
+ }
+
+ // Given the iteration so far, how much of the pre-State::Body path is left?
+ #[inline]
+ fn len_before_body(&self) -> usize {
+ let root = if self.front <= State::StartDir && self.has_physical_root {
+ 1
+ } else {
+ 0
+ };
+ let cur_dir = if self.front <= State::StartDir && self.include_cur_dir() {
+ 1
+ } else {
+ 0
+ };
+ self.prefix_remaining() + root + cur_dir
+ }
+
+ // is the iteration complete?
+ #[inline]
+ fn finished(&self) -> bool {
+ self.front == State::Done || self.back == State::Done || self.front > self.back
+ }
+
+ #[inline]
+ fn is_sep_byte(&self, b: u8) -> bool {
+ if self.prefix_verbatim() {
+ is_verbatim_sep(b)
+ } else {
+ is_sep_byte(b)
+ }
+ }
+
+ /// Extracts a slice corresponding to the portion of the path remaining for iteration.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::path::Path;
+ ///
+ /// let mut components = Path::new("/tmp/foo/bar.txt").components();
+ /// components.next();
+ /// components.next();
+ ///
+ /// assert_eq!(Path::new("foo/bar.txt"), components.as_path());
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn as_path(&self) -> &'a Path {
+ let mut comps = self.clone();
+ if comps.front == State::Body {
+ comps.trim_left();
+ }
+ if comps.back == State::Body {
+ comps.trim_right();
+ }
+ unsafe { Path::from_u8_slice(comps.path) }
+ }
+
+ /// Is the *original* path rooted?
+ fn has_root(&self) -> bool {
+ if self.has_physical_root {
+ return true;
+ }
+ if let Some(p) = self.prefix {
+ if p.has_implicit_root() {
+ return true;
+ }
+ }
+ false
+ }
+
+ /// Should the normalized path include a leading . ?
+ fn include_cur_dir(&self) -> bool {
+ if self.has_root() {
+ return false;
+ }
+ let mut iter = self.path[self.prefix_len()..].iter();
+ match (iter.next(), iter.next()) {
+ (Some(&b'.'), None) => true,
+ (Some(&b'.'), Some(&b)) => self.is_sep_byte(b),
+ _ => false,
+ }
+ }
+
+ // parse a given byte sequence into the corresponding path component
+ fn parse_single_component<'b>(&self, comp: &'b [u8]) -> Option<Component<'b>> {
+ match comp {
+ b"." if self.prefix_verbatim() => Some(Component::CurDir),
+ b"." => None, // . components are normalized away, except at
+ // the beginning of a path, which is treated
+ // separately via `include_cur_dir`
+ b".." => Some(Component::ParentDir),
+ b"" => None,
+ _ => Some(Component::Normal(unsafe { u8_slice_as_os_str(comp) })),
+ }
+ }
+
+ // parse a component from the left, saying how many bytes to consume to
+ // remove the component
+ fn parse_next_component(&self) -> (usize, Option<Component<'a>>) {
+ debug_assert!(self.front == State::Body);
+ let (extra, comp) = match self.path.iter().position(|b| self.is_sep_byte(*b)) {
+ None => (0, self.path),
+ Some(i) => (1, &self.path[..i]),
+ };
+ (comp.len() + extra, self.parse_single_component(comp))
+ }
+
+ // parse a component from the right, saying how many bytes to consume to
+ // remove the component
+ fn parse_next_component_back(&self) -> (usize, Option<Component<'a>>) {
+ debug_assert!(self.back == State::Body);
+ let start = self.len_before_body();
+ let (extra, comp) = match self.path[start..].iter().rposition(|b| self.is_sep_byte(*b)) {
+ None => (0, &self.path[start..]),
+ Some(i) => (1, &self.path[start + i + 1..]),
+ };
+ (comp.len() + extra, self.parse_single_component(comp))
+ }
+
+ // trim away repeated separators (i.e., empty components) on the left
+ fn trim_left(&mut self) {
+ while !self.path.is_empty() {
+ let (size, comp) = self.parse_next_component();
+ if comp.is_some() {
+ return;
+ } else {
+ self.path = &self.path[size..];
+ }
+ }
+ }
+
+ // trim away repeated separators (i.e., empty components) on the right
+ fn trim_right(&mut self) {
+ while self.path.len() > self.len_before_body() {
+ let (size, comp) = self.parse_next_component_back();
+ if comp.is_some() {
+ return;
+ } else {
+ self.path = &self.path[..self.path.len() - size];
+ }
+ }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRef<Path> for Components<'_> {
+ fn as_ref(&self) -> &Path {
+ self.as_path()
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRef<OsStr> for Components<'_> {
+ fn as_ref(&self) -> &OsStr {
+ self.as_path().as_os_str()
+ }
+}
+
+#[stable(feature = "path_iter_debug", since = "1.13.0")]
+impl fmt::Debug for Iter<'_> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ struct DebugHelper<'a>(&'a Path);
+
+ impl fmt::Debug for DebugHelper<'_> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_list()
+ .entries(self.0.iter())
+ .finish()
+ }
+ }
+
+ f.debug_tuple("Iter")
+ .field(&DebugHelper(self.as_path()))
+ .finish()
+ }
+}
+
+impl<'a> Iter<'a> {
+ /// Extracts a slice corresponding to the portion of the path remaining for iteration.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::path::Path;
+ ///
+ /// let mut iter = Path::new("/tmp/foo/bar.txt").iter();
+ /// iter.next();
+ /// iter.next();
+ ///
+ /// assert_eq!(Path::new("foo/bar.txt"), iter.as_path());
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn as_path(&self) -> &'a Path {
+ self.inner.as_path()
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRef<Path> for Iter<'_> {
+ fn as_ref(&self) -> &Path {
+ self.as_path()
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRef<OsStr> for Iter<'_> {
+ fn as_ref(&self) -> &OsStr {
+ self.as_path().as_os_str()
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a> Iterator for Iter<'a> {
+ type Item = &'a OsStr;
+
+ fn next(&mut self) -> Option<&'a OsStr> {
+ self.inner.next().map(Component::as_os_str)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a> DoubleEndedIterator for Iter<'a> {
+ fn next_back(&mut self) -> Option<&'a OsStr> {
+ self.inner.next_back().map(Component::as_os_str)
+ }
+}
+
+#[stable(feature = "fused", since = "1.26.0")]
+impl FusedIterator for Iter<'_> {}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a> Iterator for Components<'a> {
+ type Item = Component<'a>;
+
+ fn next(&mut self) -> Option<Component<'a>> {
+ while !self.finished() {
+ match self.front {
+ State::Prefix if self.prefix_len() > 0 => {
+ self.front = State::StartDir;
+ debug_assert!(self.prefix_len() <= self.path.len());
+ let raw = &self.path[..self.prefix_len()];
+ self.path = &self.path[self.prefix_len()..];
+ return Some(Component::Prefix(PrefixComponent {
+ raw: unsafe { u8_slice_as_os_str(raw) },
+ parsed: self.prefix.unwrap(),
+ }));
+ }
+ State::Prefix => {
+ self.front = State::StartDir;
+ }
+ State::StartDir => {
+ self.front = State::Body;
+ if self.has_physical_root {
+ debug_assert!(!self.path.is_empty());
+ self.path = &self.path[1..];
+ return Some(Component::RootDir);
+ } else if let Some(p) = self.prefix {
+ if p.has_implicit_root() && !p.is_verbatim() {
+ return Some(Component::RootDir);
+ }
+ } else if self.include_cur_dir() {
+ debug_assert!(!self.path.is_empty());
+ self.path = &self.path[1..];
+ return Some(Component::CurDir);
+ }
+ }
+ State::Body if !self.path.is_empty() => {
+ let (size, comp) = self.parse_next_component();
+ self.path = &self.path[size..];
+ if comp.is_some() {
+ return comp;
+ }
+ }
+ State::Body => {
+ self.front = State::Done;
+ }
+ State::Done => unreachable!(),
+ }
+ }
+ None
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a> DoubleEndedIterator for Components<'a> {
+ fn next_back(&mut self) -> Option<Component<'a>> {
+ while !self.finished() {
+ match self.back {
+ State::Body if self.path.len() > self.len_before_body() => {
+ let (size, comp) = self.parse_next_component_back();
+ self.path = &self.path[..self.path.len() - size];
+ if comp.is_some() {
+ return comp;
+ }
+ }
+ State::Body => {
+ self.back = State::StartDir;
+ }
+ State::StartDir => {
+ self.back = State::Prefix;
+ if self.has_physical_root {
+ self.path = &self.path[..self.path.len() - 1];
+ return Some(Component::RootDir);
+ } else if let Some(p) = self.prefix {
+ if p.has_implicit_root() && !p.is_verbatim() {
+ return Some(Component::RootDir);
+ }
+ } else if self.include_cur_dir() {
+ self.path = &self.path[..self.path.len() - 1];
+ return Some(Component::CurDir);
+ }
+ }
+ State::Prefix if self.prefix_len() > 0 => {
+ self.back = State::Done;
+ return Some(Component::Prefix(PrefixComponent {
+ raw: unsafe { u8_slice_as_os_str(self.path) },
+ parsed: self.prefix.unwrap(),
+ }));
+ }
+ State::Prefix => {
+ self.back = State::Done;
+ return None;
+ }
+ State::Done => unreachable!(),
+ }
+ }
+ None
+ }
+}
+
+#[stable(feature = "fused", since = "1.26.0")]
+impl FusedIterator for Components<'_> {}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a> cmp::PartialEq for Components<'a> {
+ fn eq(&self, other: &Components<'a>) -> bool {
+ Iterator::eq(self.clone(), other.clone())
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl cmp::Eq for Components<'_> {}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a> cmp::PartialOrd for Components<'a> {
+ fn partial_cmp(&self, other: &Components<'a>) -> Option<cmp::Ordering> {
+ Iterator::partial_cmp(self.clone(), other.clone())
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl cmp::Ord for Components<'_> {
+ fn cmp(&self, other: &Self) -> cmp::Ordering {
+ Iterator::cmp(self.clone(), other.clone())
+ }
+}
+
+/// An iterator over [`Path`] and its ancestors.
+///
+/// This `struct` is created by the [`ancestors`] method on [`Path`].
+/// See its documentation for more.
+///
+/// # Examples
+///
+/// ```
+/// use std::path::Path;
+///
+/// let path = Path::new("/foo/bar");
+///
+/// for ancestor in path.ancestors() {
+/// println!("{}", ancestor.display());
+/// }
+/// ```
+///
+/// [`ancestors`]: struct.Path.html#method.ancestors
+/// [`Path`]: struct.Path.html
+#[derive(Copy, Clone, Debug)]
+#[stable(feature = "path_ancestors", since = "1.28.0")]
+pub struct Ancestors<'a> {
+ next: Option<&'a Path>,
+}
+
+#[stable(feature = "path_ancestors", since = "1.28.0")]
+impl<'a> Iterator for Ancestors<'a> {
+ type Item = &'a Path;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ let next = self.next;
+ self.next = next.and_then(Path::parent);
+ next
+ }
+}
+
+#[stable(feature = "path_ancestors", since = "1.28.0")]
+impl FusedIterator for Ancestors<'_> {}
+
+////////////////////////////////////////////////////////////////////////////////
+// Basic types and traits
+////////////////////////////////////////////////////////////////////////////////
+
+/// An owned, mutable path (akin to [`String`]).
+///
+/// This type provides methods like [`push`] and [`set_extension`] that mutate
+/// the path in place. It also implements [`Deref`] to [`Path`], meaning that
+/// all methods on [`Path`] slices are available on `PathBuf` values as well.
+///
+/// [`String`]: ../string/struct.String.html
+/// [`Path`]: struct.Path.html
+/// [`push`]: struct.PathBuf.html#method.push
+/// [`set_extension`]: struct.PathBuf.html#method.set_extension
+/// [`Deref`]: ../ops/trait.Deref.html
+///
+/// More details about the overall approach can be found in
+/// the [module documentation](index.html).
+///
+/// # Examples
+///
+/// You can use [`push`] to build up a `PathBuf` from
+/// components:
+///
+/// ```
+/// use std::path::PathBuf;
+///
+/// let mut path = PathBuf::new();
+///
+/// path.push(r"C:\");
+/// path.push("windows");
+/// path.push("system32");
+///
+/// path.set_extension("dll");
+/// ```
+///
+/// However, [`push`] is best used for dynamic situations. This is a better way
+/// to do this when you know all of the components ahead of time:
+///
+/// ```
+/// use std::path::PathBuf;
+///
+/// let path: PathBuf = [r"C:\", "windows", "system32.dll"].iter().collect();
+/// ```
+///
+/// We can still do better than this! Since these are all strings, we can use
+/// `From::from`:
+///
+/// ```
+/// use std::path::PathBuf;
+///
+/// let path = PathBuf::from(r"C:\windows\system32.dll");
+/// ```
+///
+/// Which method works best depends on what kind of situation you're in.
+#[derive(Clone)]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct PathBuf {
+ inner: OsString,
+}
+
+impl PathBuf {
+ fn as_mut_vec(&mut self) -> &mut Vec<u8> {
+ unsafe { &mut *(self as *mut PathBuf as *mut Vec<u8>) }
+ }
+
+ /// Allocates an empty `PathBuf`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::path::PathBuf;
+ ///
+ /// let path = PathBuf::new();
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn new() -> PathBuf {
+ PathBuf { inner: OsString::new() }
+ }
+
+ /// Creates a new `PathBuf` with a given capacity used to create the
+ /// internal [`OsString`]. See [`with_capacity`] defined on [`OsString`].
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(path_buf_capacity)]
+ /// use std::path::PathBuf;
+ ///
+ /// let mut path = PathBuf::with_capacity(10);
+ /// let capacity = path.capacity();
+ ///
+ /// // This push is done without reallocating
+ /// path.push(r"C:\");
+ ///
+ /// assert_eq!(capacity, path.capacity());
+ /// ```
+ ///
+ /// [`with_capacity`]: ../ffi/struct.OsString.html#method.with_capacity
+ /// [`OsString`]: ../ffi/struct.OsString.html
+ #[unstable(feature = "path_buf_capacity", issue = "58234")]
+ pub fn with_capacity(capacity: usize) -> PathBuf {
+ PathBuf {
+ inner: OsString::with_capacity(capacity)
+ }
+ }
+
+ /// Coerces to a [`Path`] slice.
+ ///
+ /// [`Path`]: struct.Path.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::path::{Path, PathBuf};
+ ///
+ /// let p = PathBuf::from("/test");
+ /// assert_eq!(Path::new("/test"), p.as_path());
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn as_path(&self) -> &Path {
+ self
+ }
+
+ /// Extends `self` with `path`.
+ ///
+ /// If `path` is absolute, it replaces the current path.
+ ///
+ /// On Windows:
+ ///
+ /// * if `path` has a root but no prefix (e.g., `\windows`), it
+ /// replaces everything except for the prefix (if any) of `self`.
+ /// * if `path` has a prefix but no root, it replaces `self`.
+ ///
+ /// # Examples
+ ///
+ /// Pushing a relative path extends the existing path:
+ ///
+ /// ```
+ /// use std::path::PathBuf;
+ ///
+ /// let mut path = PathBuf::from("/tmp");
+ /// path.push("file.bk");
+ /// assert_eq!(path, PathBuf::from("/tmp/file.bk"));
+ /// ```
+ ///
+ /// Pushing an absolute path replaces the existing path:
+ ///
+ /// ```
+ /// use std::path::PathBuf;
+ ///
+ /// let mut path = PathBuf::from("/tmp");
+ /// path.push("/etc");
+ /// assert_eq!(path, PathBuf::from("/etc"));
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn push<P: AsRef<Path>>(&mut self, path: P) {
+ self._push(path.as_ref())
+ }
+
+ fn _push(&mut self, path: &Path) {
+ // in general, a separator is needed if the rightmost byte is not a separator
+ let mut need_sep = self.as_mut_vec().last().map(|c| !is_sep_byte(*c)).unwrap_or(false);
+
+ // in the special case of `C:` on Windows, do *not* add a separator
+ {
+ let comps = self.components();
+ if comps.prefix_len() > 0 && comps.prefix_len() == comps.path.len() &&
+ comps.prefix.unwrap().is_drive() {
+ need_sep = false
+ }
+ }
+
+ // absolute `path` replaces `self`
+ if path.is_absolute() || path.prefix().is_some() {
+ self.as_mut_vec().truncate(0);
+
+ // `path` has a root but no prefix, e.g., `\windows` (Windows only)
+ } else if path.has_root() {
+ let prefix_len = self.components().prefix_remaining();
+ self.as_mut_vec().truncate(prefix_len);
+
+ // `path` is a pure relative path
+ } else if need_sep {
+ self.inner.push(MAIN_SEP_STR);
+ }
+
+ self.inner.push(path);
+ }
+
+ /// Truncates `self` to [`self.parent`].
+ ///
+ /// Returns `false` and does nothing if [`self.parent`] is [`None`].
+ /// Otherwise, returns `true`.
+ ///
+ /// [`None`]: ../../std/option/enum.Option.html#variant.None
+ /// [`self.parent`]: struct.PathBuf.html#method.parent
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::path::{Path, PathBuf};
+ ///
+ /// let mut p = PathBuf::from("/test/test.rs");
+ ///
+ /// p.pop();
+ /// assert_eq!(Path::new("/test"), p);
+ /// p.pop();
+ /// assert_eq!(Path::new("/"), p);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn pop(&mut self) -> bool {
+ match self.parent().map(|p| p.as_u8_slice().len()) {
+ Some(len) => {
+ self.as_mut_vec().truncate(len);
+ true
+ }
+ None => false,
+ }
+ }
+
+ /// Updates [`self.file_name`] to `file_name`.
+ ///
+ /// If [`self.file_name`] was [`None`], this is equivalent to pushing
+ /// `file_name`.
+ ///
+ /// Otherwise it is equivalent to calling [`pop`] and then pushing
+ /// `file_name`. The new path will be a sibling of the original path.
+ /// (That is, it will have the same parent.)
+ ///
+ /// [`self.file_name`]: struct.PathBuf.html#method.file_name
+ /// [`None`]: ../../std/option/enum.Option.html#variant.None
+ /// [`pop`]: struct.PathBuf.html#method.pop
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::path::PathBuf;
+ ///
+ /// let mut buf = PathBuf::from("/");
+ /// assert!(buf.file_name() == None);
+ /// buf.set_file_name("bar");
+ /// assert!(buf == PathBuf::from("/bar"));
+ /// assert!(buf.file_name().is_some());
+ /// buf.set_file_name("baz.txt");
+ /// assert!(buf == PathBuf::from("/baz.txt"));
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn set_file_name<S: AsRef<OsStr>>(&mut self, file_name: S) {
+ self._set_file_name(file_name.as_ref())
+ }
+
+ fn _set_file_name(&mut self, file_name: &OsStr) {
+ if self.file_name().is_some() {
+ let popped = self.pop();
+ debug_assert!(popped);
+ }
+ self.push(file_name);
+ }
+
+ /// Updates [`self.extension`] to `extension`.
+ ///
+ /// Returns `false` and does nothing if [`self.file_name`] is [`None`],
+ /// returns `true` and updates the extension otherwise.
+ ///
+ /// If [`self.extension`] is [`None`], the extension is added; otherwise
+ /// it is replaced.
+ ///
+ /// [`self.file_name`]: struct.PathBuf.html#method.file_name
+ /// [`self.extension`]: struct.PathBuf.html#method.extension
+ /// [`None`]: ../../std/option/enum.Option.html#variant.None
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::path::{Path, PathBuf};
+ ///
+ /// let mut p = PathBuf::from("/feel/the");
+ ///
+ /// p.set_extension("force");
+ /// assert_eq!(Path::new("/feel/the.force"), p.as_path());
+ ///
+ /// p.set_extension("dark_side");
+ /// assert_eq!(Path::new("/feel/the.dark_side"), p.as_path());
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn set_extension<S: AsRef<OsStr>>(&mut self, extension: S) -> bool {
+ self._set_extension(extension.as_ref())
+ }
+
+ fn _set_extension(&mut self, extension: &OsStr) -> bool {
+ if self.file_name().is_none() {
+ return false;
+ }
+
+ let mut stem = match self.file_stem() {
+ Some(stem) => stem.to_os_string(),
+ None => OsString::new(),
+ };
+
+ if !os_str_as_u8_slice(extension).is_empty() {
+ stem.push(".");
+ stem.push(extension);
+ }
+ self.set_file_name(&stem);
+
+ true
+ }
+
+ /// Consumes the `PathBuf`, yielding its internal [`OsString`] storage.
+ ///
+ /// [`OsString`]: ../ffi/struct.OsString.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::path::PathBuf;
+ ///
+ /// let p = PathBuf::from("/the/head");
+ /// let os_str = p.into_os_string();
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn into_os_string(self) -> OsString {
+ self.inner
+ }
+
+ /// Converts this `PathBuf` into a [boxed][`Box`] [`Path`].
+ ///
+ /// [`Box`]: ../../std/boxed/struct.Box.html
+ /// [`Path`]: struct.Path.html
+ #[stable(feature = "into_boxed_path", since = "1.20.0")]
+ pub fn into_boxed_path(self) -> Box<Path> {
+ let rw = Box::into_raw(self.inner.into_boxed_os_str()) as *mut Path;
+ unsafe { Box::from_raw(rw) }
+ }
+
+ /// Invokes [`capacity`] on the underlying instance of [`OsString`].
+ ///
+ /// [`capacity`]: ../ffi/struct.OsString.html#method.capacity
+ /// [`OsString`]: ../ffi/struct.OsString.html
+ #[unstable(feature = "path_buf_capacity", issue = "58234")]
+ pub fn capacity(&self) -> usize {
+ self.inner.capacity()
+ }
+
+ /// Invokes [`clear`] on the underlying instance of [`OsString`].
+ ///
+ /// [`clear`]: ../ffi/struct.OsString.html#method.clear
+ /// [`OsString`]: ../ffi/struct.OsString.html
+ #[unstable(feature = "path_buf_capacity", issue = "58234")]
+ pub fn clear(&mut self) {
+ self.inner.clear()
+ }
+
+ /// Invokes [`reserve`] on the underlying instance of [`OsString`].
+ ///
+ /// [`reserve`]: ../ffi/struct.OsString.html#method.reserve
+ /// [`OsString`]: ../ffi/struct.OsString.html
+ #[unstable(feature = "path_buf_capacity", issue = "58234")]
+ pub fn reserve(&mut self, additional: usize) {
+ self.inner.reserve(additional)
+ }
+
+ /// Invokes [`reserve_exact`] on the underlying instance of [`OsString`].
+ ///
+ /// [`reserve_exact`]: ../ffi/struct.OsString.html#method.reserve_exact
+ /// [`OsString`]: ../ffi/struct.OsString.html
+ #[unstable(feature = "path_buf_capacity", issue = "58234")]
+ pub fn reserve_exact(&mut self, additional: usize) {
+ self.inner.reserve_exact(additional)
+ }
+
+ /// Invokes [`shrink_to_fit`] on the underlying instance of [`OsString`].
+ ///
+ /// [`shrink_to_fit`]: ../ffi/struct.OsString.html#method.shrink_to_fit
+ /// [`OsString`]: ../ffi/struct.OsString.html
+ #[unstable(feature = "path_buf_capacity", issue = "58234")]
+ pub fn shrink_to_fit(&mut self) {
+ self.inner.shrink_to_fit()
+ }
+
+ /// Invokes [`shrink_to`] on the underlying instance of [`OsString`].
+ ///
+ /// [`shrink_to`]: ../ffi/struct.OsString.html#method.shrink_to
+ /// [`OsString`]: ../ffi/struct.OsString.html
+ #[unstable(feature = "path_buf_capacity", issue = "58234")]
+ pub fn shrink_to(&mut self, min_capacity: usize) {
+ self.inner.shrink_to(min_capacity)
+ }
+}
+
+#[stable(feature = "box_from_path", since = "1.17.0")]
+impl From<&Path> for Box<Path> {
+ fn from(path: &Path) -> Box<Path> {
+ let boxed: Box<OsStr> = path.inner.into();
+ let rw = Box::into_raw(boxed) as *mut Path;
+ unsafe { Box::from_raw(rw) }
+ }
+}
+
+#[stable(feature = "path_buf_from_box", since = "1.18.0")]
+impl From<Box<Path>> for PathBuf {
+ /// Converts a `Box<Path>` into a `PathBuf`
+ ///
+ /// This conversion does not allocate or copy memory.
+ fn from(boxed: Box<Path>) -> PathBuf {
+ boxed.into_path_buf()
+ }
+}
+
+#[stable(feature = "box_from_path_buf", since = "1.20.0")]
+impl From<PathBuf> for Box<Path> {
+ /// Converts a `PathBuf` into a `Box<Path>`
+ ///
+ /// This conversion currently should not allocate memory,
+ /// but this behavior is not guaranteed on all platforms or in all future versions.
+ fn from(p: PathBuf) -> Box<Path> {
+ p.into_boxed_path()
+ }
+}
+
+#[stable(feature = "more_box_slice_clone", since = "1.29.0")]
+impl Clone for Box<Path> {
+ #[inline]
+ fn clone(&self) -> Self {
+ self.to_path_buf().into_boxed_path()
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T: ?Sized + AsRef<OsStr>> From<&T> for PathBuf {
+ fn from(s: &T) -> PathBuf {
+ PathBuf::from(s.as_ref().to_os_string())
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl From<OsString> for PathBuf {
+ /// Converts a `OsString` into a `PathBuf`
+ ///
+ /// This conversion does not allocate or copy memory.
+ fn from(s: OsString) -> PathBuf {
+ PathBuf { inner: s }
+ }
+}
+
+#[stable(feature = "from_path_buf_for_os_string", since = "1.14.0")]
+impl From<PathBuf> for OsString {
+ /// Converts a `PathBuf` into a `OsString`
+ ///
+ /// This conversion does not allocate or copy memory.
+ fn from(path_buf : PathBuf) -> OsString {
+ path_buf.inner
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl From<String> for PathBuf {
+ /// Converts a `String` into a `PathBuf`
+ ///
+ /// This conversion does not allocate or copy memory.
+ fn from(s: String) -> PathBuf {
+ PathBuf::from(OsString::from(s))
+ }
+}
+
+#[stable(feature = "path_from_str", since = "1.32.0")]
+impl FromStr for PathBuf {
+ type Err = core::convert::Infallible;
+
+ fn from_str(s: &str) -> Result<Self, Self::Err> {
+ Ok(PathBuf::from(s))
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<P: AsRef<Path>> iter::FromIterator<P> for PathBuf {
+ fn from_iter<I: IntoIterator<Item = P>>(iter: I) -> PathBuf {
+ let mut buf = PathBuf::new();
+ buf.extend(iter);
+ buf
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<P: AsRef<Path>> iter::Extend<P> for PathBuf {
+ fn extend<I: IntoIterator<Item = P>>(&mut self, iter: I) {
+ iter.into_iter().for_each(move |p| self.push(p.as_ref()));
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl fmt::Debug for PathBuf {
+ fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt::Debug::fmt(&**self, formatter)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl ops::Deref for PathBuf {
+ type Target = Path;
+
+ fn deref(&self) -> &Path {
+ Path::new(&self.inner)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Borrow<Path> for PathBuf {
+ fn borrow(&self) -> &Path {
+ self.deref()
+ }
+}
+
+#[stable(feature = "default_for_pathbuf", since = "1.17.0")]
+impl Default for PathBuf {
+ fn default() -> Self {
+ PathBuf::new()
+ }
+}
+
+#[stable(feature = "cow_from_path", since = "1.6.0")]
+impl<'a> From<&'a Path> for Cow<'a, Path> {
+ #[inline]
+ fn from(s: &'a Path) -> Cow<'a, Path> {
+ Cow::Borrowed(s)
+ }
+}
+
+#[stable(feature = "cow_from_path", since = "1.6.0")]
+impl<'a> From<PathBuf> for Cow<'a, Path> {
+ #[inline]
+ fn from(s: PathBuf) -> Cow<'a, Path> {
+ Cow::Owned(s)
+ }
+}
+
+#[stable(feature = "cow_from_pathbuf_ref", since = "1.28.0")]
+impl<'a> From<&'a PathBuf> for Cow<'a, Path> {
+ #[inline]
+ fn from(p: &'a PathBuf) -> Cow<'a, Path> {
+ Cow::Borrowed(p.as_path())
+ }
+}
+
+#[stable(feature = "pathbuf_from_cow_path", since = "1.28.0")]
+impl<'a> From<Cow<'a, Path>> for PathBuf {
+ #[inline]
+ fn from(p: Cow<'a, Path>) -> Self {
+ p.into_owned()
+ }
+}
+
+#[stable(feature = "shared_from_slice2", since = "1.24.0")]
+impl From<PathBuf> for Arc<Path> {
+ /// Converts a Path into a Rc by copying the Path data into a new Rc buffer.
+ #[inline]
+ fn from(s: PathBuf) -> Arc<Path> {
+ let arc: Arc<OsStr> = Arc::from(s.into_os_string());
+ unsafe { Arc::from_raw(Arc::into_raw(arc) as *const Path) }
+ }
+}
+
+#[stable(feature = "shared_from_slice2", since = "1.24.0")]
+impl From<&Path> for Arc<Path> {
+ /// Converts a Path into a Rc by copying the Path data into a new Rc buffer.
+ #[inline]
+ fn from(s: &Path) -> Arc<Path> {
+ let arc: Arc<OsStr> = Arc::from(s.as_os_str());
+ unsafe { Arc::from_raw(Arc::into_raw(arc) as *const Path) }
+ }
+}
+
+#[stable(feature = "shared_from_slice2", since = "1.24.0")]
+impl From<PathBuf> for Rc<Path> {
+ /// Converts a Path into a Rc by copying the Path data into a new Rc buffer.
+ #[inline]
+ fn from(s: PathBuf) -> Rc<Path> {
+ let rc: Rc<OsStr> = Rc::from(s.into_os_string());
+ unsafe { Rc::from_raw(Rc::into_raw(rc) as *const Path) }
+ }
+}
+
+#[stable(feature = "shared_from_slice2", since = "1.24.0")]
+impl From<&Path> for Rc<Path> {
+ /// Converts a Path into a Rc by copying the Path data into a new Rc buffer.
+ #[inline]
+ fn from(s: &Path) -> Rc<Path> {
+ let rc: Rc<OsStr> = Rc::from(s.as_os_str());
+ unsafe { Rc::from_raw(Rc::into_raw(rc) as *const Path) }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl ToOwned for Path {
+ type Owned = PathBuf;
+ fn to_owned(&self) -> PathBuf {
+ self.to_path_buf()
+ }
+ fn clone_into(&self, target: &mut PathBuf) {
+ self.inner.clone_into(&mut target.inner);
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl cmp::PartialEq for PathBuf {
+ fn eq(&self, other: &PathBuf) -> bool {
+ self.components() == other.components()
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Hash for PathBuf {
+ fn hash<H: Hasher>(&self, h: &mut H) {
+ self.as_path().hash(h)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl cmp::Eq for PathBuf {}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl cmp::PartialOrd for PathBuf {
+ fn partial_cmp(&self, other: &PathBuf) -> Option<cmp::Ordering> {
+ self.components().partial_cmp(other.components())
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl cmp::Ord for PathBuf {
+ fn cmp(&self, other: &PathBuf) -> cmp::Ordering {
+ self.components().cmp(other.components())
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRef<OsStr> for PathBuf {
+ fn as_ref(&self) -> &OsStr {
+ &self.inner[..]
+ }
+}
+
+/// A slice of a path (akin to [`str`]).
+///
+/// This type supports a number of operations for inspecting a path, including
+/// breaking the path into its components (separated by `/` on Unix and by either
+/// `/` or `\` on Windows), extracting the file name, determining whether the path
+/// is absolute, and so on.
+///
+/// This is an *unsized* type, meaning that it must always be used behind a
+/// pointer like `&` or [`Box`]. For an owned version of this type,
+/// see [`PathBuf`].
+///
+/// [`str`]: ../primitive.str.html
+/// [`Box`]: ../boxed/struct.Box.html
+/// [`PathBuf`]: struct.PathBuf.html
+///
+/// More details about the overall approach can be found in
+/// the [module documentation](index.html).
+///
+/// # Examples
+///
+/// ```
+/// use std::path::Path;
+/// use std::ffi::OsStr;
+///
+/// // Note: this example does work on Windows
+/// let path = Path::new("./foo/bar.txt");
+///
+/// let parent = path.parent();
+/// assert_eq!(parent, Some(Path::new("./foo")));
+///
+/// let file_stem = path.file_stem();
+/// assert_eq!(file_stem, Some(OsStr::new("bar")));
+///
+/// let extension = path.extension();
+/// assert_eq!(extension, Some(OsStr::new("txt")));
+/// ```
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct Path {
+ inner: OsStr,
+}
+
+/// An error returned from [`Path::strip_prefix`][`strip_prefix`] if the prefix
+/// was not found.
+///
+/// This `struct` is created by the [`strip_prefix`] method on [`Path`].
+/// See its documentation for more.
+///
+/// [`strip_prefix`]: struct.Path.html#method.strip_prefix
+/// [`Path`]: struct.Path.html
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[stable(since = "1.7.0", feature = "strip_prefix")]
+pub struct StripPrefixError(());
+
+impl Path {
+ // The following (private!) function allows construction of a path from a u8
+ // slice, which is only safe when it is known to follow the OsStr encoding.
+ unsafe fn from_u8_slice(s: &[u8]) -> &Path {
+ Path::new(u8_slice_as_os_str(s))
+ }
+ // The following (private!) function reveals the byte encoding used for OsStr.
+ fn as_u8_slice(&self) -> &[u8] {
+ os_str_as_u8_slice(&self.inner)
+ }
+
+ /// Directly wraps a string slice as a `Path` slice.
+ ///
+ /// This is a cost-free conversion.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::path::Path;
+ ///
+ /// Path::new("foo.txt");
+ /// ```
+ ///
+ /// You can create `Path`s from `String`s, or even other `Path`s:
+ ///
+ /// ```
+ /// use std::path::Path;
+ ///
+ /// let string = String::from("foo.txt");
+ /// let from_string = Path::new(&string);
+ /// let from_path = Path::new(&from_string);
+ /// assert_eq!(from_string, from_path);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn new<S: AsRef<OsStr> + ?Sized>(s: &S) -> &Path {
+ unsafe { &*(s.as_ref() as *const OsStr as *const Path) }
+ }
+
+ /// Yields the underlying [`OsStr`] slice.
+ ///
+ /// [`OsStr`]: ../ffi/struct.OsStr.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::path::Path;
+ ///
+ /// let os_str = Path::new("foo.txt").as_os_str();
+ /// assert_eq!(os_str, std::ffi::OsStr::new("foo.txt"));
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn as_os_str(&self) -> &OsStr {
+ &self.inner
+ }
+
+ /// Yields a [`&str`] slice if the `Path` is valid unicode.
+ ///
+ /// This conversion may entail doing a check for UTF-8 validity.
+ ///
+ /// [`&str`]: ../primitive.str.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::path::Path;
+ ///
+ /// let path = Path::new("foo.txt");
+ /// assert_eq!(path.to_str(), Some("foo.txt"));
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn to_str(&self) -> Option<&str> {
+ self.inner.to_str()
+ }
+
+ /// Converts a `Path` to a [`Cow<str>`].
+ ///
+ /// Any non-Unicode sequences are replaced with
+ /// [`U+FFFD REPLACEMENT CHARACTER`][U+FFFD].
+ ///
+ /// [`Cow<str>`]: ../borrow/enum.Cow.html
+ /// [U+FFFD]: ../char/constant.REPLACEMENT_CHARACTER.html
+ ///
+ /// # Examples
+ ///
+ /// Calling `to_string_lossy` on a `Path` with valid unicode:
+ ///
+ /// ```
+ /// use std::path::Path;
+ ///
+ /// let path = Path::new("foo.txt");
+ /// assert_eq!(path.to_string_lossy(), "foo.txt");
+ /// ```
+ ///
+ /// Had `path` contained invalid unicode, the `to_string_lossy` call might
+ /// have returned `"fo�.txt"`.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn to_string_lossy(&self) -> Cow<'_, str> {
+ self.inner.to_string_lossy()
+ }
+
+ /// Converts a `Path` to an owned [`PathBuf`].
+ ///
+ /// [`PathBuf`]: struct.PathBuf.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::path::Path;
+ ///
+ /// let path_buf = Path::new("foo.txt").to_path_buf();
+ /// assert_eq!(path_buf, std::path::PathBuf::from("foo.txt"));
+ /// ```
+ #[rustc_conversion_suggestion]
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn to_path_buf(&self) -> PathBuf {
+ PathBuf::from(self.inner.to_os_string())
+ }
+
+ /// Returns `true` if the `Path` is absolute, i.e., if it is independent of
+ /// the current directory.
+ ///
+ /// * On Unix, a path is absolute if it starts with the root, so
+ /// `is_absolute` and [`has_root`] are equivalent.
+ ///
+ /// * On Windows, a path is absolute if it has a prefix and starts with the
+ /// root: `c:\windows` is absolute, while `c:temp` and `\temp` are not.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::path::Path;
+ ///
+ /// assert!(!Path::new("foo.txt").is_absolute());
+ /// ```
+ ///
+ /// [`has_root`]: #method.has_root
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[allow(deprecated)]
+ pub fn is_absolute(&self) -> bool {
+ if cfg!(target_os = "redox") {
+ // FIXME: Allow Redox prefixes
+ self.has_root() || has_redox_scheme(self.as_u8_slice())
+ } else {
+ self.has_root() && (cfg!(unix) || self.prefix().is_some())
+ }
+ }
+
+ /// Returns `true` if the `Path` is relative, i.e., not absolute.
+ ///
+ /// See [`is_absolute`]'s documentation for more details.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::path::Path;
+ ///
+ /// assert!(Path::new("foo.txt").is_relative());
+ /// ```
+ ///
+ /// [`is_absolute`]: #method.is_absolute
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn is_relative(&self) -> bool {
+ !self.is_absolute()
+ }
+
+ fn prefix(&self) -> Option<Prefix<'_>> {
+ self.components().prefix
+ }
+
+ /// Returns `true` if the `Path` has a root.
+ ///
+ /// * On Unix, a path has a root if it begins with `/`.
+ ///
+ /// * On Windows, a path has a root if it:
+ /// * has no prefix and begins with a separator, e.g., `\windows`
+ /// * has a prefix followed by a separator, e.g., `c:\windows` but not `c:windows`
+ /// * has any non-disk prefix, e.g., `\\server\share`
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::path::Path;
+ ///
+ /// assert!(Path::new("/etc/passwd").has_root());
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn has_root(&self) -> bool {
+ self.components().has_root()
+ }
+
+ /// Returns the `Path` without its final component, if there is one.
+ ///
+ /// Returns [`None`] if the path terminates in a root or prefix.
+ ///
+ /// [`None`]: ../../std/option/enum.Option.html#variant.None
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::path::Path;
+ ///
+ /// let path = Path::new("/foo/bar");
+ /// let parent = path.parent().unwrap();
+ /// assert_eq!(parent, Path::new("/foo"));
+ ///
+ /// let grand_parent = parent.parent().unwrap();
+ /// assert_eq!(grand_parent, Path::new("/"));
+ /// assert_eq!(grand_parent.parent(), None);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn parent(&self) -> Option<&Path> {
+ let mut comps = self.components();
+ let comp = comps.next_back();
+ comp.and_then(|p| {
+ match p {
+ Component::Normal(_) |
+ Component::CurDir |
+ Component::ParentDir => Some(comps.as_path()),
+ _ => None,
+ }
+ })
+ }
+
+ /// Produces an iterator over `Path` and its ancestors.
+ ///
+ /// The iterator will yield the `Path` that is returned if the [`parent`] method is used zero
+ /// or more times. That means, the iterator will yield `&self`, `&self.parent().unwrap()`,
+ /// `&self.parent().unwrap().parent().unwrap()` and so on. If the [`parent`] method returns
+ /// [`None`], the iterator will do likewise. The iterator will always yield at least one value,
+ /// namely `&self`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::path::Path;
+ ///
+ /// let mut ancestors = Path::new("/foo/bar").ancestors();
+ /// assert_eq!(ancestors.next(), Some(Path::new("/foo/bar")));
+ /// assert_eq!(ancestors.next(), Some(Path::new("/foo")));
+ /// assert_eq!(ancestors.next(), Some(Path::new("/")));
+ /// assert_eq!(ancestors.next(), None);
+ /// ```
+ ///
+ /// [`None`]: ../../std/option/enum.Option.html#variant.None
+ /// [`parent`]: struct.Path.html#method.parent
+ #[stable(feature = "path_ancestors", since = "1.28.0")]
+ pub fn ancestors(&self) -> Ancestors<'_> {
+ Ancestors {
+ next: Some(&self),
+ }
+ }
+
+ /// Returns the final component of the `Path`, if there is one.
+ ///
+ /// If the path is a normal file, this is the file name. If it's the path of a directory, this
+ /// is the directory name.
+ ///
+ /// Returns [`None`] if the path terminates in `..`.
+ ///
+ /// [`None`]: ../../std/option/enum.Option.html#variant.None
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::path::Path;
+ /// use std::ffi::OsStr;
+ ///
+ /// assert_eq!(Some(OsStr::new("bin")), Path::new("/usr/bin/").file_name());
+ /// assert_eq!(Some(OsStr::new("foo.txt")), Path::new("tmp/foo.txt").file_name());
+ /// assert_eq!(Some(OsStr::new("foo.txt")), Path::new("foo.txt/.").file_name());
+ /// assert_eq!(Some(OsStr::new("foo.txt")), Path::new("foo.txt/.//").file_name());
+ /// assert_eq!(None, Path::new("foo.txt/..").file_name());
+ /// assert_eq!(None, Path::new("/").file_name());
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn file_name(&self) -> Option<&OsStr> {
+ self.components().next_back().and_then(|p| {
+ match p {
+ Component::Normal(p) => Some(p.as_ref()),
+ _ => None,
+ }
+ })
+ }
+
+ /// Returns a path that, when joined onto `base`, yields `self`.
+ ///
+ /// # Errors
+ ///
+ /// If `base` is not a prefix of `self` (i.e., [`starts_with`]
+ /// returns `false`), returns [`Err`].
+ ///
+ /// [`starts_with`]: #method.starts_with
+ /// [`Err`]: ../../std/result/enum.Result.html#variant.Err
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::path::{Path, PathBuf};
+ ///
+ /// let path = Path::new("/test/haha/foo.txt");
+ ///
+ /// assert_eq!(path.strip_prefix("/"), Ok(Path::new("test/haha/foo.txt")));
+ /// assert_eq!(path.strip_prefix("/test"), Ok(Path::new("haha/foo.txt")));
+ /// assert_eq!(path.strip_prefix("/test/"), Ok(Path::new("haha/foo.txt")));
+ /// assert_eq!(path.strip_prefix("/test/haha/foo.txt"), Ok(Path::new("")));
+ /// assert_eq!(path.strip_prefix("/test/haha/foo.txt/"), Ok(Path::new("")));
+ /// assert_eq!(path.strip_prefix("test").is_ok(), false);
+ /// assert_eq!(path.strip_prefix("/haha").is_ok(), false);
+ ///
+ /// let prefix = PathBuf::from("/test/");
+ /// assert_eq!(path.strip_prefix(prefix), Ok(Path::new("haha/foo.txt")));
+ /// ```
+ #[stable(since = "1.7.0", feature = "path_strip_prefix")]
+ pub fn strip_prefix<P>(&self, base: P)
+ -> Result<&Path, StripPrefixError>
+ where P: AsRef<Path>
+ {
+ self._strip_prefix(base.as_ref())
+ }
+
+ fn _strip_prefix(&self, base: &Path)
+ -> Result<&Path, StripPrefixError> {
+ iter_after(self.components(), base.components())
+ .map(|c| c.as_path())
+ .ok_or(StripPrefixError(()))
+ }
+
+ /// Determines whether `base` is a prefix of `self`.
+ ///
+ /// Only considers whole path components to match.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::path::Path;
+ ///
+ /// let path = Path::new("/etc/passwd");
+ ///
+ /// assert!(path.starts_with("/etc"));
+ /// assert!(path.starts_with("/etc/"));
+ /// assert!(path.starts_with("/etc/passwd"));
+ /// assert!(path.starts_with("/etc/passwd/"));
+ ///
+ /// assert!(!path.starts_with("/e"));
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn starts_with<P: AsRef<Path>>(&self, base: P) -> bool {
+ self._starts_with(base.as_ref())
+ }
+
+ fn _starts_with(&self, base: &Path) -> bool {
+ iter_after(self.components(), base.components()).is_some()
+ }
+
+ /// Determines whether `child` is a suffix of `self`.
+ ///
+ /// Only considers whole path components to match.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::path::Path;
+ ///
+ /// let path = Path::new("/etc/passwd");
+ ///
+ /// assert!(path.ends_with("passwd"));
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn ends_with<P: AsRef<Path>>(&self, child: P) -> bool {
+ self._ends_with(child.as_ref())
+ }
+
+ fn _ends_with(&self, child: &Path) -> bool {
+ iter_after(self.components().rev(), child.components().rev()).is_some()
+ }
+
+ /// Extracts the stem (non-extension) portion of [`self.file_name`].
+ ///
+ /// [`self.file_name`]: struct.Path.html#method.file_name
+ ///
+ /// The stem is:
+ ///
+ /// * [`None`], if there is no file name;
+ /// * The entire file name if there is no embedded `.`;
+ /// * The entire file name if the file name begins with `.` and has no other `.`s within;
+ /// * Otherwise, the portion of the file name before the final `.`
+ ///
+ /// [`None`]: ../../std/option/enum.Option.html#variant.None
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::path::Path;
+ ///
+ /// let path = Path::new("foo.rs");
+ ///
+ /// assert_eq!("foo", path.file_stem().unwrap());
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn file_stem(&self) -> Option<&OsStr> {
+ self.file_name().map(split_file_at_dot).and_then(|(before, after)| before.or(after))
+ }
+
+ /// Extracts the extension of [`self.file_name`], if possible.
+ ///
+ /// The extension is:
+ ///
+ /// * [`None`], if there is no file name;
+ /// * [`None`], if there is no embedded `.`;
+ /// * [`None`], if the file name begins with `.` and has no other `.`s within;
+ /// * Otherwise, the portion of the file name after the final `.`
+ ///
+ /// [`self.file_name`]: struct.Path.html#method.file_name
+ /// [`None`]: ../../std/option/enum.Option.html#variant.None
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::path::Path;
+ ///
+ /// let path = Path::new("foo.rs");
+ ///
+ /// assert_eq!("rs", path.extension().unwrap());
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn extension(&self) -> Option<&OsStr> {
+ self.file_name().map(split_file_at_dot).and_then(|(before, after)| before.and(after))
+ }
+
+ /// Creates an owned [`PathBuf`] with `path` adjoined to `self`.
+ ///
+ /// See [`PathBuf::push`] for more details on what it means to adjoin a path.
+ ///
+ /// [`PathBuf`]: struct.PathBuf.html
+ /// [`PathBuf::push`]: struct.PathBuf.html#method.push
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::path::{Path, PathBuf};
+ ///
+ /// assert_eq!(Path::new("/etc").join("passwd"), PathBuf::from("/etc/passwd"));
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn join<P: AsRef<Path>>(&self, path: P) -> PathBuf {
+ self._join(path.as_ref())
+ }
+
+ fn _join(&self, path: &Path) -> PathBuf {
+ let mut buf = self.to_path_buf();
+ buf.push(path);
+ buf
+ }
+
+ /// Creates an owned [`PathBuf`] like `self` but with the given file name.
+ ///
+ /// See [`PathBuf::set_file_name`] for more details.
+ ///
+ /// [`PathBuf`]: struct.PathBuf.html
+ /// [`PathBuf::set_file_name`]: struct.PathBuf.html#method.set_file_name
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::path::{Path, PathBuf};
+ ///
+ /// let path = Path::new("/tmp/foo.txt");
+ /// assert_eq!(path.with_file_name("bar.txt"), PathBuf::from("/tmp/bar.txt"));
+ ///
+ /// let path = Path::new("/tmp");
+ /// assert_eq!(path.with_file_name("var"), PathBuf::from("/var"));
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn with_file_name<S: AsRef<OsStr>>(&self, file_name: S) -> PathBuf {
+ self._with_file_name(file_name.as_ref())
+ }
+
+ fn _with_file_name(&self, file_name: &OsStr) -> PathBuf {
+ let mut buf = self.to_path_buf();
+ buf.set_file_name(file_name);
+ buf
+ }
+
+ /// Creates an owned [`PathBuf`] like `self` but with the given extension.
+ ///
+ /// See [`PathBuf::set_extension`] for more details.
+ ///
+ /// [`PathBuf`]: struct.PathBuf.html
+ /// [`PathBuf::set_extension`]: struct.PathBuf.html#method.set_extension
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::path::{Path, PathBuf};
+ ///
+ /// let path = Path::new("foo.rs");
+ /// assert_eq!(path.with_extension("txt"), PathBuf::from("foo.txt"));
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn with_extension<S: AsRef<OsStr>>(&self, extension: S) -> PathBuf {
+ self._with_extension(extension.as_ref())
+ }
+
+ fn _with_extension(&self, extension: &OsStr) -> PathBuf {
+ let mut buf = self.to_path_buf();
+ buf.set_extension(extension);
+ buf
+ }
+
+ /// Produces an iterator over the [`Component`]s of the path.
+ ///
+ /// When parsing the path, there is a small amount of normalization:
+ ///
+ /// * Repeated separators are ignored, so `a/b` and `a//b` both have
+ /// `a` and `b` as components.
+ ///
+ /// * Occurrences of `.` are normalized away, except if they are at the
+ /// beginning of the path. For example, `a/./b`, `a/b/`, `a/b/.` and
+ /// `a/b` all have `a` and `b` as components, but `./a/b` starts with
+ /// an additional [`CurDir`] component.
+ ///
+ /// * A trailing slash is normalized away, `/a/b` and `/a/b/` are equivalent.
+ ///
+ /// Note that no other normalization takes place; in particular, `a/c`
+ /// and `a/b/../c` are distinct, to account for the possibility that `b`
+ /// is a symbolic link (so its parent isn't `a`).
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::path::{Path, Component};
+ /// use std::ffi::OsStr;
+ ///
+ /// let mut components = Path::new("/tmp/foo.txt").components();
+ ///
+ /// assert_eq!(components.next(), Some(Component::RootDir));
+ /// assert_eq!(components.next(), Some(Component::Normal(OsStr::new("tmp"))));
+ /// assert_eq!(components.next(), Some(Component::Normal(OsStr::new("foo.txt"))));
+ /// assert_eq!(components.next(), None)
+ /// ```
+ ///
+ /// [`Component`]: enum.Component.html
+ /// [`CurDir`]: enum.Component.html#variant.CurDir
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn components(&self) -> Components<'_> {
+ let prefix = parse_prefix(self.as_os_str());
+ Components {
+ path: self.as_u8_slice(),
+ prefix,
+ has_physical_root: has_physical_root(self.as_u8_slice(), prefix) ||
+ has_redox_scheme(self.as_u8_slice()),
+ front: State::Prefix,
+ back: State::Body,
+ }
+ }
+
+ /// Produces an iterator over the path's components viewed as [`OsStr`]
+ /// slices.
+ ///
+ /// For more information about the particulars of how the path is separated
+ /// into components, see [`components`].
+ ///
+ /// [`components`]: #method.components
+ /// [`OsStr`]: ../ffi/struct.OsStr.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::path::{self, Path};
+ /// use std::ffi::OsStr;
+ ///
+ /// let mut it = Path::new("/tmp/foo.txt").iter();
+ /// assert_eq!(it.next(), Some(OsStr::new(&path::MAIN_SEPARATOR.to_string())));
+ /// assert_eq!(it.next(), Some(OsStr::new("tmp")));
+ /// assert_eq!(it.next(), Some(OsStr::new("foo.txt")));
+ /// assert_eq!(it.next(), None)
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn iter(&self) -> Iter<'_> {
+ Iter { inner: self.components() }
+ }
+
+ /// Returns an object that implements [`Display`] for safely printing paths
+ /// that may contain non-Unicode data.
+ ///
+ /// [`Display`]: ../fmt/trait.Display.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::path::Path;
+ ///
+ /// let path = Path::new("/tmp/foo.rs");
+ ///
+ /// println!("{}", path.display());
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn display(&self) -> Display<'_> {
+ Display { path: self }
+ }
+
+ /// Queries the file system to get information about a file, directory, etc.
+ ///
+ /// This function will traverse symbolic links to query information about the
+ /// destination file.
+ ///
+ /// This is an alias to [`fs::metadata`].
+ ///
+ /// [`fs::metadata`]: ../fs/fn.metadata.html
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::path::Path;
+ ///
+ /// let path = Path::new("/Minas/tirith");
+ /// let metadata = path.metadata().expect("metadata call failed");
+ /// println!("{:?}", metadata.file_type());
+ /// ```
+ #[stable(feature = "path_ext", since = "1.5.0")]
+ pub fn metadata(&self) -> io::Result<fs::Metadata> {
+ fs::metadata(self)
+ }
+
+ /// Queries the metadata about a file without following symlinks.
+ ///
+ /// This is an alias to [`fs::symlink_metadata`].
+ ///
+ /// [`fs::symlink_metadata`]: ../fs/fn.symlink_metadata.html
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::path::Path;
+ ///
+ /// let path = Path::new("/Minas/tirith");
+ /// let metadata = path.symlink_metadata().expect("symlink_metadata call failed");
+ /// println!("{:?}", metadata.file_type());
+ /// ```
+ #[stable(feature = "path_ext", since = "1.5.0")]
+ pub fn symlink_metadata(&self) -> io::Result<fs::Metadata> {
+ fs::symlink_metadata(self)
+ }
+
+ /// Returns the canonical, absolute form of the path with all intermediate
+ /// components normalized and symbolic links resolved.
+ ///
+ /// This is an alias to [`fs::canonicalize`].
+ ///
+ /// [`fs::canonicalize`]: ../fs/fn.canonicalize.html
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::path::{Path, PathBuf};
+ ///
+ /// let path = Path::new("/foo/test/../test/bar.rs");
+ /// assert_eq!(path.canonicalize().unwrap(), PathBuf::from("/foo/test/bar.rs"));
+ /// ```
+ #[stable(feature = "path_ext", since = "1.5.0")]
+ pub fn canonicalize(&self) -> io::Result<PathBuf> {
+ fs::canonicalize(self)
+ }
+
+ /// Reads a symbolic link, returning the file that the link points to.
+ ///
+ /// This is an alias to [`fs::read_link`].
+ ///
+ /// [`fs::read_link`]: ../fs/fn.read_link.html
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::path::Path;
+ ///
+ /// let path = Path::new("/laputa/sky_castle.rs");
+ /// let path_link = path.read_link().expect("read_link call failed");
+ /// ```
+ #[stable(feature = "path_ext", since = "1.5.0")]
+ pub fn read_link(&self) -> io::Result<PathBuf> {
+ fs::read_link(self)
+ }
+
+ /// Returns an iterator over the entries within a directory.
+ ///
+ /// The iterator will yield instances of [`io::Result`]`<`[`DirEntry`]`>`. New
+ /// errors may be encountered after an iterator is initially constructed.
+ ///
+ /// This is an alias to [`fs::read_dir`].
+ ///
+ /// [`io::Result`]: ../io/type.Result.html
+ /// [`DirEntry`]: ../fs/struct.DirEntry.html
+ /// [`fs::read_dir`]: ../fs/fn.read_dir.html
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::path::Path;
+ ///
+ /// let path = Path::new("/laputa");
+ /// for entry in path.read_dir().expect("read_dir call failed") {
+ /// if let Ok(entry) = entry {
+ /// println!("{:?}", entry.path());
+ /// }
+ /// }
+ /// ```
+ #[stable(feature = "path_ext", since = "1.5.0")]
+ pub fn read_dir(&self) -> io::Result<fs::ReadDir> {
+ fs::read_dir(self)
+ }
+
+ /// Returns `true` if the path points at an existing entity.
+ ///
+ /// This function will traverse symbolic links to query information about the
+ /// destination file. In case of broken symbolic links this will return `false`.
+ ///
+ /// If you cannot access the directory containing the file, e.g., because of a
+ /// permission error, this will return `false`.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::path::Path;
+ /// assert_eq!(Path::new("does_not_exist.txt").exists(), false);
+ /// ```
+ ///
+ /// # See Also
+ ///
+ /// This is a convenience function that coerces errors to false. If you want to
+ /// check errors, call [fs::metadata].
+ ///
+ /// [fs::metadata]: ../../std/fs/fn.metadata.html
+ #[stable(feature = "path_ext", since = "1.5.0")]
+ pub fn exists(&self) -> bool {
+ fs::metadata(self).is_ok()
+ }
+
+ /// Returns `true` if the path exists on disk and is pointing at a regular file.
+ ///
+ /// This function will traverse symbolic links to query information about the
+ /// destination file. In case of broken symbolic links this will return `false`.
+ ///
+ /// If you cannot access the directory containing the file, e.g., because of a
+ /// permission error, this will return `false`.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::path::Path;
+ /// assert_eq!(Path::new("./is_a_directory/").is_file(), false);
+ /// assert_eq!(Path::new("a_file.txt").is_file(), true);
+ /// ```
+ ///
+ /// # See Also
+ ///
+ /// This is a convenience function that coerces errors to false. If you want to
+ /// check errors, call [fs::metadata] and handle its Result. Then call
+ /// [fs::Metadata::is_file] if it was Ok.
+ ///
+ /// [fs::metadata]: ../../std/fs/fn.metadata.html
+ /// [fs::Metadata::is_file]: ../../std/fs/struct.Metadata.html#method.is_file
+ #[stable(feature = "path_ext", since = "1.5.0")]
+ pub fn is_file(&self) -> bool {
+ fs::metadata(self).map(|m| m.is_file()).unwrap_or(false)
+ }
+
+ /// Returns `true` if the path exists on disk and is pointing at a directory.
+ ///
+ /// This function will traverse symbolic links to query information about the
+ /// destination file. In case of broken symbolic links this will return `false`.
+ ///
+ /// If you cannot access the directory containing the file, e.g., because of a
+ /// permission error, this will return `false`.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::path::Path;
+ /// assert_eq!(Path::new("./is_a_directory/").is_dir(), true);
+ /// assert_eq!(Path::new("a_file.txt").is_dir(), false);
+ /// ```
+ ///
+ /// # See Also
+ ///
+ /// This is a convenience function that coerces errors to false. If you want to
+ /// check errors, call [fs::metadata] and handle its Result. Then call
+ /// [fs::Metadata::is_dir] if it was Ok.
+ ///
+ /// [fs::metadata]: ../../std/fs/fn.metadata.html
+ /// [fs::Metadata::is_dir]: ../../std/fs/struct.Metadata.html#method.is_dir
+ #[stable(feature = "path_ext", since = "1.5.0")]
+ pub fn is_dir(&self) -> bool {
+ fs::metadata(self).map(|m| m.is_dir()).unwrap_or(false)
+ }
+
+ /// Converts a [`Box<Path>`][`Box`] into a [`PathBuf`] without copying or
+ /// allocating.
+ ///
+ /// [`Box`]: ../../std/boxed/struct.Box.html
+ /// [`PathBuf`]: struct.PathBuf.html
+ #[stable(feature = "into_boxed_path", since = "1.20.0")]
+ pub fn into_path_buf(self: Box<Path>) -> PathBuf {
+ let rw = Box::into_raw(self) as *mut OsStr;
+ let inner = unsafe { Box::from_raw(rw) };
+ PathBuf { inner: OsString::from(inner) }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRef<OsStr> for Path {
+ fn as_ref(&self) -> &OsStr {
+ &self.inner
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl fmt::Debug for Path {
+ fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt::Debug::fmt(&self.inner, formatter)
+ }
+}
+
+/// Helper struct for safely printing paths with [`format!`] and `{}`.
+///
+/// A [`Path`] might contain non-Unicode data. This `struct` implements the
+/// [`Display`] trait in a way that mitigates that. It is created by the
+/// [`display`][`Path::display`] method on [`Path`].
+///
+/// # Examples
+///
+/// ```
+/// use std::path::Path;
+///
+/// let path = Path::new("/tmp/foo.rs");
+///
+/// println!("{}", path.display());
+/// ```
+///
+/// [`Display`]: ../../std/fmt/trait.Display.html
+/// [`format!`]: ../../std/macro.format.html
+/// [`Path`]: struct.Path.html
+/// [`Path::display`]: struct.Path.html#method.display
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct Display<'a> {
+ path: &'a Path,
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl fmt::Debug for Display<'_> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt::Debug::fmt(&self.path, f)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl fmt::Display for Display<'_> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ self.path.inner.display(f)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl cmp::PartialEq for Path {
+ fn eq(&self, other: &Path) -> bool {
+ self.components().eq(other.components())
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Hash for Path {
+ fn hash<H: Hasher>(&self, h: &mut H) {
+ for component in self.components() {
+ component.hash(h);
+ }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl cmp::Eq for Path {}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl cmp::PartialOrd for Path {
+ fn partial_cmp(&self, other: &Path) -> Option<cmp::Ordering> {
+ self.components().partial_cmp(other.components())
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl cmp::Ord for Path {
+ fn cmp(&self, other: &Path) -> cmp::Ordering {
+ self.components().cmp(other.components())
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRef<Path> for Path {
+ fn as_ref(&self) -> &Path {
+ self
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRef<Path> for OsStr {
+ fn as_ref(&self) -> &Path {
+ Path::new(self)
+ }
+}
+
+#[stable(feature = "cow_os_str_as_ref_path", since = "1.8.0")]
+impl AsRef<Path> for Cow<'_, OsStr> {
+ fn as_ref(&self) -> &Path {
+ Path::new(self)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRef<Path> for OsString {
+ fn as_ref(&self) -> &Path {
+ Path::new(self)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRef<Path> for str {
+ fn as_ref(&self) -> &Path {
+ Path::new(self)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRef<Path> for String {
+ fn as_ref(&self) -> &Path {
+ Path::new(self)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRef<Path> for PathBuf {
+ fn as_ref(&self) -> &Path {
+ self
+ }
+}
+
+#[stable(feature = "path_into_iter", since = "1.6.0")]
+impl<'a> IntoIterator for &'a PathBuf {
+ type Item = &'a OsStr;
+ type IntoIter = Iter<'a>;
+ fn into_iter(self) -> Iter<'a> { self.iter() }
+}
+
+#[stable(feature = "path_into_iter", since = "1.6.0")]
+impl<'a> IntoIterator for &'a Path {
+ type Item = &'a OsStr;
+ type IntoIter = Iter<'a>;
+ fn into_iter(self) -> Iter<'a> { self.iter() }
+}
+
+macro_rules! impl_cmp {
+ ($lhs:ty, $rhs: ty) => {
+ #[stable(feature = "partialeq_path", since = "1.6.0")]
+ impl<'a, 'b> PartialEq<$rhs> for $lhs {
+ #[inline]
+ fn eq(&self, other: &$rhs) -> bool { <Path as PartialEq>::eq(self, other) }
+ }
+
+ #[stable(feature = "partialeq_path", since = "1.6.0")]
+ impl<'a, 'b> PartialEq<$lhs> for $rhs {
+ #[inline]
+ fn eq(&self, other: &$lhs) -> bool { <Path as PartialEq>::eq(self, other) }
+ }
+
+ #[stable(feature = "cmp_path", since = "1.8.0")]
+ impl<'a, 'b> PartialOrd<$rhs> for $lhs {
+ #[inline]
+ fn partial_cmp(&self, other: &$rhs) -> Option<cmp::Ordering> {
+ <Path as PartialOrd>::partial_cmp(self, other)
+ }
+ }
+
+ #[stable(feature = "cmp_path", since = "1.8.0")]
+ impl<'a, 'b> PartialOrd<$lhs> for $rhs {
+ #[inline]
+ fn partial_cmp(&self, other: &$lhs) -> Option<cmp::Ordering> {
+ <Path as PartialOrd>::partial_cmp(self, other)
+ }
+ }
+ }
+}
+
+impl_cmp!(PathBuf, Path);
+impl_cmp!(PathBuf, &'a Path);
+impl_cmp!(Cow<'a, Path>, Path);
+impl_cmp!(Cow<'a, Path>, &'b Path);
+impl_cmp!(Cow<'a, Path>, PathBuf);
+
+macro_rules! impl_cmp_os_str {
+ ($lhs:ty, $rhs: ty) => {
+ #[stable(feature = "cmp_path", since = "1.8.0")]
+ impl<'a, 'b> PartialEq<$rhs> for $lhs {
+ #[inline]
+ fn eq(&self, other: &$rhs) -> bool { <Path as PartialEq>::eq(self, other.as_ref()) }
+ }
+
+ #[stable(feature = "cmp_path", since = "1.8.0")]
+ impl<'a, 'b> PartialEq<$lhs> for $rhs {
+ #[inline]
+ fn eq(&self, other: &$lhs) -> bool { <Path as PartialEq>::eq(self.as_ref(), other) }
+ }
+
+ #[stable(feature = "cmp_path", since = "1.8.0")]
+ impl<'a, 'b> PartialOrd<$rhs> for $lhs {
+ #[inline]
+ fn partial_cmp(&self, other: &$rhs) -> Option<cmp::Ordering> {
+ <Path as PartialOrd>::partial_cmp(self, other.as_ref())
+ }
+ }
+
+ #[stable(feature = "cmp_path", since = "1.8.0")]
+ impl<'a, 'b> PartialOrd<$lhs> for $rhs {
+ #[inline]
+ fn partial_cmp(&self, other: &$lhs) -> Option<cmp::Ordering> {
+ <Path as PartialOrd>::partial_cmp(self.as_ref(), other)
+ }
+ }
+ }
+}
+
+impl_cmp_os_str!(PathBuf, OsStr);
+impl_cmp_os_str!(PathBuf, &'a OsStr);
+impl_cmp_os_str!(PathBuf, Cow<'a, OsStr>);
+impl_cmp_os_str!(PathBuf, OsString);
+impl_cmp_os_str!(Path, OsStr);
+impl_cmp_os_str!(Path, &'a OsStr);
+impl_cmp_os_str!(Path, Cow<'a, OsStr>);
+impl_cmp_os_str!(Path, OsString);
+impl_cmp_os_str!(&'a Path, OsStr);
+impl_cmp_os_str!(&'a Path, Cow<'b, OsStr>);
+impl_cmp_os_str!(&'a Path, OsString);
+impl_cmp_os_str!(Cow<'a, Path>, OsStr);
+impl_cmp_os_str!(Cow<'a, Path>, &'b OsStr);
+impl_cmp_os_str!(Cow<'a, Path>, OsString);
+
+#[stable(since = "1.7.0", feature = "strip_prefix")]
+impl fmt::Display for StripPrefixError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ self.description().fmt(f)
+ }
+}
+
+#[stable(since = "1.7.0", feature = "strip_prefix")]
+impl Error for StripPrefixError {
+ fn description(&self) -> &str { "prefix not found" }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ use crate::rc::Rc;
+ use crate::sync::Arc;
+
+ macro_rules! t(
+ ($path:expr, iter: $iter:expr) => (
+ {
+ let path = Path::new($path);
+
+ // Forward iteration
+ let comps = path.iter()
+ .map(|p| p.to_string_lossy().into_owned())
+ .collect::<Vec<String>>();
+ let exp: &[&str] = &$iter;
+ let exps = exp.iter().map(|s| s.to_string()).collect::<Vec<String>>();
+ assert!(comps == exps, "iter: Expected {:?}, found {:?}",
+ exps, comps);
+
+ // Reverse iteration
+ let comps = Path::new($path).iter().rev()
+ .map(|p| p.to_string_lossy().into_owned())
+ .collect::<Vec<String>>();
+ let exps = exps.into_iter().rev().collect::<Vec<String>>();
+ assert!(comps == exps, "iter().rev(): Expected {:?}, found {:?}",
+ exps, comps);
+ }
+ );
+
+ ($path:expr, has_root: $has_root:expr, is_absolute: $is_absolute:expr) => (
+ {
+ let path = Path::new($path);
+
+ let act_root = path.has_root();
+ assert!(act_root == $has_root, "has_root: Expected {:?}, found {:?}",
+ $has_root, act_root);
+
+ let act_abs = path.is_absolute();
+ assert!(act_abs == $is_absolute, "is_absolute: Expected {:?}, found {:?}",
+ $is_absolute, act_abs);
+ }
+ );
+
+ ($path:expr, parent: $parent:expr, file_name: $file:expr) => (
+ {
+ let path = Path::new($path);
+
+ let parent = path.parent().map(|p| p.to_str().unwrap());
+ let exp_parent: Option<&str> = $parent;
+ assert!(parent == exp_parent, "parent: Expected {:?}, found {:?}",
+ exp_parent, parent);
+
+ let file = path.file_name().map(|p| p.to_str().unwrap());
+ let exp_file: Option<&str> = $file;
+ assert!(file == exp_file, "file_name: Expected {:?}, found {:?}",
+ exp_file, file);
+ }
+ );
+
+ ($path:expr, file_stem: $file_stem:expr, extension: $extension:expr) => (
+ {
+ let path = Path::new($path);
+
+ let stem = path.file_stem().map(|p| p.to_str().unwrap());
+ let exp_stem: Option<&str> = $file_stem;
+ assert!(stem == exp_stem, "file_stem: Expected {:?}, found {:?}",
+ exp_stem, stem);
+
+ let ext = path.extension().map(|p| p.to_str().unwrap());
+ let exp_ext: Option<&str> = $extension;
+ assert!(ext == exp_ext, "extension: Expected {:?}, found {:?}",
+ exp_ext, ext);
+ }
+ );
+
+ ($path:expr, iter: $iter:expr,
+ has_root: $has_root:expr, is_absolute: $is_absolute:expr,
+ parent: $parent:expr, file_name: $file:expr,
+ file_stem: $file_stem:expr, extension: $extension:expr) => (
+ {
+ t!($path, iter: $iter);
+ t!($path, has_root: $has_root, is_absolute: $is_absolute);
+ t!($path, parent: $parent, file_name: $file);
+ t!($path, file_stem: $file_stem, extension: $extension);
+ }
+ );
+ );
+
+ #[test]
+ fn into() {
+ use crate::borrow::Cow;
+
+ let static_path = Path::new("/home/foo");
+ let static_cow_path: Cow<'static, Path> = static_path.into();
+ let pathbuf = PathBuf::from("/home/foo");
+
+ {
+ let path: &Path = &pathbuf;
+ let borrowed_cow_path: Cow<'_, Path> = path.into();
+
+ assert_eq!(static_cow_path, borrowed_cow_path);
+ }
+
+ let owned_cow_path: Cow<'static, Path> = pathbuf.into();
+
+ assert_eq!(static_cow_path, owned_cow_path);
+ }
+
+ #[test]
+ #[cfg(unix)]
+ pub fn test_decompositions_unix() {
+ t!("",
+ iter: [],
+ has_root: false,
+ is_absolute: false,
+ parent: None,
+ file_name: None,
+ file_stem: None,
+ extension: None
+ );
+
+ t!("foo",
+ iter: ["foo"],
+ has_root: false,
+ is_absolute: false,
+ parent: Some(""),
+ file_name: Some("foo"),
+ file_stem: Some("foo"),
+ extension: None
+ );
+
+ t!("/",
+ iter: ["/"],
+ has_root: true,
+ is_absolute: true,
+ parent: None,
+ file_name: None,
+ file_stem: None,
+ extension: None
+ );
+
+ t!("/foo",
+ iter: ["/", "foo"],
+ has_root: true,
+ is_absolute: true,
+ parent: Some("/"),
+ file_name: Some("foo"),
+ file_stem: Some("foo"),
+ extension: None
+ );
+
+ t!("foo/",
+ iter: ["foo"],
+ has_root: false,
+ is_absolute: false,
+ parent: Some(""),
+ file_name: Some("foo"),
+ file_stem: Some("foo"),
+ extension: None
+ );
+
+ t!("/foo/",
+ iter: ["/", "foo"],
+ has_root: true,
+ is_absolute: true,
+ parent: Some("/"),
+ file_name: Some("foo"),
+ file_stem: Some("foo"),
+ extension: None
+ );
+
+ t!("foo/bar",
+ iter: ["foo", "bar"],
+ has_root: false,
+ is_absolute: false,
+ parent: Some("foo"),
+ file_name: Some("bar"),
+ file_stem: Some("bar"),
+ extension: None
+ );
+
+ t!("/foo/bar",
+ iter: ["/", "foo", "bar"],
+ has_root: true,
+ is_absolute: true,
+ parent: Some("/foo"),
+ file_name: Some("bar"),
+ file_stem: Some("bar"),
+ extension: None
+ );
+
+ t!("///foo///",
+ iter: ["/", "foo"],
+ has_root: true,
+ is_absolute: true,
+ parent: Some("/"),
+ file_name: Some("foo"),
+ file_stem: Some("foo"),
+ extension: None
+ );
+
+ t!("///foo///bar",
+ iter: ["/", "foo", "bar"],
+ has_root: true,
+ is_absolute: true,
+ parent: Some("///foo"),
+ file_name: Some("bar"),
+ file_stem: Some("bar"),
+ extension: None
+ );
+
+ t!("./.",
+ iter: ["."],
+ has_root: false,
+ is_absolute: false,
+ parent: Some(""),
+ file_name: None,
+ file_stem: None,
+ extension: None
+ );
+
+ t!("/..",
+ iter: ["/", ".."],
+ has_root: true,
+ is_absolute: true,
+ parent: Some("/"),
+ file_name: None,
+ file_stem: None,
+ extension: None
+ );
+
+ t!("../",
+ iter: [".."],
+ has_root: false,
+ is_absolute: false,
+ parent: Some(""),
+ file_name: None,
+ file_stem: None,
+ extension: None
+ );
+
+ t!("foo/.",
+ iter: ["foo"],
+ has_root: false,
+ is_absolute: false,
+ parent: Some(""),
+ file_name: Some("foo"),
+ file_stem: Some("foo"),
+ extension: None
+ );
+
+ t!("foo/..",
+ iter: ["foo", ".."],
+ has_root: false,
+ is_absolute: false,
+ parent: Some("foo"),
+ file_name: None,
+ file_stem: None,
+ extension: None
+ );
+
+ t!("foo/./",
+ iter: ["foo"],
+ has_root: false,
+ is_absolute: false,
+ parent: Some(""),
+ file_name: Some("foo"),
+ file_stem: Some("foo"),
+ extension: None
+ );
+
+ t!("foo/./bar",
+ iter: ["foo", "bar"],
+ has_root: false,
+ is_absolute: false,
+ parent: Some("foo"),
+ file_name: Some("bar"),
+ file_stem: Some("bar"),
+ extension: None
+ );
+
+ t!("foo/../",
+ iter: ["foo", ".."],
+ has_root: false,
+ is_absolute: false,
+ parent: Some("foo"),
+ file_name: None,
+ file_stem: None,
+ extension: None
+ );
+
+ t!("foo/../bar",
+ iter: ["foo", "..", "bar"],
+ has_root: false,
+ is_absolute: false,
+ parent: Some("foo/.."),
+ file_name: Some("bar"),
+ file_stem: Some("bar"),
+ extension: None
+ );
+
+ t!("./a",
+ iter: [".", "a"],
+ has_root: false,
+ is_absolute: false,
+ parent: Some("."),
+ file_name: Some("a"),
+ file_stem: Some("a"),
+ extension: None
+ );
+
+ t!(".",
+ iter: ["."],
+ has_root: false,
+ is_absolute: false,
+ parent: Some(""),
+ file_name: None,
+ file_stem: None,
+ extension: None
+ );
+
+ t!("./",
+ iter: ["."],
+ has_root: false,
+ is_absolute: false,
+ parent: Some(""),
+ file_name: None,
+ file_stem: None,
+ extension: None
+ );
+
+ t!("a/b",
+ iter: ["a", "b"],
+ has_root: false,
+ is_absolute: false,
+ parent: Some("a"),
+ file_name: Some("b"),
+ file_stem: Some("b"),
+ extension: None
+ );
+
+ t!("a//b",
+ iter: ["a", "b"],
+ has_root: false,
+ is_absolute: false,
+ parent: Some("a"),
+ file_name: Some("b"),
+ file_stem: Some("b"),
+ extension: None
+ );
+
+ t!("a/./b",
+ iter: ["a", "b"],
+ has_root: false,
+ is_absolute: false,
+ parent: Some("a"),
+ file_name: Some("b"),
+ file_stem: Some("b"),
+ extension: None
+ );
+
+ t!("a/b/c",
+ iter: ["a", "b", "c"],
+ has_root: false,
+ is_absolute: false,
+ parent: Some("a/b"),
+ file_name: Some("c"),
+ file_stem: Some("c"),
+ extension: None
+ );
+
+ t!(".foo",
+ iter: [".foo"],
+ has_root: false,
+ is_absolute: false,
+ parent: Some(""),
+ file_name: Some(".foo"),
+ file_stem: Some(".foo"),
+ extension: None
+ );
+ }
+
+ #[test]
+ #[cfg(windows)]
+ pub fn test_decompositions_windows() {
+ t!("",
+ iter: [],
+ has_root: false,
+ is_absolute: false,
+ parent: None,
+ file_name: None,
+ file_stem: None,
+ extension: None
+ );
+
+ t!("foo",
+ iter: ["foo"],
+ has_root: false,
+ is_absolute: false,
+ parent: Some(""),
+ file_name: Some("foo"),
+ file_stem: Some("foo"),
+ extension: None
+ );
+
+ t!("/",
+ iter: ["\\"],
+ has_root: true,
+ is_absolute: false,
+ parent: None,
+ file_name: None,
+ file_stem: None,
+ extension: None
+ );
+
+ t!("\\",
+ iter: ["\\"],
+ has_root: true,
+ is_absolute: false,
+ parent: None,
+ file_name: None,
+ file_stem: None,
+ extension: None
+ );
+
+ t!("c:",
+ iter: ["c:"],
+ has_root: false,
+ is_absolute: false,
+ parent: None,
+ file_name: None,
+ file_stem: None,
+ extension: None
+ );
+
+ t!("c:\\",
+ iter: ["c:", "\\"],
+ has_root: true,
+ is_absolute: true,
+ parent: None,
+ file_name: None,
+ file_stem: None,
+ extension: None
+ );
+
+ t!("c:/",
+ iter: ["c:", "\\"],
+ has_root: true,
+ is_absolute: true,
+ parent: None,
+ file_name: None,
+ file_stem: None,
+ extension: None
+ );
+
+ t!("/foo",
+ iter: ["\\", "foo"],
+ has_root: true,
+ is_absolute: false,
+ parent: Some("/"),
+ file_name: Some("foo"),
+ file_stem: Some("foo"),
+ extension: None
+ );
+
+ t!("foo/",
+ iter: ["foo"],
+ has_root: false,
+ is_absolute: false,
+ parent: Some(""),
+ file_name: Some("foo"),
+ file_stem: Some("foo"),
+ extension: None
+ );
+
+ t!("/foo/",
+ iter: ["\\", "foo"],
+ has_root: true,
+ is_absolute: false,
+ parent: Some("/"),
+ file_name: Some("foo"),
+ file_stem: Some("foo"),
+ extension: None
+ );
+
+ t!("foo/bar",
+ iter: ["foo", "bar"],
+ has_root: false,
+ is_absolute: false,
+ parent: Some("foo"),
+ file_name: Some("bar"),
+ file_stem: Some("bar"),
+ extension: None
+ );
+
+ t!("/foo/bar",
+ iter: ["\\", "foo", "bar"],
+ has_root: true,
+ is_absolute: false,
+ parent: Some("/foo"),
+ file_name: Some("bar"),
+ file_stem: Some("bar"),
+ extension: None
+ );
+
+ t!("///foo///",
+ iter: ["\\", "foo"],
+ has_root: true,
+ is_absolute: false,
+ parent: Some("/"),
+ file_name: Some("foo"),
+ file_stem: Some("foo"),
+ extension: None
+ );
+
+ t!("///foo///bar",
+ iter: ["\\", "foo", "bar"],
+ has_root: true,
+ is_absolute: false,
+ parent: Some("///foo"),
+ file_name: Some("bar"),
+ file_stem: Some("bar"),
+ extension: None
+ );
+
+ t!("./.",
+ iter: ["."],
+ has_root: false,
+ is_absolute: false,
+ parent: Some(""),
+ file_name: None,
+ file_stem: None,
+ extension: None
+ );
+
+ t!("/..",
+ iter: ["\\", ".."],
+ has_root: true,
+ is_absolute: false,
+ parent: Some("/"),
+ file_name: None,
+ file_stem: None,
+ extension: None
+ );
+
+ t!("../",
+ iter: [".."],
+ has_root: false,
+ is_absolute: false,
+ parent: Some(""),
+ file_name: None,
+ file_stem: None,
+ extension: None
+ );
+
+ t!("foo/.",
+ iter: ["foo"],
+ has_root: false,
+ is_absolute: false,
+ parent: Some(""),
+ file_name: Some("foo"),
+ file_stem: Some("foo"),
+ extension: None
+ );
+
+ t!("foo/..",
+ iter: ["foo", ".."],
+ has_root: false,
+ is_absolute: false,
+ parent: Some("foo"),
+ file_name: None,
+ file_stem: None,
+ extension: None
+ );
+
+ t!("foo/./",
+ iter: ["foo"],
+ has_root: false,
+ is_absolute: false,
+ parent: Some(""),
+ file_name: Some("foo"),
+ file_stem: Some("foo"),
+ extension: None
+ );
+
+ t!("foo/./bar",
+ iter: ["foo", "bar"],
+ has_root: false,
+ is_absolute: false,
+ parent: Some("foo"),
+ file_name: Some("bar"),
+ file_stem: Some("bar"),
+ extension: None
+ );
+
+ t!("foo/../",
+ iter: ["foo", ".."],
+ has_root: false,
+ is_absolute: false,
+ parent: Some("foo"),
+ file_name: None,
+ file_stem: None,
+ extension: None
+ );
+
+ t!("foo/../bar",
+ iter: ["foo", "..", "bar"],
+ has_root: false,
+ is_absolute: false,
+ parent: Some("foo/.."),
+ file_name: Some("bar"),
+ file_stem: Some("bar"),
+ extension: None
+ );
+
+ t!("./a",
+ iter: [".", "a"],
+ has_root: false,
+ is_absolute: false,
+ parent: Some("."),
+ file_name: Some("a"),
+ file_stem: Some("a"),
+ extension: None
+ );
+
+ t!(".",
+ iter: ["."],
+ has_root: false,
+ is_absolute: false,
+ parent: Some(""),
+ file_name: None,
+ file_stem: None,
+ extension: None
+ );
+
+ t!("./",
+ iter: ["."],
+ has_root: false,
+ is_absolute: false,
+ parent: Some(""),
+ file_name: None,
+ file_stem: None,
+ extension: None
+ );
+
+ t!("a/b",
+ iter: ["a", "b"],
+ has_root: false,
+ is_absolute: false,
+ parent: Some("a"),
+ file_name: Some("b"),
+ file_stem: Some("b"),
+ extension: None
+ );
+
+ t!("a//b",
+ iter: ["a", "b"],
+ has_root: false,
+ is_absolute: false,
+ parent: Some("a"),
+ file_name: Some("b"),
+ file_stem: Some("b"),
+ extension: None
+ );
+
+ t!("a/./b",
+ iter: ["a", "b"],
+ has_root: false,
+ is_absolute: false,
+ parent: Some("a"),
+ file_name: Some("b"),
+ file_stem: Some("b"),
+ extension: None
+ );
+
+ t!("a/b/c",
+ iter: ["a", "b", "c"],
+ has_root: false,
+ is_absolute: false,
+ parent: Some("a/b"),
+ file_name: Some("c"),
+ file_stem: Some("c"),
+ extension: None);
+
+ t!("a\\b\\c",
+ iter: ["a", "b", "c"],
+ has_root: false,
+ is_absolute: false,
+ parent: Some("a\\b"),
+ file_name: Some("c"),
+ file_stem: Some("c"),
+ extension: None
+ );
+
+ t!("\\a",
+ iter: ["\\", "a"],
+ has_root: true,
+ is_absolute: false,
+ parent: Some("\\"),
+ file_name: Some("a"),
+ file_stem: Some("a"),
+ extension: None
+ );
+
+ t!("c:\\foo.txt",
+ iter: ["c:", "\\", "foo.txt"],
+ has_root: true,
+ is_absolute: true,
+ parent: Some("c:\\"),
+ file_name: Some("foo.txt"),
+ file_stem: Some("foo"),
+ extension: Some("txt")
+ );
+
+ t!("\\\\server\\share\\foo.txt",
+ iter: ["\\\\server\\share", "\\", "foo.txt"],
+ has_root: true,
+ is_absolute: true,
+ parent: Some("\\\\server\\share\\"),
+ file_name: Some("foo.txt"),
+ file_stem: Some("foo"),
+ extension: Some("txt")
+ );
+
+ t!("\\\\server\\share",
+ iter: ["\\\\server\\share", "\\"],
+ has_root: true,
+ is_absolute: true,
+ parent: None,
+ file_name: None,
+ file_stem: None,
+ extension: None
+ );
+
+ t!("\\\\server",
+ iter: ["\\", "server"],
+ has_root: true,
+ is_absolute: false,
+ parent: Some("\\"),
+ file_name: Some("server"),
+ file_stem: Some("server"),
+ extension: None
+ );
+
+ t!("\\\\?\\bar\\foo.txt",
+ iter: ["\\\\?\\bar", "\\", "foo.txt"],
+ has_root: true,
+ is_absolute: true,
+ parent: Some("\\\\?\\bar\\"),
+ file_name: Some("foo.txt"),
+ file_stem: Some("foo"),
+ extension: Some("txt")
+ );
+
+ t!("\\\\?\\bar",
+ iter: ["\\\\?\\bar"],
+ has_root: true,
+ is_absolute: true,
+ parent: None,
+ file_name: None,
+ file_stem: None,
+ extension: None
+ );
+
+ t!("\\\\?\\",
+ iter: ["\\\\?\\"],
+ has_root: true,
+ is_absolute: true,
+ parent: None,
+ file_name: None,
+ file_stem: None,
+ extension: None
+ );
+
+ t!("\\\\?\\UNC\\server\\share\\foo.txt",
+ iter: ["\\\\?\\UNC\\server\\share", "\\", "foo.txt"],
+ has_root: true,
+ is_absolute: true,
+ parent: Some("\\\\?\\UNC\\server\\share\\"),
+ file_name: Some("foo.txt"),
+ file_stem: Some("foo"),
+ extension: Some("txt")
+ );
+
+ t!("\\\\?\\UNC\\server",
+ iter: ["\\\\?\\UNC\\server"],
+ has_root: true,
+ is_absolute: true,
+ parent: None,
+ file_name: None,
+ file_stem: None,
+ extension: None
+ );
+
+ t!("\\\\?\\UNC\\",
+ iter: ["\\\\?\\UNC\\"],
+ has_root: true,
+ is_absolute: true,
+ parent: None,
+ file_name: None,
+ file_stem: None,
+ extension: None
+ );
+
+ t!("\\\\?\\C:\\foo.txt",
+ iter: ["\\\\?\\C:", "\\", "foo.txt"],
+ has_root: true,
+ is_absolute: true,
+ parent: Some("\\\\?\\C:\\"),
+ file_name: Some("foo.txt"),
+ file_stem: Some("foo"),
+ extension: Some("txt")
+ );
+
+
+ t!("\\\\?\\C:\\",
+ iter: ["\\\\?\\C:", "\\"],
+ has_root: true,
+ is_absolute: true,
+ parent: None,
+ file_name: None,
+ file_stem: None,
+ extension: None
+ );
+
+
+ t!("\\\\?\\C:",
+ iter: ["\\\\?\\C:"],
+ has_root: true,
+ is_absolute: true,
+ parent: None,
+ file_name: None,
+ file_stem: None,
+ extension: None
+ );
+
+
+ t!("\\\\?\\foo/bar",
+ iter: ["\\\\?\\foo/bar"],
+ has_root: true,
+ is_absolute: true,
+ parent: None,
+ file_name: None,
+ file_stem: None,
+ extension: None
+ );
+
+
+ t!("\\\\?\\C:/foo",
+ iter: ["\\\\?\\C:/foo"],
+ has_root: true,
+ is_absolute: true,
+ parent: None,
+ file_name: None,
+ file_stem: None,
+ extension: None
+ );
+
+
+ t!("\\\\.\\foo\\bar",
+ iter: ["\\\\.\\foo", "\\", "bar"],
+ has_root: true,
+ is_absolute: true,
+ parent: Some("\\\\.\\foo\\"),
+ file_name: Some("bar"),
+ file_stem: Some("bar"),
+ extension: None
+ );
+
+
+ t!("\\\\.\\foo",
+ iter: ["\\\\.\\foo", "\\"],
+ has_root: true,
+ is_absolute: true,
+ parent: None,
+ file_name: None,
+ file_stem: None,
+ extension: None
+ );
+
+
+ t!("\\\\.\\foo/bar",
+ iter: ["\\\\.\\foo/bar", "\\"],
+ has_root: true,
+ is_absolute: true,
+ parent: None,
+ file_name: None,
+ file_stem: None,
+ extension: None
+ );
+
+
+ t!("\\\\.\\foo\\bar/baz",
+ iter: ["\\\\.\\foo", "\\", "bar", "baz"],
+ has_root: true,
+ is_absolute: true,
+ parent: Some("\\\\.\\foo\\bar"),
+ file_name: Some("baz"),
+ file_stem: Some("baz"),
+ extension: None
+ );
+
+
+ t!("\\\\.\\",
+ iter: ["\\\\.\\", "\\"],
+ has_root: true,
+ is_absolute: true,
+ parent: None,
+ file_name: None,
+ file_stem: None,
+ extension: None
+ );
+
+ t!("\\\\?\\a\\b\\",
+ iter: ["\\\\?\\a", "\\", "b"],
+ has_root: true,
+ is_absolute: true,
+ parent: Some("\\\\?\\a\\"),
+ file_name: Some("b"),
+ file_stem: Some("b"),
+ extension: None
+ );
+ }
+
+ #[test]
+ pub fn test_stem_ext() {
+ t!("foo",
+ file_stem: Some("foo"),
+ extension: None
+ );
+
+ t!("foo.",
+ file_stem: Some("foo"),
+ extension: Some("")
+ );
+
+ t!(".foo",
+ file_stem: Some(".foo"),
+ extension: None
+ );
+
+ t!("foo.txt",
+ file_stem: Some("foo"),
+ extension: Some("txt")
+ );
+
+ t!("foo.bar.txt",
+ file_stem: Some("foo.bar"),
+ extension: Some("txt")
+ );
+
+ t!("foo.bar.",
+ file_stem: Some("foo.bar"),
+ extension: Some("")
+ );
+
+ t!(".",
+ file_stem: None,
+ extension: None
+ );
+
+ t!("..",
+ file_stem: None,
+ extension: None
+ );
+
+ t!("",
+ file_stem: None,
+ extension: None
+ );
+ }
+
+ #[test]
+ pub fn test_push() {
+ macro_rules! tp(
+ ($path:expr, $push:expr, $expected:expr) => ( {
+ let mut actual = PathBuf::from($path);
+ actual.push($push);
+ assert!(actual.to_str() == Some($expected),
+ "pushing {:?} onto {:?}: Expected {:?}, got {:?}",
+ $push, $path, $expected, actual.to_str().unwrap());
+ });
+ );
+
+ if cfg!(unix) || cfg!(all(target_env = "sgx", target_vendor = "fortanix")) {
+ tp!("", "foo", "foo");
+ tp!("foo", "bar", "foo/bar");
+ tp!("foo/", "bar", "foo/bar");
+ tp!("foo//", "bar", "foo//bar");
+ tp!("foo/.", "bar", "foo/./bar");
+ tp!("foo./.", "bar", "foo././bar");
+ tp!("foo", "", "foo/");
+ tp!("foo", ".", "foo/.");
+ tp!("foo", "..", "foo/..");
+ tp!("foo", "/", "/");
+ tp!("/foo/bar", "/", "/");
+ tp!("/foo/bar", "/baz", "/baz");
+ tp!("/foo/bar", "./baz", "/foo/bar/./baz");
+ } else {
+ tp!("", "foo", "foo");
+ tp!("foo", "bar", r"foo\bar");
+ tp!("foo/", "bar", r"foo/bar");
+ tp!(r"foo\", "bar", r"foo\bar");
+ tp!("foo//", "bar", r"foo//bar");
+ tp!(r"foo\\", "bar", r"foo\\bar");
+ tp!("foo/.", "bar", r"foo/.\bar");
+ tp!("foo./.", "bar", r"foo./.\bar");
+ tp!(r"foo\.", "bar", r"foo\.\bar");
+ tp!(r"foo.\.", "bar", r"foo.\.\bar");
+ tp!("foo", "", "foo\\");
+ tp!("foo", ".", r"foo\.");
+ tp!("foo", "..", r"foo\..");
+ tp!("foo", "/", "/");
+ tp!("foo", r"\", r"\");
+ tp!("/foo/bar", "/", "/");
+ tp!(r"\foo\bar", r"\", r"\");
+ tp!("/foo/bar", "/baz", "/baz");
+ tp!("/foo/bar", r"\baz", r"\baz");
+ tp!("/foo/bar", "./baz", r"/foo/bar\./baz");
+ tp!("/foo/bar", r".\baz", r"/foo/bar\.\baz");
+
+ tp!("c:\\", "windows", "c:\\windows");
+ tp!("c:", "windows", "c:windows");
+
+ tp!("a\\b\\c", "d", "a\\b\\c\\d");
+ tp!("\\a\\b\\c", "d", "\\a\\b\\c\\d");
+ tp!("a\\b", "c\\d", "a\\b\\c\\d");
+ tp!("a\\b", "\\c\\d", "\\c\\d");
+ tp!("a\\b", ".", "a\\b\\.");
+ tp!("a\\b", "..\\c", "a\\b\\..\\c");
+ tp!("a\\b", "C:a.txt", "C:a.txt");
+ tp!("a\\b", "C:\\a.txt", "C:\\a.txt");
+ tp!("C:\\a", "C:\\b.txt", "C:\\b.txt");
+ tp!("C:\\a\\b\\c", "C:d", "C:d");
+ tp!("C:a\\b\\c", "C:d", "C:d");
+ tp!("C:", r"a\b\c", r"C:a\b\c");
+ tp!("C:", r"..\a", r"C:..\a");
+ tp!("\\\\server\\share\\foo",
+ "bar",
+ "\\\\server\\share\\foo\\bar");
+ tp!("\\\\server\\share\\foo", "C:baz", "C:baz");
+ tp!("\\\\?\\C:\\a\\b", "C:c\\d", "C:c\\d");
+ tp!("\\\\?\\C:a\\b", "C:c\\d", "C:c\\d");
+ tp!("\\\\?\\C:\\a\\b", "C:\\c\\d", "C:\\c\\d");
+ tp!("\\\\?\\foo\\bar", "baz", "\\\\?\\foo\\bar\\baz");
+ tp!("\\\\?\\UNC\\server\\share\\foo",
+ "bar",
+ "\\\\?\\UNC\\server\\share\\foo\\bar");
+ tp!("\\\\?\\UNC\\server\\share", "C:\\a", "C:\\a");
+ tp!("\\\\?\\UNC\\server\\share", "C:a", "C:a");
+
+ // Note: modified from old path API
+ tp!("\\\\?\\UNC\\server", "foo", "\\\\?\\UNC\\server\\foo");
+
+ tp!("C:\\a",
+ "\\\\?\\UNC\\server\\share",
+ "\\\\?\\UNC\\server\\share");
+ tp!("\\\\.\\foo\\bar", "baz", "\\\\.\\foo\\bar\\baz");
+ tp!("\\\\.\\foo\\bar", "C:a", "C:a");
+ // again, not sure about the following, but I'm assuming \\.\ should be verbatim
+ tp!("\\\\.\\foo", "..\\bar", "\\\\.\\foo\\..\\bar");
+
+ tp!("\\\\?\\C:", "foo", "\\\\?\\C:\\foo"); // this is a weird one
+ }
+ }
+
+ #[test]
+ pub fn test_pop() {
+ macro_rules! tp(
+ ($path:expr, $expected:expr, $output:expr) => ( {
+ let mut actual = PathBuf::from($path);
+ let output = actual.pop();
+ assert!(actual.to_str() == Some($expected) && output == $output,
+ "popping from {:?}: Expected {:?}/{:?}, got {:?}/{:?}",
+ $path, $expected, $output,
+ actual.to_str().unwrap(), output);
+ });
+ );
+
+ tp!("", "", false);
+ tp!("/", "/", false);
+ tp!("foo", "", true);
+ tp!(".", "", true);
+ tp!("/foo", "/", true);
+ tp!("/foo/bar", "/foo", true);
+ tp!("foo/bar", "foo", true);
+ tp!("foo/.", "", true);
+ tp!("foo//bar", "foo", true);
+
+ if cfg!(windows) {
+ tp!("a\\b\\c", "a\\b", true);
+ tp!("\\a", "\\", true);
+ tp!("\\", "\\", false);
+
+ tp!("C:\\a\\b", "C:\\a", true);
+ tp!("C:\\a", "C:\\", true);
+ tp!("C:\\", "C:\\", false);
+ tp!("C:a\\b", "C:a", true);
+ tp!("C:a", "C:", true);
+ tp!("C:", "C:", false);
+ tp!("\\\\server\\share\\a\\b", "\\\\server\\share\\a", true);
+ tp!("\\\\server\\share\\a", "\\\\server\\share\\", true);
+ tp!("\\\\server\\share", "\\\\server\\share", false);
+ tp!("\\\\?\\a\\b\\c", "\\\\?\\a\\b", true);
+ tp!("\\\\?\\a\\b", "\\\\?\\a\\", true);
+ tp!("\\\\?\\a", "\\\\?\\a", false);
+ tp!("\\\\?\\C:\\a\\b", "\\\\?\\C:\\a", true);
+ tp!("\\\\?\\C:\\a", "\\\\?\\C:\\", true);
+ tp!("\\\\?\\C:\\", "\\\\?\\C:\\", false);
+ tp!("\\\\?\\UNC\\server\\share\\a\\b",
+ "\\\\?\\UNC\\server\\share\\a",
+ true);
+ tp!("\\\\?\\UNC\\server\\share\\a",
+ "\\\\?\\UNC\\server\\share\\",
+ true);
+ tp!("\\\\?\\UNC\\server\\share",
+ "\\\\?\\UNC\\server\\share",
+ false);
+ tp!("\\\\.\\a\\b\\c", "\\\\.\\a\\b", true);
+ tp!("\\\\.\\a\\b", "\\\\.\\a\\", true);
+ tp!("\\\\.\\a", "\\\\.\\a", false);
+
+ tp!("\\\\?\\a\\b\\", "\\\\?\\a\\", true);
+ }
+ }
+
+ #[test]
+ pub fn test_set_file_name() {
+ macro_rules! tfn(
+ ($path:expr, $file:expr, $expected:expr) => ( {
+ let mut p = PathBuf::from($path);
+ p.set_file_name($file);
+ assert!(p.to_str() == Some($expected),
+ "setting file name of {:?} to {:?}: Expected {:?}, got {:?}",
+ $path, $file, $expected,
+ p.to_str().unwrap());
+ });
+ );
+
+ tfn!("foo", "foo", "foo");
+ tfn!("foo", "bar", "bar");
+ tfn!("foo", "", "");
+ tfn!("", "foo", "foo");
+ if cfg!(unix) || cfg!(all(target_env = "sgx", target_vendor = "fortanix")) {
+ tfn!(".", "foo", "./foo");
+ tfn!("foo/", "bar", "bar");
+ tfn!("foo/.", "bar", "bar");
+ tfn!("..", "foo", "../foo");
+ tfn!("foo/..", "bar", "foo/../bar");
+ tfn!("/", "foo", "/foo");
+ } else {
+ tfn!(".", "foo", r".\foo");
+ tfn!(r"foo\", "bar", r"bar");
+ tfn!(r"foo\.", "bar", r"bar");
+ tfn!("..", "foo", r"..\foo");
+ tfn!(r"foo\..", "bar", r"foo\..\bar");
+ tfn!(r"\", "foo", r"\foo");
+ }
+ }
+
+ #[test]
+ pub fn test_set_extension() {
+ macro_rules! tfe(
+ ($path:expr, $ext:expr, $expected:expr, $output:expr) => ( {
+ let mut p = PathBuf::from($path);
+ let output = p.set_extension($ext);
+ assert!(p.to_str() == Some($expected) && output == $output,
+ "setting extension of {:?} to {:?}: Expected {:?}/{:?}, got {:?}/{:?}",
+ $path, $ext, $expected, $output,
+ p.to_str().unwrap(), output);
+ });
+ );
+
+ tfe!("foo", "txt", "foo.txt", true);
+ tfe!("foo.bar", "txt", "foo.txt", true);
+ tfe!("foo.bar.baz", "txt", "foo.bar.txt", true);
+ tfe!(".test", "txt", ".test.txt", true);
+ tfe!("foo.txt", "", "foo", true);
+ tfe!("foo", "", "foo", true);
+ tfe!("", "foo", "", false);
+ tfe!(".", "foo", ".", false);
+ tfe!("foo/", "bar", "foo.bar", true);
+ tfe!("foo/.", "bar", "foo.bar", true);
+ tfe!("..", "foo", "..", false);
+ tfe!("foo/..", "bar", "foo/..", false);
+ tfe!("/", "foo", "/", false);
+ }
+
+ #[test]
+ fn test_eq_receivers() {
+ use crate::borrow::Cow;
+
+ let borrowed: &Path = Path::new("foo/bar");
+ let mut owned: PathBuf = PathBuf::new();
+ owned.push("foo");
+ owned.push("bar");
+ let borrowed_cow: Cow<'_, Path> = borrowed.into();
+ let owned_cow: Cow<'_, Path> = owned.clone().into();
+
+ macro_rules! t {
+ ($($current:expr),+) => {
+ $(
+ assert_eq!($current, borrowed);
+ assert_eq!($current, owned);
+ assert_eq!($current, borrowed_cow);
+ assert_eq!($current, owned_cow);
+ )+
+ }
+ }
+
+ t!(borrowed, owned, borrowed_cow, owned_cow);
+ }
+
+ #[test]
+ pub fn test_compare() {
+ use crate::hash::{Hash, Hasher};
+ use crate::collections::hash_map::DefaultHasher;
+
+ fn hash<T: Hash>(t: T) -> u64 {
+ let mut s = DefaultHasher::new();
+ t.hash(&mut s);
+ s.finish()
+ }
+
+ macro_rules! tc(
+ ($path1:expr, $path2:expr, eq: $eq:expr,
+ starts_with: $starts_with:expr, ends_with: $ends_with:expr,
+ relative_from: $relative_from:expr) => ({
+ let path1 = Path::new($path1);
+ let path2 = Path::new($path2);
+
+ let eq = path1 == path2;
+ assert!(eq == $eq, "{:?} == {:?}, expected {:?}, got {:?}",
+ $path1, $path2, $eq, eq);
+ assert!($eq == (hash(path1) == hash(path2)),
+ "{:?} == {:?}, expected {:?}, got {} and {}",
+ $path1, $path2, $eq, hash(path1), hash(path2));
+
+ let starts_with = path1.starts_with(path2);
+ assert!(starts_with == $starts_with,
+ "{:?}.starts_with({:?}), expected {:?}, got {:?}", $path1, $path2,
+ $starts_with, starts_with);
+
+ let ends_with = path1.ends_with(path2);
+ assert!(ends_with == $ends_with,
+ "{:?}.ends_with({:?}), expected {:?}, got {:?}", $path1, $path2,
+ $ends_with, ends_with);
+
+ let relative_from = path1.strip_prefix(path2)
+ .map(|p| p.to_str().unwrap())
+ .ok();
+ let exp: Option<&str> = $relative_from;
+ assert!(relative_from == exp,
+ "{:?}.strip_prefix({:?}), expected {:?}, got {:?}",
+ $path1, $path2, exp, relative_from);
+ });
+ );
+
+ tc!("", "",
+ eq: true,
+ starts_with: true,
+ ends_with: true,
+ relative_from: Some("")
+ );
+
+ tc!("foo", "",
+ eq: false,
+ starts_with: true,
+ ends_with: true,
+ relative_from: Some("foo")
+ );
+
+ tc!("", "foo",
+ eq: false,
+ starts_with: false,
+ ends_with: false,
+ relative_from: None
+ );
+
+ tc!("foo", "foo",
+ eq: true,
+ starts_with: true,
+ ends_with: true,
+ relative_from: Some("")
+ );
+
+ tc!("foo/", "foo",
+ eq: true,
+ starts_with: true,
+ ends_with: true,
+ relative_from: Some("")
+ );
+
+ tc!("foo/bar", "foo",
+ eq: false,
+ starts_with: true,
+ ends_with: false,
+ relative_from: Some("bar")
+ );
+
+ tc!("foo/bar/baz", "foo/bar",
+ eq: false,
+ starts_with: true,
+ ends_with: false,
+ relative_from: Some("baz")
+ );
+
+ tc!("foo/bar", "foo/bar/baz",
+ eq: false,
+ starts_with: false,
+ ends_with: false,
+ relative_from: None
+ );
+
+ tc!("./foo/bar/", ".",
+ eq: false,
+ starts_with: true,
+ ends_with: false,
+ relative_from: Some("foo/bar")
+ );
+
+ if cfg!(windows) {
+ tc!(r"C:\src\rust\cargo-test\test\Cargo.toml",
+ r"c:\src\rust\cargo-test\test",
+ eq: false,
+ starts_with: true,
+ ends_with: false,
+ relative_from: Some("Cargo.toml")
+ );
+
+ tc!(r"c:\foo", r"C:\foo",
+ eq: true,
+ starts_with: true,
+ ends_with: true,
+ relative_from: Some("")
+ );
+ }
+ }
+
+ #[test]
+ fn test_components_debug() {
+ let path = Path::new("/tmp");
+
+ let mut components = path.components();
+
+ let expected = "Components([RootDir, Normal(\"tmp\")])";
+ let actual = format!("{:?}", components);
+ assert_eq!(expected, actual);
+
+ let _ = components.next().unwrap();
+ let expected = "Components([Normal(\"tmp\")])";
+ let actual = format!("{:?}", components);
+ assert_eq!(expected, actual);
+
+ let _ = components.next().unwrap();
+ let expected = "Components([])";
+ let actual = format!("{:?}", components);
+ assert_eq!(expected, actual);
+ }
+
+ #[cfg(unix)]
+ #[test]
+ fn test_iter_debug() {
+ let path = Path::new("/tmp");
+
+ let mut iter = path.iter();
+
+ let expected = "Iter([\"/\", \"tmp\"])";
+ let actual = format!("{:?}", iter);
+ assert_eq!(expected, actual);
+
+ let _ = iter.next().unwrap();
+ let expected = "Iter([\"tmp\"])";
+ let actual = format!("{:?}", iter);
+ assert_eq!(expected, actual);
+
+ let _ = iter.next().unwrap();
+ let expected = "Iter([])";
+ let actual = format!("{:?}", iter);
+ assert_eq!(expected, actual);
+ }
+
+ #[test]
+ fn into_boxed() {
+ let orig: &str = "some/sort/of/path";
+ let path = Path::new(orig);
+ let boxed: Box<Path> = Box::from(path);
+ let path_buf = path.to_owned().into_boxed_path().into_path_buf();
+ assert_eq!(path, &*boxed);
+ assert_eq!(&*boxed, &*path_buf);
+ assert_eq!(&*path_buf, path);
+ }
+
+ #[test]
+ fn test_clone_into() {
+ let mut path_buf = PathBuf::from("supercalifragilisticexpialidocious");
+ let path = Path::new("short");
+ path.clone_into(&mut path_buf);
+ assert_eq!(path, path_buf);
+ assert!(path_buf.into_os_string().capacity() >= 15);
+ }
+
+ #[test]
+ fn display_format_flags() {
+ assert_eq!(format!("a{:#<5}b", Path::new("").display()), "a#####b");
+ assert_eq!(format!("a{:#<5}b", Path::new("a").display()), "aa####b");
+ }
+
+ #[test]
+ fn into_rc() {
+ let orig = "hello/world";
+ let path = Path::new(orig);
+ let rc: Rc<Path> = Rc::from(path);
+ let arc: Arc<Path> = Arc::from(path);
+
+ assert_eq!(&*rc, path);
+ assert_eq!(&*arc, path);
+
+ let rc2: Rc<Path> = Rc::from(path.to_owned());
+ let arc2: Arc<Path> = Arc::from(path.to_owned());
+
+ assert_eq!(&*rc2, path);
+ assert_eq!(&*arc2, path);
+ }
+}
diff --git a/src/libstd/prelude/mod.rs b/src/libstd/prelude/mod.rs
new file mode 100644
index 0000000..551e982
--- /dev/null
+++ b/src/libstd/prelude/mod.rs
@@ -0,0 +1,139 @@
+//! The Rust Prelude.
+//!
+//! Rust comes with a variety of things in its standard library. However, if
+//! you had to manually import every single thing that you used, it would be
+//! very verbose. But importing a lot of things that a program never uses isn't
+//! good either. A balance needs to be struck.
+//!
+//! The *prelude* is the list of things that Rust automatically imports into
+//! every Rust program. It's kept as small as possible, and is focused on
+//! things, particularly traits, which are used in almost every single Rust
+//! program.
+//!
+//! On a technical level, Rust inserts
+//!
+//! ```
+//! # #[allow(unused_extern_crates)]
+//! extern crate std;
+//! ```
+//!
+//! into the crate root of every crate, and
+//!
+//! ```
+//! # #[allow(unused_imports)]
+//! use std::prelude::v1::*;
+//! ```
+//!
+//! into every module.
+//!
+//! # Other preludes
+//!
+//! Preludes can be seen as a pattern to make using multiple types more
+//! convenient. As such, you'll find other preludes in the standard library,
+//! such as [`std::io::prelude`]. Various libraries in the Rust ecosystem may
+//! also define their own preludes.
+//!
+//! [`std::io::prelude`]: ../io/prelude/index.html
+//!
+//! The difference between 'the prelude' and these other preludes is that they
+//! are not automatically `use`'d, and must be imported manually. This is still
+//! easier than importing all of their constituent components.
+//!
+//! # Prelude contents
+//!
+//! The current version of the prelude (version 1) lives in
+//! [`std::prelude::v1`], and re-exports the following.
+//!
+//! * [`std::marker`]::{[`Copy`], [`Send`], [`Sized`], [`Sync`], [`Unpin`]}. The
+//! marker traits indicate fundamental properties of types.
+//! * [`std::ops`]::{[`Drop`], [`Fn`], [`FnMut`], [`FnOnce`]}. Various
+//! operations for both destructors and overloading `()`.
+//! * [`std::mem`]::[`drop`][`mem::drop`], a convenience function for explicitly
+//! dropping a value.
+//! * [`std::boxed`]::[`Box`], a way to allocate values on the heap.
+//! * [`std::borrow`]::[`ToOwned`], The conversion trait that defines
+//! [`to_owned`], the generic method for creating an owned type from a
+//! borrowed type.
+//! * [`std::clone`]::[`Clone`], the ubiquitous trait that defines
+//! [`clone`][`Clone::clone`], the method for producing a copy of a value.
+//! * [`std::cmp`]::{[`PartialEq`], [`PartialOrd`], [`Eq`], [`Ord`] }. The
+//! comparison traits, which implement the comparison operators and are often
+//! seen in trait bounds.
+//! * [`std::convert`]::{[`AsRef`], [`AsMut`], [`Into`], [`From`]}. Generic
+//! conversions, used by savvy API authors to create overloaded methods.
+//! * [`std::default`]::[`Default`], types that have default values.
+//! * [`std::iter`]::{[`Iterator`], [`Extend`], [`IntoIterator`],
+//! [`DoubleEndedIterator`], [`ExactSizeIterator`]}. Iterators of various
+//! kinds.
+//! * [`std::option`]::[`Option`]::{`self`, `Some`, `None`}. A type which
+//! expresses the presence or absence of a value. This type is so commonly
+//! used, its variants are also exported.
+//! * [`std::result`]::[`Result`]::{`self`, `Ok`, `Err`}. A type for functions
+//! that may succeed or fail. Like [`Option`], its variants are exported as
+//! well.
+//! * [`std::slice`]::[`SliceConcatExt`], a trait that exists for technical
+//! reasons, but shouldn't have to exist. It provides a few useful methods on
+//! slices.
+//! * [`std::string`]::{[`String`], [`ToString`]}, heap allocated strings.
+//! * [`std::vec`]::[`Vec`](../vec/struct.Vec.html), a growable, heap-allocated
+//! vector.
+//!
+//! [`AsMut`]: ../convert/trait.AsMut.html
+//! [`AsRef`]: ../convert/trait.AsRef.html
+//! [`Box`]: ../boxed/struct.Box.html
+//! [`Clone`]: ../clone/trait.Clone.html
+//! [`Copy`]: ../marker/trait.Copy.html
+//! [`Default`]: ../default/trait.Default.html
+//! [`DoubleEndedIterator`]: ../iter/trait.DoubleEndedIterator.html
+//! [`Drop`]: ../ops/trait.Drop.html
+//! [`Eq`]: ../cmp/trait.Eq.html
+//! [`ExactSizeIterator`]: ../iter/trait.ExactSizeIterator.html
+//! [`Extend`]: ../iter/trait.Extend.html
+//! [`FnMut`]: ../ops/trait.FnMut.html
+//! [`FnOnce`]: ../ops/trait.FnOnce.html
+//! [`Fn`]: ../ops/trait.Fn.html
+//! [`From`]: ../convert/trait.From.html
+//! [`IntoIterator`]: ../iter/trait.IntoIterator.html
+//! [`Into`]: ../convert/trait.Into.html
+//! [`Iterator`]: ../iter/trait.Iterator.html
+//! [`Option`]: ../option/enum.Option.html
+//! [`Ord`]: ../cmp/trait.Ord.html
+//! [`PartialEq`]: ../cmp/trait.PartialEq.html
+//! [`PartialOrd`]: ../cmp/trait.PartialOrd.html
+//! [`Result`]: ../result/enum.Result.html
+//! [`Send`]: ../marker/trait.Send.html
+//! [`Sized`]: ../marker/trait.Sized.html
+//! [`SliceConcatExt`]: ../slice/trait.SliceConcatExt.html
+//! [`String`]: ../string/struct.String.html
+//! [`Sync`]: ../marker/trait.Sync.html
+//! [`ToOwned`]: ../borrow/trait.ToOwned.html
+//! [`ToString`]: ../string/trait.ToString.html
+//! [`Unpin`]: ../marker/trait.Unpin.html
+//! [`Vec`]: ../vec/struct.Vec.html
+//! [`Clone::clone`]: ../clone/trait.Clone.html#tymethod.clone
+//! [`mem::drop`]: ../mem/fn.drop.html
+//! [`std::borrow`]: ../borrow/index.html
+//! [`std::boxed`]: ../boxed/index.html
+//! [`std::clone`]: ../clone/index.html
+//! [`std::cmp`]: ../cmp/index.html
+//! [`std::convert`]: ../convert/index.html
+//! [`std::default`]: ../default/index.html
+//! [`std::iter`]: ../iter/index.html
+//! [`std::marker`]: ../marker/index.html
+//! [`std::mem`]: ../mem/index.html
+//! [`std::ops`]: ../ops/index.html
+//! [`std::option`]: ../option/index.html
+//! [`std::prelude::v1`]: v1/index.html
+//! [`std::result`]: ../result/index.html
+//! [`std::slice`]: ../slice/index.html
+//! [`std::string`]: ../string/index.html
+//! [`std::vec`]: ../vec/index.html
+//! [`to_owned`]: ../borrow/trait.ToOwned.html#tymethod.to_owned
+//! [book-closures]: ../../book/ch13-01-closures.html
+//! [book-dtor]: ../../book/ch15-03-drop.html
+//! [book-enums]: ../../book/ch06-01-defining-an-enum.html
+//! [book-iter]: ../../book/ch13-02-iterators.html
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+pub mod v1;
diff --git a/src/libstd/prelude/v1.rs b/src/libstd/prelude/v1.rs
new file mode 100644
index 0000000..ce1e8e3
--- /dev/null
+++ b/src/libstd/prelude/v1.rs
@@ -0,0 +1,69 @@
+//! The first version of the prelude of The Rust Standard Library.
+//!
+//! See the [module-level documentation](../index.html) for more.
+
+
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+// Re-exported core operators
+#[stable(feature = "rust1", since = "1.0.0")]
+#[doc(no_inline)]
+pub use crate::marker::{Copy, Send, Sized, Sync, Unpin};
+#[stable(feature = "rust1", since = "1.0.0")]
+#[doc(no_inline)]
+pub use crate::ops::{Drop, Fn, FnMut, FnOnce};
+
+// Re-exported functions
+#[stable(feature = "rust1", since = "1.0.0")]
+#[doc(no_inline)]
+pub use crate::mem::drop;
+
+// Re-exported types and traits
+#[stable(feature = "rust1", since = "1.0.0")]
+#[doc(no_inline)]
+pub use crate::clone::Clone;
+#[stable(feature = "rust1", since = "1.0.0")]
+#[doc(no_inline)]
+pub use crate::cmp::{PartialEq, PartialOrd, Eq, Ord};
+#[stable(feature = "rust1", since = "1.0.0")]
+#[doc(no_inline)]
+pub use crate::convert::{AsRef, AsMut, Into, From};
+#[stable(feature = "rust1", since = "1.0.0")]
+#[doc(no_inline)]
+pub use crate::default::Default;
+#[stable(feature = "rust1", since = "1.0.0")]
+#[doc(no_inline)]
+pub use crate::iter::{Iterator, Extend, IntoIterator};
+#[stable(feature = "rust1", since = "1.0.0")]
+#[doc(no_inline)]
+pub use crate::iter::{DoubleEndedIterator, ExactSizeIterator};
+#[stable(feature = "rust1", since = "1.0.0")]
+#[doc(no_inline)]
+pub use crate::option::Option::{self, Some, None};
+#[stable(feature = "rust1", since = "1.0.0")]
+#[doc(no_inline)]
+pub use crate::result::Result::{self, Ok, Err};
+
+
+// The file so far is equivalent to src/libcore/prelude/v1.rs,
+// and below to src/liballoc/prelude.rs.
+// Those files are duplicated rather than using glob imports
+// because we want docs to show these re-exports as pointing to within `std`.
+
+
+#[stable(feature = "rust1", since = "1.0.0")]
+#[doc(no_inline)]
+pub use crate::boxed::Box;
+#[stable(feature = "rust1", since = "1.0.0")]
+#[doc(no_inline)]
+pub use crate::borrow::ToOwned;
+#[stable(feature = "rust1", since = "1.0.0")]
+#[doc(no_inline)]
+pub use crate::slice::SliceConcatExt;
+#[stable(feature = "rust1", since = "1.0.0")]
+#[doc(no_inline)]
+pub use crate::string::{String, ToString};
+#[stable(feature = "rust1", since = "1.0.0")]
+#[doc(no_inline)]
+pub use crate::vec::Vec;
diff --git a/src/libstd/primitive_docs.rs b/src/libstd/primitive_docs.rs
new file mode 100644
index 0000000..94fece1
--- /dev/null
+++ b/src/libstd/primitive_docs.rs
@@ -0,0 +1,1114 @@
+#[doc(primitive = "bool")]
+#[doc(alias = "true")]
+#[doc(alias = "false")]
+//
+/// The boolean type.
+///
+/// The `bool` represents a value, which could only be either `true` or `false`. If you cast
+/// a `bool` into an integer, `true` will be 1 and `false` will be 0.
+///
+/// # Basic usage
+///
+/// `bool` implements various traits, such as [`BitAnd`], [`BitOr`], [`Not`], etc.,
+/// which allow us to perform boolean operations using `&`, `|` and `!`.
+///
+/// `if` always demands a `bool` value. [`assert!`], being an important macro in testing,
+/// checks whether an expression returns `true`.
+///
+/// ```
+/// let bool_val = true & false | false;
+/// assert!(!bool_val);
+/// ```
+///
+/// [`assert!`]: macro.assert.html
+/// [`BitAnd`]: ops/trait.BitAnd.html
+/// [`BitOr`]: ops/trait.BitOr.html
+/// [`Not`]: ops/trait.Not.html
+///
+/// # Examples
+///
+/// A trivial example of the usage of `bool`,
+///
+/// ```
+/// let praise_the_borrow_checker = true;
+///
+/// // using the `if` conditional
+/// if praise_the_borrow_checker {
+/// println!("oh, yeah!");
+/// } else {
+/// println!("what?!!");
+/// }
+///
+/// // ... or, a match pattern
+/// match praise_the_borrow_checker {
+/// true => println!("keep praising!"),
+/// false => println!("you should praise!"),
+/// }
+/// ```
+///
+/// Also, since `bool` implements the [`Copy`](marker/trait.Copy.html) trait, we don't
+/// have to worry about the move semantics (just like the integer and float primitives).
+///
+/// Now an example of `bool` cast to integer type:
+///
+/// ```
+/// assert_eq!(true as i32, 1);
+/// assert_eq!(false as i32, 0);
+/// ```
+#[stable(feature = "rust1", since = "1.0.0")]
+mod prim_bool { }
+
+#[doc(primitive = "never")]
+#[doc(alias = "!")]
+//
+/// The `!` type, also called "never".
+///
+/// `!` represents the type of computations which never resolve to any value at all. For example,
+/// the [`exit`] function `fn exit(code: i32) -> !` exits the process without ever returning, and
+/// so returns `!`.
+///
+/// `break`, `continue` and `return` expressions also have type `!`. For example we are allowed to
+/// write:
+///
+/// ```
+/// #![feature(never_type)]
+/// # fn foo() -> u32 {
+/// let x: ! = {
+/// return 123
+/// };
+/// # }
+/// ```
+///
+/// Although the `let` is pointless here, it illustrates the meaning of `!`. Since `x` is never
+/// assigned a value (because `return` returns from the entire function), `x` can be given type
+/// `!`. We could also replace `return 123` with a `panic!` or a never-ending `loop` and this code
+/// would still be valid.
+///
+/// A more realistic usage of `!` is in this code:
+///
+/// ```
+/// # fn get_a_number() -> Option<u32> { None }
+/// # loop {
+/// let num: u32 = match get_a_number() {
+/// Some(num) => num,
+/// None => break,
+/// };
+/// # }
+/// ```
+///
+/// Both match arms must produce values of type [`u32`], but since `break` never produces a value
+/// at all we know it can never produce a value which isn't a [`u32`]. This illustrates another
+/// behaviour of the `!` type - expressions with type `!` will coerce into any other type.
+///
+/// [`u32`]: primitive.str.html
+/// [`exit`]: process/fn.exit.html
+///
+/// # `!` and generics
+///
+/// ## Infallible errors
+///
+/// The main place you'll see `!` used explicitly is in generic code. Consider the [`FromStr`]
+/// trait:
+///
+/// ```
+/// trait FromStr: Sized {
+/// type Err;
+/// fn from_str(s: &str) -> Result<Self, Self::Err>;
+/// }
+/// ```
+///
+/// When implementing this trait for [`String`] we need to pick a type for [`Err`]. And since
+/// converting a string into a string will never result in an error, the appropriate type is `!`.
+/// (Currently the type actually used is an enum with no variants, though this is only because `!`
+/// was added to Rust at a later date and it may change in the future). With an [`Err`] type of
+/// `!`, if we have to call [`String::from_str`] for some reason the result will be a
+/// [`Result<String, !>`] which we can unpack like this:
+///
+/// ```ignore (string-from-str-error-type-is-not-never-yet)
+/// #[feature(exhaustive_patterns)]
+/// // NOTE: this does not work today!
+/// let Ok(s) = String::from_str("hello");
+/// ```
+///
+/// Since the [`Err`] variant contains a `!`, it can never occur. If the `exhaustive_patterns`
+/// feature is present this means we can exhaustively match on [`Result<T, !>`] by just taking the
+/// [`Ok`] variant. This illustrates another behaviour of `!` - it can be used to "delete" certain
+/// enum variants from generic types like `Result`.
+///
+/// ## Infinite loops
+///
+/// While [`Result<T, !>`] is very useful for removing errors, `!` can also be used to remove
+/// successes as well. If we think of [`Result<T, !>`] as "if this function returns, it has not
+/// errored," we get a very intuitive idea of [`Result<!, E>`] as well: if the function returns, it
+/// *has* errored.
+///
+/// For example, consider the case of a simple web server, which can be simplified to:
+///
+/// ```ignore (hypothetical-example)
+/// loop {
+/// let (client, request) = get_request().expect("disconnected");
+/// let response = request.process();
+/// response.send(client);
+/// }
+/// ```
+///
+/// Currently, this isn't ideal, because we simply panic whenever we fail to get a new connection.
+/// Instead, we'd like to keep track of this error, like this:
+///
+/// ```ignore (hypothetical-example)
+/// loop {
+/// match get_request() {
+/// Err(err) => break err,
+/// Ok((client, request)) => {
+/// let response = request.process();
+/// response.send(client);
+/// },
+/// }
+/// }
+/// ```
+///
+/// Now, when the server disconnects, we exit the loop with an error instead of panicking. While it
+/// might be intuitive to simply return the error, we might want to wrap it in a [`Result<!, E>`]
+/// instead:
+///
+/// ```ignore (hypothetical-example)
+/// fn server_loop() -> Result<!, ConnectionError> {
+/// loop {
+/// let (client, request) = get_request()?;
+/// let response = request.process();
+/// response.send(client);
+/// }
+/// }
+/// ```
+///
+/// Now, we can use `?` instead of `match`, and the return type makes a lot more sense: if the loop
+/// ever stops, it means that an error occurred. We don't even have to wrap the loop in an `Ok`
+/// because `!` coerces to `Result<!, ConnectionError>` automatically.
+///
+/// [`String::from_str`]: str/trait.FromStr.html#tymethod.from_str
+/// [`Result<String, !>`]: result/enum.Result.html
+/// [`Result<T, !>`]: result/enum.Result.html
+/// [`Result<!, E>`]: result/enum.Result.html
+/// [`Ok`]: result/enum.Result.html#variant.Ok
+/// [`String`]: string/struct.String.html
+/// [`Err`]: result/enum.Result.html#variant.Err
+/// [`FromStr`]: str/trait.FromStr.html
+///
+/// # `!` and traits
+///
+/// When writing your own traits, `!` should have an `impl` whenever there is an obvious `impl`
+/// which doesn't `panic!`. As it turns out, most traits can have an `impl` for `!`. Take [`Debug`]
+/// for example:
+///
+/// ```
+/// #![feature(never_type)]
+/// # use std::fmt;
+/// # trait Debug {
+/// # fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result;
+/// # }
+/// impl Debug for ! {
+/// fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+/// *self
+/// }
+/// }
+/// ```
+///
+/// Once again we're using `!`'s ability to coerce into any other type, in this case
+/// [`fmt::Result`]. Since this method takes a `&!` as an argument we know that it can never be
+/// called (because there is no value of type `!` for it to be called with). Writing `*self`
+/// essentially tells the compiler "We know that this code can never be run, so just treat the
+/// entire function body as having type [`fmt::Result`]". This pattern can be used a lot when
+/// implementing traits for `!`. Generally, any trait which only has methods which take a `self`
+/// parameter should have such an impl.
+///
+/// On the other hand, one trait which would not be appropriate to implement is [`Default`]:
+///
+/// ```
+/// trait Default {
+/// fn default() -> Self;
+/// }
+/// ```
+///
+/// Since `!` has no values, it has no default value either. It's true that we could write an
+/// `impl` for this which simply panics, but the same is true for any type (we could `impl
+/// Default` for (eg.) [`File`] by just making [`default()`] panic.)
+///
+/// [`fmt::Result`]: fmt/type.Result.html
+/// [`File`]: fs/struct.File.html
+/// [`Debug`]: fmt/trait.Debug.html
+/// [`Default`]: default/trait.Default.html
+/// [`default()`]: default/trait.Default.html#tymethod.default
+///
+#[unstable(feature = "never_type", issue = "35121")]
+mod prim_never { }
+
+#[doc(primitive = "char")]
+//
+/// A character type.
+///
+/// The `char` type represents a single character. More specifically, since
+/// 'character' isn't a well-defined concept in Unicode, `char` is a '[Unicode
+/// scalar value]', which is similar to, but not the same as, a '[Unicode code
+/// point]'.
+///
+/// [Unicode scalar value]: http://www.unicode.org/glossary/#unicode_scalar_value
+/// [Unicode code point]: http://www.unicode.org/glossary/#code_point
+///
+/// This documentation describes a number of methods and trait implementations on the
+/// `char` type. For technical reasons, there is additional, separate
+/// documentation in [the `std::char` module](char/index.html) as well.
+///
+/// # Representation
+///
+/// `char` is always four bytes in size. This is a different representation than
+/// a given character would have as part of a [`String`]. For example:
+///
+/// ```
+/// let v = vec!['h', 'e', 'l', 'l', 'o'];
+///
+/// // five elements times four bytes for each element
+/// assert_eq!(20, v.len() * std::mem::size_of::<char>());
+///
+/// let s = String::from("hello");
+///
+/// // five elements times one byte per element
+/// assert_eq!(5, s.len() * std::mem::size_of::<u8>());
+/// ```
+///
+/// [`String`]: string/struct.String.html
+///
+/// As always, remember that a human intuition for 'character' may not map to
+/// Unicode's definitions. For example, despite looking similar, the 'é'
+/// character is one Unicode code point while 'é' is two Unicode code points:
+///
+/// ```
+/// let mut chars = "é".chars();
+/// // U+00e9: 'latin small letter e with acute'
+/// assert_eq!(Some('\u{00e9}'), chars.next());
+/// assert_eq!(None, chars.next());
+///
+/// let mut chars = "é".chars();
+/// // U+0065: 'latin small letter e'
+/// assert_eq!(Some('\u{0065}'), chars.next());
+/// // U+0301: 'combining acute accent'
+/// assert_eq!(Some('\u{0301}'), chars.next());
+/// assert_eq!(None, chars.next());
+/// ```
+///
+/// This means that the contents of the first string above _will_ fit into a
+/// `char` while the contents of the second string _will not_. Trying to create
+/// a `char` literal with the contents of the second string gives an error:
+///
+/// ```text
+/// error: character literal may only contain one codepoint: 'é'
+/// let c = 'é';
+/// ^^^
+/// ```
+///
+/// Another implication of the 4-byte fixed size of a `char` is that
+/// per-`char` processing can end up using a lot more memory:
+///
+/// ```
+/// let s = String::from("love: ❤️");
+/// let v: Vec<char> = s.chars().collect();
+///
+/// assert_eq!(12, std::mem::size_of_val(&s[..]));
+/// assert_eq!(32, std::mem::size_of_val(&v[..]));
+/// ```
+#[stable(feature = "rust1", since = "1.0.0")]
+mod prim_char { }
+
+#[doc(primitive = "unit")]
+//
+/// The `()` type, sometimes called "unit" or "nil".
+///
+/// The `()` type has exactly one value `()`, and is used when there
+/// is no other meaningful value that could be returned. `()` is most
+/// commonly seen implicitly: functions without a `-> ...` implicitly
+/// have return type `()`, that is, these are equivalent:
+///
+/// ```rust
+/// fn long() -> () {}
+///
+/// fn short() {}
+/// ```
+///
+/// The semicolon `;` can be used to discard the result of an
+/// expression at the end of a block, making the expression (and thus
+/// the block) evaluate to `()`. For example,
+///
+/// ```rust
+/// fn returns_i64() -> i64 {
+/// 1i64
+/// }
+/// fn returns_unit() {
+/// 1i64;
+/// }
+///
+/// let is_i64 = {
+/// returns_i64()
+/// };
+/// let is_unit = {
+/// returns_i64();
+/// };
+/// ```
+///
+#[stable(feature = "rust1", since = "1.0.0")]
+mod prim_unit { }
+
+#[doc(primitive = "pointer")]
+//
+/// Raw, unsafe pointers, `*const T`, and `*mut T`.
+///
+/// *[See also the `std::ptr` module](ptr/index.html).*
+///
+/// Working with raw pointers in Rust is uncommon,
+/// typically limited to a few patterns.
+///
+/// Use the [`null`] and [`null_mut`] functions to create null pointers, and the
+/// [`is_null`] method of the `*const T` and `*mut T` types to check for null.
+/// The `*const T` and `*mut T` types also define the [`offset`] method, for
+/// pointer math.
+///
+/// # Common ways to create raw pointers
+///
+/// ## 1. Coerce a reference (`&T`) or mutable reference (`&mut T`).
+///
+/// ```
+/// let my_num: i32 = 10;
+/// let my_num_ptr: *const i32 = &my_num;
+/// let mut my_speed: i32 = 88;
+/// let my_speed_ptr: *mut i32 = &mut my_speed;
+/// ```
+///
+/// To get a pointer to a boxed value, dereference the box:
+///
+/// ```
+/// let my_num: Box<i32> = Box::new(10);
+/// let my_num_ptr: *const i32 = &*my_num;
+/// let mut my_speed: Box<i32> = Box::new(88);
+/// let my_speed_ptr: *mut i32 = &mut *my_speed;
+/// ```
+///
+/// This does not take ownership of the original allocation
+/// and requires no resource management later,
+/// but you must not use the pointer after its lifetime.
+///
+/// ## 2. Consume a box (`Box<T>`).
+///
+/// The [`into_raw`] function consumes a box and returns
+/// the raw pointer. It doesn't destroy `T` or deallocate any memory.
+///
+/// ```
+/// let my_speed: Box<i32> = Box::new(88);
+/// let my_speed: *mut i32 = Box::into_raw(my_speed);
+///
+/// // By taking ownership of the original `Box<T>` though
+/// // we are obligated to put it together later to be destroyed.
+/// unsafe {
+/// drop(Box::from_raw(my_speed));
+/// }
+/// ```
+///
+/// Note that here the call to [`drop`] is for clarity - it indicates
+/// that we are done with the given value and it should be destroyed.
+///
+/// ## 3. Get it from C.
+///
+/// ```
+/// # #![feature(rustc_private)]
+/// extern crate libc;
+///
+/// use std::mem;
+///
+/// fn main() {
+/// unsafe {
+/// let my_num: *mut i32 = libc::malloc(mem::size_of::<i32>()) as *mut i32;
+/// if my_num.is_null() {
+/// panic!("failed to allocate memory");
+/// }
+/// libc::free(my_num as *mut libc::c_void);
+/// }
+/// }
+/// ```
+///
+/// Usually you wouldn't literally use `malloc` and `free` from Rust,
+/// but C APIs hand out a lot of pointers generally, so are a common source
+/// of raw pointers in Rust.
+///
+/// [`null`]: ../std/ptr/fn.null.html
+/// [`null_mut`]: ../std/ptr/fn.null_mut.html
+/// [`is_null`]: ../std/primitive.pointer.html#method.is_null
+/// [`offset`]: ../std/primitive.pointer.html#method.offset
+/// [`into_raw`]: ../std/boxed/struct.Box.html#method.into_raw
+/// [`drop`]: ../std/mem/fn.drop.html
+#[stable(feature = "rust1", since = "1.0.0")]
+mod prim_pointer { }
+
+#[doc(primitive = "array")]
+//
+/// A fixed-size array, denoted `[T; N]`, for the element type, `T`, and the
+/// non-negative compile-time constant size, `N`.
+///
+/// There are two syntactic forms for creating an array:
+///
+/// * A list with each element, i.e., `[x, y, z]`.
+/// * A repeat expression `[x; N]`, which produces an array with `N` copies of `x`.
+/// The type of `x` must be [`Copy`][copy].
+///
+/// Arrays of sizes from 0 to 32 (inclusive) implement the following traits if
+/// the element type allows it:
+///
+/// - [`Debug`][debug]
+/// - [`IntoIterator`][intoiterator] (implemented for `&[T; N]` and `&mut [T; N]`)
+/// - [`PartialEq`][partialeq], [`PartialOrd`][partialord], [`Eq`][eq], [`Ord`][ord]
+/// - [`Hash`][hash]
+/// - [`AsRef`][asref], [`AsMut`][asmut]
+/// - [`Borrow`][borrow], [`BorrowMut`][borrowmut]
+/// - [`Default`][default]
+///
+/// This limitation on the size `N` exists because Rust does not yet support
+/// code that is generic over the size of an array type. `[Foo; 3]` and `[Bar; 3]`
+/// are instances of same generic type `[T; 3]`, but `[Foo; 3]` and `[Foo; 5]` are
+/// entirely different types. As a stopgap, trait implementations are
+/// statically generated up to size 32.
+///
+/// Arrays of *any* size are [`Copy`][copy] if the element type is [`Copy`][copy]
+/// and [`Clone`][clone] if the element type is [`Clone`][clone]. This works
+/// because [`Copy`][copy] and [`Clone`][clone] traits are specially known
+/// to the compiler.
+///
+/// Arrays coerce to [slices (`[T]`)][slice], so a slice method may be called on
+/// an array. Indeed, this provides most of the API for working with arrays.
+/// Slices have a dynamic size and do not coerce to arrays.
+///
+/// There is no way to move elements out of an array. See [`mem::replace`][replace]
+/// for an alternative.
+///
+/// # Examples
+///
+/// ```
+/// let mut array: [i32; 3] = [0; 3];
+///
+/// array[1] = 1;
+/// array[2] = 2;
+///
+/// assert_eq!([1, 2], &array[1..]);
+///
+/// // This loop prints: 0 1 2
+/// for x in &array {
+/// print!("{} ", x);
+/// }
+/// ```
+///
+/// An array itself is not iterable:
+///
+/// ```compile_fail,E0277
+/// let array: [i32; 3] = [0; 3];
+///
+/// for x in array { }
+/// // error: the trait bound `[i32; 3]: std::iter::Iterator` is not satisfied
+/// ```
+///
+/// The solution is to coerce the array to a slice by calling a slice method:
+///
+/// ```
+/// # let array: [i32; 3] = [0; 3];
+/// for x in array.iter() { }
+/// ```
+///
+/// If the array has 32 or fewer elements (see above), you can also use the
+/// array reference's [`IntoIterator`] implementation:
+///
+/// ```
+/// # let array: [i32; 3] = [0; 3];
+/// for x in &array { }
+/// ```
+///
+/// [slice]: primitive.slice.html
+/// [copy]: marker/trait.Copy.html
+/// [clone]: clone/trait.Clone.html
+/// [debug]: fmt/trait.Debug.html
+/// [intoiterator]: iter/trait.IntoIterator.html
+/// [partialeq]: cmp/trait.PartialEq.html
+/// [partialord]: cmp/trait.PartialOrd.html
+/// [eq]: cmp/trait.Eq.html
+/// [ord]: cmp/trait.Ord.html
+/// [hash]: hash/trait.Hash.html
+/// [asref]: convert/trait.AsRef.html
+/// [asmut]: convert/trait.AsMut.html
+/// [borrow]: borrow/trait.Borrow.html
+/// [borrowmut]: borrow/trait.BorrowMut.html
+/// [default]: default/trait.Default.html
+/// [replace]: mem/fn.replace.html
+/// [`IntoIterator`]: iter/trait.IntoIterator.html
+///
+#[stable(feature = "rust1", since = "1.0.0")]
+mod prim_array { }
+
+#[doc(primitive = "slice")]
+#[doc(alias = "[")]
+#[doc(alias = "]")]
+#[doc(alias = "[]")]
+/// A dynamically-sized view into a contiguous sequence, `[T]`.
+///
+/// *[See also the `std::slice` module](slice/index.html).*
+///
+/// Slices are a view into a block of memory represented as a pointer and a
+/// length.
+///
+/// ```
+/// // slicing a Vec
+/// let vec = vec![1, 2, 3];
+/// let int_slice = &vec[..];
+/// // coercing an array to a slice
+/// let str_slice: &[&str] = &["one", "two", "three"];
+/// ```
+///
+/// Slices are either mutable or shared. The shared slice type is `&[T]`,
+/// while the mutable slice type is `&mut [T]`, where `T` represents the element
+/// type. For example, you can mutate the block of memory that a mutable slice
+/// points to:
+///
+/// ```
+/// let mut x = [1, 2, 3];
+/// let x = &mut x[..]; // Take a full slice of `x`.
+/// x[1] = 7;
+/// assert_eq!(x, &[1, 7, 3]);
+/// ```
+#[stable(feature = "rust1", since = "1.0.0")]
+mod prim_slice { }
+
+#[doc(primitive = "str")]
+//
+/// String slices.
+///
+/// *[See also the `std::str` module](str/index.html).*
+///
+/// The `str` type, also called a 'string slice', is the most primitive string
+/// type. It is usually seen in its borrowed form, `&str`. It is also the type
+/// of string literals, `&'static str`.
+///
+/// String slices are always valid UTF-8.
+///
+/// # Examples
+///
+/// String literals are string slices:
+///
+/// ```
+/// let hello = "Hello, world!";
+///
+/// // with an explicit type annotation
+/// let hello: &'static str = "Hello, world!";
+/// ```
+///
+/// They are `'static` because they're stored directly in the final binary, and
+/// so will be valid for the `'static` duration.
+///
+/// # Representation
+///
+/// A `&str` is made up of two components: a pointer to some bytes, and a
+/// length. You can look at these with the [`as_ptr`] and [`len`] methods:
+///
+/// ```
+/// use std::slice;
+/// use std::str;
+///
+/// let story = "Once upon a time...";
+///
+/// let ptr = story.as_ptr();
+/// let len = story.len();
+///
+/// // story has nineteen bytes
+/// assert_eq!(19, len);
+///
+/// // We can re-build a str out of ptr and len. This is all unsafe because
+/// // we are responsible for making sure the two components are valid:
+/// let s = unsafe {
+/// // First, we build a &[u8]...
+/// let slice = slice::from_raw_parts(ptr, len);
+///
+/// // ... and then convert that slice into a string slice
+/// str::from_utf8(slice)
+/// };
+///
+/// assert_eq!(s, Ok(story));
+/// ```
+///
+/// [`as_ptr`]: #method.as_ptr
+/// [`len`]: #method.len
+///
+/// Note: This example shows the internals of `&str`. `unsafe` should not be
+/// used to get a string slice under normal circumstances. Use `as_slice`
+/// instead.
+#[stable(feature = "rust1", since = "1.0.0")]
+mod prim_str { }
+
+#[doc(primitive = "tuple")]
+#[doc(alias = "(")]
+#[doc(alias = ")")]
+#[doc(alias = "()")]
+//
+/// A finite heterogeneous sequence, `(T, U, ..)`.
+///
+/// Let's cover each of those in turn:
+///
+/// Tuples are *finite*. In other words, a tuple has a length. Here's a tuple
+/// of length `3`:
+///
+/// ```
+/// ("hello", 5, 'c');
+/// ```
+///
+/// 'Length' is also sometimes called 'arity' here; each tuple of a different
+/// length is a different, distinct type.
+///
+/// Tuples are *heterogeneous*. This means that each element of the tuple can
+/// have a different type. In that tuple above, it has the type:
+///
+/// ```
+/// # let _:
+/// (&'static str, i32, char)
+/// # = ("hello", 5, 'c');
+/// ```
+///
+/// Tuples are a *sequence*. This means that they can be accessed by position;
+/// this is called 'tuple indexing', and it looks like this:
+///
+/// ```rust
+/// let tuple = ("hello", 5, 'c');
+///
+/// assert_eq!(tuple.0, "hello");
+/// assert_eq!(tuple.1, 5);
+/// assert_eq!(tuple.2, 'c');
+/// ```
+///
+/// For more about tuples, see [the book](../book/ch03-02-data-types.html#the-tuple-type).
+///
+/// # Trait implementations
+///
+/// If every type inside a tuple implements one of the following traits, then a
+/// tuple itself also implements it.
+///
+/// * [`Clone`]
+/// * [`Copy`]
+/// * [`PartialEq`]
+/// * [`Eq`]
+/// * [`PartialOrd`]
+/// * [`Ord`]
+/// * [`Debug`]
+/// * [`Default`]
+/// * [`Hash`]
+///
+/// [`Clone`]: clone/trait.Clone.html
+/// [`Copy`]: marker/trait.Copy.html
+/// [`PartialEq`]: cmp/trait.PartialEq.html
+/// [`Eq`]: cmp/trait.Eq.html
+/// [`PartialOrd`]: cmp/trait.PartialOrd.html
+/// [`Ord`]: cmp/trait.Ord.html
+/// [`Debug`]: fmt/trait.Debug.html
+/// [`Default`]: default/trait.Default.html
+/// [`Hash`]: hash/trait.Hash.html
+///
+/// Due to a temporary restriction in Rust's type system, these traits are only
+/// implemented on tuples of arity 12 or less. In the future, this may change.
+///
+/// # Examples
+///
+/// Basic usage:
+///
+/// ```
+/// let tuple = ("hello", 5, 'c');
+///
+/// assert_eq!(tuple.0, "hello");
+/// ```
+///
+/// Tuples are often used as a return type when you want to return more than
+/// one value:
+///
+/// ```
+/// fn calculate_point() -> (i32, i32) {
+/// // Don't do a calculation, that's not the point of the example
+/// (4, 5)
+/// }
+///
+/// let point = calculate_point();
+///
+/// assert_eq!(point.0, 4);
+/// assert_eq!(point.1, 5);
+///
+/// // Combining this with patterns can be nicer.
+///
+/// let (x, y) = calculate_point();
+///
+/// assert_eq!(x, 4);
+/// assert_eq!(y, 5);
+/// ```
+///
+#[stable(feature = "rust1", since = "1.0.0")]
+mod prim_tuple { }
+
+#[doc(primitive = "f32")]
+/// The 32-bit floating point type.
+///
+/// *[See also the `std::f32` module](f32/index.html).*
+///
+#[stable(feature = "rust1", since = "1.0.0")]
+mod prim_f32 { }
+
+#[doc(primitive = "f64")]
+//
+/// The 64-bit floating point type.
+///
+/// *[See also the `std::f64` module](f64/index.html).*
+///
+#[stable(feature = "rust1", since = "1.0.0")]
+mod prim_f64 { }
+
+#[doc(primitive = "i8")]
+//
+/// The 8-bit signed integer type.
+///
+/// *[See also the `std::i8` module](i8/index.html).*
+#[stable(feature = "rust1", since = "1.0.0")]
+mod prim_i8 { }
+
+#[doc(primitive = "i16")]
+//
+/// The 16-bit signed integer type.
+///
+/// *[See also the `std::i16` module](i16/index.html).*
+#[stable(feature = "rust1", since = "1.0.0")]
+mod prim_i16 { }
+
+#[doc(primitive = "i32")]
+//
+/// The 32-bit signed integer type.
+///
+/// *[See also the `std::i32` module](i32/index.html).*
+#[stable(feature = "rust1", since = "1.0.0")]
+mod prim_i32 { }
+
+#[doc(primitive = "i64")]
+//
+/// The 64-bit signed integer type.
+///
+/// *[See also the `std::i64` module](i64/index.html).*
+#[stable(feature = "rust1", since = "1.0.0")]
+mod prim_i64 { }
+
+#[doc(primitive = "i128")]
+//
+/// The 128-bit signed integer type.
+///
+/// *[See also the `std::i128` module](i128/index.html).*
+#[stable(feature = "i128", since="1.26.0")]
+mod prim_i128 { }
+
+#[doc(primitive = "u8")]
+//
+/// The 8-bit unsigned integer type.
+///
+/// *[See also the `std::u8` module](u8/index.html).*
+#[stable(feature = "rust1", since = "1.0.0")]
+mod prim_u8 { }
+
+#[doc(primitive = "u16")]
+//
+/// The 16-bit unsigned integer type.
+///
+/// *[See also the `std::u16` module](u16/index.html).*
+#[stable(feature = "rust1", since = "1.0.0")]
+mod prim_u16 { }
+
+#[doc(primitive = "u32")]
+//
+/// The 32-bit unsigned integer type.
+///
+/// *[See also the `std::u32` module](u32/index.html).*
+#[stable(feature = "rust1", since = "1.0.0")]
+mod prim_u32 { }
+
+#[doc(primitive = "u64")]
+//
+/// The 64-bit unsigned integer type.
+///
+/// *[See also the `std::u64` module](u64/index.html).*
+#[stable(feature = "rust1", since = "1.0.0")]
+mod prim_u64 { }
+
+#[doc(primitive = "u128")]
+//
+/// The 128-bit unsigned integer type.
+///
+/// *[See also the `std::u128` module](u128/index.html).*
+#[stable(feature = "i128", since="1.26.0")]
+mod prim_u128 { }
+
+#[doc(primitive = "isize")]
+//
+/// The pointer-sized signed integer type.
+///
+/// *[See also the `std::isize` module](isize/index.html).*
+///
+/// The size of this primitive is how many bytes it takes to reference any
+/// location in memory. For example, on a 32 bit target, this is 4 bytes
+/// and on a 64 bit target, this is 8 bytes.
+#[stable(feature = "rust1", since = "1.0.0")]
+mod prim_isize { }
+
+#[doc(primitive = "usize")]
+//
+/// The pointer-sized unsigned integer type.
+///
+/// *[See also the `std::usize` module](usize/index.html).*
+///
+/// The size of this primitive is how many bytes it takes to reference any
+/// location in memory. For example, on a 32 bit target, this is 4 bytes
+/// and on a 64 bit target, this is 8 bytes.
+#[stable(feature = "rust1", since = "1.0.0")]
+mod prim_usize { }
+
+#[doc(primitive = "reference")]
+#[doc(alias = "&")]
+//
+/// References, both shared and mutable.
+///
+/// A reference represents a borrow of some owned value. You can get one by using the `&` or `&mut`
+/// operators on a value, or by using a `ref` or `ref mut` pattern.
+///
+/// For those familiar with pointers, a reference is just a pointer that is assumed to not be null.
+/// In fact, `Option<&T>` has the same memory representation as a nullable pointer, and can be
+/// passed across FFI boundaries as such.
+///
+/// In most cases, references can be used much like the original value. Field access, method
+/// calling, and indexing work the same (save for mutability rules, of course). In addition, the
+/// comparison operators transparently defer to the referent's implementation, allowing references
+/// to be compared the same as owned values.
+///
+/// References have a lifetime attached to them, which represents the scope for which the borrow is
+/// valid. A lifetime is said to "outlive" another one if its representative scope is as long or
+/// longer than the other. The `'static` lifetime is the longest lifetime, which represents the
+/// total life of the program. For example, string literals have a `'static` lifetime because the
+/// text data is embedded into the binary of the program, rather than in an allocation that needs
+/// to be dynamically managed.
+///
+/// `&mut T` references can be freely coerced into `&T` references with the same referent type, and
+/// references with longer lifetimes can be freely coerced into references with shorter ones.
+///
+/// Reference equality by address, instead of comparing the values pointed to, is accomplished via
+/// implicit reference-pointer coercion and raw pointer equality via [`ptr::eq`], while
+/// [`PartialEq`] compares values.
+///
+/// [`ptr::eq`]: ptr/fn.eq.html
+/// [`PartialEq`]: cmp/trait.PartialEq.html
+///
+/// ```
+/// use std::ptr;
+///
+/// let five = 5;
+/// let other_five = 5;
+/// let five_ref = &five;
+/// let same_five_ref = &five;
+/// let other_five_ref = &other_five;
+///
+/// assert!(five_ref == same_five_ref);
+/// assert!(five_ref == other_five_ref);
+///
+/// assert!(ptr::eq(five_ref, same_five_ref));
+/// assert!(!ptr::eq(five_ref, other_five_ref));
+/// ```
+///
+/// For more information on how to use references, see [the book's section on "References and
+/// Borrowing"][book-refs].
+///
+/// [book-refs]: ../book/ch04-02-references-and-borrowing.html
+///
+/// # Trait implementations
+///
+/// The following traits are implemented for all `&T`, regardless of the type of its referent:
+///
+/// * [`Copy`]
+/// * [`Clone`] \(Note that this will not defer to `T`'s `Clone` implementation if it exists!)
+/// * [`Deref`]
+/// * [`Borrow`]
+/// * [`Pointer`]
+///
+/// [`Copy`]: marker/trait.Copy.html
+/// [`Clone`]: clone/trait.Clone.html
+/// [`Deref`]: ops/trait.Deref.html
+/// [`Borrow`]: borrow/trait.Borrow.html
+/// [`Pointer`]: fmt/trait.Pointer.html
+///
+/// `&mut T` references get all of the above except `Copy` and `Clone` (to prevent creating
+/// multiple simultaneous mutable borrows), plus the following, regardless of the type of its
+/// referent:
+///
+/// * [`DerefMut`]
+/// * [`BorrowMut`]
+///
+/// [`DerefMut`]: ops/trait.DerefMut.html
+/// [`BorrowMut`]: borrow/trait.BorrowMut.html
+///
+/// The following traits are implemented on `&T` references if the underlying `T` also implements
+/// that trait:
+///
+/// * All the traits in [`std::fmt`] except [`Pointer`] and [`fmt::Write`]
+/// * [`PartialOrd`]
+/// * [`Ord`]
+/// * [`PartialEq`]
+/// * [`Eq`]
+/// * [`AsRef`]
+/// * [`Fn`] \(in addition, `&T` references get [`FnMut`] and [`FnOnce`] if `T: Fn`)
+/// * [`Hash`]
+/// * [`ToSocketAddrs`]
+///
+/// [`std::fmt`]: fmt/index.html
+/// [`fmt::Write`]: fmt/trait.Write.html
+/// [`PartialOrd`]: cmp/trait.PartialOrd.html
+/// [`Ord`]: cmp/trait.Ord.html
+/// [`PartialEq`]: cmp/trait.PartialEq.html
+/// [`Eq`]: cmp/trait.Eq.html
+/// [`AsRef`]: convert/trait.AsRef.html
+/// [`Fn`]: ops/trait.Fn.html
+/// [`FnMut`]: ops/trait.FnMut.html
+/// [`FnOnce`]: ops/trait.FnOnce.html
+/// [`Hash`]: hash/trait.Hash.html
+/// [`ToSocketAddrs`]: net/trait.ToSocketAddrs.html
+///
+/// `&mut T` references get all of the above except `ToSocketAddrs`, plus the following, if `T`
+/// implements that trait:
+///
+/// * [`AsMut`]
+/// * [`FnMut`] \(in addition, `&mut T` references get [`FnOnce`] if `T: FnMut`)
+/// * [`fmt::Write`]
+/// * [`Iterator`]
+/// * [`DoubleEndedIterator`]
+/// * [`ExactSizeIterator`]
+/// * [`FusedIterator`]
+/// * [`TrustedLen`]
+/// * [`Send`] \(note that `&T` references only get `Send` if `T: Sync`)
+/// * [`io::Write`]
+/// * [`Read`]
+/// * [`Seek`]
+/// * [`BufRead`]
+///
+/// [`AsMut`]: convert/trait.AsMut.html
+/// [`Iterator`]: iter/trait.Iterator.html
+/// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html
+/// [`ExactSizeIterator`]: iter/trait.ExactSizeIterator.html
+/// [`FusedIterator`]: iter/trait.FusedIterator.html
+/// [`TrustedLen`]: iter/trait.TrustedLen.html
+/// [`Send`]: marker/trait.Send.html
+/// [`io::Write`]: io/trait.Write.html
+/// [`Read`]: io/trait.Read.html
+/// [`Seek`]: io/trait.Seek.html
+/// [`BufRead`]: io/trait.BufRead.html
+///
+/// Note that due to method call deref coercion, simply calling a trait method will act like they
+/// work on references as well as they do on owned values! The implementations described here are
+/// meant for generic contexts, where the final type `T` is a type parameter or otherwise not
+/// locally known.
+#[stable(feature = "rust1", since = "1.0.0")]
+mod prim_ref { }
+
+#[doc(primitive = "fn")]
+//
+/// Function pointers, like `fn(usize) -> bool`.
+///
+/// *See also the traits [`Fn`], [`FnMut`], and [`FnOnce`].*
+///
+/// [`Fn`]: ops/trait.Fn.html
+/// [`FnMut`]: ops/trait.FnMut.html
+/// [`FnOnce`]: ops/trait.FnOnce.html
+///
+/// Plain function pointers are obtained by casting either plain functions, or closures that don't
+/// capture an environment:
+///
+/// ```
+/// fn add_one(x: usize) -> usize {
+/// x + 1
+/// }
+///
+/// let ptr: fn(usize) -> usize = add_one;
+/// assert_eq!(ptr(5), 6);
+///
+/// let clos: fn(usize) -> usize = |x| x + 5;
+/// assert_eq!(clos(5), 10);
+/// ```
+///
+/// In addition to varying based on their signature, function pointers come in two flavors: safe
+/// and unsafe. Plain `fn()` function pointers can only point to safe functions,
+/// while `unsafe fn()` function pointers can point to safe or unsafe functions.
+///
+/// ```
+/// fn add_one(x: usize) -> usize {
+/// x + 1
+/// }
+///
+/// unsafe fn add_one_unsafely(x: usize) -> usize {
+/// x + 1
+/// }
+///
+/// let safe_ptr: fn(usize) -> usize = add_one;
+///
+/// //ERROR: mismatched types: expected normal fn, found unsafe fn
+/// //let bad_ptr: fn(usize) -> usize = add_one_unsafely;
+///
+/// let unsafe_ptr: unsafe fn(usize) -> usize = add_one_unsafely;
+/// let really_safe_ptr: unsafe fn(usize) -> usize = add_one;
+/// ```
+///
+/// On top of that, function pointers can vary based on what ABI they use. This is achieved by
+/// adding the `extern` keyword to the type name, followed by the ABI in question. For example,
+/// `fn()` is different from `extern "C" fn()`, which itself is different from `extern "stdcall"
+/// fn()`, and so on for the various ABIs that Rust supports. Non-`extern` functions have an ABI
+/// of `"Rust"`, and `extern` functions without an explicit ABI have an ABI of `"C"`. For more
+/// information, see [the nomicon's section on foreign calling conventions][nomicon-abi].
+///
+/// [nomicon-abi]: ../nomicon/ffi.html#foreign-calling-conventions
+///
+/// Extern function declarations with the "C" or "cdecl" ABIs can also be *variadic*, allowing them
+/// to be called with a variable number of arguments. Normal rust functions, even those with an
+/// `extern "ABI"`, cannot be variadic. For more information, see [the nomicon's section on
+/// variadic functions][nomicon-variadic].
+///
+/// [nomicon-variadic]: ../nomicon/ffi.html#variadic-functions
+///
+/// These markers can be combined, so `unsafe extern "stdcall" fn()` is a valid type.
+///
+/// Like references in rust, function pointers are assumed to not be null, so if you want to pass a
+/// function pointer over FFI and be able to accommodate null pointers, make your type
+/// `Option<fn()>` with your required signature.
+///
+/// Function pointers implement the following traits:
+///
+/// * [`Clone`]
+/// * [`PartialEq`]
+/// * [`Eq`]
+/// * [`PartialOrd`]
+/// * [`Ord`]
+/// * [`Hash`]
+/// * [`Pointer`]
+/// * [`Debug`]
+///
+/// [`Clone`]: clone/trait.Clone.html
+/// [`PartialEq`]: cmp/trait.PartialEq.html
+/// [`Eq`]: cmp/trait.Eq.html
+/// [`PartialOrd`]: cmp/trait.PartialOrd.html
+/// [`Ord`]: cmp/trait.Ord.html
+/// [`Hash`]: hash/trait.Hash.html
+/// [`Pointer`]: fmt/trait.Pointer.html
+/// [`Debug`]: fmt/trait.Debug.html
+///
+/// Due to a temporary restriction in Rust's type system, these traits are only implemented on
+/// functions that take 12 arguments or less, with the `"Rust"` and `"C"` ABIs. In the future, this
+/// may change.
+///
+/// In addition, function pointers of *any* signature, ABI, or safety are [`Copy`], and all *safe*
+/// function pointers implement [`Fn`], [`FnMut`], and [`FnOnce`]. This works because these traits
+/// are specially known to the compiler.
+///
+/// [`Copy`]: marker/trait.Copy.html
+#[stable(feature = "rust1", since = "1.0.0")]
+mod prim_fn { }
diff --git a/src/libstd/process.rs b/src/libstd/process.rs
new file mode 100644
index 0000000..e0c9b7c
--- /dev/null
+++ b/src/libstd/process.rs
@@ -0,0 +1,2044 @@
+//! A module for working with processes.
+//!
+//! This module is mostly concerned with spawning and interacting with child
+//! processes, but it also provides [`abort`] and [`exit`] for terminating the
+//! current process.
+//!
+//! # Spawning a process
+//!
+//! The [`Command`] struct is used to configure and spawn processes:
+//!
+//! ```no_run
+//! use std::process::Command;
+//!
+//! let output = Command::new("echo")
+//! .arg("Hello world")
+//! .output()
+//! .expect("Failed to execute command");
+//!
+//! assert_eq!(b"Hello world\n", output.stdout.as_slice());
+//! ```
+//!
+//! Several methods on [`Command`], such as [`spawn`] or [`output`], can be used
+//! to spawn a process. In particular, [`output`] spawns the child process and
+//! waits until the process terminates, while [`spawn`] will return a [`Child`]
+//! that represents the spawned child process.
+//!
+//! # Handling I/O
+//!
+//! The [`stdout`], [`stdin`], and [`stderr`] of a child process can be
+//! configured by passing an [`Stdio`] to the corresponding method on
+//! [`Command`]. Once spawned, they can be accessed from the [`Child`]. For
+//! example, piping output from one command into another command can be done
+//! like so:
+//!
+//! ```no_run
+//! use std::process::{Command, Stdio};
+//!
+//! // stdout must be configured with `Stdio::piped` in order to use
+//! // `echo_child.stdout`
+//! let echo_child = Command::new("echo")
+//! .arg("Oh no, a tpyo!")
+//! .stdout(Stdio::piped())
+//! .spawn()
+//! .expect("Failed to start echo process");
+//!
+//! // Note that `echo_child` is moved here, but we won't be needing
+//! // `echo_child` anymore
+//! let echo_out = echo_child.stdout.expect("Failed to open echo stdout");
+//!
+//! let mut sed_child = Command::new("sed")
+//! .arg("s/tpyo/typo/")
+//! .stdin(Stdio::from(echo_out))
+//! .stdout(Stdio::piped())
+//! .spawn()
+//! .expect("Failed to start sed process");
+//!
+//! let output = sed_child.wait_with_output().expect("Failed to wait on sed");
+//! assert_eq!(b"Oh no, a typo!\n", output.stdout.as_slice());
+//! ```
+//!
+//! Note that [`ChildStderr`] and [`ChildStdout`] implement [`Read`] and
+//! [`ChildStdin`] implements [`Write`]:
+//!
+//! ```no_run
+//! use std::process::{Command, Stdio};
+//! use std::io::Write;
+//!
+//! let mut child = Command::new("/bin/cat")
+//! .stdin(Stdio::piped())
+//! .stdout(Stdio::piped())
+//! .spawn()
+//! .expect("failed to execute child");
+//!
+//! {
+//! // limited borrow of stdin
+//! let stdin = child.stdin.as_mut().expect("failed to get stdin");
+//! stdin.write_all(b"test").expect("failed to write to stdin");
+//! }
+//!
+//! let output = child
+//! .wait_with_output()
+//! .expect("failed to wait on child");
+//!
+//! assert_eq!(b"test", output.stdout.as_slice());
+//! ```
+//!
+//! [`abort`]: fn.abort.html
+//! [`exit`]: fn.exit.html
+//!
+//! [`Command`]: struct.Command.html
+//! [`spawn`]: struct.Command.html#method.spawn
+//! [`output`]: struct.Command.html#method.output
+//!
+//! [`Child`]: struct.Child.html
+//! [`ChildStdin`]: struct.ChildStdin.html
+//! [`ChildStdout`]: struct.ChildStdout.html
+//! [`ChildStderr`]: struct.ChildStderr.html
+//! [`Stdio`]: struct.Stdio.html
+//!
+//! [`stdout`]: struct.Command.html#method.stdout
+//! [`stdin`]: struct.Command.html#method.stdin
+//! [`stderr`]: struct.Command.html#method.stderr
+//!
+//! [`Write`]: ../io/trait.Write.html
+//! [`Read`]: ../io/trait.Read.html
+
+#![stable(feature = "process", since = "1.0.0")]
+
+use crate::io::prelude::*;
+
+use crate::ffi::OsStr;
+use crate::fmt;
+use crate::fs;
+use crate::io::{self, Initializer};
+use crate::path::Path;
+use crate::str;
+use crate::sys::pipe::{read2, AnonPipe};
+use crate::sys::process as imp;
+use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
+
+/// Representation of a running or exited child process.
+///
+/// This structure is used to represent and manage child processes. A child
+/// process is created via the [`Command`] struct, which configures the
+/// spawning process and can itself be constructed using a builder-style
+/// interface.
+///
+/// There is no implementation of [`Drop`] for child processes,
+/// so if you do not ensure the `Child` has exited then it will continue to
+/// run, even after the `Child` handle to the child process has gone out of
+/// scope.
+///
+/// Calling [`wait`](#method.wait) (or other functions that wrap around it) will make
+/// the parent process wait until the child has actually exited before
+/// continuing.
+///
+/// # Examples
+///
+/// ```should_panic
+/// use std::process::Command;
+///
+/// let mut child = Command::new("/bin/cat")
+/// .arg("file.txt")
+/// .spawn()
+/// .expect("failed to execute child");
+///
+/// let ecode = child.wait()
+/// .expect("failed to wait on child");
+///
+/// assert!(ecode.success());
+/// ```
+///
+/// [`Command`]: struct.Command.html
+/// [`Drop`]: ../../core/ops/trait.Drop.html
+/// [`wait`]: #method.wait
+#[stable(feature = "process", since = "1.0.0")]
+pub struct Child {
+ handle: imp::Process,
+
+ /// The handle for writing to the child's standard input (stdin), if it has
+ /// been captured.
+ #[stable(feature = "process", since = "1.0.0")]
+ pub stdin: Option<ChildStdin>,
+
+ /// The handle for reading from the child's standard output (stdout), if it
+ /// has been captured.
+ #[stable(feature = "process", since = "1.0.0")]
+ pub stdout: Option<ChildStdout>,
+
+ /// The handle for reading from the child's standard error (stderr), if it
+ /// has been captured.
+ #[stable(feature = "process", since = "1.0.0")]
+ pub stderr: Option<ChildStderr>,
+}
+
+impl AsInner<imp::Process> for Child {
+ fn as_inner(&self) -> &imp::Process { &self.handle }
+}
+
+impl FromInner<(imp::Process, imp::StdioPipes)> for Child {
+ fn from_inner((handle, io): (imp::Process, imp::StdioPipes)) -> Child {
+ Child {
+ handle,
+ stdin: io.stdin.map(ChildStdin::from_inner),
+ stdout: io.stdout.map(ChildStdout::from_inner),
+ stderr: io.stderr.map(ChildStderr::from_inner),
+ }
+ }
+}
+
+impl IntoInner<imp::Process> for Child {
+ fn into_inner(self) -> imp::Process { self.handle }
+}
+
+#[stable(feature = "std_debug", since = "1.16.0")]
+impl fmt::Debug for Child {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("Child")
+ .field("stdin", &self.stdin)
+ .field("stdout", &self.stdout)
+ .field("stderr", &self.stderr)
+ .finish()
+ }
+}
+
+/// A handle to a child process's standard input (stdin).
+///
+/// This struct is used in the [`stdin`] field on [`Child`].
+///
+/// When an instance of `ChildStdin` is [dropped], the `ChildStdin`'s underlying
+/// file handle will be closed. If the child process was blocked on input prior
+/// to being dropped, it will become unblocked after dropping.
+///
+/// [`Child`]: struct.Child.html
+/// [`stdin`]: struct.Child.html#structfield.stdin
+/// [dropped]: ../ops/trait.Drop.html
+#[stable(feature = "process", since = "1.0.0")]
+pub struct ChildStdin {
+ inner: AnonPipe
+}
+
+#[stable(feature = "process", since = "1.0.0")]
+impl Write for ChildStdin {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ self.inner.write(buf)
+ }
+
+ fn flush(&mut self) -> io::Result<()> {
+ Ok(())
+ }
+}
+
+impl AsInner<AnonPipe> for ChildStdin {
+ fn as_inner(&self) -> &AnonPipe { &self.inner }
+}
+
+impl IntoInner<AnonPipe> for ChildStdin {
+ fn into_inner(self) -> AnonPipe { self.inner }
+}
+
+impl FromInner<AnonPipe> for ChildStdin {
+ fn from_inner(pipe: AnonPipe) -> ChildStdin {
+ ChildStdin { inner: pipe }
+ }
+}
+
+#[stable(feature = "std_debug", since = "1.16.0")]
+impl fmt::Debug for ChildStdin {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.pad("ChildStdin { .. }")
+ }
+}
+
+/// A handle to a child process's standard output (stdout).
+///
+/// This struct is used in the [`stdout`] field on [`Child`].
+///
+/// When an instance of `ChildStdout` is [dropped], the `ChildStdout`'s
+/// underlying file handle will be closed.
+///
+/// [`Child`]: struct.Child.html
+/// [`stdout`]: struct.Child.html#structfield.stdout
+/// [dropped]: ../ops/trait.Drop.html
+#[stable(feature = "process", since = "1.0.0")]
+pub struct ChildStdout {
+ inner: AnonPipe
+}
+
+#[stable(feature = "process", since = "1.0.0")]
+impl Read for ChildStdout {
+ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+ self.inner.read(buf)
+ }
+ #[inline]
+ unsafe fn initializer(&self) -> Initializer {
+ Initializer::nop()
+ }
+}
+
+impl AsInner<AnonPipe> for ChildStdout {
+ fn as_inner(&self) -> &AnonPipe { &self.inner }
+}
+
+impl IntoInner<AnonPipe> for ChildStdout {
+ fn into_inner(self) -> AnonPipe { self.inner }
+}
+
+impl FromInner<AnonPipe> for ChildStdout {
+ fn from_inner(pipe: AnonPipe) -> ChildStdout {
+ ChildStdout { inner: pipe }
+ }
+}
+
+#[stable(feature = "std_debug", since = "1.16.0")]
+impl fmt::Debug for ChildStdout {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.pad("ChildStdout { .. }")
+ }
+}
+
+/// A handle to a child process's stderr.
+///
+/// This struct is used in the [`stderr`] field on [`Child`].
+///
+/// When an instance of `ChildStderr` is [dropped], the `ChildStderr`'s
+/// underlying file handle will be closed.
+///
+/// [`Child`]: struct.Child.html
+/// [`stderr`]: struct.Child.html#structfield.stderr
+/// [dropped]: ../ops/trait.Drop.html
+#[stable(feature = "process", since = "1.0.0")]
+pub struct ChildStderr {
+ inner: AnonPipe
+}
+
+#[stable(feature = "process", since = "1.0.0")]
+impl Read for ChildStderr {
+ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+ self.inner.read(buf)
+ }
+ #[inline]
+ unsafe fn initializer(&self) -> Initializer {
+ Initializer::nop()
+ }
+}
+
+impl AsInner<AnonPipe> for ChildStderr {
+ fn as_inner(&self) -> &AnonPipe { &self.inner }
+}
+
+impl IntoInner<AnonPipe> for ChildStderr {
+ fn into_inner(self) -> AnonPipe { self.inner }
+}
+
+impl FromInner<AnonPipe> for ChildStderr {
+ fn from_inner(pipe: AnonPipe) -> ChildStderr {
+ ChildStderr { inner: pipe }
+ }
+}
+
+#[stable(feature = "std_debug", since = "1.16.0")]
+impl fmt::Debug for ChildStderr {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.pad("ChildStderr { .. }")
+ }
+}
+
+/// A process builder, providing fine-grained control
+/// over how a new process should be spawned.
+///
+/// A default configuration can be
+/// generated using `Command::new(program)`, where `program` gives a path to the
+/// program to be executed. Additional builder methods allow the configuration
+/// to be changed (for example, by adding arguments) prior to spawning:
+///
+/// ```
+/// use std::process::Command;
+///
+/// let output = if cfg!(target_os = "windows") {
+/// Command::new("cmd")
+/// .args(&["/C", "echo hello"])
+/// .output()
+/// .expect("failed to execute process")
+/// } else {
+/// Command::new("sh")
+/// .arg("-c")
+/// .arg("echo hello")
+/// .output()
+/// .expect("failed to execute process")
+/// };
+///
+/// let hello = output.stdout;
+/// ```
+///
+/// `Command` can be reused to spawn multiple processes. The builder methods
+/// change the command without needing to immediately spawn the process.
+///
+/// ```no_run
+/// use std::process::Command;
+///
+/// let mut echo_hello = Command::new("sh");
+/// echo_hello.arg("-c")
+/// .arg("echo hello");
+/// let hello_1 = echo_hello.output().expect("failed to execute process");
+/// let hello_2 = echo_hello.output().expect("failed to execute process");
+/// ```
+///
+/// Similarly, you can call builder methods after spawning a process and then
+/// spawn a new process with the modified settings.
+///
+/// ```no_run
+/// use std::process::Command;
+///
+/// let mut list_dir = Command::new("ls");
+///
+/// // Execute `ls` in the current directory of the program.
+/// list_dir.status().expect("process failed to execute");
+///
+/// println!("");
+///
+/// // Change `ls` to execute in the root directory.
+/// list_dir.current_dir("/");
+///
+/// // And then execute `ls` again but in the root directory.
+/// list_dir.status().expect("process failed to execute");
+/// ```
+#[stable(feature = "process", since = "1.0.0")]
+pub struct Command {
+ inner: imp::Command,
+}
+
+impl Command {
+ /// Constructs a new `Command` for launching the program at
+ /// path `program`, with the following default configuration:
+ ///
+ /// * No arguments to the program
+ /// * Inherit the current process's environment
+ /// * Inherit the current process's working directory
+ /// * Inherit stdin/stdout/stderr for `spawn` or `status`, but create pipes for `output`
+ ///
+ /// Builder methods are provided to change these defaults and
+ /// otherwise configure the process.
+ ///
+ /// If `program` is not an absolute path, the `PATH` will be searched in
+ /// an OS-defined way.
+ ///
+ /// The search path to be used may be controlled by setting the
+ /// `PATH` environment variable on the Command,
+ /// but this has some implementation limitations on Windows
+ /// (see issue #37519).
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```no_run
+ /// use std::process::Command;
+ ///
+ /// Command::new("sh")
+ /// .spawn()
+ /// .expect("sh command failed to start");
+ /// ```
+ #[stable(feature = "process", since = "1.0.0")]
+ pub fn new<S: AsRef<OsStr>>(program: S) -> Command {
+ Command { inner: imp::Command::new(program.as_ref()) }
+ }
+
+ /// Adds an argument to pass to the program.
+ ///
+ /// Only one argument can be passed per use. So instead of:
+ ///
+ /// ```no_run
+ /// # std::process::Command::new("sh")
+ /// .arg("-C /path/to/repo")
+ /// # ;
+ /// ```
+ ///
+ /// usage would be:
+ ///
+ /// ```no_run
+ /// # std::process::Command::new("sh")
+ /// .arg("-C")
+ /// .arg("/path/to/repo")
+ /// # ;
+ /// ```
+ ///
+ /// To pass multiple arguments see [`args`].
+ ///
+ /// [`args`]: #method.args
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```no_run
+ /// use std::process::Command;
+ ///
+ /// Command::new("ls")
+ /// .arg("-l")
+ /// .arg("-a")
+ /// .spawn()
+ /// .expect("ls command failed to start");
+ /// ```
+ #[stable(feature = "process", since = "1.0.0")]
+ pub fn arg<S: AsRef<OsStr>>(&mut self, arg: S) -> &mut Command {
+ self.inner.arg(arg.as_ref());
+ self
+ }
+
+ /// Adds multiple arguments to pass to the program.
+ ///
+ /// To pass a single argument see [`arg`].
+ ///
+ /// [`arg`]: #method.arg
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```no_run
+ /// use std::process::Command;
+ ///
+ /// Command::new("ls")
+ /// .args(&["-l", "-a"])
+ /// .spawn()
+ /// .expect("ls command failed to start");
+ /// ```
+ #[stable(feature = "process", since = "1.0.0")]
+ pub fn args<I, S>(&mut self, args: I) -> &mut Command
+ where I: IntoIterator<Item=S>, S: AsRef<OsStr>
+ {
+ for arg in args {
+ self.arg(arg.as_ref());
+ }
+ self
+ }
+
+ /// Inserts or updates an environment variable mapping.
+ ///
+ /// Note that environment variable names are case-insensitive (but case-preserving) on Windows,
+ /// and case-sensitive on all other platforms.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```no_run
+ /// use std::process::Command;
+ ///
+ /// Command::new("ls")
+ /// .env("PATH", "/bin")
+ /// .spawn()
+ /// .expect("ls command failed to start");
+ /// ```
+ #[stable(feature = "process", since = "1.0.0")]
+ pub fn env<K, V>(&mut self, key: K, val: V) -> &mut Command
+ where K: AsRef<OsStr>, V: AsRef<OsStr>
+ {
+ self.inner.env_mut().set(key.as_ref(), val.as_ref());
+ self
+ }
+
+ /// Adds or updates multiple environment variable mappings.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```no_run
+ /// use std::process::{Command, Stdio};
+ /// use std::env;
+ /// use std::collections::HashMap;
+ ///
+ /// let filtered_env : HashMap<String, String> =
+ /// env::vars().filter(|&(ref k, _)|
+ /// k == "TERM" || k == "TZ" || k == "LANG" || k == "PATH"
+ /// ).collect();
+ ///
+ /// Command::new("printenv")
+ /// .stdin(Stdio::null())
+ /// .stdout(Stdio::inherit())
+ /// .env_clear()
+ /// .envs(&filtered_env)
+ /// .spawn()
+ /// .expect("printenv failed to start");
+ /// ```
+ #[stable(feature = "command_envs", since = "1.19.0")]
+ pub fn envs<I, K, V>(&mut self, vars: I) -> &mut Command
+ where I: IntoIterator<Item=(K, V)>, K: AsRef<OsStr>, V: AsRef<OsStr>
+ {
+ for (ref key, ref val) in vars {
+ self.inner.env_mut().set(key.as_ref(), val.as_ref());
+ }
+ self
+ }
+
+ /// Removes an environment variable mapping.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```no_run
+ /// use std::process::Command;
+ ///
+ /// Command::new("ls")
+ /// .env_remove("PATH")
+ /// .spawn()
+ /// .expect("ls command failed to start");
+ /// ```
+ #[stable(feature = "process", since = "1.0.0")]
+ pub fn env_remove<K: AsRef<OsStr>>(&mut self, key: K) -> &mut Command {
+ self.inner.env_mut().remove(key.as_ref());
+ self
+ }
+
+ /// Clears the entire environment map for the child process.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```no_run
+ /// use std::process::Command;
+ ///
+ /// Command::new("ls")
+ /// .env_clear()
+ /// .spawn()
+ /// .expect("ls command failed to start");
+ /// ```
+ #[stable(feature = "process", since = "1.0.0")]
+ pub fn env_clear(&mut self) -> &mut Command {
+ self.inner.env_mut().clear();
+ self
+ }
+
+ /// Sets the working directory for the child process.
+ ///
+ /// # Platform-specific behavior
+ ///
+ /// If the program path is relative (e.g., `"./script.sh"`), it's ambiguous
+ /// whether it should be interpreted relative to the parent's working
+ /// directory or relative to `current_dir`. The behavior in this case is
+ /// platform specific and unstable, and it's recommended to use
+ /// [`canonicalize`] to get an absolute program path instead.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```no_run
+ /// use std::process::Command;
+ ///
+ /// Command::new("ls")
+ /// .current_dir("/bin")
+ /// .spawn()
+ /// .expect("ls command failed to start");
+ /// ```
+ ///
+ /// [`canonicalize`]: ../fs/fn.canonicalize.html
+ #[stable(feature = "process", since = "1.0.0")]
+ pub fn current_dir<P: AsRef<Path>>(&mut self, dir: P) -> &mut Command {
+ self.inner.cwd(dir.as_ref().as_ref());
+ self
+ }
+
+ /// Configuration for the child process's standard input (stdin) handle.
+ ///
+ /// Defaults to [`inherit`] when used with `spawn` or `status`, and
+ /// defaults to [`piped`] when used with `output`.
+ ///
+ /// [`inherit`]: struct.Stdio.html#method.inherit
+ /// [`piped`]: struct.Stdio.html#method.piped
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```no_run
+ /// use std::process::{Command, Stdio};
+ ///
+ /// Command::new("ls")
+ /// .stdin(Stdio::null())
+ /// .spawn()
+ /// .expect("ls command failed to start");
+ /// ```
+ #[stable(feature = "process", since = "1.0.0")]
+ pub fn stdin<T: Into<Stdio>>(&mut self, cfg: T) -> &mut Command {
+ self.inner.stdin(cfg.into().0);
+ self
+ }
+
+ /// Configuration for the child process's standard output (stdout) handle.
+ ///
+ /// Defaults to [`inherit`] when used with `spawn` or `status`, and
+ /// defaults to [`piped`] when used with `output`.
+ ///
+ /// [`inherit`]: struct.Stdio.html#method.inherit
+ /// [`piped`]: struct.Stdio.html#method.piped
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```no_run
+ /// use std::process::{Command, Stdio};
+ ///
+ /// Command::new("ls")
+ /// .stdout(Stdio::null())
+ /// .spawn()
+ /// .expect("ls command failed to start");
+ /// ```
+ #[stable(feature = "process", since = "1.0.0")]
+ pub fn stdout<T: Into<Stdio>>(&mut self, cfg: T) -> &mut Command {
+ self.inner.stdout(cfg.into().0);
+ self
+ }
+
+ /// Configuration for the child process's standard error (stderr) handle.
+ ///
+ /// Defaults to [`inherit`] when used with `spawn` or `status`, and
+ /// defaults to [`piped`] when used with `output`.
+ ///
+ /// [`inherit`]: struct.Stdio.html#method.inherit
+ /// [`piped`]: struct.Stdio.html#method.piped
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```no_run
+ /// use std::process::{Command, Stdio};
+ ///
+ /// Command::new("ls")
+ /// .stderr(Stdio::null())
+ /// .spawn()
+ /// .expect("ls command failed to start");
+ /// ```
+ #[stable(feature = "process", since = "1.0.0")]
+ pub fn stderr<T: Into<Stdio>>(&mut self, cfg: T) -> &mut Command {
+ self.inner.stderr(cfg.into().0);
+ self
+ }
+
+ /// Executes the command as a child process, returning a handle to it.
+ ///
+ /// By default, stdin, stdout and stderr are inherited from the parent.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```no_run
+ /// use std::process::Command;
+ ///
+ /// Command::new("ls")
+ /// .spawn()
+ /// .expect("ls command failed to start");
+ /// ```
+ #[stable(feature = "process", since = "1.0.0")]
+ pub fn spawn(&mut self) -> io::Result<Child> {
+ self.inner.spawn(imp::Stdio::Inherit, true).map(Child::from_inner)
+ }
+
+ /// Executes the command as a child process, waiting for it to finish and
+ /// collecting all of its output.
+ ///
+ /// By default, stdout and stderr are captured (and used to provide the
+ /// resulting output). Stdin is not inherited from the parent and any
+ /// attempt by the child process to read from the stdin stream will result
+ /// in the stream immediately closing.
+ ///
+ /// # Examples
+ ///
+ /// ```should_panic
+ /// use std::process::Command;
+ /// use std::io::{self, Write};
+ /// let output = Command::new("/bin/cat")
+ /// .arg("file.txt")
+ /// .output()
+ /// .expect("failed to execute process");
+ ///
+ /// println!("status: {}", output.status);
+ /// io::stdout().write_all(&output.stdout).unwrap();
+ /// io::stderr().write_all(&output.stderr).unwrap();
+ ///
+ /// assert!(output.status.success());
+ /// ```
+ #[stable(feature = "process", since = "1.0.0")]
+ pub fn output(&mut self) -> io::Result<Output> {
+ self.inner.spawn(imp::Stdio::MakePipe, false).map(Child::from_inner)
+ .and_then(|p| p.wait_with_output())
+ }
+
+ /// Executes a command as a child process, waiting for it to finish and
+ /// collecting its exit status.
+ ///
+ /// By default, stdin, stdout and stderr are inherited from the parent.
+ ///
+ /// # Examples
+ ///
+ /// ```should_panic
+ /// use std::process::Command;
+ ///
+ /// let status = Command::new("/bin/cat")
+ /// .arg("file.txt")
+ /// .status()
+ /// .expect("failed to execute process");
+ ///
+ /// println!("process exited with: {}", status);
+ ///
+ /// assert!(status.success());
+ /// ```
+ #[stable(feature = "process", since = "1.0.0")]
+ pub fn status(&mut self) -> io::Result<ExitStatus> {
+ self.inner.spawn(imp::Stdio::Inherit, true).map(Child::from_inner)
+ .and_then(|mut p| p.wait())
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl fmt::Debug for Command {
+ /// Format the program and arguments of a Command for display. Any
+ /// non-utf8 data is lossily converted using the utf8 replacement
+ /// character.
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ self.inner.fmt(f)
+ }
+}
+
+impl AsInner<imp::Command> for Command {
+ fn as_inner(&self) -> &imp::Command { &self.inner }
+}
+
+impl AsInnerMut<imp::Command> for Command {
+ fn as_inner_mut(&mut self) -> &mut imp::Command { &mut self.inner }
+}
+
+/// The output of a finished process.
+///
+/// This is returned in a Result by either the [`output`] method of a
+/// [`Command`], or the [`wait_with_output`] method of a [`Child`]
+/// process.
+///
+/// [`Command`]: struct.Command.html
+/// [`Child`]: struct.Child.html
+/// [`output`]: struct.Command.html#method.output
+/// [`wait_with_output`]: struct.Child.html#method.wait_with_output
+#[derive(PartialEq, Eq, Clone)]
+#[stable(feature = "process", since = "1.0.0")]
+pub struct Output {
+ /// The status (exit code) of the process.
+ #[stable(feature = "process", since = "1.0.0")]
+ pub status: ExitStatus,
+ /// The data that the process wrote to stdout.
+ #[stable(feature = "process", since = "1.0.0")]
+ pub stdout: Vec<u8>,
+ /// The data that the process wrote to stderr.
+ #[stable(feature = "process", since = "1.0.0")]
+ pub stderr: Vec<u8>,
+}
+
+// If either stderr or stdout are valid utf8 strings it prints the valid
+// strings, otherwise it prints the byte sequence instead
+#[stable(feature = "process_output_debug", since = "1.7.0")]
+impl fmt::Debug for Output {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+
+ let stdout_utf8 = str::from_utf8(&self.stdout);
+ let stdout_debug: &dyn fmt::Debug = match stdout_utf8 {
+ Ok(ref str) => str,
+ Err(_) => &self.stdout
+ };
+
+ let stderr_utf8 = str::from_utf8(&self.stderr);
+ let stderr_debug: &dyn fmt::Debug = match stderr_utf8 {
+ Ok(ref str) => str,
+ Err(_) => &self.stderr
+ };
+
+ fmt.debug_struct("Output")
+ .field("status", &self.status)
+ .field("stdout", stdout_debug)
+ .field("stderr", stderr_debug)
+ .finish()
+ }
+}
+
+/// Describes what to do with a standard I/O stream for a child process when
+/// passed to the [`stdin`], [`stdout`], and [`stderr`] methods of [`Command`].
+///
+/// [`stdin`]: struct.Command.html#method.stdin
+/// [`stdout`]: struct.Command.html#method.stdout
+/// [`stderr`]: struct.Command.html#method.stderr
+/// [`Command`]: struct.Command.html
+#[stable(feature = "process", since = "1.0.0")]
+pub struct Stdio(imp::Stdio);
+
+impl Stdio {
+ /// A new pipe should be arranged to connect the parent and child processes.
+ ///
+ /// # Examples
+ ///
+ /// With stdout:
+ ///
+ /// ```no_run
+ /// use std::process::{Command, Stdio};
+ ///
+ /// let output = Command::new("echo")
+ /// .arg("Hello, world!")
+ /// .stdout(Stdio::piped())
+ /// .output()
+ /// .expect("Failed to execute command");
+ ///
+ /// assert_eq!(String::from_utf8_lossy(&output.stdout), "Hello, world!\n");
+ /// // Nothing echoed to console
+ /// ```
+ ///
+ /// With stdin:
+ ///
+ /// ```no_run
+ /// use std::io::Write;
+ /// use std::process::{Command, Stdio};
+ ///
+ /// let mut child = Command::new("rev")
+ /// .stdin(Stdio::piped())
+ /// .stdout(Stdio::piped())
+ /// .spawn()
+ /// .expect("Failed to spawn child process");
+ ///
+ /// {
+ /// let mut stdin = child.stdin.as_mut().expect("Failed to open stdin");
+ /// stdin.write_all("Hello, world!".as_bytes()).expect("Failed to write to stdin");
+ /// }
+ ///
+ /// let output = child.wait_with_output().expect("Failed to read stdout");
+ /// assert_eq!(String::from_utf8_lossy(&output.stdout), "!dlrow ,olleH\n");
+ /// ```
+ #[stable(feature = "process", since = "1.0.0")]
+ pub fn piped() -> Stdio { Stdio(imp::Stdio::MakePipe) }
+
+ /// The child inherits from the corresponding parent descriptor.
+ ///
+ /// # Examples
+ ///
+ /// With stdout:
+ ///
+ /// ```no_run
+ /// use std::process::{Command, Stdio};
+ ///
+ /// let output = Command::new("echo")
+ /// .arg("Hello, world!")
+ /// .stdout(Stdio::inherit())
+ /// .output()
+ /// .expect("Failed to execute command");
+ ///
+ /// assert_eq!(String::from_utf8_lossy(&output.stdout), "");
+ /// // "Hello, world!" echoed to console
+ /// ```
+ ///
+ /// With stdin:
+ ///
+ /// ```no_run
+ /// use std::process::{Command, Stdio};
+ /// use std::io::{self, Write};
+ ///
+ /// let output = Command::new("rev")
+ /// .stdin(Stdio::inherit())
+ /// .stdout(Stdio::piped())
+ /// .output()
+ /// .expect("Failed to execute command");
+ ///
+ /// print!("You piped in the reverse of: ");
+ /// io::stdout().write_all(&output.stdout).unwrap();
+ /// ```
+ #[stable(feature = "process", since = "1.0.0")]
+ pub fn inherit() -> Stdio { Stdio(imp::Stdio::Inherit) }
+
+ /// This stream will be ignored. This is the equivalent of attaching the
+ /// stream to `/dev/null`
+ ///
+ /// # Examples
+ ///
+ /// With stdout:
+ ///
+ /// ```no_run
+ /// use std::process::{Command, Stdio};
+ ///
+ /// let output = Command::new("echo")
+ /// .arg("Hello, world!")
+ /// .stdout(Stdio::null())
+ /// .output()
+ /// .expect("Failed to execute command");
+ ///
+ /// assert_eq!(String::from_utf8_lossy(&output.stdout), "");
+ /// // Nothing echoed to console
+ /// ```
+ ///
+ /// With stdin:
+ ///
+ /// ```no_run
+ /// use std::process::{Command, Stdio};
+ ///
+ /// let output = Command::new("rev")
+ /// .stdin(Stdio::null())
+ /// .stdout(Stdio::piped())
+ /// .output()
+ /// .expect("Failed to execute command");
+ ///
+ /// assert_eq!(String::from_utf8_lossy(&output.stdout), "");
+ /// // Ignores any piped-in input
+ /// ```
+ #[stable(feature = "process", since = "1.0.0")]
+ pub fn null() -> Stdio { Stdio(imp::Stdio::Null) }
+}
+
+impl FromInner<imp::Stdio> for Stdio {
+ fn from_inner(inner: imp::Stdio) -> Stdio {
+ Stdio(inner)
+ }
+}
+
+#[stable(feature = "std_debug", since = "1.16.0")]
+impl fmt::Debug for Stdio {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.pad("Stdio { .. }")
+ }
+}
+
+#[stable(feature = "stdio_from", since = "1.20.0")]
+impl From<ChildStdin> for Stdio {
+ /// Converts a `ChildStdin` into a `Stdio`
+ ///
+ /// # Examples
+ ///
+ /// `ChildStdin` will be converted to `Stdio` using `Stdio::from` under the hood.
+ ///
+ /// ```rust,no_run
+ /// use std::process::{Command, Stdio};
+ ///
+ /// let reverse = Command::new("rev")
+ /// .stdin(Stdio::piped())
+ /// .spawn()
+ /// .expect("failed reverse command");
+ ///
+ /// let _echo = Command::new("echo")
+ /// .arg("Hello, world!")
+ /// .stdout(reverse.stdin.unwrap()) // Converted into a Stdio here
+ /// .output()
+ /// .expect("failed echo command");
+ ///
+ /// // "!dlrow ,olleH" echoed to console
+ /// ```
+ fn from(child: ChildStdin) -> Stdio {
+ Stdio::from_inner(child.into_inner().into())
+ }
+}
+
+#[stable(feature = "stdio_from", since = "1.20.0")]
+impl From<ChildStdout> for Stdio {
+ /// Converts a `ChildStdout` into a `Stdio`
+ ///
+ /// # Examples
+ ///
+ /// `ChildStdout` will be converted to `Stdio` using `Stdio::from` under the hood.
+ ///
+ /// ```rust,no_run
+ /// use std::process::{Command, Stdio};
+ ///
+ /// let hello = Command::new("echo")
+ /// .arg("Hello, world!")
+ /// .stdout(Stdio::piped())
+ /// .spawn()
+ /// .expect("failed echo command");
+ ///
+ /// let reverse = Command::new("rev")
+ /// .stdin(hello.stdout.unwrap()) // Converted into a Stdio here
+ /// .output()
+ /// .expect("failed reverse command");
+ ///
+ /// assert_eq!(reverse.stdout, b"!dlrow ,olleH\n");
+ /// ```
+ fn from(child: ChildStdout) -> Stdio {
+ Stdio::from_inner(child.into_inner().into())
+ }
+}
+
+#[stable(feature = "stdio_from", since = "1.20.0")]
+impl From<ChildStderr> for Stdio {
+ /// Converts a `ChildStderr` into a `Stdio`
+ ///
+ /// # Examples
+ ///
+ /// ```rust,no_run
+ /// use std::process::{Command, Stdio};
+ ///
+ /// let reverse = Command::new("rev")
+ /// .arg("non_existing_file.txt")
+ /// .stderr(Stdio::piped())
+ /// .spawn()
+ /// .expect("failed reverse command");
+ ///
+ /// let cat = Command::new("cat")
+ /// .arg("-")
+ /// .stdin(reverse.stderr.unwrap()) // Converted into a Stdio here
+ /// .output()
+ /// .expect("failed echo command");
+ ///
+ /// assert_eq!(
+ /// String::from_utf8_lossy(&cat.stdout),
+ /// "rev: cannot open non_existing_file.txt: No such file or directory\n"
+ /// );
+ /// ```
+ fn from(child: ChildStderr) -> Stdio {
+ Stdio::from_inner(child.into_inner().into())
+ }
+}
+
+#[stable(feature = "stdio_from", since = "1.20.0")]
+impl From<fs::File> for Stdio {
+ /// Converts a `File` into a `Stdio`
+ ///
+ /// # Examples
+ ///
+ /// `File` will be converted to `Stdio` using `Stdio::from` under the hood.
+ ///
+ /// ```rust,no_run
+ /// use std::fs::File;
+ /// use std::process::Command;
+ ///
+ /// // With the `foo.txt` file containing `Hello, world!"
+ /// let file = File::open("foo.txt").unwrap();
+ ///
+ /// let reverse = Command::new("rev")
+ /// .stdin(file) // Implicit File conversion into a Stdio
+ /// .output()
+ /// .expect("failed reverse command");
+ ///
+ /// assert_eq!(reverse.stdout, b"!dlrow ,olleH");
+ /// ```
+ fn from(file: fs::File) -> Stdio {
+ Stdio::from_inner(file.into_inner().into())
+ }
+}
+
+/// Describes the result of a process after it has terminated.
+///
+/// This `struct` is used to represent the exit status of a child process.
+/// Child processes are created via the [`Command`] struct and their exit
+/// status is exposed through the [`status`] method.
+///
+/// [`Command`]: struct.Command.html
+/// [`status`]: struct.Command.html#method.status
+#[derive(PartialEq, Eq, Clone, Copy, Debug)]
+#[stable(feature = "process", since = "1.0.0")]
+pub struct ExitStatus(imp::ExitStatus);
+
+impl ExitStatus {
+ /// Was termination successful? Signal termination is not considered a
+ /// success, and success is defined as a zero exit status.
+ ///
+ /// # Examples
+ ///
+ /// ```rust,no_run
+ /// use std::process::Command;
+ ///
+ /// let status = Command::new("mkdir")
+ /// .arg("projects")
+ /// .status()
+ /// .expect("failed to execute mkdir");
+ ///
+ /// if status.success() {
+ /// println!("'projects/' directory created");
+ /// } else {
+ /// println!("failed to create 'projects/' directory");
+ /// }
+ /// ```
+ #[stable(feature = "process", since = "1.0.0")]
+ pub fn success(&self) -> bool {
+ self.0.success()
+ }
+
+ /// Returns the exit code of the process, if any.
+ ///
+ /// On Unix, this will return `None` if the process was terminated
+ /// by a signal; `std::os::unix` provides an extension trait for
+ /// extracting the signal and other details from the `ExitStatus`.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::process::Command;
+ ///
+ /// let status = Command::new("mkdir")
+ /// .arg("projects")
+ /// .status()
+ /// .expect("failed to execute mkdir");
+ ///
+ /// match status.code() {
+ /// Some(code) => println!("Exited with status code: {}", code),
+ /// None => println!("Process terminated by signal")
+ /// }
+ /// ```
+ #[stable(feature = "process", since = "1.0.0")]
+ pub fn code(&self) -> Option<i32> {
+ self.0.code()
+ }
+}
+
+impl AsInner<imp::ExitStatus> for ExitStatus {
+ fn as_inner(&self) -> &imp::ExitStatus { &self.0 }
+}
+
+impl FromInner<imp::ExitStatus> for ExitStatus {
+ fn from_inner(s: imp::ExitStatus) -> ExitStatus {
+ ExitStatus(s)
+ }
+}
+
+#[stable(feature = "process", since = "1.0.0")]
+impl fmt::Display for ExitStatus {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ self.0.fmt(f)
+ }
+}
+
+/// This type represents the status code a process can return to its
+/// parent under normal termination.
+///
+/// Numeric values used in this type don't have portable meanings, and
+/// different platforms may mask different amounts of them.
+///
+/// For the platform's canonical successful and unsuccessful codes, see
+/// the [`SUCCESS`] and [`FAILURE`] associated items.
+///
+/// [`SUCCESS`]: #associatedconstant.SUCCESS
+/// [`FAILURE`]: #associatedconstant.FAILURE
+///
+/// **Warning**: While various forms of this were discussed in [RFC #1937],
+/// it was ultimately cut from that RFC, and thus this type is more subject
+/// to change even than the usual unstable item churn.
+///
+/// [RFC #1937]: https://github.com/rust-lang/rfcs/pull/1937
+#[derive(Clone, Copy, Debug)]
+#[unstable(feature = "process_exitcode_placeholder", issue = "48711")]
+pub struct ExitCode(imp::ExitCode);
+
+#[unstable(feature = "process_exitcode_placeholder", issue = "48711")]
+impl ExitCode {
+ /// The canonical ExitCode for successful termination on this platform.
+ ///
+ /// Note that a `()`-returning `main` implicitly results in a successful
+ /// termination, so there's no need to return this from `main` unless
+ /// you're also returning other possible codes.
+ #[unstable(feature = "process_exitcode_placeholder", issue = "48711")]
+ pub const SUCCESS: ExitCode = ExitCode(imp::ExitCode::SUCCESS);
+
+ /// The canonical ExitCode for unsuccessful termination on this platform.
+ ///
+ /// If you're only returning this and `SUCCESS` from `main`, consider
+ /// instead returning `Err(_)` and `Ok(())` respectively, which will
+ /// return the same codes (but will also `eprintln!` the error).
+ #[unstable(feature = "process_exitcode_placeholder", issue = "48711")]
+ pub const FAILURE: ExitCode = ExitCode(imp::ExitCode::FAILURE);
+}
+
+impl Child {
+ /// Forces the child process to exit. If the child has already exited, an [`InvalidInput`]
+ /// error is returned.
+ ///
+ /// The mapping to [`ErrorKind`]s is not part of the compatibility contract of the function,
+ /// especially the [`Other`] kind might change to more specific kinds in the future.
+ ///
+ /// This is equivalent to sending a SIGKILL on Unix platforms.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```no_run
+ /// use std::process::Command;
+ ///
+ /// let mut command = Command::new("yes");
+ /// if let Ok(mut child) = command.spawn() {
+ /// child.kill().expect("command wasn't running");
+ /// } else {
+ /// println!("yes command didn't start");
+ /// }
+ /// ```
+ ///
+ /// [`ErrorKind`]: ../io/enum.ErrorKind.html
+ /// [`InvalidInput`]: ../io/enum.ErrorKind.html#variant.InvalidInput
+ /// [`Other`]: ../io/enum.ErrorKind.html#variant.Other
+ #[stable(feature = "process", since = "1.0.0")]
+ pub fn kill(&mut self) -> io::Result<()> {
+ self.handle.kill()
+ }
+
+ /// Returns the OS-assigned process identifier associated with this child.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```no_run
+ /// use std::process::Command;
+ ///
+ /// let mut command = Command::new("ls");
+ /// if let Ok(child) = command.spawn() {
+ /// println!("Child's ID is {}", child.id());
+ /// } else {
+ /// println!("ls command didn't start");
+ /// }
+ /// ```
+ #[stable(feature = "process_id", since = "1.3.0")]
+ pub fn id(&self) -> u32 {
+ self.handle.id()
+ }
+
+ /// Waits for the child to exit completely, returning the status that it
+ /// exited with. This function will continue to have the same return value
+ /// after it has been called at least once.
+ ///
+ /// The stdin handle to the child process, if any, will be closed
+ /// before waiting. This helps avoid deadlock: it ensures that the
+ /// child does not block waiting for input from the parent, while
+ /// the parent waits for the child to exit.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```no_run
+ /// use std::process::Command;
+ ///
+ /// let mut command = Command::new("ls");
+ /// if let Ok(mut child) = command.spawn() {
+ /// child.wait().expect("command wasn't running");
+ /// println!("Child has finished its execution!");
+ /// } else {
+ /// println!("ls command didn't start");
+ /// }
+ /// ```
+ #[stable(feature = "process", since = "1.0.0")]
+ pub fn wait(&mut self) -> io::Result<ExitStatus> {
+ drop(self.stdin.take());
+ self.handle.wait().map(ExitStatus)
+ }
+
+ /// Attempts to collect the exit status of the child if it has already
+ /// exited.
+ ///
+ /// This function will not block the calling thread and will only
+ /// check to see if the child process has exited or not. If the child has
+ /// exited then on Unix the process ID is reaped. This function is
+ /// guaranteed to repeatedly return a successful exit status so long as the
+ /// child has already exited.
+ ///
+ /// If the child has exited, then `Ok(Some(status))` is returned. If the
+ /// exit status is not available at this time then `Ok(None)` is returned.
+ /// If an error occurs, then that error is returned.
+ ///
+ /// Note that unlike `wait`, this function will not attempt to drop stdin.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```no_run
+ /// use std::process::Command;
+ ///
+ /// let mut child = Command::new("ls").spawn().unwrap();
+ ///
+ /// match child.try_wait() {
+ /// Ok(Some(status)) => println!("exited with: {}", status),
+ /// Ok(None) => {
+ /// println!("status not ready yet, let's really wait");
+ /// let res = child.wait();
+ /// println!("result: {:?}", res);
+ /// }
+ /// Err(e) => println!("error attempting to wait: {}", e),
+ /// }
+ /// ```
+ #[stable(feature = "process_try_wait", since = "1.18.0")]
+ pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
+ Ok(self.handle.try_wait()?.map(ExitStatus))
+ }
+
+ /// Simultaneously waits for the child to exit and collect all remaining
+ /// output on the stdout/stderr handles, returning an `Output`
+ /// instance.
+ ///
+ /// The stdin handle to the child process, if any, will be closed
+ /// before waiting. This helps avoid deadlock: it ensures that the
+ /// child does not block waiting for input from the parent, while
+ /// the parent waits for the child to exit.
+ ///
+ /// By default, stdin, stdout and stderr are inherited from the parent.
+ /// In order to capture the output into this `Result<Output>` it is
+ /// necessary to create new pipes between parent and child. Use
+ /// `stdout(Stdio::piped())` or `stderr(Stdio::piped())`, respectively.
+ ///
+ /// # Examples
+ ///
+ /// ```should_panic
+ /// use std::process::{Command, Stdio};
+ ///
+ /// let child = Command::new("/bin/cat")
+ /// .arg("file.txt")
+ /// .stdout(Stdio::piped())
+ /// .spawn()
+ /// .expect("failed to execute child");
+ ///
+ /// let output = child
+ /// .wait_with_output()
+ /// .expect("failed to wait on child");
+ ///
+ /// assert!(output.status.success());
+ /// ```
+ ///
+ #[stable(feature = "process", since = "1.0.0")]
+ pub fn wait_with_output(mut self) -> io::Result<Output> {
+ drop(self.stdin.take());
+
+ let (mut stdout, mut stderr) = (Vec::new(), Vec::new());
+ match (self.stdout.take(), self.stderr.take()) {
+ (None, None) => {}
+ (Some(mut out), None) => {
+ let res = out.read_to_end(&mut stdout);
+ res.unwrap();
+ }
+ (None, Some(mut err)) => {
+ let res = err.read_to_end(&mut stderr);
+ res.unwrap();
+ }
+ (Some(out), Some(err)) => {
+ let res = read2(out.inner, &mut stdout, err.inner, &mut stderr);
+ res.unwrap();
+ }
+ }
+
+ let status = self.wait()?;
+ Ok(Output {
+ status,
+ stdout,
+ stderr,
+ })
+ }
+}
+
+/// Terminates the current process with the specified exit code.
+///
+/// This function will never return and will immediately terminate the current
+/// process. The exit code is passed through to the underlying OS and will be
+/// available for consumption by another process.
+///
+/// Note that because this function never returns, and that it terminates the
+/// process, no destructors on the current stack or any other thread's stack
+/// will be run. If a clean shutdown is needed it is recommended to only call
+/// this function at a known point where there are no more destructors left
+/// to run.
+///
+/// ## Platform-specific behavior
+///
+/// **Unix**: On Unix-like platforms, it is unlikely that all 32 bits of `exit`
+/// will be visible to a parent process inspecting the exit code. On most
+/// Unix-like platforms, only the eight least-significant bits are considered.
+///
+/// # Examples
+///
+/// Due to this function’s behavior regarding destructors, a conventional way
+/// to use the function is to extract the actual computation to another
+/// function and compute the exit code from its return value:
+///
+/// ```
+/// fn run_app() -> Result<(), ()> {
+/// // Application logic here
+/// Ok(())
+/// }
+///
+/// fn main() {
+/// ::std::process::exit(match run_app() {
+/// Ok(_) => 0,
+/// Err(err) => {
+/// eprintln!("error: {:?}", err);
+/// 1
+/// }
+/// });
+/// }
+/// ```
+///
+/// Due to [platform-specific behavior], the exit code for this example will be
+/// `0` on Linux, but `256` on Windows:
+///
+/// ```no_run
+/// use std::process;
+///
+/// process::exit(0x0100);
+/// ```
+///
+/// [platform-specific behavior]: #platform-specific-behavior
+#[stable(feature = "rust1", since = "1.0.0")]
+pub fn exit(code: i32) -> ! {
+ crate::sys_common::cleanup();
+ crate::sys::os::exit(code)
+}
+
+/// Terminates the process in an abnormal fashion.
+///
+/// The function will never return and will immediately terminate the current
+/// process in a platform specific "abnormal" manner.
+///
+/// Note that because this function never returns, and that it terminates the
+/// process, no destructors on the current stack or any other thread's stack
+/// will be run.
+///
+/// This is in contrast to the default behaviour of [`panic!`] which unwinds
+/// the current thread's stack and calls all destructors.
+/// When `panic="abort"` is set, either as an argument to `rustc` or in a
+/// crate's Cargo.toml, [`panic!`] and `abort` are similar. However,
+/// [`panic!`] will still call the [panic hook] while `abort` will not.
+///
+/// If a clean shutdown is needed it is recommended to only call
+/// this function at a known point where there are no more destructors left
+/// to run.
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::process;
+///
+/// fn main() {
+/// println!("aborting");
+///
+/// process::abort();
+///
+/// // execution never gets here
+/// }
+/// ```
+///
+/// The `abort` function terminates the process, so the destructor will not
+/// get run on the example below:
+///
+/// ```no_run
+/// use std::process;
+///
+/// struct HasDrop;
+///
+/// impl Drop for HasDrop {
+/// fn drop(&mut self) {
+/// println!("This will never be printed!");
+/// }
+/// }
+///
+/// fn main() {
+/// let _x = HasDrop;
+/// process::abort();
+/// // the destructor implemented for HasDrop will never get run
+/// }
+/// ```
+///
+/// [`panic!`]: ../../std/macro.panic.html
+/// [panic hook]: ../../std/panic/fn.set_hook.html
+#[stable(feature = "process_abort", since = "1.17.0")]
+pub fn abort() -> ! {
+ unsafe { crate::sys::abort_internal() };
+}
+
+/// Returns the OS-assigned process identifier associated with this process.
+///
+/// # Examples
+///
+/// Basic usage:
+///
+/// ```no_run
+/// use std::process;
+///
+/// println!("My pid is {}", process::id());
+/// ```
+///
+///
+#[stable(feature = "getpid", since = "1.26.0")]
+pub fn id() -> u32 {
+ crate::sys::os::getpid()
+}
+
+/// A trait for implementing arbitrary return types in the `main` function.
+///
+/// The c-main function only supports to return integers as return type.
+/// So, every type implementing the `Termination` trait has to be converted
+/// to an integer.
+///
+/// The default implementations are returning `libc::EXIT_SUCCESS` to indicate
+/// a successful execution. In case of a failure, `libc::EXIT_FAILURE` is returned.
+#[cfg_attr(not(test), lang = "termination")]
+#[unstable(feature = "termination_trait_lib", issue = "43301")]
+#[rustc_on_unimplemented(
+ message="`main` has invalid return type `{Self}`",
+ label="`main` can only return types that implement `{Termination}`")]
+pub trait Termination {
+ /// Is called to get the representation of the value as status code.
+ /// This status code is returned to the operating system.
+ fn report(self) -> i32;
+}
+
+#[unstable(feature = "termination_trait_lib", issue = "43301")]
+impl Termination for () {
+ #[inline]
+ fn report(self) -> i32 { ExitCode::SUCCESS.report() }
+}
+
+#[unstable(feature = "termination_trait_lib", issue = "43301")]
+impl<E: fmt::Debug> Termination for Result<(), E> {
+ fn report(self) -> i32 {
+ match self {
+ Ok(()) => ().report(),
+ Err(err) => Err::<!, _>(err).report(),
+ }
+ }
+}
+
+#[unstable(feature = "termination_trait_lib", issue = "43301")]
+impl Termination for ! {
+ fn report(self) -> i32 { self }
+}
+
+#[unstable(feature = "termination_trait_lib", issue = "43301")]
+impl<E: fmt::Debug> Termination for Result<!, E> {
+ fn report(self) -> i32 {
+ let Err(err) = self;
+ eprintln!("Error: {:?}", err);
+ ExitCode::FAILURE.report()
+ }
+}
+
+#[unstable(feature = "termination_trait_lib", issue = "43301")]
+impl Termination for ExitCode {
+ #[inline]
+ fn report(self) -> i32 {
+ self.0.as_i32()
+ }
+}
+
+#[cfg(all(test, not(any(target_os = "cloudabi", target_os = "emscripten", target_env = "sgx"))))]
+mod tests {
+ use crate::io::prelude::*;
+
+ use crate::io::ErrorKind;
+ use crate::str;
+ use super::{Command, Output, Stdio};
+
+ // FIXME(#10380) these tests should not all be ignored on android.
+
+ #[test]
+ #[cfg_attr(target_os = "android", ignore)]
+ fn smoke() {
+ let p = if cfg!(target_os = "windows") {
+ Command::new("cmd").args(&["/C", "exit 0"]).spawn()
+ } else {
+ Command::new("true").spawn()
+ };
+ assert!(p.is_ok());
+ let mut p = p.unwrap();
+ assert!(p.wait().unwrap().success());
+ }
+
+ #[test]
+ #[cfg_attr(target_os = "android", ignore)]
+ fn smoke_failure() {
+ match Command::new("if-this-is-a-binary-then-the-world-has-ended").spawn() {
+ Ok(..) => panic!(),
+ Err(..) => {}
+ }
+ }
+
+ #[test]
+ #[cfg_attr(target_os = "android", ignore)]
+ fn exit_reported_right() {
+ let p = if cfg!(target_os = "windows") {
+ Command::new("cmd").args(&["/C", "exit 1"]).spawn()
+ } else {
+ Command::new("false").spawn()
+ };
+ assert!(p.is_ok());
+ let mut p = p.unwrap();
+ assert!(p.wait().unwrap().code() == Some(1));
+ drop(p.wait());
+ }
+
+ #[test]
+ #[cfg(unix)]
+ #[cfg_attr(target_os = "android", ignore)]
+ fn signal_reported_right() {
+ use crate::os::unix::process::ExitStatusExt;
+
+ let mut p = Command::new("/bin/sh")
+ .arg("-c").arg("read a")
+ .stdin(Stdio::piped())
+ .spawn().unwrap();
+ p.kill().unwrap();
+ match p.wait().unwrap().signal() {
+ Some(9) => {},
+ result => panic!("not terminated by signal 9 (instead, {:?})",
+ result),
+ }
+ }
+
+ pub fn run_output(mut cmd: Command) -> String {
+ let p = cmd.spawn();
+ assert!(p.is_ok());
+ let mut p = p.unwrap();
+ assert!(p.stdout.is_some());
+ let mut ret = String::new();
+ p.stdout.as_mut().unwrap().read_to_string(&mut ret).unwrap();
+ assert!(p.wait().unwrap().success());
+ return ret;
+ }
+
+ #[test]
+ #[cfg_attr(target_os = "android", ignore)]
+ fn stdout_works() {
+ if cfg!(target_os = "windows") {
+ let mut cmd = Command::new("cmd");
+ cmd.args(&["/C", "echo foobar"]).stdout(Stdio::piped());
+ assert_eq!(run_output(cmd), "foobar\r\n");
+ } else {
+ let mut cmd = Command::new("echo");
+ cmd.arg("foobar").stdout(Stdio::piped());
+ assert_eq!(run_output(cmd), "foobar\n");
+ }
+ }
+
+ #[test]
+ #[cfg_attr(any(windows, target_os = "android"), ignore)]
+ fn set_current_dir_works() {
+ let mut cmd = Command::new("/bin/sh");
+ cmd.arg("-c").arg("pwd")
+ .current_dir("/")
+ .stdout(Stdio::piped());
+ assert_eq!(run_output(cmd), "/\n");
+ }
+
+ #[test]
+ #[cfg_attr(any(windows, target_os = "android"), ignore)]
+ fn stdin_works() {
+ let mut p = Command::new("/bin/sh")
+ .arg("-c").arg("read line; echo $line")
+ .stdin(Stdio::piped())
+ .stdout(Stdio::piped())
+ .spawn().unwrap();
+ p.stdin.as_mut().unwrap().write("foobar".as_bytes()).unwrap();
+ drop(p.stdin.take());
+ let mut out = String::new();
+ p.stdout.as_mut().unwrap().read_to_string(&mut out).unwrap();
+ assert!(p.wait().unwrap().success());
+ assert_eq!(out, "foobar\n");
+ }
+
+
+ #[test]
+ #[cfg_attr(target_os = "android", ignore)]
+ #[cfg(unix)]
+ fn uid_works() {
+ use crate::os::unix::prelude::*;
+
+ let mut p = Command::new("/bin/sh")
+ .arg("-c").arg("true")
+ .uid(unsafe { libc::getuid() })
+ .gid(unsafe { libc::getgid() })
+ .spawn().unwrap();
+ assert!(p.wait().unwrap().success());
+ }
+
+ #[test]
+ #[cfg_attr(target_os = "android", ignore)]
+ #[cfg(unix)]
+ fn uid_to_root_fails() {
+ use crate::os::unix::prelude::*;
+
+ // if we're already root, this isn't a valid test. Most of the bots run
+ // as non-root though (android is an exception).
+ if unsafe { libc::getuid() == 0 } { return }
+ assert!(Command::new("/bin/ls").uid(0).gid(0).spawn().is_err());
+ }
+
+ #[test]
+ #[cfg_attr(target_os = "android", ignore)]
+ fn test_process_status() {
+ let mut status = if cfg!(target_os = "windows") {
+ Command::new("cmd").args(&["/C", "exit 1"]).status().unwrap()
+ } else {
+ Command::new("false").status().unwrap()
+ };
+ assert!(status.code() == Some(1));
+
+ status = if cfg!(target_os = "windows") {
+ Command::new("cmd").args(&["/C", "exit 0"]).status().unwrap()
+ } else {
+ Command::new("true").status().unwrap()
+ };
+ assert!(status.success());
+ }
+
+ #[test]
+ fn test_process_output_fail_to_start() {
+ match Command::new("/no-binary-by-this-name-should-exist").output() {
+ Err(e) => assert_eq!(e.kind(), ErrorKind::NotFound),
+ Ok(..) => panic!()
+ }
+ }
+
+ #[test]
+ #[cfg_attr(target_os = "android", ignore)]
+ fn test_process_output_output() {
+ let Output {status, stdout, stderr}
+ = if cfg!(target_os = "windows") {
+ Command::new("cmd").args(&["/C", "echo hello"]).output().unwrap()
+ } else {
+ Command::new("echo").arg("hello").output().unwrap()
+ };
+ let output_str = str::from_utf8(&stdout).unwrap();
+
+ assert!(status.success());
+ assert_eq!(output_str.trim().to_string(), "hello");
+ assert_eq!(stderr, Vec::new());
+ }
+
+ #[test]
+ #[cfg_attr(target_os = "android", ignore)]
+ fn test_process_output_error() {
+ let Output {status, stdout, stderr}
+ = if cfg!(target_os = "windows") {
+ Command::new("cmd").args(&["/C", "mkdir ."]).output().unwrap()
+ } else {
+ Command::new("mkdir").arg("./").output().unwrap()
+ };
+
+ assert!(status.code() == Some(1));
+ assert_eq!(stdout, Vec::new());
+ assert!(!stderr.is_empty());
+ }
+
+ #[test]
+ #[cfg_attr(target_os = "android", ignore)]
+ fn test_finish_once() {
+ let mut prog = if cfg!(target_os = "windows") {
+ Command::new("cmd").args(&["/C", "exit 1"]).spawn().unwrap()
+ } else {
+ Command::new("false").spawn().unwrap()
+ };
+ assert!(prog.wait().unwrap().code() == Some(1));
+ }
+
+ #[test]
+ #[cfg_attr(target_os = "android", ignore)]
+ fn test_finish_twice() {
+ let mut prog = if cfg!(target_os = "windows") {
+ Command::new("cmd").args(&["/C", "exit 1"]).spawn().unwrap()
+ } else {
+ Command::new("false").spawn().unwrap()
+ };
+ assert!(prog.wait().unwrap().code() == Some(1));
+ assert!(prog.wait().unwrap().code() == Some(1));
+ }
+
+ #[test]
+ #[cfg_attr(target_os = "android", ignore)]
+ fn test_wait_with_output_once() {
+ let prog = if cfg!(target_os = "windows") {
+ Command::new("cmd").args(&["/C", "echo hello"]).stdout(Stdio::piped()).spawn().unwrap()
+ } else {
+ Command::new("echo").arg("hello").stdout(Stdio::piped()).spawn().unwrap()
+ };
+
+ let Output {status, stdout, stderr} = prog.wait_with_output().unwrap();
+ let output_str = str::from_utf8(&stdout).unwrap();
+
+ assert!(status.success());
+ assert_eq!(output_str.trim().to_string(), "hello");
+ assert_eq!(stderr, Vec::new());
+ }
+
+ #[cfg(all(unix, not(target_os="android")))]
+ pub fn env_cmd() -> Command {
+ Command::new("env")
+ }
+ #[cfg(target_os="android")]
+ pub fn env_cmd() -> Command {
+ let mut cmd = Command::new("/system/bin/sh");
+ cmd.arg("-c").arg("set");
+ cmd
+ }
+
+ #[cfg(windows)]
+ pub fn env_cmd() -> Command {
+ let mut cmd = Command::new("cmd");
+ cmd.arg("/c").arg("set");
+ cmd
+ }
+
+ #[test]
+ fn test_override_env() {
+ use crate::env;
+
+ // In some build environments (such as chrooted Nix builds), `env` can
+ // only be found in the explicitly-provided PATH env variable, not in
+ // default places such as /bin or /usr/bin. So we need to pass through
+ // PATH to our sub-process.
+ let mut cmd = env_cmd();
+ cmd.env_clear().env("RUN_TEST_NEW_ENV", "123");
+ if let Some(p) = env::var_os("PATH") {
+ cmd.env("PATH", &p);
+ }
+ let result = cmd.output().unwrap();
+ let output = String::from_utf8_lossy(&result.stdout).to_string();
+
+ assert!(output.contains("RUN_TEST_NEW_ENV=123"),
+ "didn't find RUN_TEST_NEW_ENV inside of:\n\n{}", output);
+ }
+
+ #[test]
+ fn test_add_to_env() {
+ let result = env_cmd().env("RUN_TEST_NEW_ENV", "123").output().unwrap();
+ let output = String::from_utf8_lossy(&result.stdout).to_string();
+
+ assert!(output.contains("RUN_TEST_NEW_ENV=123"),
+ "didn't find RUN_TEST_NEW_ENV inside of:\n\n{}", output);
+ }
+
+ #[test]
+ fn test_capture_env_at_spawn() {
+ use crate::env;
+
+ let mut cmd = env_cmd();
+ cmd.env("RUN_TEST_NEW_ENV1", "123");
+
+ // This variable will not be present if the environment has already
+ // been captured above.
+ env::set_var("RUN_TEST_NEW_ENV2", "456");
+ let result = cmd.output().unwrap();
+ env::remove_var("RUN_TEST_NEW_ENV2");
+
+ let output = String::from_utf8_lossy(&result.stdout).to_string();
+
+ assert!(output.contains("RUN_TEST_NEW_ENV1=123"),
+ "didn't find RUN_TEST_NEW_ENV1 inside of:\n\n{}", output);
+ assert!(output.contains("RUN_TEST_NEW_ENV2=456"),
+ "didn't find RUN_TEST_NEW_ENV2 inside of:\n\n{}", output);
+ }
+
+ // Regression tests for #30858.
+ #[test]
+ fn test_interior_nul_in_progname_is_error() {
+ match Command::new("has-some-\0\0s-inside").spawn() {
+ Err(e) => assert_eq!(e.kind(), ErrorKind::InvalidInput),
+ Ok(_) => panic!(),
+ }
+ }
+
+ #[test]
+ fn test_interior_nul_in_arg_is_error() {
+ match Command::new("echo").arg("has-some-\0\0s-inside").spawn() {
+ Err(e) => assert_eq!(e.kind(), ErrorKind::InvalidInput),
+ Ok(_) => panic!(),
+ }
+ }
+
+ #[test]
+ fn test_interior_nul_in_args_is_error() {
+ match Command::new("echo").args(&["has-some-\0\0s-inside"]).spawn() {
+ Err(e) => assert_eq!(e.kind(), ErrorKind::InvalidInput),
+ Ok(_) => panic!(),
+ }
+ }
+
+ #[test]
+ fn test_interior_nul_in_current_dir_is_error() {
+ match Command::new("echo").current_dir("has-some-\0\0s-inside").spawn() {
+ Err(e) => assert_eq!(e.kind(), ErrorKind::InvalidInput),
+ Ok(_) => panic!(),
+ }
+ }
+
+ // Regression tests for #30862.
+ #[test]
+ fn test_interior_nul_in_env_key_is_error() {
+ match env_cmd().env("has-some-\0\0s-inside", "value").spawn() {
+ Err(e) => assert_eq!(e.kind(), ErrorKind::InvalidInput),
+ Ok(_) => panic!(),
+ }
+ }
+
+ #[test]
+ fn test_interior_nul_in_env_value_is_error() {
+ match env_cmd().env("key", "has-some-\0\0s-inside").spawn() {
+ Err(e) => assert_eq!(e.kind(), ErrorKind::InvalidInput),
+ Ok(_) => panic!(),
+ }
+ }
+
+ /// Tests that process creation flags work by debugging a process.
+ /// Other creation flags make it hard or impossible to detect
+ /// behavioral changes in the process.
+ #[test]
+ #[cfg(windows)]
+ fn test_creation_flags() {
+ use crate::os::windows::process::CommandExt;
+ use crate::sys::c::{BOOL, DWORD, INFINITE};
+ #[repr(C, packed)]
+ struct DEBUG_EVENT {
+ pub event_code: DWORD,
+ pub process_id: DWORD,
+ pub thread_id: DWORD,
+ // This is a union in the real struct, but we don't
+ // need this data for the purposes of this test.
+ pub _junk: [u8; 164],
+ }
+
+ extern "system" {
+ fn WaitForDebugEvent(lpDebugEvent: *mut DEBUG_EVENT, dwMilliseconds: DWORD) -> BOOL;
+ fn ContinueDebugEvent(dwProcessId: DWORD, dwThreadId: DWORD,
+ dwContinueStatus: DWORD) -> BOOL;
+ }
+
+ const DEBUG_PROCESS: DWORD = 1;
+ const EXIT_PROCESS_DEBUG_EVENT: DWORD = 5;
+ const DBG_EXCEPTION_NOT_HANDLED: DWORD = 0x80010001;
+
+ let mut child = Command::new("cmd")
+ .creation_flags(DEBUG_PROCESS)
+ .stdin(Stdio::piped()).spawn().unwrap();
+ child.stdin.take().unwrap().write_all(b"exit\r\n").unwrap();
+ let mut events = 0;
+ let mut event = DEBUG_EVENT {
+ event_code: 0,
+ process_id: 0,
+ thread_id: 0,
+ _junk: [0; 164],
+ };
+ loop {
+ if unsafe { WaitForDebugEvent(&mut event as *mut DEBUG_EVENT, INFINITE) } == 0 {
+ panic!("WaitForDebugEvent failed!");
+ }
+ events += 1;
+
+ if event.event_code == EXIT_PROCESS_DEBUG_EVENT {
+ break;
+ }
+
+ if unsafe { ContinueDebugEvent(event.process_id,
+ event.thread_id,
+ DBG_EXCEPTION_NOT_HANDLED) } == 0 {
+ panic!("ContinueDebugEvent failed!");
+ }
+ }
+ assert!(events > 0);
+ }
+
+ #[test]
+ fn test_command_implements_send() {
+ fn take_send_type<T: Send>(_: T) {}
+ take_send_type(Command::new(""))
+ }
+}
diff --git a/src/libstd/rt.rs b/src/libstd/rt.rs
new file mode 100644
index 0000000..cf45eb0
--- /dev/null
+++ b/src/libstd/rt.rs
@@ -0,0 +1,65 @@
+//! Runtime services
+//!
+//! The `rt` module provides a narrow set of runtime services,
+//! including the global heap (exported in `heap`) and unwinding and
+//! backtrace support. The APIs in this module are highly unstable,
+//! and should be considered as private implementation details for the
+//! time being.
+
+#![unstable(feature = "rt",
+ reason = "this public module should not exist and is highly likely \
+ to disappear",
+ issue = "0")]
+#![doc(hidden)]
+
+
+// Re-export some of our utilities which are expected by other crates.
+pub use crate::panicking::{begin_panic, begin_panic_fmt, update_panic_count};
+
+// To reduce the generated code of the new `lang_start`, this function is doing
+// the real work.
+#[cfg(not(test))]
+fn lang_start_internal(main: &(dyn Fn() -> i32 + Sync + crate::panic::RefUnwindSafe),
+ argc: isize, argv: *const *const u8) -> isize {
+ use crate::panic;
+ use crate::sys;
+ use crate::sys_common;
+ use crate::sys_common::thread_info;
+ use crate::thread::Thread;
+
+ sys::init();
+
+ unsafe {
+ let main_guard = sys::thread::guard::init();
+ sys::stack_overflow::init();
+
+ // Next, set up the current Thread with the guard information we just
+ // created. Note that this isn't necessary in general for new threads,
+ // but we just do this to name the main thread and to give it correct
+ // info about the stack bounds.
+ let thread = Thread::new(Some("main".to_owned()));
+ thread_info::set(main_guard, thread);
+
+ // Store our args if necessary in a squirreled away location
+ sys::args::init(argc, argv);
+
+ // Let's run some code!
+ #[cfg(feature = "backtrace")]
+ let exit_code = panic::catch_unwind(|| {
+ sys_common::backtrace::__rust_begin_short_backtrace(move || main())
+ });
+ #[cfg(not(feature = "backtrace"))]
+ let exit_code = panic::catch_unwind(move || main());
+
+ sys_common::cleanup();
+ exit_code.unwrap_or(101) as isize
+ }
+}
+
+#[cfg(not(test))]
+#[lang = "start"]
+fn lang_start<T: crate::process::Termination + 'static>
+ (main: fn() -> T, argc: isize, argv: *const *const u8) -> isize
+{
+ lang_start_internal(&move || main().report(), argc, argv)
+}
diff --git a/src/libstd/sync/barrier.rs b/src/libstd/sync/barrier.rs
new file mode 100644
index 0000000..23ba63a
--- /dev/null
+++ b/src/libstd/sync/barrier.rs
@@ -0,0 +1,222 @@
+use crate::fmt;
+use crate::sync::{Mutex, Condvar};
+
+/// A barrier enables multiple threads to synchronize the beginning
+/// of some computation.
+///
+/// # Examples
+///
+/// ```
+/// use std::sync::{Arc, Barrier};
+/// use std::thread;
+///
+/// let mut handles = Vec::with_capacity(10);
+/// let barrier = Arc::new(Barrier::new(10));
+/// for _ in 0..10 {
+/// let c = barrier.clone();
+/// // The same messages will be printed together.
+/// // You will NOT see any interleaving.
+/// handles.push(thread::spawn(move|| {
+/// println!("before wait");
+/// c.wait();
+/// println!("after wait");
+/// }));
+/// }
+/// // Wait for other threads to finish.
+/// for handle in handles {
+/// handle.join().unwrap();
+/// }
+/// ```
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct Barrier {
+ lock: Mutex<BarrierState>,
+ cvar: Condvar,
+ num_threads: usize,
+}
+
+// The inner state of a double barrier
+struct BarrierState {
+ count: usize,
+ generation_id: usize,
+}
+
+/// A `BarrierWaitResult` is returned by [`wait`] when all threads in the [`Barrier`]
+/// have rendezvoused.
+///
+/// [`wait`]: struct.Barrier.html#method.wait
+/// [`Barrier`]: struct.Barrier.html
+///
+/// # Examples
+///
+/// ```
+/// use std::sync::Barrier;
+///
+/// let barrier = Barrier::new(1);
+/// let barrier_wait_result = barrier.wait();
+/// ```
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct BarrierWaitResult(bool);
+
+#[stable(feature = "std_debug", since = "1.16.0")]
+impl fmt::Debug for Barrier {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.pad("Barrier { .. }")
+ }
+}
+
+impl Barrier {
+ /// Creates a new barrier that can block a given number of threads.
+ ///
+ /// A barrier will block `n`-1 threads which call [`wait`] and then wake up
+ /// all threads at once when the `n`th thread calls [`wait`].
+ ///
+ /// [`wait`]: #method.wait
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::sync::Barrier;
+ ///
+ /// let barrier = Barrier::new(10);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn new(n: usize) -> Barrier {
+ Barrier {
+ lock: Mutex::new(BarrierState {
+ count: 0,
+ generation_id: 0,
+ }),
+ cvar: Condvar::new(),
+ num_threads: n,
+ }
+ }
+
+ /// Blocks the current thread until all threads have rendezvoused here.
+ ///
+ /// Barriers are re-usable after all threads have rendezvoused once, and can
+ /// be used continuously.
+ ///
+ /// A single (arbitrary) thread will receive a [`BarrierWaitResult`] that
+ /// returns `true` from [`is_leader`] when returning from this function, and
+ /// all other threads will receive a result that will return `false` from
+ /// [`is_leader`].
+ ///
+ /// [`BarrierWaitResult`]: struct.BarrierWaitResult.html
+ /// [`is_leader`]: struct.BarrierWaitResult.html#method.is_leader
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::sync::{Arc, Barrier};
+ /// use std::thread;
+ ///
+ /// let mut handles = Vec::with_capacity(10);
+ /// let barrier = Arc::new(Barrier::new(10));
+ /// for _ in 0..10 {
+ /// let c = barrier.clone();
+ /// // The same messages will be printed together.
+ /// // You will NOT see any interleaving.
+ /// handles.push(thread::spawn(move|| {
+ /// println!("before wait");
+ /// c.wait();
+ /// println!("after wait");
+ /// }));
+ /// }
+ /// // Wait for other threads to finish.
+ /// for handle in handles {
+ /// handle.join().unwrap();
+ /// }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn wait(&self) -> BarrierWaitResult {
+ let mut lock = self.lock.lock().unwrap();
+ let local_gen = lock.generation_id;
+ lock.count += 1;
+ if lock.count < self.num_threads {
+ // We need a while loop to guard against spurious wakeups.
+ // http://en.wikipedia.org/wiki/Spurious_wakeup
+ while local_gen == lock.generation_id &&
+ lock.count < self.num_threads {
+ lock = self.cvar.wait(lock).unwrap();
+ }
+ BarrierWaitResult(false)
+ } else {
+ lock.count = 0;
+ lock.generation_id = lock.generation_id.wrapping_add(1);
+ self.cvar.notify_all();
+ BarrierWaitResult(true)
+ }
+ }
+}
+
+#[stable(feature = "std_debug", since = "1.16.0")]
+impl fmt::Debug for BarrierWaitResult {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("BarrierWaitResult")
+ .field("is_leader", &self.is_leader())
+ .finish()
+ }
+}
+
+impl BarrierWaitResult {
+ /// Returns `true` if this thread from [`wait`] is the "leader thread".
+ ///
+ /// Only one thread will have `true` returned from their result, all other
+ /// threads will have `false` returned.
+ ///
+ /// [`wait`]: struct.Barrier.html#method.wait
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::sync::Barrier;
+ ///
+ /// let barrier = Barrier::new(1);
+ /// let barrier_wait_result = barrier.wait();
+ /// println!("{:?}", barrier_wait_result.is_leader());
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn is_leader(&self) -> bool { self.0 }
+}
+
+#[cfg(test)]
+mod tests {
+ use crate::sync::{Arc, Barrier};
+ use crate::sync::mpsc::{channel, TryRecvError};
+ use crate::thread;
+
+ #[test]
+ #[cfg_attr(target_os = "emscripten", ignore)]
+ fn test_barrier() {
+ const N: usize = 10;
+
+ let barrier = Arc::new(Barrier::new(N));
+ let (tx, rx) = channel();
+
+ for _ in 0..N - 1 {
+ let c = barrier.clone();
+ let tx = tx.clone();
+ thread::spawn(move|| {
+ tx.send(c.wait().is_leader()).unwrap();
+ });
+ }
+
+ // At this point, all spawned threads should be blocked,
+ // so we shouldn't get anything from the port
+ assert!(match rx.try_recv() {
+ Err(TryRecvError::Empty) => true,
+ _ => false,
+ });
+
+ let mut leader_found = barrier.wait().is_leader();
+
+ // Now, the barrier is cleared and we should get data.
+ for _ in 0..N - 1 {
+ if rx.recv().unwrap() {
+ assert!(!leader_found);
+ leader_found = true;
+ }
+ }
+ assert!(leader_found);
+ }
+}
diff --git a/src/libstd/sync/condvar.rs b/src/libstd/sync/condvar.rs
new file mode 100644
index 0000000..ffb9ce1
--- /dev/null
+++ b/src/libstd/sync/condvar.rs
@@ -0,0 +1,833 @@
+use crate::fmt;
+use crate::sync::atomic::{AtomicUsize, Ordering};
+use crate::sync::{mutex, MutexGuard, PoisonError};
+use crate::sys_common::condvar as sys;
+use crate::sys_common::mutex as sys_mutex;
+use crate::sys_common::poison::{self, LockResult};
+use crate::time::{Duration, Instant};
+
+/// A type indicating whether a timed wait on a condition variable returned
+/// due to a time out or not.
+///
+/// It is returned by the [`wait_timeout`] method.
+///
+/// [`wait_timeout`]: struct.Condvar.html#method.wait_timeout
+#[derive(Debug, PartialEq, Eq, Copy, Clone)]
+#[stable(feature = "wait_timeout", since = "1.5.0")]
+pub struct WaitTimeoutResult(bool);
+
+impl WaitTimeoutResult {
+ /// Returns `true` if the wait was known to have timed out.
+ ///
+ /// # Examples
+ ///
+ /// This example spawns a thread which will update the boolean value and
+ /// then wait 100 milliseconds before notifying the condvar.
+ ///
+ /// The main thread will wait with a timeout on the condvar and then leave
+ /// once the boolean has been updated and notified.
+ ///
+ /// ```
+ /// use std::sync::{Arc, Mutex, Condvar};
+ /// use std::thread;
+ /// use std::time::Duration;
+ ///
+ /// let pair = Arc::new((Mutex::new(false), Condvar::new()));
+ /// let pair2 = pair.clone();
+ ///
+ /// thread::spawn(move|| {
+ /// let &(ref lock, ref cvar) = &*pair2;
+ ///
+ /// // Let's wait 20 milliseconds before notifying the condvar.
+ /// thread::sleep(Duration::from_millis(20));
+ ///
+ /// let mut started = lock.lock().unwrap();
+ /// // We update the boolean value.
+ /// *started = true;
+ /// cvar.notify_one();
+ /// });
+ ///
+ /// // Wait for the thread to start up.
+ /// let &(ref lock, ref cvar) = &*pair;
+ /// let mut started = lock.lock().unwrap();
+ /// loop {
+ /// // Let's put a timeout on the condvar's wait.
+ /// let result = cvar.wait_timeout(started, Duration::from_millis(10)).unwrap();
+ /// // 10 milliseconds have passed, or maybe the value changed!
+ /// started = result.0;
+ /// if *started == true {
+ /// // We received the notification and the value has been updated, we can leave.
+ /// break
+ /// }
+ /// }
+ /// ```
+ #[stable(feature = "wait_timeout", since = "1.5.0")]
+ pub fn timed_out(&self) -> bool {
+ self.0
+ }
+}
+
+/// A Condition Variable
+///
+/// Condition variables represent the ability to block a thread such that it
+/// consumes no CPU time while waiting for an event to occur. Condition
+/// variables are typically associated with a boolean predicate (a condition)
+/// and a mutex. The predicate is always verified inside of the mutex before
+/// determining that a thread must block.
+///
+/// Functions in this module will block the current **thread** of execution and
+/// are bindings to system-provided condition variables where possible. Note
+/// that this module places one additional restriction over the system condition
+/// variables: each condvar can be used with precisely one mutex at runtime. Any
+/// attempt to use multiple mutexes on the same condition variable will result
+/// in a runtime panic. If this is not desired, then the unsafe primitives in
+/// `sys` do not have this restriction but may result in undefined behavior.
+///
+/// # Examples
+///
+/// ```
+/// use std::sync::{Arc, Mutex, Condvar};
+/// use std::thread;
+///
+/// let pair = Arc::new((Mutex::new(false), Condvar::new()));
+/// let pair2 = pair.clone();
+///
+/// // Inside of our lock, spawn a new thread, and then wait for it to start.
+/// thread::spawn(move|| {
+/// let &(ref lock, ref cvar) = &*pair2;
+/// let mut started = lock.lock().unwrap();
+/// *started = true;
+/// // We notify the condvar that the value has changed.
+/// cvar.notify_one();
+/// });
+///
+/// // Wait for the thread to start up.
+/// let &(ref lock, ref cvar) = &*pair;
+/// let mut started = lock.lock().unwrap();
+/// while !*started {
+/// started = cvar.wait(started).unwrap();
+/// }
+/// ```
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct Condvar {
+ inner: Box<sys::Condvar>,
+ mutex: AtomicUsize,
+}
+
+impl Condvar {
+ /// Creates a new condition variable which is ready to be waited on and
+ /// notified.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::sync::Condvar;
+ ///
+ /// let condvar = Condvar::new();
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn new() -> Condvar {
+ let mut c = Condvar {
+ inner: box sys::Condvar::new(),
+ mutex: AtomicUsize::new(0),
+ };
+ unsafe {
+ c.inner.init();
+ }
+ c
+ }
+
+ /// Blocks the current thread until this condition variable receives a
+ /// notification.
+ ///
+ /// This function will atomically unlock the mutex specified (represented by
+ /// `guard`) and block the current thread. This means that any calls
+ /// to [`notify_one`] or [`notify_all`] which happen logically after the
+ /// mutex is unlocked are candidates to wake this thread up. When this
+ /// function call returns, the lock specified will have been re-acquired.
+ ///
+ /// Note that this function is susceptible to spurious wakeups. Condition
+ /// variables normally have a boolean predicate associated with them, and
+ /// the predicate must always be checked each time this function returns to
+ /// protect against spurious wakeups.
+ ///
+ /// # Errors
+ ///
+ /// This function will return an error if the mutex being waited on is
+ /// poisoned when this thread re-acquires the lock. For more information,
+ /// see information about [poisoning] on the [`Mutex`] type.
+ ///
+ /// # Panics
+ ///
+ /// This function will [`panic!`] if it is used with more than one mutex
+ /// over time. Each condition variable is dynamically bound to exactly one
+ /// mutex to ensure defined behavior across platforms. If this functionality
+ /// is not desired, then unsafe primitives in `sys` are provided.
+ ///
+ /// [`notify_one`]: #method.notify_one
+ /// [`notify_all`]: #method.notify_all
+ /// [poisoning]: ../sync/struct.Mutex.html#poisoning
+ /// [`Mutex`]: ../sync/struct.Mutex.html
+ /// [`panic!`]: ../../std/macro.panic.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::sync::{Arc, Mutex, Condvar};
+ /// use std::thread;
+ ///
+ /// let pair = Arc::new((Mutex::new(false), Condvar::new()));
+ /// let pair2 = pair.clone();
+ ///
+ /// thread::spawn(move|| {
+ /// let &(ref lock, ref cvar) = &*pair2;
+ /// let mut started = lock.lock().unwrap();
+ /// *started = true;
+ /// // We notify the condvar that the value has changed.
+ /// cvar.notify_one();
+ /// });
+ ///
+ /// // Wait for the thread to start up.
+ /// let &(ref lock, ref cvar) = &*pair;
+ /// let mut started = lock.lock().unwrap();
+ /// // As long as the value inside the `Mutex<bool>` is `false`, we wait.
+ /// while !*started {
+ /// started = cvar.wait(started).unwrap();
+ /// }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn wait<'a, T>(&self, guard: MutexGuard<'a, T>)
+ -> LockResult<MutexGuard<'a, T>> {
+ let poisoned = unsafe {
+ let lock = mutex::guard_lock(&guard);
+ self.verify(lock);
+ self.inner.wait(lock);
+ mutex::guard_poison(&guard).get()
+ };
+ if poisoned {
+ Err(PoisonError::new(guard))
+ } else {
+ Ok(guard)
+ }
+ }
+
+ /// Blocks the current thread until this condition variable receives a
+ /// notification and the required condition is met. Spurious wakeups are
+ /// ignored and this function will only return once the condition has been
+ /// met.
+ ///
+ /// This function will atomically unlock the mutex specified (represented by
+ /// `guard`) and block the current thread. This means that any calls
+ /// to [`notify_one`] or [`notify_all`] which happen logically after the
+ /// mutex is unlocked are candidates to wake this thread up. When this
+ /// function call returns, the lock specified will have been re-acquired.
+ ///
+ /// # Errors
+ ///
+ /// This function will return an error if the mutex being waited on is
+ /// poisoned when this thread re-acquires the lock. For more information,
+ /// see information about [poisoning] on the [`Mutex`] type.
+ ///
+ /// [`notify_one`]: #method.notify_one
+ /// [`notify_all`]: #method.notify_all
+ /// [poisoning]: ../sync/struct.Mutex.html#poisoning
+ /// [`Mutex`]: ../sync/struct.Mutex.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(wait_until)]
+ ///
+ /// use std::sync::{Arc, Mutex, Condvar};
+ /// use std::thread;
+ ///
+ /// let pair = Arc::new((Mutex::new(false), Condvar::new()));
+ /// let pair2 = pair.clone();
+ ///
+ /// thread::spawn(move|| {
+ /// let &(ref lock, ref cvar) = &*pair2;
+ /// let mut started = lock.lock().unwrap();
+ /// *started = true;
+ /// // We notify the condvar that the value has changed.
+ /// cvar.notify_one();
+ /// });
+ ///
+ /// // Wait for the thread to start up.
+ /// let &(ref lock, ref cvar) = &*pair;
+ /// // As long as the value inside the `Mutex<bool>` is `false`, we wait.
+ /// let _guard = cvar.wait_until(lock.lock().unwrap(), |started| { *started }).unwrap();
+ /// ```
+ #[unstable(feature = "wait_until", issue = "47960")]
+ pub fn wait_until<'a, T, F>(&self, mut guard: MutexGuard<'a, T>,
+ mut condition: F)
+ -> LockResult<MutexGuard<'a, T>>
+ where F: FnMut(&mut T) -> bool {
+ while !condition(&mut *guard) {
+ guard = self.wait(guard)?;
+ }
+ Ok(guard)
+ }
+
+
+ /// Waits on this condition variable for a notification, timing out after a
+ /// specified duration.
+ ///
+ /// The semantics of this function are equivalent to [`wait`]
+ /// except that the thread will be blocked for roughly no longer
+ /// than `ms` milliseconds. This method should not be used for
+ /// precise timing due to anomalies such as preemption or platform
+ /// differences that may not cause the maximum amount of time
+ /// waited to be precisely `ms`.
+ ///
+ /// Note that the best effort is made to ensure that the time waited is
+ /// measured with a monotonic clock, and not affected by the changes made to
+ /// the system time.
+ ///
+ /// The returned boolean is `false` only if the timeout is known
+ /// to have elapsed.
+ ///
+ /// Like [`wait`], the lock specified will be re-acquired when this function
+ /// returns, regardless of whether the timeout elapsed or not.
+ ///
+ /// [`wait`]: #method.wait
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::sync::{Arc, Mutex, Condvar};
+ /// use std::thread;
+ ///
+ /// let pair = Arc::new((Mutex::new(false), Condvar::new()));
+ /// let pair2 = pair.clone();
+ ///
+ /// thread::spawn(move|| {
+ /// let &(ref lock, ref cvar) = &*pair2;
+ /// let mut started = lock.lock().unwrap();
+ /// *started = true;
+ /// // We notify the condvar that the value has changed.
+ /// cvar.notify_one();
+ /// });
+ ///
+ /// // Wait for the thread to start up.
+ /// let &(ref lock, ref cvar) = &*pair;
+ /// let mut started = lock.lock().unwrap();
+ /// // As long as the value inside the `Mutex<bool>` is `false`, we wait.
+ /// loop {
+ /// let result = cvar.wait_timeout_ms(started, 10).unwrap();
+ /// // 10 milliseconds have passed, or maybe the value changed!
+ /// started = result.0;
+ /// if *started == true {
+ /// // We received the notification and the value has been updated, we can leave.
+ /// break
+ /// }
+ /// }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_deprecated(since = "1.6.0", reason = "replaced by `std::sync::Condvar::wait_timeout`")]
+ pub fn wait_timeout_ms<'a, T>(&self, guard: MutexGuard<'a, T>, ms: u32)
+ -> LockResult<(MutexGuard<'a, T>, bool)> {
+ let res = self.wait_timeout(guard, Duration::from_millis(ms as u64));
+ poison::map_result(res, |(a, b)| {
+ (a, !b.timed_out())
+ })
+ }
+
+ /// Waits on this condition variable for a notification, timing out after a
+ /// specified duration.
+ ///
+ /// The semantics of this function are equivalent to [`wait`] except that
+ /// the thread will be blocked for roughly no longer than `dur`. This
+ /// method should not be used for precise timing due to anomalies such as
+ /// preemption or platform differences that may not cause the maximum
+ /// amount of time waited to be precisely `dur`.
+ ///
+ /// Note that the best effort is made to ensure that the time waited is
+ /// measured with a monotonic clock, and not affected by the changes made to
+ /// the system time. This function is susceptible to spurious wakeups.
+ /// Condition variables normally have a boolean predicate associated with
+ /// them, and the predicate must always be checked each time this function
+ /// returns to protect against spurious wakeups. Additionally, it is
+ /// typically desirable for the time-out to not exceed some duration in
+ /// spite of spurious wakes, thus the sleep-duration is decremented by the
+ /// amount slept. Alternatively, use the `wait_timeout_until` method
+ /// to wait until a condition is met with a total time-out regardless
+ /// of spurious wakes.
+ ///
+ /// The returned [`WaitTimeoutResult`] value indicates if the timeout is
+ /// known to have elapsed.
+ ///
+ /// Like [`wait`], the lock specified will be re-acquired when this function
+ /// returns, regardless of whether the timeout elapsed or not.
+ ///
+ /// [`wait`]: #method.wait
+ /// [`wait_timeout_until`]: #method.wait_timeout_until
+ /// [`WaitTimeoutResult`]: struct.WaitTimeoutResult.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::sync::{Arc, Mutex, Condvar};
+ /// use std::thread;
+ /// use std::time::Duration;
+ ///
+ /// let pair = Arc::new((Mutex::new(false), Condvar::new()));
+ /// let pair2 = pair.clone();
+ ///
+ /// thread::spawn(move|| {
+ /// let &(ref lock, ref cvar) = &*pair2;
+ /// let mut started = lock.lock().unwrap();
+ /// *started = true;
+ /// // We notify the condvar that the value has changed.
+ /// cvar.notify_one();
+ /// });
+ ///
+ /// // wait for the thread to start up
+ /// let &(ref lock, ref cvar) = &*pair;
+ /// let mut started = lock.lock().unwrap();
+ /// // as long as the value inside the `Mutex<bool>` is `false`, we wait
+ /// loop {
+ /// let result = cvar.wait_timeout(started, Duration::from_millis(10)).unwrap();
+ /// // 10 milliseconds have passed, or maybe the value changed!
+ /// started = result.0;
+ /// if *started == true {
+ /// // We received the notification and the value has been updated, we can leave.
+ /// break
+ /// }
+ /// }
+ /// ```
+ #[stable(feature = "wait_timeout", since = "1.5.0")]
+ pub fn wait_timeout<'a, T>(&self, guard: MutexGuard<'a, T>,
+ dur: Duration)
+ -> LockResult<(MutexGuard<'a, T>, WaitTimeoutResult)> {
+ let (poisoned, result) = unsafe {
+ let lock = mutex::guard_lock(&guard);
+ self.verify(lock);
+ let success = self.inner.wait_timeout(lock, dur);
+ (mutex::guard_poison(&guard).get(), WaitTimeoutResult(!success))
+ };
+ if poisoned {
+ Err(PoisonError::new((guard, result)))
+ } else {
+ Ok((guard, result))
+ }
+ }
+
+ /// Waits on this condition variable for a notification, timing out after a
+ /// specified duration. Spurious wakes will not cause this function to
+ /// return.
+ ///
+ /// The semantics of this function are equivalent to [`wait_until`] except
+ /// that the thread will be blocked for roughly no longer than `dur`. This
+ /// method should not be used for precise timing due to anomalies such as
+ /// preemption or platform differences that may not cause the maximum
+ /// amount of time waited to be precisely `dur`.
+ ///
+ /// Note that the best effort is made to ensure that the time waited is
+ /// measured with a monotonic clock, and not affected by the changes made to
+ /// the system time.
+ ///
+ /// The returned [`WaitTimeoutResult`] value indicates if the timeout is
+ /// known to have elapsed without the condition being met.
+ ///
+ /// Like [`wait_until`], the lock specified will be re-acquired when this
+ /// function returns, regardless of whether the timeout elapsed or not.
+ ///
+ /// [`wait_until`]: #method.wait_until
+ /// [`wait_timeout`]: #method.wait_timeout
+ /// [`WaitTimeoutResult`]: struct.WaitTimeoutResult.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(wait_timeout_until)]
+ ///
+ /// use std::sync::{Arc, Mutex, Condvar};
+ /// use std::thread;
+ /// use std::time::Duration;
+ ///
+ /// let pair = Arc::new((Mutex::new(false), Condvar::new()));
+ /// let pair2 = pair.clone();
+ ///
+ /// thread::spawn(move|| {
+ /// let &(ref lock, ref cvar) = &*pair2;
+ /// let mut started = lock.lock().unwrap();
+ /// *started = true;
+ /// // We notify the condvar that the value has changed.
+ /// cvar.notify_one();
+ /// });
+ ///
+ /// // wait for the thread to start up
+ /// let &(ref lock, ref cvar) = &*pair;
+ /// let result = cvar.wait_timeout_until(
+ /// lock.lock().unwrap(),
+ /// Duration::from_millis(100),
+ /// |&mut started| started,
+ /// ).unwrap();
+ /// if result.1.timed_out() {
+ /// // timed-out without the condition ever evaluating to true.
+ /// }
+ /// // access the locked mutex via result.0
+ /// ```
+ #[unstable(feature = "wait_timeout_until", issue = "47960")]
+ pub fn wait_timeout_until<'a, T, F>(&self, mut guard: MutexGuard<'a, T>,
+ dur: Duration, mut condition: F)
+ -> LockResult<(MutexGuard<'a, T>, WaitTimeoutResult)>
+ where F: FnMut(&mut T) -> bool {
+ let start = Instant::now();
+ loop {
+ if condition(&mut *guard) {
+ return Ok((guard, WaitTimeoutResult(false)));
+ }
+ let timeout = match dur.checked_sub(start.elapsed()) {
+ Some(timeout) => timeout,
+ None => return Ok((guard, WaitTimeoutResult(true))),
+ };
+ guard = self.wait_timeout(guard, timeout)?.0;
+ }
+ }
+
+ /// Wakes up one blocked thread on this condvar.
+ ///
+ /// If there is a blocked thread on this condition variable, then it will
+ /// be woken up from its call to [`wait`] or [`wait_timeout`]. Calls to
+ /// `notify_one` are not buffered in any way.
+ ///
+ /// To wake up all threads, see [`notify_all`].
+ ///
+ /// [`wait`]: #method.wait
+ /// [`wait_timeout`]: #method.wait_timeout
+ /// [`notify_all`]: #method.notify_all
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::sync::{Arc, Mutex, Condvar};
+ /// use std::thread;
+ ///
+ /// let pair = Arc::new((Mutex::new(false), Condvar::new()));
+ /// let pair2 = pair.clone();
+ ///
+ /// thread::spawn(move|| {
+ /// let &(ref lock, ref cvar) = &*pair2;
+ /// let mut started = lock.lock().unwrap();
+ /// *started = true;
+ /// // We notify the condvar that the value has changed.
+ /// cvar.notify_one();
+ /// });
+ ///
+ /// // Wait for the thread to start up.
+ /// let &(ref lock, ref cvar) = &*pair;
+ /// let mut started = lock.lock().unwrap();
+ /// // As long as the value inside the `Mutex<bool>` is `false`, we wait.
+ /// while !*started {
+ /// started = cvar.wait(started).unwrap();
+ /// }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn notify_one(&self) {
+ unsafe { self.inner.notify_one() }
+ }
+
+ /// Wakes up all blocked threads on this condvar.
+ ///
+ /// This method will ensure that any current waiters on the condition
+ /// variable are awoken. Calls to `notify_all()` are not buffered in any
+ /// way.
+ ///
+ /// To wake up only one thread, see [`notify_one`].
+ ///
+ /// [`notify_one`]: #method.notify_one
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::sync::{Arc, Mutex, Condvar};
+ /// use std::thread;
+ ///
+ /// let pair = Arc::new((Mutex::new(false), Condvar::new()));
+ /// let pair2 = pair.clone();
+ ///
+ /// thread::spawn(move|| {
+ /// let &(ref lock, ref cvar) = &*pair2;
+ /// let mut started = lock.lock().unwrap();
+ /// *started = true;
+ /// // We notify the condvar that the value has changed.
+ /// cvar.notify_all();
+ /// });
+ ///
+ /// // Wait for the thread to start up.
+ /// let &(ref lock, ref cvar) = &*pair;
+ /// let mut started = lock.lock().unwrap();
+ /// // As long as the value inside the `Mutex<bool>` is `false`, we wait.
+ /// while !*started {
+ /// started = cvar.wait(started).unwrap();
+ /// }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn notify_all(&self) {
+ unsafe { self.inner.notify_all() }
+ }
+
+ fn verify(&self, mutex: &sys_mutex::Mutex) {
+ let addr = mutex as *const _ as usize;
+ match self.mutex.compare_and_swap(0, addr, Ordering::SeqCst) {
+ // If we got out 0, then we have successfully bound the mutex to
+ // this cvar.
+ 0 => {}
+
+ // If we get out a value that's the same as `addr`, then someone
+ // already beat us to the punch.
+ n if n == addr => {}
+
+ // Anything else and we're using more than one mutex on this cvar,
+ // which is currently disallowed.
+ _ => panic!("attempted to use a condition variable with two \
+ mutexes"),
+ }
+ }
+}
+
+#[stable(feature = "std_debug", since = "1.16.0")]
+impl fmt::Debug for Condvar {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.pad("Condvar { .. }")
+ }
+}
+
+#[stable(feature = "condvar_default", since = "1.10.0")]
+impl Default for Condvar {
+ /// Creates a `Condvar` which is ready to be waited on and notified.
+ fn default() -> Condvar {
+ Condvar::new()
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Drop for Condvar {
+ fn drop(&mut self) {
+ unsafe { self.inner.destroy() }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ /// #![feature(wait_until)]
+ use crate::sync::mpsc::channel;
+ use crate::sync::{Condvar, Mutex, Arc};
+ use crate::sync::atomic::{AtomicBool, Ordering};
+ use crate::thread;
+ use crate::time::Duration;
+ use crate::u64;
+
+ #[test]
+ fn smoke() {
+ let c = Condvar::new();
+ c.notify_one();
+ c.notify_all();
+ }
+
+ #[test]
+ #[cfg_attr(target_os = "emscripten", ignore)]
+ fn notify_one() {
+ let m = Arc::new(Mutex::new(()));
+ let m2 = m.clone();
+ let c = Arc::new(Condvar::new());
+ let c2 = c.clone();
+
+ let g = m.lock().unwrap();
+ let _t = thread::spawn(move|| {
+ let _g = m2.lock().unwrap();
+ c2.notify_one();
+ });
+ let g = c.wait(g).unwrap();
+ drop(g);
+ }
+
+ #[test]
+ #[cfg_attr(target_os = "emscripten", ignore)]
+ fn notify_all() {
+ const N: usize = 10;
+
+ let data = Arc::new((Mutex::new(0), Condvar::new()));
+ let (tx, rx) = channel();
+ for _ in 0..N {
+ let data = data.clone();
+ let tx = tx.clone();
+ thread::spawn(move|| {
+ let &(ref lock, ref cond) = &*data;
+ let mut cnt = lock.lock().unwrap();
+ *cnt += 1;
+ if *cnt == N {
+ tx.send(()).unwrap();
+ }
+ while *cnt != 0 {
+ cnt = cond.wait(cnt).unwrap();
+ }
+ tx.send(()).unwrap();
+ });
+ }
+ drop(tx);
+
+ let &(ref lock, ref cond) = &*data;
+ rx.recv().unwrap();
+ let mut cnt = lock.lock().unwrap();
+ *cnt = 0;
+ cond.notify_all();
+ drop(cnt);
+
+ for _ in 0..N {
+ rx.recv().unwrap();
+ }
+ }
+
+ #[test]
+ #[cfg_attr(target_os = "emscripten", ignore)]
+ fn wait_until() {
+ let pair = Arc::new((Mutex::new(false), Condvar::new()));
+ let pair2 = pair.clone();
+
+ // Inside of our lock, spawn a new thread, and then wait for it to start.
+ thread::spawn(move|| {
+ let &(ref lock, ref cvar) = &*pair2;
+ let mut started = lock.lock().unwrap();
+ *started = true;
+ // We notify the condvar that the value has changed.
+ cvar.notify_one();
+ });
+
+ // Wait for the thread to start up.
+ let &(ref lock, ref cvar) = &*pair;
+ let guard = cvar.wait_until(lock.lock().unwrap(), |started| {
+ *started
+ });
+ assert!(*guard.unwrap());
+ }
+
+ #[test]
+ #[cfg_attr(target_os = "emscripten", ignore)]
+ #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
+ fn wait_timeout_wait() {
+ let m = Arc::new(Mutex::new(()));
+ let c = Arc::new(Condvar::new());
+
+ loop {
+ let g = m.lock().unwrap();
+ let (_g, no_timeout) = c.wait_timeout(g, Duration::from_millis(1)).unwrap();
+ // spurious wakeups mean this isn't necessarily true
+ // so execute test again, if not timeout
+ if !no_timeout.timed_out() {
+ continue;
+ }
+
+ break;
+ }
+ }
+
+ #[test]
+ #[cfg_attr(target_os = "emscripten", ignore)]
+ #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
+ fn wait_timeout_until_wait() {
+ let m = Arc::new(Mutex::new(()));
+ let c = Arc::new(Condvar::new());
+
+ let g = m.lock().unwrap();
+ let (_g, wait) = c.wait_timeout_until(g, Duration::from_millis(1), |_| { false }).unwrap();
+ // no spurious wakeups. ensure it timed-out
+ assert!(wait.timed_out());
+ }
+
+ #[test]
+ #[cfg_attr(target_os = "emscripten", ignore)]
+ fn wait_timeout_until_instant_satisfy() {
+ let m = Arc::new(Mutex::new(()));
+ let c = Arc::new(Condvar::new());
+
+ let g = m.lock().unwrap();
+ let (_g, wait) = c.wait_timeout_until(g, Duration::from_millis(0), |_| { true }).unwrap();
+ // ensure it didn't time-out even if we were not given any time.
+ assert!(!wait.timed_out());
+ }
+
+ #[test]
+ #[cfg_attr(target_os = "emscripten", ignore)]
+ #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
+ fn wait_timeout_until_wake() {
+ let pair = Arc::new((Mutex::new(false), Condvar::new()));
+ let pair_copy = pair.clone();
+
+ let &(ref m, ref c) = &*pair;
+ let g = m.lock().unwrap();
+ let _t = thread::spawn(move || {
+ let &(ref lock, ref cvar) = &*pair_copy;
+ let mut started = lock.lock().unwrap();
+ thread::sleep(Duration::from_millis(1));
+ *started = true;
+ cvar.notify_one();
+ });
+ let (g2, wait) = c.wait_timeout_until(g, Duration::from_millis(u64::MAX), |&mut notified| {
+ notified
+ }).unwrap();
+ // ensure it didn't time-out even if we were not given any time.
+ assert!(!wait.timed_out());
+ assert!(*g2);
+ }
+
+ #[test]
+ #[cfg_attr(target_os = "emscripten", ignore)]
+ #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
+ fn wait_timeout_wake() {
+ let m = Arc::new(Mutex::new(()));
+ let c = Arc::new(Condvar::new());
+
+ loop {
+ let g = m.lock().unwrap();
+
+ let c2 = c.clone();
+ let m2 = m.clone();
+
+ let notified = Arc::new(AtomicBool::new(false));
+ let notified_copy = notified.clone();
+
+ let t = thread::spawn(move || {
+ let _g = m2.lock().unwrap();
+ thread::sleep(Duration::from_millis(1));
+ notified_copy.store(true, Ordering::SeqCst);
+ c2.notify_one();
+ });
+ let (g, timeout_res) = c.wait_timeout(g, Duration::from_millis(u64::MAX)).unwrap();
+ assert!(!timeout_res.timed_out());
+ // spurious wakeups mean this isn't necessarily true
+ // so execute test again, if not notified
+ if !notified.load(Ordering::SeqCst) {
+ t.join().unwrap();
+ continue;
+ }
+ drop(g);
+
+ t.join().unwrap();
+
+ break;
+ }
+ }
+
+ #[test]
+ #[should_panic]
+ #[cfg_attr(target_os = "emscripten", ignore)]
+ fn two_mutexes() {
+ let m = Arc::new(Mutex::new(()));
+ let m2 = m.clone();
+ let c = Arc::new(Condvar::new());
+ let c2 = c.clone();
+
+ let mut g = m.lock().unwrap();
+ let _t = thread::spawn(move|| {
+ let _g = m2.lock().unwrap();
+ c2.notify_one();
+ });
+ g = c.wait(g).unwrap();
+ drop(g);
+
+ let m = Mutex::new(());
+ let _ = c.wait(m.lock().unwrap()).unwrap();
+ }
+}
diff --git a/src/libstd/sync/mod.rs b/src/libstd/sync/mod.rs
new file mode 100644
index 0000000..809ee88
--- /dev/null
+++ b/src/libstd/sync/mod.rs
@@ -0,0 +1,178 @@
+//! Useful synchronization primitives.
+//!
+//! ## The need for synchronization
+//!
+//! Conceptually, a Rust program is a series of operations which will
+//! be executed on a computer. The timeline of events happening in the
+//! program is consistent with the order of the operations in the code.
+//!
+//! Consider the following code, operating on some global static variables:
+//!
+//! ```rust
+//! static mut A: u32 = 0;
+//! static mut B: u32 = 0;
+//! static mut C: u32 = 0;
+//!
+//! fn main() {
+//! unsafe {
+//! A = 3;
+//! B = 4;
+//! A = A + B;
+//! C = B;
+//! println!("{} {} {}", A, B, C);
+//! C = A;
+//! }
+//! }
+//! ```
+//!
+//! It appears as if some variables stored in memory are changed, an addition
+//! is performed, result is stored in `A` and the variable `C` is
+//! modified twice.
+//!
+//! When only a single thread is involved, the results are as expected:
+//! the line `7 4 4` gets printed.
+//!
+//! As for what happens behind the scenes, when optimizations are enabled the
+//! final generated machine code might look very different from the code:
+//!
+//! - The first store to `C` might be moved before the store to `A` or `B`,
+//! _as if_ we had written `C = 4; A = 3; B = 4`.
+//!
+//! - Assignment of `A + B` to `A` might be removed, since the sum can be stored
+//! in a temporary location until it gets printed, with the global variable
+//! never getting updated.
+//!
+//! - The final result could be determined just by looking at the code
+//! at compile time, so [constant folding] might turn the whole
+//! block into a simple `println!("7 4 4")`.
+//!
+//! The compiler is allowed to perform any combination of these
+//! optimizations, as long as the final optimized code, when executed,
+//! produces the same results as the one without optimizations.
+//!
+//! Due to the [concurrency] involved in modern computers, assumptions
+//! about the program's execution order are often wrong. Access to
+//! global variables can lead to nondeterministic results, **even if**
+//! compiler optimizations are disabled, and it is **still possible**
+//! to introduce synchronization bugs.
+//!
+//! Note that thanks to Rust's safety guarantees, accessing global (static)
+//! variables requires `unsafe` code, assuming we don't use any of the
+//! synchronization primitives in this module.
+//!
+//! [constant folding]: https://en.wikipedia.org/wiki/Constant_folding
+//! [concurrency]: https://en.wikipedia.org/wiki/Concurrency_(computer_science)
+//!
+//! ## Out-of-order execution
+//!
+//! Instructions can execute in a different order from the one we define, due to
+//! various reasons:
+//!
+//! - The **compiler** reordering instructions: If the compiler can issue an
+//! instruction at an earlier point, it will try to do so. For example, it
+//! might hoist memory loads at the top of a code block, so that the CPU can
+//! start [prefetching] the values from memory.
+//!
+//! In single-threaded scenarios, this can cause issues when writing
+//! signal handlers or certain kinds of low-level code.
+//! Use [compiler fences] to prevent this reordering.
+//!
+//! - A **single processor** executing instructions [out-of-order]:
+//! Modern CPUs are capable of [superscalar] execution,
+//! i.e., multiple instructions might be executing at the same time,
+//! even though the machine code describes a sequential process.
+//!
+//! This kind of reordering is handled transparently by the CPU.
+//!
+//! - A **multiprocessor** system executing multiple hardware threads
+//! at the same time: In multi-threaded scenarios, you can use two
+//! kinds of primitives to deal with synchronization:
+//! - [memory fences] to ensure memory accesses are made visible to
+//! other CPUs in the right order.
+//! - [atomic operations] to ensure simultaneous access to the same
+//! memory location doesn't lead to undefined behavior.
+//!
+//! [prefetching]: https://en.wikipedia.org/wiki/Cache_prefetching
+//! [compiler fences]: crate::sync::atomic::compiler_fence
+//! [out-of-order]: https://en.wikipedia.org/wiki/Out-of-order_execution
+//! [superscalar]: https://en.wikipedia.org/wiki/Superscalar_processor
+//! [memory fences]: crate::sync::atomic::fence
+//! [atomic operations]: crate::sync::atomic
+//!
+//! ## Higher-level synchronization objects
+//!
+//! Most of the low-level synchronization primitives are quite error-prone and
+//! inconvenient to use, which is why the standard library also exposes some
+//! higher-level synchronization objects.
+//!
+//! These abstractions can be built out of lower-level primitives.
+//! For efficiency, the sync objects in the standard library are usually
+//! implemented with help from the operating system's kernel, which is
+//! able to reschedule the threads while they are blocked on acquiring
+//! a lock.
+//!
+//! The following is an overview of the available synchronization
+//! objects:
+//!
+//! - [`Arc`]: Atomically Reference-Counted pointer, which can be used
+//! in multithreaded environments to prolong the lifetime of some
+//! data until all the threads have finished using it.
+//!
+//! - [`Barrier`]: Ensures multiple threads will wait for each other
+//! to reach a point in the program, before continuing execution all
+//! together.
+//!
+//! - [`Condvar`]: Condition Variable, providing the ability to block
+//! a thread while waiting for an event to occur.
+//!
+//! - [`mpsc`]: Multi-producer, single-consumer queues, used for
+//! message-based communication. Can provide a lightweight
+//! inter-thread synchronisation mechanism, at the cost of some
+//! extra memory.
+//!
+//! - [`Mutex`]: Mutual Exclusion mechanism, which ensures that at
+//! most one thread at a time is able to access some data.
+//!
+//! - [`Once`]: Used for thread-safe, one-time initialization of a
+//! global variable.
+//!
+//! - [`RwLock`]: Provides a mutual exclusion mechanism which allows
+//! multiple readers at the same time, while allowing only one
+//! writer at a time. In some cases, this can be more efficient than
+//! a mutex.
+//!
+//! [`Arc`]: crate::sync::Arc
+//! [`Barrier`]: crate::sync::Barrier
+//! [`Condvar`]: crate::sync::Condvar
+//! [`mpsc`]: crate::sync::mpsc
+//! [`Mutex`]: crate::sync::Mutex
+//! [`Once`]: crate::sync::Once
+//! [`RwLock`]: crate::sync::RwLock
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use alloc_crate::sync::{Arc, Weak};
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use core::sync::atomic;
+
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use self::barrier::{Barrier, BarrierWaitResult};
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use self::condvar::{Condvar, WaitTimeoutResult};
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use self::mutex::{Mutex, MutexGuard};
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use self::once::{Once, OnceState, ONCE_INIT};
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use crate::sys_common::poison::{PoisonError, TryLockError, TryLockResult, LockResult};
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use self::rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard};
+
+pub mod mpsc;
+
+mod barrier;
+mod condvar;
+mod mutex;
+mod once;
+mod rwlock;
diff --git a/src/libstd/sync/mpsc/blocking.rs b/src/libstd/sync/mpsc/blocking.rs
new file mode 100644
index 0000000..6eacfae
--- /dev/null
+++ b/src/libstd/sync/mpsc/blocking.rs
@@ -0,0 +1,86 @@
+//! Generic support for building blocking abstractions.
+
+use crate::thread::{self, Thread};
+use crate::sync::atomic::{AtomicBool, Ordering};
+use crate::sync::Arc;
+use crate::mem;
+use crate::time::Instant;
+
+struct Inner {
+ thread: Thread,
+ woken: AtomicBool,
+}
+
+unsafe impl Send for Inner {}
+unsafe impl Sync for Inner {}
+
+#[derive(Clone)]
+pub struct SignalToken {
+ inner: Arc<Inner>,
+}
+
+pub struct WaitToken {
+ inner: Arc<Inner>,
+}
+
+impl !Send for WaitToken {}
+
+impl !Sync for WaitToken {}
+
+pub fn tokens() -> (WaitToken, SignalToken) {
+ let inner = Arc::new(Inner {
+ thread: thread::current(),
+ woken: AtomicBool::new(false),
+ });
+ let wait_token = WaitToken {
+ inner: inner.clone(),
+ };
+ let signal_token = SignalToken {
+ inner,
+ };
+ (wait_token, signal_token)
+}
+
+impl SignalToken {
+ pub fn signal(&self) -> bool {
+ let wake = !self.inner.woken.compare_and_swap(false, true, Ordering::SeqCst);
+ if wake {
+ self.inner.thread.unpark();
+ }
+ wake
+ }
+
+ /// Converts to an unsafe usize value. Useful for storing in a pipe's state
+ /// flag.
+ #[inline]
+ pub unsafe fn cast_to_usize(self) -> usize {
+ mem::transmute(self.inner)
+ }
+
+ /// Converts from an unsafe usize value. Useful for retrieving a pipe's state
+ /// flag.
+ #[inline]
+ pub unsafe fn cast_from_usize(signal_ptr: usize) -> SignalToken {
+ SignalToken { inner: mem::transmute(signal_ptr) }
+ }
+}
+
+impl WaitToken {
+ pub fn wait(self) {
+ while !self.inner.woken.load(Ordering::SeqCst) {
+ thread::park()
+ }
+ }
+
+ /// Returns `true` if we wake up normally.
+ pub fn wait_max_until(self, end: Instant) -> bool {
+ while !self.inner.woken.load(Ordering::SeqCst) {
+ let now = Instant::now();
+ if now >= end {
+ return false;
+ }
+ thread::park_timeout(end - now)
+ }
+ true
+ }
+}
diff --git a/src/libstd/sync/mpsc/cache_aligned.rs b/src/libstd/sync/mpsc/cache_aligned.rs
new file mode 100644
index 0000000..b14a9e5
--- /dev/null
+++ b/src/libstd/sync/mpsc/cache_aligned.rs
@@ -0,0 +1,27 @@
+use crate::ops::{Deref, DerefMut};
+
+#[derive(Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
+#[repr(align(64))]
+pub(super) struct Aligner;
+
+#[derive(Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub(super) struct CacheAligned<T>(pub T, pub Aligner);
+
+impl<T> Deref for CacheAligned<T> {
+ type Target = T;
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+}
+
+impl<T> DerefMut for CacheAligned<T> {
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ &mut self.0
+ }
+}
+
+impl<T> CacheAligned<T> {
+ pub(super) fn new(t: T) -> Self {
+ CacheAligned(t, Aligner)
+ }
+}
diff --git a/src/libstd/sync/mpsc/mod.rs b/src/libstd/sync/mpsc/mod.rs
new file mode 100644
index 0000000..bc32b8e
--- /dev/null
+++ b/src/libstd/sync/mpsc/mod.rs
@@ -0,0 +1,3145 @@
+//! Multi-producer, single-consumer FIFO queue communication primitives.
+//!
+//! This module provides message-based communication over channels, concretely
+//! defined among three types:
+//!
+//! * [`Sender`]
+//! * [`SyncSender`]
+//! * [`Receiver`]
+//!
+//! A [`Sender`] or [`SyncSender`] is used to send data to a [`Receiver`]. Both
+//! senders are clone-able (multi-producer) such that many threads can send
+//! simultaneously to one receiver (single-consumer).
+//!
+//! These channels come in two flavors:
+//!
+//! 1. An asynchronous, infinitely buffered channel. The [`channel`] function
+//! will return a `(Sender, Receiver)` tuple where all sends will be
+//! **asynchronous** (they never block). The channel conceptually has an
+//! infinite buffer.
+//!
+//! 2. A synchronous, bounded channel. The [`sync_channel`] function will
+//! return a `(SyncSender, Receiver)` tuple where the storage for pending
+//! messages is a pre-allocated buffer of a fixed size. All sends will be
+//! **synchronous** by blocking until there is buffer space available. Note
+//! that a bound of 0 is allowed, causing the channel to become a "rendezvous"
+//! channel where each sender atomically hands off a message to a receiver.
+//!
+//! [`Sender`]: ../../../std/sync/mpsc/struct.Sender.html
+//! [`SyncSender`]: ../../../std/sync/mpsc/struct.SyncSender.html
+//! [`Receiver`]: ../../../std/sync/mpsc/struct.Receiver.html
+//! [`send`]: ../../../std/sync/mpsc/struct.Sender.html#method.send
+//! [`channel`]: ../../../std/sync/mpsc/fn.channel.html
+//! [`sync_channel`]: ../../../std/sync/mpsc/fn.sync_channel.html
+//!
+//! ## Disconnection
+//!
+//! The send and receive operations on channels will all return a [`Result`]
+//! indicating whether the operation succeeded or not. An unsuccessful operation
+//! is normally indicative of the other half of a channel having "hung up" by
+//! being dropped in its corresponding thread.
+//!
+//! Once half of a channel has been deallocated, most operations can no longer
+//! continue to make progress, so [`Err`] will be returned. Many applications
+//! will continue to [`unwrap`] the results returned from this module,
+//! instigating a propagation of failure among threads if one unexpectedly dies.
+//!
+//! [`Result`]: ../../../std/result/enum.Result.html
+//! [`Err`]: ../../../std/result/enum.Result.html#variant.Err
+//! [`unwrap`]: ../../../std/result/enum.Result.html#method.unwrap
+//!
+//! # Examples
+//!
+//! Simple usage:
+//!
+//! ```
+//! use std::thread;
+//! use std::sync::mpsc::channel;
+//!
+//! // Create a simple streaming channel
+//! let (tx, rx) = channel();
+//! thread::spawn(move|| {
+//! tx.send(10).unwrap();
+//! });
+//! assert_eq!(rx.recv().unwrap(), 10);
+//! ```
+//!
+//! Shared usage:
+//!
+//! ```
+//! use std::thread;
+//! use std::sync::mpsc::channel;
+//!
+//! // Create a shared channel that can be sent along from many threads
+//! // where tx is the sending half (tx for transmission), and rx is the receiving
+//! // half (rx for receiving).
+//! let (tx, rx) = channel();
+//! for i in 0..10 {
+//! let tx = tx.clone();
+//! thread::spawn(move|| {
+//! tx.send(i).unwrap();
+//! });
+//! }
+//!
+//! for _ in 0..10 {
+//! let j = rx.recv().unwrap();
+//! assert!(0 <= j && j < 10);
+//! }
+//! ```
+//!
+//! Propagating panics:
+//!
+//! ```
+//! use std::sync::mpsc::channel;
+//!
+//! // The call to recv() will return an error because the channel has already
+//! // hung up (or been deallocated)
+//! let (tx, rx) = channel::<i32>();
+//! drop(tx);
+//! assert!(rx.recv().is_err());
+//! ```
+//!
+//! Synchronous channels:
+//!
+//! ```
+//! use std::thread;
+//! use std::sync::mpsc::sync_channel;
+//!
+//! let (tx, rx) = sync_channel::<i32>(0);
+//! thread::spawn(move|| {
+//! // This will wait for the parent thread to start receiving
+//! tx.send(53).unwrap();
+//! });
+//! rx.recv().unwrap();
+//! ```
+
+#![stable(feature = "rust1", since = "1.0.0")]
+#![allow(deprecated)] // for mpsc_select
+
+// A description of how Rust's channel implementation works
+//
+// Channels are supposed to be the basic building block for all other
+// concurrent primitives that are used in Rust. As a result, the channel type
+// needs to be highly optimized, flexible, and broad enough for use everywhere.
+//
+// The choice of implementation of all channels is to be built on lock-free data
+// structures. The channels themselves are then consequently also lock-free data
+// structures. As always with lock-free code, this is a very "here be dragons"
+// territory, especially because I'm unaware of any academic papers that have
+// gone into great length about channels of these flavors.
+//
+// ## Flavors of channels
+//
+// From the perspective of a consumer of this library, there is only one flavor
+// of channel. This channel can be used as a stream and cloned to allow multiple
+// senders. Under the hood, however, there are actually three flavors of
+// channels in play.
+//
+// * Flavor::Oneshots - these channels are highly optimized for the one-send use
+// case. They contain as few atomics as possible and
+// involve one and exactly one allocation.
+// * Streams - these channels are optimized for the non-shared use case. They
+// use a different concurrent queue that is more tailored for this
+// use case. The initial allocation of this flavor of channel is not
+// optimized.
+// * Shared - this is the most general form of channel that this module offers,
+// a channel with multiple senders. This type is as optimized as it
+// can be, but the previous two types mentioned are much faster for
+// their use-cases.
+//
+// ## Concurrent queues
+//
+// The basic idea of Rust's Sender/Receiver types is that send() never blocks,
+// but recv() obviously blocks. This means that under the hood there must be
+// some shared and concurrent queue holding all of the actual data.
+//
+// With two flavors of channels, two flavors of queues are also used. We have
+// chosen to use queues from a well-known author that are abbreviated as SPSC
+// and MPSC (single producer, single consumer and multiple producer, single
+// consumer). SPSC queues are used for streams while MPSC queues are used for
+// shared channels.
+//
+// ### SPSC optimizations
+//
+// The SPSC queue found online is essentially a linked list of nodes where one
+// half of the nodes are the "queue of data" and the other half of nodes are a
+// cache of unused nodes. The unused nodes are used such that an allocation is
+// not required on every push() and a free doesn't need to happen on every
+// pop().
+//
+// As found online, however, the cache of nodes is of an infinite size. This
+// means that if a channel at one point in its life had 50k items in the queue,
+// then the queue will always have the capacity for 50k items. I believed that
+// this was an unnecessary limitation of the implementation, so I have altered
+// the queue to optionally have a bound on the cache size.
+//
+// By default, streams will have an unbounded SPSC queue with a small-ish cache
+// size. The hope is that the cache is still large enough to have very fast
+// send() operations while not too large such that millions of channels can
+// coexist at once.
+//
+// ### MPSC optimizations
+//
+// Right now the MPSC queue has not been optimized. Like the SPSC queue, it uses
+// a linked list under the hood to earn its unboundedness, but I have not put
+// forth much effort into having a cache of nodes similar to the SPSC queue.
+//
+// For now, I believe that this is "ok" because shared channels are not the most
+// common type, but soon we may wish to revisit this queue choice and determine
+// another candidate for backend storage of shared channels.
+//
+// ## Overview of the Implementation
+//
+// Now that there's a little background on the concurrent queues used, it's
+// worth going into much more detail about the channels themselves. The basic
+// pseudocode for a send/recv are:
+//
+//
+// send(t) recv()
+// queue.push(t) return if queue.pop()
+// if increment() == -1 deschedule {
+// wakeup() if decrement() > 0
+// cancel_deschedule()
+// }
+// queue.pop()
+//
+// As mentioned before, there are no locks in this implementation, only atomic
+// instructions are used.
+//
+// ### The internal atomic counter
+//
+// Every channel has a shared counter with each half to keep track of the size
+// of the queue. This counter is used to abort descheduling by the receiver and
+// to know when to wake up on the sending side.
+//
+// As seen in the pseudocode, senders will increment this count and receivers
+// will decrement the count. The theory behind this is that if a sender sees a
+// -1 count, it will wake up the receiver, and if the receiver sees a 1+ count,
+// then it doesn't need to block.
+//
+// The recv() method has a beginning call to pop(), and if successful, it needs
+// to decrement the count. It is a crucial implementation detail that this
+// decrement does *not* happen to the shared counter. If this were the case,
+// then it would be possible for the counter to be very negative when there were
+// no receivers waiting, in which case the senders would have to determine when
+// it was actually appropriate to wake up a receiver.
+//
+// Instead, the "steal count" is kept track of separately (not atomically
+// because it's only used by receivers), and then the decrement() call when
+// descheduling will lump in all of the recent steals into one large decrement.
+//
+// The implication of this is that if a sender sees a -1 count, then there's
+// guaranteed to be a waiter waiting!
+//
+// ## Native Implementation
+//
+// A major goal of these channels is to work seamlessly on and off the runtime.
+// All of the previous race conditions have been worded in terms of
+// scheduler-isms (which is obviously not available without the runtime).
+//
+// For now, native usage of channels (off the runtime) will fall back onto
+// mutexes/cond vars for descheduling/atomic decisions. The no-contention path
+// is still entirely lock-free, the "deschedule" blocks above are surrounded by
+// a mutex and the "wakeup" blocks involve grabbing a mutex and signaling on a
+// condition variable.
+//
+// ## Select
+//
+// Being able to support selection over channels has greatly influenced this
+// design, and not only does selection need to work inside the runtime, but also
+// outside the runtime.
+//
+// The implementation is fairly straightforward. The goal of select() is not to
+// return some data, but only to return which channel can receive data without
+// blocking. The implementation is essentially the entire blocking procedure
+// followed by an increment as soon as its woken up. The cancellation procedure
+// involves an increment and swapping out of to_wake to acquire ownership of the
+// thread to unblock.
+//
+// Sadly this current implementation requires multiple allocations, so I have
+// seen the throughput of select() be much worse than it should be. I do not
+// believe that there is anything fundamental that needs to change about these
+// channels, however, in order to support a more efficient select().
+//
+// # Conclusion
+//
+// And now that you've seen all the races that I found and attempted to fix,
+// here's the code for you to find some more!
+
+use crate::sync::Arc;
+use crate::error;
+use crate::fmt;
+use crate::mem;
+use crate::cell::UnsafeCell;
+use crate::time::{Duration, Instant};
+
+#[unstable(feature = "mpsc_select", issue = "27800")]
+pub use self::select::{Select, Handle};
+use self::select::StartResult;
+use self::select::StartResult::*;
+use self::blocking::SignalToken;
+
+#[cfg(all(test, not(target_os = "emscripten")))]
+mod select_tests;
+
+mod blocking;
+mod oneshot;
+mod select;
+mod shared;
+mod stream;
+mod sync;
+mod mpsc_queue;
+mod spsc_queue;
+
+mod cache_aligned;
+
+/// The receiving half of Rust's [`channel`][] (or [`sync_channel`]) type.
+/// This half can only be owned by one thread.
+///
+/// Messages sent to the channel can be retrieved using [`recv`].
+///
+/// [`channel`]: fn.channel.html
+/// [`sync_channel`]: fn.sync_channel.html
+/// [`recv`]: struct.Receiver.html#method.recv
+///
+/// # Examples
+///
+/// ```rust
+/// use std::sync::mpsc::channel;
+/// use std::thread;
+/// use std::time::Duration;
+///
+/// let (send, recv) = channel();
+///
+/// thread::spawn(move || {
+/// send.send("Hello world!").unwrap();
+/// thread::sleep(Duration::from_secs(2)); // block for two seconds
+/// send.send("Delayed for 2 seconds").unwrap();
+/// });
+///
+/// println!("{}", recv.recv().unwrap()); // Received immediately
+/// println!("Waiting...");
+/// println!("{}", recv.recv().unwrap()); // Received after 2 seconds
+/// ```
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct Receiver<T> {
+ inner: UnsafeCell<Flavor<T>>,
+}
+
+// The receiver port can be sent from place to place, so long as it
+// is not used to receive non-sendable things.
+#[stable(feature = "rust1", since = "1.0.0")]
+unsafe impl<T: Send> Send for Receiver<T> { }
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T> !Sync for Receiver<T> { }
+
+/// An iterator over messages on a [`Receiver`], created by [`iter`].
+///
+/// This iterator will block whenever [`next`] is called,
+/// waiting for a new message, and [`None`] will be returned
+/// when the corresponding channel has hung up.
+///
+/// [`iter`]: struct.Receiver.html#method.iter
+/// [`Receiver`]: struct.Receiver.html
+/// [`next`]: ../../../std/iter/trait.Iterator.html#tymethod.next
+/// [`None`]: ../../../std/option/enum.Option.html#variant.None
+///
+/// # Examples
+///
+/// ```rust
+/// use std::sync::mpsc::channel;
+/// use std::thread;
+///
+/// let (send, recv) = channel();
+///
+/// thread::spawn(move || {
+/// send.send(1u8).unwrap();
+/// send.send(2u8).unwrap();
+/// send.send(3u8).unwrap();
+/// });
+///
+/// for x in recv.iter() {
+/// println!("Got: {}", x);
+/// }
+/// ```
+#[stable(feature = "rust1", since = "1.0.0")]
+#[derive(Debug)]
+pub struct Iter<'a, T: 'a> {
+ rx: &'a Receiver<T>
+}
+
+/// An iterator that attempts to yield all pending values for a [`Receiver`],
+/// created by [`try_iter`].
+///
+/// [`None`] will be returned when there are no pending values remaining or
+/// if the corresponding channel has hung up.
+///
+/// This iterator will never block the caller in order to wait for data to
+/// become available. Instead, it will return [`None`].
+///
+/// [`Receiver`]: struct.Receiver.html
+/// [`try_iter`]: struct.Receiver.html#method.try_iter
+/// [`None`]: ../../../std/option/enum.Option.html#variant.None
+///
+/// # Examples
+///
+/// ```rust
+/// use std::sync::mpsc::channel;
+/// use std::thread;
+/// use std::time::Duration;
+///
+/// let (sender, receiver) = channel();
+///
+/// // Nothing is in the buffer yet
+/// assert!(receiver.try_iter().next().is_none());
+/// println!("Nothing in the buffer...");
+///
+/// thread::spawn(move || {
+/// sender.send(1).unwrap();
+/// sender.send(2).unwrap();
+/// sender.send(3).unwrap();
+/// });
+///
+/// println!("Going to sleep...");
+/// thread::sleep(Duration::from_secs(2)); // block for two seconds
+///
+/// for x in receiver.try_iter() {
+/// println!("Got: {}", x);
+/// }
+/// ```
+#[stable(feature = "receiver_try_iter", since = "1.15.0")]
+#[derive(Debug)]
+pub struct TryIter<'a, T: 'a> {
+ rx: &'a Receiver<T>
+}
+
+/// An owning iterator over messages on a [`Receiver`],
+/// created by **Receiver::into_iter**.
+///
+/// This iterator will block whenever [`next`]
+/// is called, waiting for a new message, and [`None`] will be
+/// returned if the corresponding channel has hung up.
+///
+/// [`Receiver`]: struct.Receiver.html
+/// [`next`]: ../../../std/iter/trait.Iterator.html#tymethod.next
+/// [`None`]: ../../../std/option/enum.Option.html#variant.None
+///
+/// # Examples
+///
+/// ```rust
+/// use std::sync::mpsc::channel;
+/// use std::thread;
+///
+/// let (send, recv) = channel();
+///
+/// thread::spawn(move || {
+/// send.send(1u8).unwrap();
+/// send.send(2u8).unwrap();
+/// send.send(3u8).unwrap();
+/// });
+///
+/// for x in recv.into_iter() {
+/// println!("Got: {}", x);
+/// }
+/// ```
+#[stable(feature = "receiver_into_iter", since = "1.1.0")]
+#[derive(Debug)]
+pub struct IntoIter<T> {
+ rx: Receiver<T>
+}
+
+/// The sending-half of Rust's asynchronous [`channel`] type. This half can only be
+/// owned by one thread, but it can be cloned to send to other threads.
+///
+/// Messages can be sent through this channel with [`send`].
+///
+/// [`channel`]: fn.channel.html
+/// [`send`]: struct.Sender.html#method.send
+///
+/// # Examples
+///
+/// ```rust
+/// use std::sync::mpsc::channel;
+/// use std::thread;
+///
+/// let (sender, receiver) = channel();
+/// let sender2 = sender.clone();
+///
+/// // First thread owns sender
+/// thread::spawn(move || {
+/// sender.send(1).unwrap();
+/// });
+///
+/// // Second thread owns sender2
+/// thread::spawn(move || {
+/// sender2.send(2).unwrap();
+/// });
+///
+/// let msg = receiver.recv().unwrap();
+/// let msg2 = receiver.recv().unwrap();
+///
+/// assert_eq!(3, msg + msg2);
+/// ```
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct Sender<T> {
+ inner: UnsafeCell<Flavor<T>>,
+}
+
+// The send port can be sent from place to place, so long as it
+// is not used to send non-sendable things.
+#[stable(feature = "rust1", since = "1.0.0")]
+unsafe impl<T: Send> Send for Sender<T> { }
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T> !Sync for Sender<T> { }
+
+/// The sending-half of Rust's synchronous [`sync_channel`] type.
+///
+/// Messages can be sent through this channel with [`send`] or [`try_send`].
+///
+/// [`send`] will block if there is no space in the internal buffer.
+///
+/// [`sync_channel`]: fn.sync_channel.html
+/// [`send`]: struct.SyncSender.html#method.send
+/// [`try_send`]: struct.SyncSender.html#method.try_send
+///
+/// # Examples
+///
+/// ```rust
+/// use std::sync::mpsc::sync_channel;
+/// use std::thread;
+///
+/// // Create a sync_channel with buffer size 2
+/// let (sync_sender, receiver) = sync_channel(2);
+/// let sync_sender2 = sync_sender.clone();
+///
+/// // First thread owns sync_sender
+/// thread::spawn(move || {
+/// sync_sender.send(1).unwrap();
+/// sync_sender.send(2).unwrap();
+/// });
+///
+/// // Second thread owns sync_sender2
+/// thread::spawn(move || {
+/// sync_sender2.send(3).unwrap();
+/// // thread will now block since the buffer is full
+/// println!("Thread unblocked!");
+/// });
+///
+/// let mut msg;
+///
+/// msg = receiver.recv().unwrap();
+/// println!("message {} received", msg);
+///
+/// // "Thread unblocked!" will be printed now
+///
+/// msg = receiver.recv().unwrap();
+/// println!("message {} received", msg);
+///
+/// msg = receiver.recv().unwrap();
+///
+/// println!("message {} received", msg);
+/// ```
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct SyncSender<T> {
+ inner: Arc<sync::Packet<T>>,
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+unsafe impl<T: Send> Send for SyncSender<T> {}
+
+/// An error returned from the [`Sender::send`] or [`SyncSender::send`]
+/// function on **channel**s.
+///
+/// A **send** operation can only fail if the receiving end of a channel is
+/// disconnected, implying that the data could never be received. The error
+/// contains the data being sent as a payload so it can be recovered.
+///
+/// [`Sender::send`]: struct.Sender.html#method.send
+/// [`SyncSender::send`]: struct.SyncSender.html#method.send
+#[stable(feature = "rust1", since = "1.0.0")]
+#[derive(PartialEq, Eq, Clone, Copy)]
+pub struct SendError<T>(#[stable(feature = "rust1", since = "1.0.0")] pub T);
+
+/// An error returned from the [`recv`] function on a [`Receiver`].
+///
+/// The [`recv`] operation can only fail if the sending half of a
+/// [`channel`][`channel`] (or [`sync_channel`]) is disconnected, implying that no further
+/// messages will ever be received.
+///
+/// [`recv`]: struct.Receiver.html#method.recv
+/// [`Receiver`]: struct.Receiver.html
+/// [`channel`]: fn.channel.html
+/// [`sync_channel`]: fn.sync_channel.html
+#[derive(PartialEq, Eq, Clone, Copy, Debug)]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct RecvError;
+
+/// This enumeration is the list of the possible reasons that [`try_recv`] could
+/// not return data when called. This can occur with both a [`channel`] and
+/// a [`sync_channel`].
+///
+/// [`try_recv`]: struct.Receiver.html#method.try_recv
+/// [`channel`]: fn.channel.html
+/// [`sync_channel`]: fn.sync_channel.html
+#[derive(PartialEq, Eq, Clone, Copy, Debug)]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub enum TryRecvError {
+ /// This **channel** is currently empty, but the **Sender**(s) have not yet
+ /// disconnected, so data may yet become available.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ Empty,
+
+ /// The **channel**'s sending half has become disconnected, and there will
+ /// never be any more data received on it.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ Disconnected,
+}
+
+/// This enumeration is the list of possible errors that made [`recv_timeout`]
+/// unable to return data when called. This can occur with both a [`channel`] and
+/// a [`sync_channel`].
+///
+/// [`recv_timeout`]: struct.Receiver.html#method.recv_timeout
+/// [`channel`]: fn.channel.html
+/// [`sync_channel`]: fn.sync_channel.html
+#[derive(PartialEq, Eq, Clone, Copy, Debug)]
+#[stable(feature = "mpsc_recv_timeout", since = "1.12.0")]
+pub enum RecvTimeoutError {
+ /// This **channel** is currently empty, but the **Sender**(s) have not yet
+ /// disconnected, so data may yet become available.
+ #[stable(feature = "mpsc_recv_timeout", since = "1.12.0")]
+ Timeout,
+ /// The **channel**'s sending half has become disconnected, and there will
+ /// never be any more data received on it.
+ #[stable(feature = "mpsc_recv_timeout", since = "1.12.0")]
+ Disconnected,
+}
+
+/// This enumeration is the list of the possible error outcomes for the
+/// [`try_send`] method.
+///
+/// [`try_send`]: struct.SyncSender.html#method.try_send
+#[stable(feature = "rust1", since = "1.0.0")]
+#[derive(PartialEq, Eq, Clone, Copy)]
+pub enum TrySendError<T> {
+ /// The data could not be sent on the [`sync_channel`] because it would require that
+ /// the callee block to send the data.
+ ///
+ /// If this is a buffered channel, then the buffer is full at this time. If
+ /// this is not a buffered channel, then there is no [`Receiver`] available to
+ /// acquire the data.
+ ///
+ /// [`sync_channel`]: fn.sync_channel.html
+ /// [`Receiver`]: struct.Receiver.html
+ #[stable(feature = "rust1", since = "1.0.0")]
+ Full(#[stable(feature = "rust1", since = "1.0.0")] T),
+
+ /// This [`sync_channel`]'s receiving half has disconnected, so the data could not be
+ /// sent. The data is returned back to the callee in this case.
+ ///
+ /// [`sync_channel`]: fn.sync_channel.html
+ #[stable(feature = "rust1", since = "1.0.0")]
+ Disconnected(#[stable(feature = "rust1", since = "1.0.0")] T),
+}
+
+enum Flavor<T> {
+ Oneshot(Arc<oneshot::Packet<T>>),
+ Stream(Arc<stream::Packet<T>>),
+ Shared(Arc<shared::Packet<T>>),
+ Sync(Arc<sync::Packet<T>>),
+}
+
+#[doc(hidden)]
+trait UnsafeFlavor<T> {
+ fn inner_unsafe(&self) -> &UnsafeCell<Flavor<T>>;
+ unsafe fn inner_mut(&self) -> &mut Flavor<T> {
+ &mut *self.inner_unsafe().get()
+ }
+ unsafe fn inner(&self) -> &Flavor<T> {
+ &*self.inner_unsafe().get()
+ }
+}
+impl<T> UnsafeFlavor<T> for Sender<T> {
+ fn inner_unsafe(&self) -> &UnsafeCell<Flavor<T>> {
+ &self.inner
+ }
+}
+impl<T> UnsafeFlavor<T> for Receiver<T> {
+ fn inner_unsafe(&self) -> &UnsafeCell<Flavor<T>> {
+ &self.inner
+ }
+}
+
+/// Creates a new asynchronous channel, returning the sender/receiver halves.
+/// All data sent on the [`Sender`] will become available on the [`Receiver`] in
+/// the same order as it was sent, and no [`send`] will block the calling thread
+/// (this channel has an "infinite buffer", unlike [`sync_channel`], which will
+/// block after its buffer limit is reached). [`recv`] will block until a message
+/// is available.
+///
+/// The [`Sender`] can be cloned to [`send`] to the same channel multiple times, but
+/// only one [`Receiver`] is supported.
+///
+/// If the [`Receiver`] is disconnected while trying to [`send`] with the
+/// [`Sender`], the [`send`] method will return a [`SendError`]. Similarly, if the
+/// [`Sender`] is disconnected while trying to [`recv`], the [`recv`] method will
+/// return a [`RecvError`].
+///
+/// [`send`]: struct.Sender.html#method.send
+/// [`recv`]: struct.Receiver.html#method.recv
+/// [`Sender`]: struct.Sender.html
+/// [`Receiver`]: struct.Receiver.html
+/// [`sync_channel`]: fn.sync_channel.html
+/// [`SendError`]: struct.SendError.html
+/// [`RecvError`]: struct.RecvError.html
+///
+/// # Examples
+///
+/// ```
+/// use std::sync::mpsc::channel;
+/// use std::thread;
+///
+/// let (sender, receiver) = channel();
+///
+/// // Spawn off an expensive computation
+/// thread::spawn(move|| {
+/// # fn expensive_computation() {}
+/// sender.send(expensive_computation()).unwrap();
+/// });
+///
+/// // Do some useful work for awhile
+///
+/// // Let's see what that answer was
+/// println!("{:?}", receiver.recv().unwrap());
+/// ```
+#[stable(feature = "rust1", since = "1.0.0")]
+pub fn channel<T>() -> (Sender<T>, Receiver<T>) {
+ let a = Arc::new(oneshot::Packet::new());
+ (Sender::new(Flavor::Oneshot(a.clone())), Receiver::new(Flavor::Oneshot(a)))
+}
+
+/// Creates a new synchronous, bounded channel.
+/// All data sent on the [`SyncSender`] will become available on the [`Receiver`]
+/// in the same order as it was sent. Like asynchronous [`channel`]s, the
+/// [`Receiver`] will block until a message becomes available. `sync_channel`
+/// differs greatly in the semantics of the sender, however.
+///
+/// This channel has an internal buffer on which messages will be queued.
+/// `bound` specifies the buffer size. When the internal buffer becomes full,
+/// future sends will *block* waiting for the buffer to open up. Note that a
+/// buffer size of 0 is valid, in which case this becomes "rendezvous channel"
+/// where each [`send`] will not return until a [`recv`] is paired with it.
+///
+/// The [`SyncSender`] can be cloned to [`send`] to the same channel multiple
+/// times, but only one [`Receiver`] is supported.
+///
+/// Like asynchronous channels, if the [`Receiver`] is disconnected while trying
+/// to [`send`] with the [`SyncSender`], the [`send`] method will return a
+/// [`SendError`]. Similarly, If the [`SyncSender`] is disconnected while trying
+/// to [`recv`], the [`recv`] method will return a [`RecvError`].
+///
+/// [`channel`]: fn.channel.html
+/// [`send`]: struct.SyncSender.html#method.send
+/// [`recv`]: struct.Receiver.html#method.recv
+/// [`SyncSender`]: struct.SyncSender.html
+/// [`Receiver`]: struct.Receiver.html
+/// [`SendError`]: struct.SendError.html
+/// [`RecvError`]: struct.RecvError.html
+///
+/// # Examples
+///
+/// ```
+/// use std::sync::mpsc::sync_channel;
+/// use std::thread;
+///
+/// let (sender, receiver) = sync_channel(1);
+///
+/// // this returns immediately
+/// sender.send(1).unwrap();
+///
+/// thread::spawn(move|| {
+/// // this will block until the previous message has been received
+/// sender.send(2).unwrap();
+/// });
+///
+/// assert_eq!(receiver.recv().unwrap(), 1);
+/// assert_eq!(receiver.recv().unwrap(), 2);
+/// ```
+#[stable(feature = "rust1", since = "1.0.0")]
+pub fn sync_channel<T>(bound: usize) -> (SyncSender<T>, Receiver<T>) {
+ let a = Arc::new(sync::Packet::new(bound));
+ (SyncSender::new(a.clone()), Receiver::new(Flavor::Sync(a)))
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Sender
+////////////////////////////////////////////////////////////////////////////////
+
+impl<T> Sender<T> {
+ fn new(inner: Flavor<T>) -> Sender<T> {
+ Sender {
+ inner: UnsafeCell::new(inner),
+ }
+ }
+
+ /// Attempts to send a value on this channel, returning it back if it could
+ /// not be sent.
+ ///
+ /// A successful send occurs when it is determined that the other end of
+ /// the channel has not hung up already. An unsuccessful send would be one
+ /// where the corresponding receiver has already been deallocated. Note
+ /// that a return value of [`Err`] means that the data will never be
+ /// received, but a return value of [`Ok`] does *not* mean that the data
+ /// will be received. It is possible for the corresponding receiver to
+ /// hang up immediately after this function returns [`Ok`].
+ ///
+ /// [`Err`]: ../../../std/result/enum.Result.html#variant.Err
+ /// [`Ok`]: ../../../std/result/enum.Result.html#variant.Ok
+ ///
+ /// This method will never block the current thread.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::sync::mpsc::channel;
+ ///
+ /// let (tx, rx) = channel();
+ ///
+ /// // This send is always successful
+ /// tx.send(1).unwrap();
+ ///
+ /// // This send will fail because the receiver is gone
+ /// drop(rx);
+ /// assert_eq!(tx.send(1).unwrap_err().0, 1);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn send(&self, t: T) -> Result<(), SendError<T>> {
+ let (new_inner, ret) = match *unsafe { self.inner() } {
+ Flavor::Oneshot(ref p) => {
+ if !p.sent() {
+ return p.send(t).map_err(SendError);
+ } else {
+ let a = Arc::new(stream::Packet::new());
+ let rx = Receiver::new(Flavor::Stream(a.clone()));
+ match p.upgrade(rx) {
+ oneshot::UpSuccess => {
+ let ret = a.send(t);
+ (a, ret)
+ }
+ oneshot::UpDisconnected => (a, Err(t)),
+ oneshot::UpWoke(token) => {
+ // This send cannot panic because the thread is
+ // asleep (we're looking at it), so the receiver
+ // can't go away.
+ a.send(t).ok().unwrap();
+ token.signal();
+ (a, Ok(()))
+ }
+ }
+ }
+ }
+ Flavor::Stream(ref p) => return p.send(t).map_err(SendError),
+ Flavor::Shared(ref p) => return p.send(t).map_err(SendError),
+ Flavor::Sync(..) => unreachable!(),
+ };
+
+ unsafe {
+ let tmp = Sender::new(Flavor::Stream(new_inner));
+ mem::swap(self.inner_mut(), tmp.inner_mut());
+ }
+ ret.map_err(SendError)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T> Clone for Sender<T> {
+ fn clone(&self) -> Sender<T> {
+ let packet = match *unsafe { self.inner() } {
+ Flavor::Oneshot(ref p) => {
+ let a = Arc::new(shared::Packet::new());
+ {
+ let guard = a.postinit_lock();
+ let rx = Receiver::new(Flavor::Shared(a.clone()));
+ let sleeper = match p.upgrade(rx) {
+ oneshot::UpSuccess |
+ oneshot::UpDisconnected => None,
+ oneshot::UpWoke(task) => Some(task),
+ };
+ a.inherit_blocker(sleeper, guard);
+ }
+ a
+ }
+ Flavor::Stream(ref p) => {
+ let a = Arc::new(shared::Packet::new());
+ {
+ let guard = a.postinit_lock();
+ let rx = Receiver::new(Flavor::Shared(a.clone()));
+ let sleeper = match p.upgrade(rx) {
+ stream::UpSuccess |
+ stream::UpDisconnected => None,
+ stream::UpWoke(task) => Some(task),
+ };
+ a.inherit_blocker(sleeper, guard);
+ }
+ a
+ }
+ Flavor::Shared(ref p) => {
+ p.clone_chan();
+ return Sender::new(Flavor::Shared(p.clone()));
+ }
+ Flavor::Sync(..) => unreachable!(),
+ };
+
+ unsafe {
+ let tmp = Sender::new(Flavor::Shared(packet.clone()));
+ mem::swap(self.inner_mut(), tmp.inner_mut());
+ }
+ Sender::new(Flavor::Shared(packet))
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T> Drop for Sender<T> {
+ fn drop(&mut self) {
+ match *unsafe { self.inner() } {
+ Flavor::Oneshot(ref p) => p.drop_chan(),
+ Flavor::Stream(ref p) => p.drop_chan(),
+ Flavor::Shared(ref p) => p.drop_chan(),
+ Flavor::Sync(..) => unreachable!(),
+ }
+ }
+}
+
+#[stable(feature = "mpsc_debug", since = "1.8.0")]
+impl<T> fmt::Debug for Sender<T> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("Sender").finish()
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// SyncSender
+////////////////////////////////////////////////////////////////////////////////
+
+impl<T> SyncSender<T> {
+ fn new(inner: Arc<sync::Packet<T>>) -> SyncSender<T> {
+ SyncSender { inner }
+ }
+
+ /// Sends a value on this synchronous channel.
+ ///
+ /// This function will *block* until space in the internal buffer becomes
+ /// available or a receiver is available to hand off the message to.
+ ///
+ /// Note that a successful send does *not* guarantee that the receiver will
+ /// ever see the data if there is a buffer on this channel. Items may be
+ /// enqueued in the internal buffer for the receiver to receive at a later
+ /// time. If the buffer size is 0, however, the channel becomes a rendezvous
+ /// channel and it guarantees that the receiver has indeed received
+ /// the data if this function returns success.
+ ///
+ /// This function will never panic, but it may return [`Err`] if the
+ /// [`Receiver`] has disconnected and is no longer able to receive
+ /// information.
+ ///
+ /// [`Err`]: ../../../std/result/enum.Result.html#variant.Err
+ /// [`Receiver`]: ../../../std/sync/mpsc/struct.Receiver.html
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// use std::sync::mpsc::sync_channel;
+ /// use std::thread;
+ ///
+ /// // Create a rendezvous sync_channel with buffer size 0
+ /// let (sync_sender, receiver) = sync_channel(0);
+ ///
+ /// thread::spawn(move || {
+ /// println!("sending message...");
+ /// sync_sender.send(1).unwrap();
+ /// // Thread is now blocked until the message is received
+ ///
+ /// println!("...message received!");
+ /// });
+ ///
+ /// let msg = receiver.recv().unwrap();
+ /// assert_eq!(1, msg);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn send(&self, t: T) -> Result<(), SendError<T>> {
+ self.inner.send(t).map_err(SendError)
+ }
+
+ /// Attempts to send a value on this channel without blocking.
+ ///
+ /// This method differs from [`send`] by returning immediately if the
+ /// channel's buffer is full or no receiver is waiting to acquire some
+ /// data. Compared with [`send`], this function has two failure cases
+ /// instead of one (one for disconnection, one for a full buffer).
+ ///
+ /// See [`send`] for notes about guarantees of whether the
+ /// receiver has received the data or not if this function is successful.
+ ///
+ /// [`send`]: ../../../std/sync/mpsc/struct.SyncSender.html#method.send
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// use std::sync::mpsc::sync_channel;
+ /// use std::thread;
+ ///
+ /// // Create a sync_channel with buffer size 1
+ /// let (sync_sender, receiver) = sync_channel(1);
+ /// let sync_sender2 = sync_sender.clone();
+ ///
+ /// // First thread owns sync_sender
+ /// thread::spawn(move || {
+ /// sync_sender.send(1).unwrap();
+ /// sync_sender.send(2).unwrap();
+ /// // Thread blocked
+ /// });
+ ///
+ /// // Second thread owns sync_sender2
+ /// thread::spawn(move || {
+ /// // This will return an error and send
+ /// // no message if the buffer is full
+ /// sync_sender2.try_send(3).is_err();
+ /// });
+ ///
+ /// let mut msg;
+ /// msg = receiver.recv().unwrap();
+ /// println!("message {} received", msg);
+ ///
+ /// msg = receiver.recv().unwrap();
+ /// println!("message {} received", msg);
+ ///
+ /// // Third message may have never been sent
+ /// match receiver.try_recv() {
+ /// Ok(msg) => println!("message {} received", msg),
+ /// Err(_) => println!("the third message was never sent"),
+ /// }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn try_send(&self, t: T) -> Result<(), TrySendError<T>> {
+ self.inner.try_send(t)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T> Clone for SyncSender<T> {
+ fn clone(&self) -> SyncSender<T> {
+ self.inner.clone_chan();
+ SyncSender::new(self.inner.clone())
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T> Drop for SyncSender<T> {
+ fn drop(&mut self) {
+ self.inner.drop_chan();
+ }
+}
+
+#[stable(feature = "mpsc_debug", since = "1.8.0")]
+impl<T> fmt::Debug for SyncSender<T> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("SyncSender").finish()
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Receiver
+////////////////////////////////////////////////////////////////////////////////
+
+impl<T> Receiver<T> {
+ fn new(inner: Flavor<T>) -> Receiver<T> {
+ Receiver { inner: UnsafeCell::new(inner) }
+ }
+
+ /// Attempts to return a pending value on this receiver without blocking.
+ ///
+ /// This method will never block the caller in order to wait for data to
+ /// become available. Instead, this will always return immediately with a
+ /// possible option of pending data on the channel.
+ ///
+ /// This is useful for a flavor of "optimistic check" before deciding to
+ /// block on a receiver.
+ ///
+ /// Compared with [`recv`], this function has two failure cases instead of one
+ /// (one for disconnection, one for an empty buffer).
+ ///
+ /// [`recv`]: struct.Receiver.html#method.recv
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// use std::sync::mpsc::{Receiver, channel};
+ ///
+ /// let (_, receiver): (_, Receiver<i32>) = channel();
+ ///
+ /// assert!(receiver.try_recv().is_err());
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn try_recv(&self) -> Result<T, TryRecvError> {
+ loop {
+ let new_port = match *unsafe { self.inner() } {
+ Flavor::Oneshot(ref p) => {
+ match p.try_recv() {
+ Ok(t) => return Ok(t),
+ Err(oneshot::Empty) => return Err(TryRecvError::Empty),
+ Err(oneshot::Disconnected) => {
+ return Err(TryRecvError::Disconnected)
+ }
+ Err(oneshot::Upgraded(rx)) => rx,
+ }
+ }
+ Flavor::Stream(ref p) => {
+ match p.try_recv() {
+ Ok(t) => return Ok(t),
+ Err(stream::Empty) => return Err(TryRecvError::Empty),
+ Err(stream::Disconnected) => {
+ return Err(TryRecvError::Disconnected)
+ }
+ Err(stream::Upgraded(rx)) => rx,
+ }
+ }
+ Flavor::Shared(ref p) => {
+ match p.try_recv() {
+ Ok(t) => return Ok(t),
+ Err(shared::Empty) => return Err(TryRecvError::Empty),
+ Err(shared::Disconnected) => {
+ return Err(TryRecvError::Disconnected)
+ }
+ }
+ }
+ Flavor::Sync(ref p) => {
+ match p.try_recv() {
+ Ok(t) => return Ok(t),
+ Err(sync::Empty) => return Err(TryRecvError::Empty),
+ Err(sync::Disconnected) => {
+ return Err(TryRecvError::Disconnected)
+ }
+ }
+ }
+ };
+ unsafe {
+ mem::swap(self.inner_mut(),
+ new_port.inner_mut());
+ }
+ }
+ }
+
+ /// Attempts to wait for a value on this receiver, returning an error if the
+ /// corresponding channel has hung up.
+ ///
+ /// This function will always block the current thread if there is no data
+ /// available and it's possible for more data to be sent. Once a message is
+ /// sent to the corresponding [`Sender`][] (or [`SyncSender`]), then this
+ /// receiver will wake up and return that message.
+ ///
+ /// If the corresponding [`Sender`] has disconnected, or it disconnects while
+ /// this call is blocking, this call will wake up and return [`Err`] to
+ /// indicate that no more messages can ever be received on this channel.
+ /// However, since channels are buffered, messages sent before the disconnect
+ /// will still be properly received.
+ ///
+ /// [`Sender`]: struct.Sender.html
+ /// [`SyncSender`]: struct.SyncSender.html
+ /// [`Err`]: ../../../std/result/enum.Result.html#variant.Err
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::sync::mpsc;
+ /// use std::thread;
+ ///
+ /// let (send, recv) = mpsc::channel();
+ /// let handle = thread::spawn(move || {
+ /// send.send(1u8).unwrap();
+ /// });
+ ///
+ /// handle.join().unwrap();
+ ///
+ /// assert_eq!(Ok(1), recv.recv());
+ /// ```
+ ///
+ /// Buffering behavior:
+ ///
+ /// ```
+ /// use std::sync::mpsc;
+ /// use std::thread;
+ /// use std::sync::mpsc::RecvError;
+ ///
+ /// let (send, recv) = mpsc::channel();
+ /// let handle = thread::spawn(move || {
+ /// send.send(1u8).unwrap();
+ /// send.send(2).unwrap();
+ /// send.send(3).unwrap();
+ /// drop(send);
+ /// });
+ ///
+ /// // wait for the thread to join so we ensure the sender is dropped
+ /// handle.join().unwrap();
+ ///
+ /// assert_eq!(Ok(1), recv.recv());
+ /// assert_eq!(Ok(2), recv.recv());
+ /// assert_eq!(Ok(3), recv.recv());
+ /// assert_eq!(Err(RecvError), recv.recv());
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn recv(&self) -> Result<T, RecvError> {
+ loop {
+ let new_port = match *unsafe { self.inner() } {
+ Flavor::Oneshot(ref p) => {
+ match p.recv(None) {
+ Ok(t) => return Ok(t),
+ Err(oneshot::Disconnected) => return Err(RecvError),
+ Err(oneshot::Upgraded(rx)) => rx,
+ Err(oneshot::Empty) => unreachable!(),
+ }
+ }
+ Flavor::Stream(ref p) => {
+ match p.recv(None) {
+ Ok(t) => return Ok(t),
+ Err(stream::Disconnected) => return Err(RecvError),
+ Err(stream::Upgraded(rx)) => rx,
+ Err(stream::Empty) => unreachable!(),
+ }
+ }
+ Flavor::Shared(ref p) => {
+ match p.recv(None) {
+ Ok(t) => return Ok(t),
+ Err(shared::Disconnected) => return Err(RecvError),
+ Err(shared::Empty) => unreachable!(),
+ }
+ }
+ Flavor::Sync(ref p) => return p.recv(None).map_err(|_| RecvError),
+ };
+ unsafe {
+ mem::swap(self.inner_mut(), new_port.inner_mut());
+ }
+ }
+ }
+
+ /// Attempts to wait for a value on this receiver, returning an error if the
+ /// corresponding channel has hung up, or if it waits more than `timeout`.
+ ///
+ /// This function will always block the current thread if there is no data
+ /// available and it's possible for more data to be sent. Once a message is
+ /// sent to the corresponding [`Sender`][] (or [`SyncSender`]), then this
+ /// receiver will wake up and return that message.
+ ///
+ /// If the corresponding [`Sender`] has disconnected, or it disconnects while
+ /// this call is blocking, this call will wake up and return [`Err`] to
+ /// indicate that no more messages can ever be received on this channel.
+ /// However, since channels are buffered, messages sent before the disconnect
+ /// will still be properly received.
+ ///
+ /// [`Sender`]: struct.Sender.html
+ /// [`SyncSender`]: struct.SyncSender.html
+ /// [`Err`]: ../../../std/result/enum.Result.html#variant.Err
+ ///
+ /// # Known Issues
+ ///
+ /// There is currently a known issue (see [`#39364`]) that causes `recv_timeout`
+ /// to panic unexpectedly with the following example:
+ ///
+ /// ```no_run
+ /// use std::sync::mpsc::channel;
+ /// use std::thread;
+ /// use std::time::Duration;
+ ///
+ /// let (tx, rx) = channel::<String>();
+ ///
+ /// thread::spawn(move || {
+ /// let d = Duration::from_millis(10);
+ /// loop {
+ /// println!("recv");
+ /// let _r = rx.recv_timeout(d);
+ /// }
+ /// });
+ ///
+ /// thread::sleep(Duration::from_millis(100));
+ /// let _c1 = tx.clone();
+ ///
+ /// thread::sleep(Duration::from_secs(1));
+ /// ```
+ ///
+ /// [`#39364`]: https://github.com/rust-lang/rust/issues/39364
+ ///
+ /// # Examples
+ ///
+ /// Successfully receiving value before encountering timeout:
+ ///
+ /// ```no_run
+ /// use std::thread;
+ /// use std::time::Duration;
+ /// use std::sync::mpsc;
+ ///
+ /// let (send, recv) = mpsc::channel();
+ ///
+ /// thread::spawn(move || {
+ /// send.send('a').unwrap();
+ /// });
+ ///
+ /// assert_eq!(
+ /// recv.recv_timeout(Duration::from_millis(400)),
+ /// Ok('a')
+ /// );
+ /// ```
+ ///
+ /// Receiving an error upon reaching timeout:
+ ///
+ /// ```no_run
+ /// use std::thread;
+ /// use std::time::Duration;
+ /// use std::sync::mpsc;
+ ///
+ /// let (send, recv) = mpsc::channel();
+ ///
+ /// thread::spawn(move || {
+ /// thread::sleep(Duration::from_millis(800));
+ /// send.send('a').unwrap();
+ /// });
+ ///
+ /// assert_eq!(
+ /// recv.recv_timeout(Duration::from_millis(400)),
+ /// Err(mpsc::RecvTimeoutError::Timeout)
+ /// );
+ /// ```
+ #[stable(feature = "mpsc_recv_timeout", since = "1.12.0")]
+ pub fn recv_timeout(&self, timeout: Duration) -> Result<T, RecvTimeoutError> {
+ // Do an optimistic try_recv to avoid the performance impact of
+ // Instant::now() in the full-channel case.
+ match self.try_recv() {
+ Ok(result) => Ok(result),
+ Err(TryRecvError::Disconnected) => Err(RecvTimeoutError::Disconnected),
+ Err(TryRecvError::Empty) => match Instant::now().checked_add(timeout) {
+ Some(deadline) => self.recv_deadline(deadline),
+ // So far in the future that it's practically the same as waiting indefinitely.
+ None => self.recv().map_err(RecvTimeoutError::from),
+ },
+ }
+ }
+
+ /// Attempts to wait for a value on this receiver, returning an error if the
+ /// corresponding channel has hung up, or if `deadline` is reached.
+ ///
+ /// This function will always block the current thread if there is no data
+ /// available and it's possible for more data to be sent. Once a message is
+ /// sent to the corresponding [`Sender`][] (or [`SyncSender`]), then this
+ /// receiver will wake up and return that message.
+ ///
+ /// If the corresponding [`Sender`] has disconnected, or it disconnects while
+ /// this call is blocking, this call will wake up and return [`Err`] to
+ /// indicate that no more messages can ever be received on this channel.
+ /// However, since channels are buffered, messages sent before the disconnect
+ /// will still be properly received.
+ ///
+ /// [`Sender`]: struct.Sender.html
+ /// [`SyncSender`]: struct.SyncSender.html
+ /// [`Err`]: ../../../std/result/enum.Result.html#variant.Err
+ ///
+ /// # Examples
+ ///
+ /// Successfully receiving value before reaching deadline:
+ ///
+ /// ```no_run
+ /// #![feature(deadline_api)]
+ /// use std::thread;
+ /// use std::time::{Duration, Instant};
+ /// use std::sync::mpsc;
+ ///
+ /// let (send, recv) = mpsc::channel();
+ ///
+ /// thread::spawn(move || {
+ /// send.send('a').unwrap();
+ /// });
+ ///
+ /// assert_eq!(
+ /// recv.recv_deadline(Instant::now() + Duration::from_millis(400)),
+ /// Ok('a')
+ /// );
+ /// ```
+ ///
+ /// Receiving an error upon reaching deadline:
+ ///
+ /// ```no_run
+ /// #![feature(deadline_api)]
+ /// use std::thread;
+ /// use std::time::{Duration, Instant};
+ /// use std::sync::mpsc;
+ ///
+ /// let (send, recv) = mpsc::channel();
+ ///
+ /// thread::spawn(move || {
+ /// thread::sleep(Duration::from_millis(800));
+ /// send.send('a').unwrap();
+ /// });
+ ///
+ /// assert_eq!(
+ /// recv.recv_deadline(Instant::now() + Duration::from_millis(400)),
+ /// Err(mpsc::RecvTimeoutError::Timeout)
+ /// );
+ /// ```
+ #[unstable(feature = "deadline_api", issue = "46316")]
+ pub fn recv_deadline(&self, deadline: Instant) -> Result<T, RecvTimeoutError> {
+ use self::RecvTimeoutError::*;
+
+ loop {
+ let port_or_empty = match *unsafe { self.inner() } {
+ Flavor::Oneshot(ref p) => {
+ match p.recv(Some(deadline)) {
+ Ok(t) => return Ok(t),
+ Err(oneshot::Disconnected) => return Err(Disconnected),
+ Err(oneshot::Upgraded(rx)) => Some(rx),
+ Err(oneshot::Empty) => None,
+ }
+ }
+ Flavor::Stream(ref p) => {
+ match p.recv(Some(deadline)) {
+ Ok(t) => return Ok(t),
+ Err(stream::Disconnected) => return Err(Disconnected),
+ Err(stream::Upgraded(rx)) => Some(rx),
+ Err(stream::Empty) => None,
+ }
+ }
+ Flavor::Shared(ref p) => {
+ match p.recv(Some(deadline)) {
+ Ok(t) => return Ok(t),
+ Err(shared::Disconnected) => return Err(Disconnected),
+ Err(shared::Empty) => None,
+ }
+ }
+ Flavor::Sync(ref p) => {
+ match p.recv(Some(deadline)) {
+ Ok(t) => return Ok(t),
+ Err(sync::Disconnected) => return Err(Disconnected),
+ Err(sync::Empty) => None,
+ }
+ }
+ };
+
+ if let Some(new_port) = port_or_empty {
+ unsafe {
+ mem::swap(self.inner_mut(), new_port.inner_mut());
+ }
+ }
+
+ // If we're already passed the deadline, and we're here without
+ // data, return a timeout, else try again.
+ if Instant::now() >= deadline {
+ return Err(Timeout);
+ }
+ }
+ }
+
+ /// Returns an iterator that will block waiting for messages, but never
+ /// [`panic!`]. It will return [`None`] when the channel has hung up.
+ ///
+ /// [`panic!`]: ../../../std/macro.panic.html
+ /// [`None`]: ../../../std/option/enum.Option.html#variant.None
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// use std::sync::mpsc::channel;
+ /// use std::thread;
+ ///
+ /// let (send, recv) = channel();
+ ///
+ /// thread::spawn(move || {
+ /// send.send(1).unwrap();
+ /// send.send(2).unwrap();
+ /// send.send(3).unwrap();
+ /// });
+ ///
+ /// let mut iter = recv.iter();
+ /// assert_eq!(iter.next(), Some(1));
+ /// assert_eq!(iter.next(), Some(2));
+ /// assert_eq!(iter.next(), Some(3));
+ /// assert_eq!(iter.next(), None);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn iter(&self) -> Iter<'_, T> {
+ Iter { rx: self }
+ }
+
+ /// Returns an iterator that will attempt to yield all pending values.
+ /// It will return `None` if there are no more pending values or if the
+ /// channel has hung up. The iterator will never [`panic!`] or block the
+ /// user by waiting for values.
+ ///
+ /// [`panic!`]: ../../../std/macro.panic.html
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::sync::mpsc::channel;
+ /// use std::thread;
+ /// use std::time::Duration;
+ ///
+ /// let (sender, receiver) = channel();
+ ///
+ /// // nothing is in the buffer yet
+ /// assert!(receiver.try_iter().next().is_none());
+ ///
+ /// thread::spawn(move || {
+ /// thread::sleep(Duration::from_secs(1));
+ /// sender.send(1).unwrap();
+ /// sender.send(2).unwrap();
+ /// sender.send(3).unwrap();
+ /// });
+ ///
+ /// // nothing is in the buffer yet
+ /// assert!(receiver.try_iter().next().is_none());
+ ///
+ /// // block for two seconds
+ /// thread::sleep(Duration::from_secs(2));
+ ///
+ /// let mut iter = receiver.try_iter();
+ /// assert_eq!(iter.next(), Some(1));
+ /// assert_eq!(iter.next(), Some(2));
+ /// assert_eq!(iter.next(), Some(3));
+ /// assert_eq!(iter.next(), None);
+ /// ```
+ #[stable(feature = "receiver_try_iter", since = "1.15.0")]
+ pub fn try_iter(&self) -> TryIter<'_, T> {
+ TryIter { rx: self }
+ }
+
+}
+
+impl<T> select::Packet for Receiver<T> {
+ fn can_recv(&self) -> bool {
+ loop {
+ let new_port = match *unsafe { self.inner() } {
+ Flavor::Oneshot(ref p) => {
+ match p.can_recv() {
+ Ok(ret) => return ret,
+ Err(upgrade) => upgrade,
+ }
+ }
+ Flavor::Stream(ref p) => {
+ match p.can_recv() {
+ Ok(ret) => return ret,
+ Err(upgrade) => upgrade,
+ }
+ }
+ Flavor::Shared(ref p) => return p.can_recv(),
+ Flavor::Sync(ref p) => return p.can_recv(),
+ };
+ unsafe {
+ mem::swap(self.inner_mut(),
+ new_port.inner_mut());
+ }
+ }
+ }
+
+ fn start_selection(&self, mut token: SignalToken) -> StartResult {
+ loop {
+ let (t, new_port) = match *unsafe { self.inner() } {
+ Flavor::Oneshot(ref p) => {
+ match p.start_selection(token) {
+ oneshot::SelSuccess => return Installed,
+ oneshot::SelCanceled => return Abort,
+ oneshot::SelUpgraded(t, rx) => (t, rx),
+ }
+ }
+ Flavor::Stream(ref p) => {
+ match p.start_selection(token) {
+ stream::SelSuccess => return Installed,
+ stream::SelCanceled => return Abort,
+ stream::SelUpgraded(t, rx) => (t, rx),
+ }
+ }
+ Flavor::Shared(ref p) => return p.start_selection(token),
+ Flavor::Sync(ref p) => return p.start_selection(token),
+ };
+ token = t;
+ unsafe {
+ mem::swap(self.inner_mut(), new_port.inner_mut());
+ }
+ }
+ }
+
+ fn abort_selection(&self) -> bool {
+ let mut was_upgrade = false;
+ loop {
+ let result = match *unsafe { self.inner() } {
+ Flavor::Oneshot(ref p) => p.abort_selection(),
+ Flavor::Stream(ref p) => p.abort_selection(was_upgrade),
+ Flavor::Shared(ref p) => return p.abort_selection(was_upgrade),
+ Flavor::Sync(ref p) => return p.abort_selection(),
+ };
+ let new_port = match result { Ok(b) => return b, Err(p) => p };
+ was_upgrade = true;
+ unsafe {
+ mem::swap(self.inner_mut(),
+ new_port.inner_mut());
+ }
+ }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a, T> Iterator for Iter<'a, T> {
+ type Item = T;
+
+ fn next(&mut self) -> Option<T> { self.rx.recv().ok() }
+}
+
+#[stable(feature = "receiver_try_iter", since = "1.15.0")]
+impl<'a, T> Iterator for TryIter<'a, T> {
+ type Item = T;
+
+ fn next(&mut self) -> Option<T> { self.rx.try_recv().ok() }
+}
+
+#[stable(feature = "receiver_into_iter", since = "1.1.0")]
+impl<'a, T> IntoIterator for &'a Receiver<T> {
+ type Item = T;
+ type IntoIter = Iter<'a, T>;
+
+ fn into_iter(self) -> Iter<'a, T> { self.iter() }
+}
+
+#[stable(feature = "receiver_into_iter", since = "1.1.0")]
+impl<T> Iterator for IntoIter<T> {
+ type Item = T;
+ fn next(&mut self) -> Option<T> { self.rx.recv().ok() }
+}
+
+#[stable(feature = "receiver_into_iter", since = "1.1.0")]
+impl <T> IntoIterator for Receiver<T> {
+ type Item = T;
+ type IntoIter = IntoIter<T>;
+
+ fn into_iter(self) -> IntoIter<T> {
+ IntoIter { rx: self }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T> Drop for Receiver<T> {
+ fn drop(&mut self) {
+ match *unsafe { self.inner() } {
+ Flavor::Oneshot(ref p) => p.drop_port(),
+ Flavor::Stream(ref p) => p.drop_port(),
+ Flavor::Shared(ref p) => p.drop_port(),
+ Flavor::Sync(ref p) => p.drop_port(),
+ }
+ }
+}
+
+#[stable(feature = "mpsc_debug", since = "1.8.0")]
+impl<T> fmt::Debug for Receiver<T> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("Receiver").finish()
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T> fmt::Debug for SendError<T> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ "SendError(..)".fmt(f)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T> fmt::Display for SendError<T> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ "sending on a closed channel".fmt(f)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T: Send> error::Error for SendError<T> {
+ fn description(&self) -> &str {
+ "sending on a closed channel"
+ }
+
+ fn cause(&self) -> Option<&dyn error::Error> {
+ None
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T> fmt::Debug for TrySendError<T> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match *self {
+ TrySendError::Full(..) => "Full(..)".fmt(f),
+ TrySendError::Disconnected(..) => "Disconnected(..)".fmt(f),
+ }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T> fmt::Display for TrySendError<T> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match *self {
+ TrySendError::Full(..) => {
+ "sending on a full channel".fmt(f)
+ }
+ TrySendError::Disconnected(..) => {
+ "sending on a closed channel".fmt(f)
+ }
+ }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T: Send> error::Error for TrySendError<T> {
+
+ fn description(&self) -> &str {
+ match *self {
+ TrySendError::Full(..) => {
+ "sending on a full channel"
+ }
+ TrySendError::Disconnected(..) => {
+ "sending on a closed channel"
+ }
+ }
+ }
+
+ fn cause(&self) -> Option<&dyn error::Error> {
+ None
+ }
+}
+
+#[stable(feature = "mpsc_error_conversions", since = "1.24.0")]
+impl<T> From<SendError<T>> for TrySendError<T> {
+ fn from(err: SendError<T>) -> TrySendError<T> {
+ match err {
+ SendError(t) => TrySendError::Disconnected(t),
+ }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl fmt::Display for RecvError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ "receiving on a closed channel".fmt(f)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl error::Error for RecvError {
+
+ fn description(&self) -> &str {
+ "receiving on a closed channel"
+ }
+
+ fn cause(&self) -> Option<&dyn error::Error> {
+ None
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl fmt::Display for TryRecvError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match *self {
+ TryRecvError::Empty => {
+ "receiving on an empty channel".fmt(f)
+ }
+ TryRecvError::Disconnected => {
+ "receiving on a closed channel".fmt(f)
+ }
+ }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl error::Error for TryRecvError {
+
+ fn description(&self) -> &str {
+ match *self {
+ TryRecvError::Empty => {
+ "receiving on an empty channel"
+ }
+ TryRecvError::Disconnected => {
+ "receiving on a closed channel"
+ }
+ }
+ }
+
+ fn cause(&self) -> Option<&dyn error::Error> {
+ None
+ }
+}
+
+#[stable(feature = "mpsc_error_conversions", since = "1.24.0")]
+impl From<RecvError> for TryRecvError {
+ fn from(err: RecvError) -> TryRecvError {
+ match err {
+ RecvError => TryRecvError::Disconnected,
+ }
+ }
+}
+
+#[stable(feature = "mpsc_recv_timeout_error", since = "1.15.0")]
+impl fmt::Display for RecvTimeoutError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match *self {
+ RecvTimeoutError::Timeout => {
+ "timed out waiting on channel".fmt(f)
+ }
+ RecvTimeoutError::Disconnected => {
+ "channel is empty and sending half is closed".fmt(f)
+ }
+ }
+ }
+}
+
+#[stable(feature = "mpsc_recv_timeout_error", since = "1.15.0")]
+impl error::Error for RecvTimeoutError {
+ fn description(&self) -> &str {
+ match *self {
+ RecvTimeoutError::Timeout => {
+ "timed out waiting on channel"
+ }
+ RecvTimeoutError::Disconnected => {
+ "channel is empty and sending half is closed"
+ }
+ }
+ }
+
+ fn cause(&self) -> Option<&dyn error::Error> {
+ None
+ }
+}
+
+#[stable(feature = "mpsc_error_conversions", since = "1.24.0")]
+impl From<RecvError> for RecvTimeoutError {
+ fn from(err: RecvError) -> RecvTimeoutError {
+ match err {
+ RecvError => RecvTimeoutError::Disconnected,
+ }
+ }
+}
+
+#[cfg(all(test, not(target_os = "emscripten")))]
+mod tests {
+ use super::*;
+ use crate::env;
+ use crate::thread;
+ use crate::time::{Duration, Instant};
+
+ pub fn stress_factor() -> usize {
+ match env::var("RUST_TEST_STRESS") {
+ Ok(val) => val.parse().unwrap(),
+ Err(..) => 1,
+ }
+ }
+
+ #[test]
+ fn smoke() {
+ let (tx, rx) = channel::<i32>();
+ tx.send(1).unwrap();
+ assert_eq!(rx.recv().unwrap(), 1);
+ }
+
+ #[test]
+ fn drop_full() {
+ let (tx, _rx) = channel::<Box<isize>>();
+ tx.send(box 1).unwrap();
+ }
+
+ #[test]
+ fn drop_full_shared() {
+ let (tx, _rx) = channel::<Box<isize>>();
+ drop(tx.clone());
+ drop(tx.clone());
+ tx.send(box 1).unwrap();
+ }
+
+ #[test]
+ fn smoke_shared() {
+ let (tx, rx) = channel::<i32>();
+ tx.send(1).unwrap();
+ assert_eq!(rx.recv().unwrap(), 1);
+ let tx = tx.clone();
+ tx.send(1).unwrap();
+ assert_eq!(rx.recv().unwrap(), 1);
+ }
+
+ #[test]
+ fn smoke_threads() {
+ let (tx, rx) = channel::<i32>();
+ let _t = thread::spawn(move|| {
+ tx.send(1).unwrap();
+ });
+ assert_eq!(rx.recv().unwrap(), 1);
+ }
+
+ #[test]
+ fn smoke_port_gone() {
+ let (tx, rx) = channel::<i32>();
+ drop(rx);
+ assert!(tx.send(1).is_err());
+ }
+
+ #[test]
+ fn smoke_shared_port_gone() {
+ let (tx, rx) = channel::<i32>();
+ drop(rx);
+ assert!(tx.send(1).is_err())
+ }
+
+ #[test]
+ fn smoke_shared_port_gone2() {
+ let (tx, rx) = channel::<i32>();
+ drop(rx);
+ let tx2 = tx.clone();
+ drop(tx);
+ assert!(tx2.send(1).is_err());
+ }
+
+ #[test]
+ fn port_gone_concurrent() {
+ let (tx, rx) = channel::<i32>();
+ let _t = thread::spawn(move|| {
+ rx.recv().unwrap();
+ });
+ while tx.send(1).is_ok() {}
+ }
+
+ #[test]
+ fn port_gone_concurrent_shared() {
+ let (tx, rx) = channel::<i32>();
+ let tx2 = tx.clone();
+ let _t = thread::spawn(move|| {
+ rx.recv().unwrap();
+ });
+ while tx.send(1).is_ok() && tx2.send(1).is_ok() {}
+ }
+
+ #[test]
+ fn smoke_chan_gone() {
+ let (tx, rx) = channel::<i32>();
+ drop(tx);
+ assert!(rx.recv().is_err());
+ }
+
+ #[test]
+ fn smoke_chan_gone_shared() {
+ let (tx, rx) = channel::<()>();
+ let tx2 = tx.clone();
+ drop(tx);
+ drop(tx2);
+ assert!(rx.recv().is_err());
+ }
+
+ #[test]
+ fn chan_gone_concurrent() {
+ let (tx, rx) = channel::<i32>();
+ let _t = thread::spawn(move|| {
+ tx.send(1).unwrap();
+ tx.send(1).unwrap();
+ });
+ while rx.recv().is_ok() {}
+ }
+
+ #[test]
+ fn stress() {
+ let (tx, rx) = channel::<i32>();
+ let t = thread::spawn(move|| {
+ for _ in 0..10000 { tx.send(1).unwrap(); }
+ });
+ for _ in 0..10000 {
+ assert_eq!(rx.recv().unwrap(), 1);
+ }
+ t.join().ok().expect("thread panicked");
+ }
+
+ #[test]
+ fn stress_shared() {
+ const AMT: u32 = 10000;
+ const NTHREADS: u32 = 8;
+ let (tx, rx) = channel::<i32>();
+
+ let t = thread::spawn(move|| {
+ for _ in 0..AMT * NTHREADS {
+ assert_eq!(rx.recv().unwrap(), 1);
+ }
+ match rx.try_recv() {
+ Ok(..) => panic!(),
+ _ => {}
+ }
+ });
+
+ for _ in 0..NTHREADS {
+ let tx = tx.clone();
+ thread::spawn(move|| {
+ for _ in 0..AMT { tx.send(1).unwrap(); }
+ });
+ }
+ drop(tx);
+ t.join().ok().expect("thread panicked");
+ }
+
+ #[test]
+ fn send_from_outside_runtime() {
+ let (tx1, rx1) = channel::<()>();
+ let (tx2, rx2) = channel::<i32>();
+ let t1 = thread::spawn(move|| {
+ tx1.send(()).unwrap();
+ for _ in 0..40 {
+ assert_eq!(rx2.recv().unwrap(), 1);
+ }
+ });
+ rx1.recv().unwrap();
+ let t2 = thread::spawn(move|| {
+ for _ in 0..40 {
+ tx2.send(1).unwrap();
+ }
+ });
+ t1.join().ok().expect("thread panicked");
+ t2.join().ok().expect("thread panicked");
+ }
+
+ #[test]
+ fn recv_from_outside_runtime() {
+ let (tx, rx) = channel::<i32>();
+ let t = thread::spawn(move|| {
+ for _ in 0..40 {
+ assert_eq!(rx.recv().unwrap(), 1);
+ }
+ });
+ for _ in 0..40 {
+ tx.send(1).unwrap();
+ }
+ t.join().ok().expect("thread panicked");
+ }
+
+ #[test]
+ fn no_runtime() {
+ let (tx1, rx1) = channel::<i32>();
+ let (tx2, rx2) = channel::<i32>();
+ let t1 = thread::spawn(move|| {
+ assert_eq!(rx1.recv().unwrap(), 1);
+ tx2.send(2).unwrap();
+ });
+ let t2 = thread::spawn(move|| {
+ tx1.send(1).unwrap();
+ assert_eq!(rx2.recv().unwrap(), 2);
+ });
+ t1.join().ok().expect("thread panicked");
+ t2.join().ok().expect("thread panicked");
+ }
+
+ #[test]
+ fn oneshot_single_thread_close_port_first() {
+ // Simple test of closing without sending
+ let (_tx, rx) = channel::<i32>();
+ drop(rx);
+ }
+
+ #[test]
+ fn oneshot_single_thread_close_chan_first() {
+ // Simple test of closing without sending
+ let (tx, _rx) = channel::<i32>();
+ drop(tx);
+ }
+
+ #[test]
+ fn oneshot_single_thread_send_port_close() {
+ // Testing that the sender cleans up the payload if receiver is closed
+ let (tx, rx) = channel::<Box<i32>>();
+ drop(rx);
+ assert!(tx.send(box 0).is_err());
+ }
+
+ #[test]
+ fn oneshot_single_thread_recv_chan_close() {
+ // Receiving on a closed chan will panic
+ let res = thread::spawn(move|| {
+ let (tx, rx) = channel::<i32>();
+ drop(tx);
+ rx.recv().unwrap();
+ }).join();
+ // What is our res?
+ assert!(res.is_err());
+ }
+
+ #[test]
+ fn oneshot_single_thread_send_then_recv() {
+ let (tx, rx) = channel::<Box<i32>>();
+ tx.send(box 10).unwrap();
+ assert!(*rx.recv().unwrap() == 10);
+ }
+
+ #[test]
+ fn oneshot_single_thread_try_send_open() {
+ let (tx, rx) = channel::<i32>();
+ assert!(tx.send(10).is_ok());
+ assert!(rx.recv().unwrap() == 10);
+ }
+
+ #[test]
+ fn oneshot_single_thread_try_send_closed() {
+ let (tx, rx) = channel::<i32>();
+ drop(rx);
+ assert!(tx.send(10).is_err());
+ }
+
+ #[test]
+ fn oneshot_single_thread_try_recv_open() {
+ let (tx, rx) = channel::<i32>();
+ tx.send(10).unwrap();
+ assert!(rx.recv() == Ok(10));
+ }
+
+ #[test]
+ fn oneshot_single_thread_try_recv_closed() {
+ let (tx, rx) = channel::<i32>();
+ drop(tx);
+ assert!(rx.recv().is_err());
+ }
+
+ #[test]
+ fn oneshot_single_thread_peek_data() {
+ let (tx, rx) = channel::<i32>();
+ assert_eq!(rx.try_recv(), Err(TryRecvError::Empty));
+ tx.send(10).unwrap();
+ assert_eq!(rx.try_recv(), Ok(10));
+ }
+
+ #[test]
+ fn oneshot_single_thread_peek_close() {
+ let (tx, rx) = channel::<i32>();
+ drop(tx);
+ assert_eq!(rx.try_recv(), Err(TryRecvError::Disconnected));
+ assert_eq!(rx.try_recv(), Err(TryRecvError::Disconnected));
+ }
+
+ #[test]
+ fn oneshot_single_thread_peek_open() {
+ let (_tx, rx) = channel::<i32>();
+ assert_eq!(rx.try_recv(), Err(TryRecvError::Empty));
+ }
+
+ #[test]
+ fn oneshot_multi_task_recv_then_send() {
+ let (tx, rx) = channel::<Box<i32>>();
+ let _t = thread::spawn(move|| {
+ assert!(*rx.recv().unwrap() == 10);
+ });
+
+ tx.send(box 10).unwrap();
+ }
+
+ #[test]
+ fn oneshot_multi_task_recv_then_close() {
+ let (tx, rx) = channel::<Box<i32>>();
+ let _t = thread::spawn(move|| {
+ drop(tx);
+ });
+ let res = thread::spawn(move|| {
+ assert!(*rx.recv().unwrap() == 10);
+ }).join();
+ assert!(res.is_err());
+ }
+
+ #[test]
+ fn oneshot_multi_thread_close_stress() {
+ for _ in 0..stress_factor() {
+ let (tx, rx) = channel::<i32>();
+ let _t = thread::spawn(move|| {
+ drop(rx);
+ });
+ drop(tx);
+ }
+ }
+
+ #[test]
+ fn oneshot_multi_thread_send_close_stress() {
+ for _ in 0..stress_factor() {
+ let (tx, rx) = channel::<i32>();
+ let _t = thread::spawn(move|| {
+ drop(rx);
+ });
+ let _ = thread::spawn(move|| {
+ tx.send(1).unwrap();
+ }).join();
+ }
+ }
+
+ #[test]
+ fn oneshot_multi_thread_recv_close_stress() {
+ for _ in 0..stress_factor() {
+ let (tx, rx) = channel::<i32>();
+ thread::spawn(move|| {
+ let res = thread::spawn(move|| {
+ rx.recv().unwrap();
+ }).join();
+ assert!(res.is_err());
+ });
+ let _t = thread::spawn(move|| {
+ thread::spawn(move|| {
+ drop(tx);
+ });
+ });
+ }
+ }
+
+ #[test]
+ fn oneshot_multi_thread_send_recv_stress() {
+ for _ in 0..stress_factor() {
+ let (tx, rx) = channel::<Box<isize>>();
+ let _t = thread::spawn(move|| {
+ tx.send(box 10).unwrap();
+ });
+ assert!(*rx.recv().unwrap() == 10);
+ }
+ }
+
+ #[test]
+ fn stream_send_recv_stress() {
+ for _ in 0..stress_factor() {
+ let (tx, rx) = channel();
+
+ send(tx, 0);
+ recv(rx, 0);
+
+ fn send(tx: Sender<Box<i32>>, i: i32) {
+ if i == 10 { return }
+
+ thread::spawn(move|| {
+ tx.send(box i).unwrap();
+ send(tx, i + 1);
+ });
+ }
+
+ fn recv(rx: Receiver<Box<i32>>, i: i32) {
+ if i == 10 { return }
+
+ thread::spawn(move|| {
+ assert!(*rx.recv().unwrap() == i);
+ recv(rx, i + 1);
+ });
+ }
+ }
+ }
+
+ #[test]
+ #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
+ fn oneshot_single_thread_recv_timeout() {
+ let (tx, rx) = channel();
+ tx.send(()).unwrap();
+ assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Ok(()));
+ assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Err(RecvTimeoutError::Timeout));
+ tx.send(()).unwrap();
+ assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Ok(()));
+ }
+
+ #[test]
+ #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
+ fn stress_recv_timeout_two_threads() {
+ let (tx, rx) = channel();
+ let stress = stress_factor() + 100;
+ let timeout = Duration::from_millis(100);
+
+ thread::spawn(move || {
+ for i in 0..stress {
+ if i % 2 == 0 {
+ thread::sleep(timeout * 2);
+ }
+ tx.send(1usize).unwrap();
+ }
+ });
+
+ let mut recv_count = 0;
+ loop {
+ match rx.recv_timeout(timeout) {
+ Ok(n) => {
+ assert_eq!(n, 1usize);
+ recv_count += 1;
+ }
+ Err(RecvTimeoutError::Timeout) => continue,
+ Err(RecvTimeoutError::Disconnected) => break,
+ }
+ }
+
+ assert_eq!(recv_count, stress);
+ }
+
+ #[test]
+ #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
+ fn recv_timeout_upgrade() {
+ let (tx, rx) = channel::<()>();
+ let timeout = Duration::from_millis(1);
+ let _tx_clone = tx.clone();
+
+ let start = Instant::now();
+ assert_eq!(rx.recv_timeout(timeout), Err(RecvTimeoutError::Timeout));
+ assert!(Instant::now() >= start + timeout);
+ }
+
+ #[test]
+ #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
+ fn stress_recv_timeout_shared() {
+ let (tx, rx) = channel();
+ let stress = stress_factor() + 100;
+
+ for i in 0..stress {
+ let tx = tx.clone();
+ thread::spawn(move || {
+ thread::sleep(Duration::from_millis(i as u64 * 10));
+ tx.send(1usize).unwrap();
+ });
+ }
+
+ drop(tx);
+
+ let mut recv_count = 0;
+ loop {
+ match rx.recv_timeout(Duration::from_millis(10)) {
+ Ok(n) => {
+ assert_eq!(n, 1usize);
+ recv_count += 1;
+ }
+ Err(RecvTimeoutError::Timeout) => continue,
+ Err(RecvTimeoutError::Disconnected) => break,
+ }
+ }
+
+ assert_eq!(recv_count, stress);
+ }
+
+ #[test]
+ #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
+ fn very_long_recv_timeout_wont_panic() {
+ let (tx, rx) = channel::<()>();
+ let join_handle = thread::spawn(move || {
+ rx.recv_timeout(Duration::from_secs(u64::max_value()))
+ });
+ thread::sleep(Duration::from_secs(1));
+ assert!(tx.send(()).is_ok());
+ assert_eq!(join_handle.join().unwrap(), Ok(()));
+ }
+
+ #[test]
+ fn recv_a_lot() {
+ // Regression test that we don't run out of stack in scheduler context
+ let (tx, rx) = channel();
+ for _ in 0..10000 { tx.send(()).unwrap(); }
+ for _ in 0..10000 { rx.recv().unwrap(); }
+ }
+
+ #[test]
+ #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
+ fn shared_recv_timeout() {
+ let (tx, rx) = channel();
+ let total = 5;
+ for _ in 0..total {
+ let tx = tx.clone();
+ thread::spawn(move|| {
+ tx.send(()).unwrap();
+ });
+ }
+
+ for _ in 0..total { rx.recv().unwrap(); }
+
+ assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Err(RecvTimeoutError::Timeout));
+ tx.send(()).unwrap();
+ assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Ok(()));
+ }
+
+ #[test]
+ fn shared_chan_stress() {
+ let (tx, rx) = channel();
+ let total = stress_factor() + 100;
+ for _ in 0..total {
+ let tx = tx.clone();
+ thread::spawn(move|| {
+ tx.send(()).unwrap();
+ });
+ }
+
+ for _ in 0..total {
+ rx.recv().unwrap();
+ }
+ }
+
+ #[test]
+ fn test_nested_recv_iter() {
+ let (tx, rx) = channel::<i32>();
+ let (total_tx, total_rx) = channel::<i32>();
+
+ let _t = thread::spawn(move|| {
+ let mut acc = 0;
+ for x in rx.iter() {
+ acc += x;
+ }
+ total_tx.send(acc).unwrap();
+ });
+
+ tx.send(3).unwrap();
+ tx.send(1).unwrap();
+ tx.send(2).unwrap();
+ drop(tx);
+ assert_eq!(total_rx.recv().unwrap(), 6);
+ }
+
+ #[test]
+ fn test_recv_iter_break() {
+ let (tx, rx) = channel::<i32>();
+ let (count_tx, count_rx) = channel();
+
+ let _t = thread::spawn(move|| {
+ let mut count = 0;
+ for x in rx.iter() {
+ if count >= 3 {
+ break;
+ } else {
+ count += x;
+ }
+ }
+ count_tx.send(count).unwrap();
+ });
+
+ tx.send(2).unwrap();
+ tx.send(2).unwrap();
+ tx.send(2).unwrap();
+ let _ = tx.send(2);
+ drop(tx);
+ assert_eq!(count_rx.recv().unwrap(), 4);
+ }
+
+ #[test]
+ fn test_recv_try_iter() {
+ let (request_tx, request_rx) = channel();
+ let (response_tx, response_rx) = channel();
+
+ // Request `x`s until we have `6`.
+ let t = thread::spawn(move|| {
+ let mut count = 0;
+ loop {
+ for x in response_rx.try_iter() {
+ count += x;
+ if count == 6 {
+ return count;
+ }
+ }
+ request_tx.send(()).unwrap();
+ }
+ });
+
+ for _ in request_rx.iter() {
+ if response_tx.send(2).is_err() {
+ break;
+ }
+ }
+
+ assert_eq!(t.join().unwrap(), 6);
+ }
+
+ #[test]
+ fn test_recv_into_iter_owned() {
+ let mut iter = {
+ let (tx, rx) = channel::<i32>();
+ tx.send(1).unwrap();
+ tx.send(2).unwrap();
+
+ rx.into_iter()
+ };
+ assert_eq!(iter.next().unwrap(), 1);
+ assert_eq!(iter.next().unwrap(), 2);
+ assert_eq!(iter.next().is_none(), true);
+ }
+
+ #[test]
+ fn test_recv_into_iter_borrowed() {
+ let (tx, rx) = channel::<i32>();
+ tx.send(1).unwrap();
+ tx.send(2).unwrap();
+ drop(tx);
+ let mut iter = (&rx).into_iter();
+ assert_eq!(iter.next().unwrap(), 1);
+ assert_eq!(iter.next().unwrap(), 2);
+ assert_eq!(iter.next().is_none(), true);
+ }
+
+ #[test]
+ fn try_recv_states() {
+ let (tx1, rx1) = channel::<i32>();
+ let (tx2, rx2) = channel::<()>();
+ let (tx3, rx3) = channel::<()>();
+ let _t = thread::spawn(move|| {
+ rx2.recv().unwrap();
+ tx1.send(1).unwrap();
+ tx3.send(()).unwrap();
+ rx2.recv().unwrap();
+ drop(tx1);
+ tx3.send(()).unwrap();
+ });
+
+ assert_eq!(rx1.try_recv(), Err(TryRecvError::Empty));
+ tx2.send(()).unwrap();
+ rx3.recv().unwrap();
+ assert_eq!(rx1.try_recv(), Ok(1));
+ assert_eq!(rx1.try_recv(), Err(TryRecvError::Empty));
+ tx2.send(()).unwrap();
+ rx3.recv().unwrap();
+ assert_eq!(rx1.try_recv(), Err(TryRecvError::Disconnected));
+ }
+
+ // This bug used to end up in a livelock inside of the Receiver destructor
+ // because the internal state of the Shared packet was corrupted
+ #[test]
+ fn destroy_upgraded_shared_port_when_sender_still_active() {
+ let (tx, rx) = channel();
+ let (tx2, rx2) = channel();
+ let _t = thread::spawn(move|| {
+ rx.recv().unwrap(); // wait on a oneshot
+ drop(rx); // destroy a shared
+ tx2.send(()).unwrap();
+ });
+ // make sure the other thread has gone to sleep
+ for _ in 0..5000 { thread::yield_now(); }
+
+ // upgrade to a shared chan and send a message
+ let t = tx.clone();
+ drop(tx);
+ t.send(()).unwrap();
+
+ // wait for the child thread to exit before we exit
+ rx2.recv().unwrap();
+ }
+
+ #[test]
+ fn issue_32114() {
+ let (tx, _) = channel();
+ let _ = tx.send(123);
+ assert_eq!(tx.send(123), Err(SendError(123)));
+ }
+}
+
+#[cfg(all(test, not(target_os = "emscripten")))]
+mod sync_tests {
+ use super::*;
+ use crate::env;
+ use crate::thread;
+ use crate::time::Duration;
+
+ pub fn stress_factor() -> usize {
+ match env::var("RUST_TEST_STRESS") {
+ Ok(val) => val.parse().unwrap(),
+ Err(..) => 1,
+ }
+ }
+
+ #[test]
+ fn smoke() {
+ let (tx, rx) = sync_channel::<i32>(1);
+ tx.send(1).unwrap();
+ assert_eq!(rx.recv().unwrap(), 1);
+ }
+
+ #[test]
+ fn drop_full() {
+ let (tx, _rx) = sync_channel::<Box<isize>>(1);
+ tx.send(box 1).unwrap();
+ }
+
+ #[test]
+ fn smoke_shared() {
+ let (tx, rx) = sync_channel::<i32>(1);
+ tx.send(1).unwrap();
+ assert_eq!(rx.recv().unwrap(), 1);
+ let tx = tx.clone();
+ tx.send(1).unwrap();
+ assert_eq!(rx.recv().unwrap(), 1);
+ }
+
+ #[test]
+ #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
+ fn recv_timeout() {
+ let (tx, rx) = sync_channel::<i32>(1);
+ assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Err(RecvTimeoutError::Timeout));
+ tx.send(1).unwrap();
+ assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Ok(1));
+ }
+
+ #[test]
+ fn smoke_threads() {
+ let (tx, rx) = sync_channel::<i32>(0);
+ let _t = thread::spawn(move|| {
+ tx.send(1).unwrap();
+ });
+ assert_eq!(rx.recv().unwrap(), 1);
+ }
+
+ #[test]
+ fn smoke_port_gone() {
+ let (tx, rx) = sync_channel::<i32>(0);
+ drop(rx);
+ assert!(tx.send(1).is_err());
+ }
+
+ #[test]
+ fn smoke_shared_port_gone2() {
+ let (tx, rx) = sync_channel::<i32>(0);
+ drop(rx);
+ let tx2 = tx.clone();
+ drop(tx);
+ assert!(tx2.send(1).is_err());
+ }
+
+ #[test]
+ fn port_gone_concurrent() {
+ let (tx, rx) = sync_channel::<i32>(0);
+ let _t = thread::spawn(move|| {
+ rx.recv().unwrap();
+ });
+ while tx.send(1).is_ok() {}
+ }
+
+ #[test]
+ fn port_gone_concurrent_shared() {
+ let (tx, rx) = sync_channel::<i32>(0);
+ let tx2 = tx.clone();
+ let _t = thread::spawn(move|| {
+ rx.recv().unwrap();
+ });
+ while tx.send(1).is_ok() && tx2.send(1).is_ok() {}
+ }
+
+ #[test]
+ fn smoke_chan_gone() {
+ let (tx, rx) = sync_channel::<i32>(0);
+ drop(tx);
+ assert!(rx.recv().is_err());
+ }
+
+ #[test]
+ fn smoke_chan_gone_shared() {
+ let (tx, rx) = sync_channel::<()>(0);
+ let tx2 = tx.clone();
+ drop(tx);
+ drop(tx2);
+ assert!(rx.recv().is_err());
+ }
+
+ #[test]
+ fn chan_gone_concurrent() {
+ let (tx, rx) = sync_channel::<i32>(0);
+ thread::spawn(move|| {
+ tx.send(1).unwrap();
+ tx.send(1).unwrap();
+ });
+ while rx.recv().is_ok() {}
+ }
+
+ #[test]
+ fn stress() {
+ let (tx, rx) = sync_channel::<i32>(0);
+ thread::spawn(move|| {
+ for _ in 0..10000 { tx.send(1).unwrap(); }
+ });
+ for _ in 0..10000 {
+ assert_eq!(rx.recv().unwrap(), 1);
+ }
+ }
+
+ #[test]
+ #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
+ fn stress_recv_timeout_two_threads() {
+ let (tx, rx) = sync_channel::<i32>(0);
+
+ thread::spawn(move|| {
+ for _ in 0..10000 { tx.send(1).unwrap(); }
+ });
+
+ let mut recv_count = 0;
+ loop {
+ match rx.recv_timeout(Duration::from_millis(1)) {
+ Ok(v) => {
+ assert_eq!(v, 1);
+ recv_count += 1;
+ },
+ Err(RecvTimeoutError::Timeout) => continue,
+ Err(RecvTimeoutError::Disconnected) => break,
+ }
+ }
+
+ assert_eq!(recv_count, 10000);
+ }
+
+ #[test]
+ #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
+ fn stress_recv_timeout_shared() {
+ const AMT: u32 = 1000;
+ const NTHREADS: u32 = 8;
+ let (tx, rx) = sync_channel::<i32>(0);
+ let (dtx, drx) = sync_channel::<()>(0);
+
+ thread::spawn(move|| {
+ let mut recv_count = 0;
+ loop {
+ match rx.recv_timeout(Duration::from_millis(10)) {
+ Ok(v) => {
+ assert_eq!(v, 1);
+ recv_count += 1;
+ },
+ Err(RecvTimeoutError::Timeout) => continue,
+ Err(RecvTimeoutError::Disconnected) => break,
+ }
+ }
+
+ assert_eq!(recv_count, AMT * NTHREADS);
+ assert!(rx.try_recv().is_err());
+
+ dtx.send(()).unwrap();
+ });
+
+ for _ in 0..NTHREADS {
+ let tx = tx.clone();
+ thread::spawn(move|| {
+ for _ in 0..AMT { tx.send(1).unwrap(); }
+ });
+ }
+
+ drop(tx);
+
+ drx.recv().unwrap();
+ }
+
+ #[test]
+ fn stress_shared() {
+ const AMT: u32 = 1000;
+ const NTHREADS: u32 = 8;
+ let (tx, rx) = sync_channel::<i32>(0);
+ let (dtx, drx) = sync_channel::<()>(0);
+
+ thread::spawn(move|| {
+ for _ in 0..AMT * NTHREADS {
+ assert_eq!(rx.recv().unwrap(), 1);
+ }
+ match rx.try_recv() {
+ Ok(..) => panic!(),
+ _ => {}
+ }
+ dtx.send(()).unwrap();
+ });
+
+ for _ in 0..NTHREADS {
+ let tx = tx.clone();
+ thread::spawn(move|| {
+ for _ in 0..AMT { tx.send(1).unwrap(); }
+ });
+ }
+ drop(tx);
+ drx.recv().unwrap();
+ }
+
+ #[test]
+ fn oneshot_single_thread_close_port_first() {
+ // Simple test of closing without sending
+ let (_tx, rx) = sync_channel::<i32>(0);
+ drop(rx);
+ }
+
+ #[test]
+ fn oneshot_single_thread_close_chan_first() {
+ // Simple test of closing without sending
+ let (tx, _rx) = sync_channel::<i32>(0);
+ drop(tx);
+ }
+
+ #[test]
+ fn oneshot_single_thread_send_port_close() {
+ // Testing that the sender cleans up the payload if receiver is closed
+ let (tx, rx) = sync_channel::<Box<i32>>(0);
+ drop(rx);
+ assert!(tx.send(box 0).is_err());
+ }
+
+ #[test]
+ fn oneshot_single_thread_recv_chan_close() {
+ // Receiving on a closed chan will panic
+ let res = thread::spawn(move|| {
+ let (tx, rx) = sync_channel::<i32>(0);
+ drop(tx);
+ rx.recv().unwrap();
+ }).join();
+ // What is our res?
+ assert!(res.is_err());
+ }
+
+ #[test]
+ fn oneshot_single_thread_send_then_recv() {
+ let (tx, rx) = sync_channel::<Box<i32>>(1);
+ tx.send(box 10).unwrap();
+ assert!(*rx.recv().unwrap() == 10);
+ }
+
+ #[test]
+ fn oneshot_single_thread_try_send_open() {
+ let (tx, rx) = sync_channel::<i32>(1);
+ assert_eq!(tx.try_send(10), Ok(()));
+ assert!(rx.recv().unwrap() == 10);
+ }
+
+ #[test]
+ fn oneshot_single_thread_try_send_closed() {
+ let (tx, rx) = sync_channel::<i32>(0);
+ drop(rx);
+ assert_eq!(tx.try_send(10), Err(TrySendError::Disconnected(10)));
+ }
+
+ #[test]
+ fn oneshot_single_thread_try_send_closed2() {
+ let (tx, _rx) = sync_channel::<i32>(0);
+ assert_eq!(tx.try_send(10), Err(TrySendError::Full(10)));
+ }
+
+ #[test]
+ fn oneshot_single_thread_try_recv_open() {
+ let (tx, rx) = sync_channel::<i32>(1);
+ tx.send(10).unwrap();
+ assert!(rx.recv() == Ok(10));
+ }
+
+ #[test]
+ fn oneshot_single_thread_try_recv_closed() {
+ let (tx, rx) = sync_channel::<i32>(0);
+ drop(tx);
+ assert!(rx.recv().is_err());
+ }
+
+ #[test]
+ fn oneshot_single_thread_try_recv_closed_with_data() {
+ let (tx, rx) = sync_channel::<i32>(1);
+ tx.send(10).unwrap();
+ drop(tx);
+ assert_eq!(rx.try_recv(), Ok(10));
+ assert_eq!(rx.try_recv(), Err(TryRecvError::Disconnected));
+ }
+
+ #[test]
+ fn oneshot_single_thread_peek_data() {
+ let (tx, rx) = sync_channel::<i32>(1);
+ assert_eq!(rx.try_recv(), Err(TryRecvError::Empty));
+ tx.send(10).unwrap();
+ assert_eq!(rx.try_recv(), Ok(10));
+ }
+
+ #[test]
+ fn oneshot_single_thread_peek_close() {
+ let (tx, rx) = sync_channel::<i32>(0);
+ drop(tx);
+ assert_eq!(rx.try_recv(), Err(TryRecvError::Disconnected));
+ assert_eq!(rx.try_recv(), Err(TryRecvError::Disconnected));
+ }
+
+ #[test]
+ fn oneshot_single_thread_peek_open() {
+ let (_tx, rx) = sync_channel::<i32>(0);
+ assert_eq!(rx.try_recv(), Err(TryRecvError::Empty));
+ }
+
+ #[test]
+ fn oneshot_multi_task_recv_then_send() {
+ let (tx, rx) = sync_channel::<Box<i32>>(0);
+ let _t = thread::spawn(move|| {
+ assert!(*rx.recv().unwrap() == 10);
+ });
+
+ tx.send(box 10).unwrap();
+ }
+
+ #[test]
+ fn oneshot_multi_task_recv_then_close() {
+ let (tx, rx) = sync_channel::<Box<i32>>(0);
+ let _t = thread::spawn(move|| {
+ drop(tx);
+ });
+ let res = thread::spawn(move|| {
+ assert!(*rx.recv().unwrap() == 10);
+ }).join();
+ assert!(res.is_err());
+ }
+
+ #[test]
+ fn oneshot_multi_thread_close_stress() {
+ for _ in 0..stress_factor() {
+ let (tx, rx) = sync_channel::<i32>(0);
+ let _t = thread::spawn(move|| {
+ drop(rx);
+ });
+ drop(tx);
+ }
+ }
+
+ #[test]
+ fn oneshot_multi_thread_send_close_stress() {
+ for _ in 0..stress_factor() {
+ let (tx, rx) = sync_channel::<i32>(0);
+ let _t = thread::spawn(move|| {
+ drop(rx);
+ });
+ let _ = thread::spawn(move || {
+ tx.send(1).unwrap();
+ }).join();
+ }
+ }
+
+ #[test]
+ fn oneshot_multi_thread_recv_close_stress() {
+ for _ in 0..stress_factor() {
+ let (tx, rx) = sync_channel::<i32>(0);
+ let _t = thread::spawn(move|| {
+ let res = thread::spawn(move|| {
+ rx.recv().unwrap();
+ }).join();
+ assert!(res.is_err());
+ });
+ let _t = thread::spawn(move|| {
+ thread::spawn(move|| {
+ drop(tx);
+ });
+ });
+ }
+ }
+
+ #[test]
+ fn oneshot_multi_thread_send_recv_stress() {
+ for _ in 0..stress_factor() {
+ let (tx, rx) = sync_channel::<Box<i32>>(0);
+ let _t = thread::spawn(move|| {
+ tx.send(box 10).unwrap();
+ });
+ assert!(*rx.recv().unwrap() == 10);
+ }
+ }
+
+ #[test]
+ fn stream_send_recv_stress() {
+ for _ in 0..stress_factor() {
+ let (tx, rx) = sync_channel::<Box<i32>>(0);
+
+ send(tx, 0);
+ recv(rx, 0);
+
+ fn send(tx: SyncSender<Box<i32>>, i: i32) {
+ if i == 10 { return }
+
+ thread::spawn(move|| {
+ tx.send(box i).unwrap();
+ send(tx, i + 1);
+ });
+ }
+
+ fn recv(rx: Receiver<Box<i32>>, i: i32) {
+ if i == 10 { return }
+
+ thread::spawn(move|| {
+ assert!(*rx.recv().unwrap() == i);
+ recv(rx, i + 1);
+ });
+ }
+ }
+ }
+
+ #[test]
+ fn recv_a_lot() {
+ // Regression test that we don't run out of stack in scheduler context
+ let (tx, rx) = sync_channel(10000);
+ for _ in 0..10000 { tx.send(()).unwrap(); }
+ for _ in 0..10000 { rx.recv().unwrap(); }
+ }
+
+ #[test]
+ fn shared_chan_stress() {
+ let (tx, rx) = sync_channel(0);
+ let total = stress_factor() + 100;
+ for _ in 0..total {
+ let tx = tx.clone();
+ thread::spawn(move|| {
+ tx.send(()).unwrap();
+ });
+ }
+
+ for _ in 0..total {
+ rx.recv().unwrap();
+ }
+ }
+
+ #[test]
+ fn test_nested_recv_iter() {
+ let (tx, rx) = sync_channel::<i32>(0);
+ let (total_tx, total_rx) = sync_channel::<i32>(0);
+
+ let _t = thread::spawn(move|| {
+ let mut acc = 0;
+ for x in rx.iter() {
+ acc += x;
+ }
+ total_tx.send(acc).unwrap();
+ });
+
+ tx.send(3).unwrap();
+ tx.send(1).unwrap();
+ tx.send(2).unwrap();
+ drop(tx);
+ assert_eq!(total_rx.recv().unwrap(), 6);
+ }
+
+ #[test]
+ fn test_recv_iter_break() {
+ let (tx, rx) = sync_channel::<i32>(0);
+ let (count_tx, count_rx) = sync_channel(0);
+
+ let _t = thread::spawn(move|| {
+ let mut count = 0;
+ for x in rx.iter() {
+ if count >= 3 {
+ break;
+ } else {
+ count += x;
+ }
+ }
+ count_tx.send(count).unwrap();
+ });
+
+ tx.send(2).unwrap();
+ tx.send(2).unwrap();
+ tx.send(2).unwrap();
+ let _ = tx.try_send(2);
+ drop(tx);
+ assert_eq!(count_rx.recv().unwrap(), 4);
+ }
+
+ #[test]
+ fn try_recv_states() {
+ let (tx1, rx1) = sync_channel::<i32>(1);
+ let (tx2, rx2) = sync_channel::<()>(1);
+ let (tx3, rx3) = sync_channel::<()>(1);
+ let _t = thread::spawn(move|| {
+ rx2.recv().unwrap();
+ tx1.send(1).unwrap();
+ tx3.send(()).unwrap();
+ rx2.recv().unwrap();
+ drop(tx1);
+ tx3.send(()).unwrap();
+ });
+
+ assert_eq!(rx1.try_recv(), Err(TryRecvError::Empty));
+ tx2.send(()).unwrap();
+ rx3.recv().unwrap();
+ assert_eq!(rx1.try_recv(), Ok(1));
+ assert_eq!(rx1.try_recv(), Err(TryRecvError::Empty));
+ tx2.send(()).unwrap();
+ rx3.recv().unwrap();
+ assert_eq!(rx1.try_recv(), Err(TryRecvError::Disconnected));
+ }
+
+ // This bug used to end up in a livelock inside of the Receiver destructor
+ // because the internal state of the Shared packet was corrupted
+ #[test]
+ fn destroy_upgraded_shared_port_when_sender_still_active() {
+ let (tx, rx) = sync_channel::<()>(0);
+ let (tx2, rx2) = sync_channel::<()>(0);
+ let _t = thread::spawn(move|| {
+ rx.recv().unwrap(); // wait on a oneshot
+ drop(rx); // destroy a shared
+ tx2.send(()).unwrap();
+ });
+ // make sure the other thread has gone to sleep
+ for _ in 0..5000 { thread::yield_now(); }
+
+ // upgrade to a shared chan and send a message
+ let t = tx.clone();
+ drop(tx);
+ t.send(()).unwrap();
+
+ // wait for the child thread to exit before we exit
+ rx2.recv().unwrap();
+ }
+
+ #[test]
+ fn send1() {
+ let (tx, rx) = sync_channel::<i32>(0);
+ let _t = thread::spawn(move|| { rx.recv().unwrap(); });
+ assert_eq!(tx.send(1), Ok(()));
+ }
+
+ #[test]
+ fn send2() {
+ let (tx, rx) = sync_channel::<i32>(0);
+ let _t = thread::spawn(move|| { drop(rx); });
+ assert!(tx.send(1).is_err());
+ }
+
+ #[test]
+ fn send3() {
+ let (tx, rx) = sync_channel::<i32>(1);
+ assert_eq!(tx.send(1), Ok(()));
+ let _t =thread::spawn(move|| { drop(rx); });
+ assert!(tx.send(1).is_err());
+ }
+
+ #[test]
+ fn send4() {
+ let (tx, rx) = sync_channel::<i32>(0);
+ let tx2 = tx.clone();
+ let (done, donerx) = channel();
+ let done2 = done.clone();
+ let _t = thread::spawn(move|| {
+ assert!(tx.send(1).is_err());
+ done.send(()).unwrap();
+ });
+ let _t = thread::spawn(move|| {
+ assert!(tx2.send(2).is_err());
+ done2.send(()).unwrap();
+ });
+ drop(rx);
+ donerx.recv().unwrap();
+ donerx.recv().unwrap();
+ }
+
+ #[test]
+ fn try_send1() {
+ let (tx, _rx) = sync_channel::<i32>(0);
+ assert_eq!(tx.try_send(1), Err(TrySendError::Full(1)));
+ }
+
+ #[test]
+ fn try_send2() {
+ let (tx, _rx) = sync_channel::<i32>(1);
+ assert_eq!(tx.try_send(1), Ok(()));
+ assert_eq!(tx.try_send(1), Err(TrySendError::Full(1)));
+ }
+
+ #[test]
+ fn try_send3() {
+ let (tx, rx) = sync_channel::<i32>(1);
+ assert_eq!(tx.try_send(1), Ok(()));
+ drop(rx);
+ assert_eq!(tx.try_send(1), Err(TrySendError::Disconnected(1)));
+ }
+
+ #[test]
+ fn issue_15761() {
+ fn repro() {
+ let (tx1, rx1) = sync_channel::<()>(3);
+ let (tx2, rx2) = sync_channel::<()>(3);
+
+ let _t = thread::spawn(move|| {
+ rx1.recv().unwrap();
+ tx2.try_send(()).unwrap();
+ });
+
+ tx1.try_send(()).unwrap();
+ rx2.recv().unwrap();
+ }
+
+ for _ in 0..100 {
+ repro()
+ }
+ }
+}
diff --git a/src/libstd/sync/mpsc/mpsc_queue.rs b/src/libstd/sync/mpsc/mpsc_queue.rs
new file mode 100644
index 0000000..8f5681b
--- /dev/null
+++ b/src/libstd/sync/mpsc/mpsc_queue.rs
@@ -0,0 +1,171 @@
+//! A mostly lock-free multi-producer, single consumer queue.
+//!
+//! This module contains an implementation of a concurrent MPSC queue. This
+//! queue can be used to share data between threads, and is also used as the
+//! building block of channels in rust.
+//!
+//! Note that the current implementation of this queue has a caveat of the `pop`
+//! method, and see the method for more information about it. Due to this
+//! caveat, this queue may not be appropriate for all use-cases.
+
+// http://www.1024cores.net/home/lock-free-algorithms
+// /queues/non-intrusive-mpsc-node-based-queue
+
+pub use self::PopResult::*;
+
+use core::ptr;
+use core::cell::UnsafeCell;
+
+use crate::boxed::Box;
+use crate::sync::atomic::{AtomicPtr, Ordering};
+
+/// A result of the `pop` function.
+pub enum PopResult<T> {
+ /// Some data has been popped
+ Data(T),
+ /// The queue is empty
+ Empty,
+ /// The queue is in an inconsistent state. Popping data should succeed, but
+ /// some pushers have yet to make enough progress in order allow a pop to
+ /// succeed. It is recommended that a pop() occur "in the near future" in
+ /// order to see if the sender has made progress or not
+ Inconsistent,
+}
+
+struct Node<T> {
+ next: AtomicPtr<Node<T>>,
+ value: Option<T>,
+}
+
+/// The multi-producer single-consumer structure. This is not cloneable, but it
+/// may be safely shared so long as it is guaranteed that there is only one
+/// popper at a time (many pushers are allowed).
+pub struct Queue<T> {
+ head: AtomicPtr<Node<T>>,
+ tail: UnsafeCell<*mut Node<T>>,
+}
+
+unsafe impl<T: Send> Send for Queue<T> { }
+unsafe impl<T: Send> Sync for Queue<T> { }
+
+impl<T> Node<T> {
+ unsafe fn new(v: Option<T>) -> *mut Node<T> {
+ Box::into_raw(box Node {
+ next: AtomicPtr::new(ptr::null_mut()),
+ value: v,
+ })
+ }
+}
+
+impl<T> Queue<T> {
+ /// Creates a new queue that is safe to share among multiple producers and
+ /// one consumer.
+ pub fn new() -> Queue<T> {
+ let stub = unsafe { Node::new(None) };
+ Queue {
+ head: AtomicPtr::new(stub),
+ tail: UnsafeCell::new(stub),
+ }
+ }
+
+ /// Pushes a new value onto this queue.
+ pub fn push(&self, t: T) {
+ unsafe {
+ let n = Node::new(Some(t));
+ let prev = self.head.swap(n, Ordering::AcqRel);
+ (*prev).next.store(n, Ordering::Release);
+ }
+ }
+
+ /// Pops some data from this queue.
+ ///
+ /// Note that the current implementation means that this function cannot
+ /// return `Option<T>`. It is possible for this queue to be in an
+ /// inconsistent state where many pushes have succeeded and completely
+ /// finished, but pops cannot return `Some(t)`. This inconsistent state
+ /// happens when a pusher is pre-empted at an inopportune moment.
+ ///
+ /// This inconsistent state means that this queue does indeed have data, but
+ /// it does not currently have access to it at this time.
+ pub fn pop(&self) -> PopResult<T> {
+ unsafe {
+ let tail = *self.tail.get();
+ let next = (*tail).next.load(Ordering::Acquire);
+
+ if !next.is_null() {
+ *self.tail.get() = next;
+ assert!((*tail).value.is_none());
+ assert!((*next).value.is_some());
+ let ret = (*next).value.take().unwrap();
+ let _: Box<Node<T>> = Box::from_raw(tail);
+ return Data(ret);
+ }
+
+ if self.head.load(Ordering::Acquire) == tail {Empty} else {Inconsistent}
+ }
+ }
+}
+
+impl<T> Drop for Queue<T> {
+ fn drop(&mut self) {
+ unsafe {
+ let mut cur = *self.tail.get();
+ while !cur.is_null() {
+ let next = (*cur).next.load(Ordering::Relaxed);
+ let _: Box<Node<T>> = Box::from_raw(cur);
+ cur = next;
+ }
+ }
+ }
+}
+
+#[cfg(all(test, not(target_os = "emscripten")))]
+mod tests {
+ use super::{Queue, Data, Empty, Inconsistent};
+ use crate::sync::mpsc::channel;
+ use crate::sync::Arc;
+ use crate::thread;
+
+ #[test]
+ fn test_full() {
+ let q: Queue<Box<_>> = Queue::new();
+ q.push(box 1);
+ q.push(box 2);
+ }
+
+ #[test]
+ fn test() {
+ let nthreads = 8;
+ let nmsgs = 1000;
+ let q = Queue::new();
+ match q.pop() {
+ Empty => {}
+ Inconsistent | Data(..) => panic!()
+ }
+ let (tx, rx) = channel();
+ let q = Arc::new(q);
+
+ for _ in 0..nthreads {
+ let tx = tx.clone();
+ let q = q.clone();
+ thread::spawn(move|| {
+ for i in 0..nmsgs {
+ q.push(i);
+ }
+ tx.send(()).unwrap();
+ });
+ }
+
+ let mut i = 0;
+ while i < nthreads * nmsgs {
+ match q.pop() {
+ Empty | Inconsistent => {},
+ Data(_) => { i += 1 }
+ }
+ }
+ drop(tx);
+ for _ in 0..nthreads {
+ rx.recv().unwrap();
+ }
+ }
+}
diff --git a/src/libstd/sync/mpsc/oneshot.rs b/src/libstd/sync/mpsc/oneshot.rs
new file mode 100644
index 0000000..5c516d5d
--- /dev/null
+++ b/src/libstd/sync/mpsc/oneshot.rs
@@ -0,0 +1,386 @@
+/// Oneshot channels/ports
+///
+/// This is the initial flavor of channels/ports used for comm module. This is
+/// an optimization for the one-use case of a channel. The major optimization of
+/// this type is to have one and exactly one allocation when the chan/port pair
+/// is created.
+///
+/// Another possible optimization would be to not use an Arc box because
+/// in theory we know when the shared packet can be deallocated (no real need
+/// for the atomic reference counting), but I was having trouble how to destroy
+/// the data early in a drop of a Port.
+///
+/// # Implementation
+///
+/// Oneshots are implemented around one atomic usize variable. This variable
+/// indicates both the state of the port/chan but also contains any threads
+/// blocked on the port. All atomic operations happen on this one word.
+///
+/// In order to upgrade a oneshot channel, an upgrade is considered a disconnect
+/// on behalf of the channel side of things (it can be mentally thought of as
+/// consuming the port). This upgrade is then also stored in the shared packet.
+/// The one caveat to consider is that when a port sees a disconnected channel
+/// it must check for data because there is no "data plus upgrade" state.
+
+pub use self::Failure::*;
+pub use self::UpgradeResult::*;
+pub use self::SelectionResult::*;
+use self::MyUpgrade::*;
+
+use crate::sync::mpsc::Receiver;
+use crate::sync::mpsc::blocking::{self, SignalToken};
+use crate::cell::UnsafeCell;
+use crate::ptr;
+use crate::sync::atomic::{AtomicUsize, Ordering};
+use crate::time::Instant;
+
+// Various states you can find a port in.
+const EMPTY: usize = 0; // initial state: no data, no blocked receiver
+const DATA: usize = 1; // data ready for receiver to take
+const DISCONNECTED: usize = 2; // channel is disconnected OR upgraded
+// Any other value represents a pointer to a SignalToken value. The
+// protocol ensures that when the state moves *to* a pointer,
+// ownership of the token is given to the packet, and when the state
+// moves *from* a pointer, ownership of the token is transferred to
+// whoever changed the state.
+
+pub struct Packet<T> {
+ // Internal state of the chan/port pair (stores the blocked thread as well)
+ state: AtomicUsize,
+ // One-shot data slot location
+ data: UnsafeCell<Option<T>>,
+ // when used for the second time, a oneshot channel must be upgraded, and
+ // this contains the slot for the upgrade
+ upgrade: UnsafeCell<MyUpgrade<T>>,
+}
+
+pub enum Failure<T> {
+ Empty,
+ Disconnected,
+ Upgraded(Receiver<T>),
+}
+
+pub enum UpgradeResult {
+ UpSuccess,
+ UpDisconnected,
+ UpWoke(SignalToken),
+}
+
+pub enum SelectionResult<T> {
+ SelCanceled,
+ SelUpgraded(SignalToken, Receiver<T>),
+ SelSuccess,
+}
+
+enum MyUpgrade<T> {
+ NothingSent,
+ SendUsed,
+ GoUp(Receiver<T>),
+}
+
+impl<T> Packet<T> {
+ pub fn new() -> Packet<T> {
+ Packet {
+ data: UnsafeCell::new(None),
+ upgrade: UnsafeCell::new(NothingSent),
+ state: AtomicUsize::new(EMPTY),
+ }
+ }
+
+ pub fn send(&self, t: T) -> Result<(), T> {
+ unsafe {
+ // Sanity check
+ match *self.upgrade.get() {
+ NothingSent => {}
+ _ => panic!("sending on a oneshot that's already sent on "),
+ }
+ assert!((*self.data.get()).is_none());
+ ptr::write(self.data.get(), Some(t));
+ ptr::write(self.upgrade.get(), SendUsed);
+
+ match self.state.swap(DATA, Ordering::SeqCst) {
+ // Sent the data, no one was waiting
+ EMPTY => Ok(()),
+
+ // Couldn't send the data, the port hung up first. Return the data
+ // back up the stack.
+ DISCONNECTED => {
+ self.state.swap(DISCONNECTED, Ordering::SeqCst);
+ ptr::write(self.upgrade.get(), NothingSent);
+ Err((&mut *self.data.get()).take().unwrap())
+ }
+
+ // Not possible, these are one-use channels
+ DATA => unreachable!(),
+
+ // There is a thread waiting on the other end. We leave the 'DATA'
+ // state inside so it'll pick it up on the other end.
+ ptr => {
+ SignalToken::cast_from_usize(ptr).signal();
+ Ok(())
+ }
+ }
+ }
+ }
+
+ // Just tests whether this channel has been sent on or not, this is only
+ // safe to use from the sender.
+ pub fn sent(&self) -> bool {
+ unsafe {
+ match *self.upgrade.get() {
+ NothingSent => false,
+ _ => true,
+ }
+ }
+ }
+
+ pub fn recv(&self, deadline: Option<Instant>) -> Result<T, Failure<T>> {
+ // Attempt to not block the thread (it's a little expensive). If it looks
+ // like we're not empty, then immediately go through to `try_recv`.
+ if self.state.load(Ordering::SeqCst) == EMPTY {
+ let (wait_token, signal_token) = blocking::tokens();
+ let ptr = unsafe { signal_token.cast_to_usize() };
+
+ // race with senders to enter the blocking state
+ if self.state.compare_and_swap(EMPTY, ptr, Ordering::SeqCst) == EMPTY {
+ if let Some(deadline) = deadline {
+ let timed_out = !wait_token.wait_max_until(deadline);
+ // Try to reset the state
+ if timed_out {
+ self.abort_selection().map_err(Upgraded)?;
+ }
+ } else {
+ wait_token.wait();
+ debug_assert!(self.state.load(Ordering::SeqCst) != EMPTY);
+ }
+ } else {
+ // drop the signal token, since we never blocked
+ drop(unsafe { SignalToken::cast_from_usize(ptr) });
+ }
+ }
+
+ self.try_recv()
+ }
+
+ pub fn try_recv(&self) -> Result<T, Failure<T>> {
+ unsafe {
+ match self.state.load(Ordering::SeqCst) {
+ EMPTY => Err(Empty),
+
+ // We saw some data on the channel, but the channel can be used
+ // again to send us an upgrade. As a result, we need to re-insert
+ // into the channel that there's no data available (otherwise we'll
+ // just see DATA next time). This is done as a cmpxchg because if
+ // the state changes under our feet we'd rather just see that state
+ // change.
+ DATA => {
+ self.state.compare_and_swap(DATA, EMPTY, Ordering::SeqCst);
+ match (&mut *self.data.get()).take() {
+ Some(data) => Ok(data),
+ None => unreachable!(),
+ }
+ }
+
+ // There's no guarantee that we receive before an upgrade happens,
+ // and an upgrade flags the channel as disconnected, so when we see
+ // this we first need to check if there's data available and *then*
+ // we go through and process the upgrade.
+ DISCONNECTED => {
+ match (&mut *self.data.get()).take() {
+ Some(data) => Ok(data),
+ None => {
+ match ptr::replace(self.upgrade.get(), SendUsed) {
+ SendUsed | NothingSent => Err(Disconnected),
+ GoUp(upgrade) => Err(Upgraded(upgrade))
+ }
+ }
+ }
+ }
+
+ // We are the sole receiver; there cannot be a blocking
+ // receiver already.
+ _ => unreachable!()
+ }
+ }
+ }
+
+ // Returns whether the upgrade was completed. If the upgrade wasn't
+ // completed, then the port couldn't get sent to the other half (it will
+ // never receive it).
+ pub fn upgrade(&self, up: Receiver<T>) -> UpgradeResult {
+ unsafe {
+ let prev = match *self.upgrade.get() {
+ NothingSent => NothingSent,
+ SendUsed => SendUsed,
+ _ => panic!("upgrading again"),
+ };
+ ptr::write(self.upgrade.get(), GoUp(up));
+
+ match self.state.swap(DISCONNECTED, Ordering::SeqCst) {
+ // If the channel is empty or has data on it, then we're good to go.
+ // Senders will check the data before the upgrade (in case we
+ // plastered over the DATA state).
+ DATA | EMPTY => UpSuccess,
+
+ // If the other end is already disconnected, then we failed the
+ // upgrade. Be sure to trash the port we were given.
+ DISCONNECTED => { ptr::replace(self.upgrade.get(), prev); UpDisconnected }
+
+ // If someone's waiting, we gotta wake them up
+ ptr => UpWoke(SignalToken::cast_from_usize(ptr))
+ }
+ }
+ }
+
+ pub fn drop_chan(&self) {
+ match self.state.swap(DISCONNECTED, Ordering::SeqCst) {
+ DATA | DISCONNECTED | EMPTY => {}
+
+ // If someone's waiting, we gotta wake them up
+ ptr => unsafe {
+ SignalToken::cast_from_usize(ptr).signal();
+ }
+ }
+ }
+
+ pub fn drop_port(&self) {
+ match self.state.swap(DISCONNECTED, Ordering::SeqCst) {
+ // An empty channel has nothing to do, and a remotely disconnected
+ // channel also has nothing to do b/c we're about to run the drop
+ // glue
+ DISCONNECTED | EMPTY => {}
+
+ // There's data on the channel, so make sure we destroy it promptly.
+ // This is why not using an arc is a little difficult (need the box
+ // to stay valid while we take the data).
+ DATA => unsafe { (&mut *self.data.get()).take().unwrap(); },
+
+ // We're the only ones that can block on this port
+ _ => unreachable!()
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ // select implementation
+ ////////////////////////////////////////////////////////////////////////////
+
+ // If Ok, the value is whether this port has data, if Err, then the upgraded
+ // port needs to be checked instead of this one.
+ pub fn can_recv(&self) -> Result<bool, Receiver<T>> {
+ unsafe {
+ match self.state.load(Ordering::SeqCst) {
+ EMPTY => Ok(false), // Welp, we tried
+ DATA => Ok(true), // we have some un-acquired data
+ DISCONNECTED if (*self.data.get()).is_some() => Ok(true), // we have data
+ DISCONNECTED => {
+ match ptr::replace(self.upgrade.get(), SendUsed) {
+ // The other end sent us an upgrade, so we need to
+ // propagate upwards whether the upgrade can receive
+ // data
+ GoUp(upgrade) => Err(upgrade),
+
+ // If the other end disconnected without sending an
+ // upgrade, then we have data to receive (the channel is
+ // disconnected).
+ up => { ptr::write(self.upgrade.get(), up); Ok(true) }
+ }
+ }
+ _ => unreachable!(), // we're the "one blocker"
+ }
+ }
+ }
+
+ // Attempts to start selection on this port. This can either succeed, fail
+ // because there is data, or fail because there is an upgrade pending.
+ pub fn start_selection(&self, token: SignalToken) -> SelectionResult<T> {
+ unsafe {
+ let ptr = token.cast_to_usize();
+ match self.state.compare_and_swap(EMPTY, ptr, Ordering::SeqCst) {
+ EMPTY => SelSuccess,
+ DATA => {
+ drop(SignalToken::cast_from_usize(ptr));
+ SelCanceled
+ }
+ DISCONNECTED if (*self.data.get()).is_some() => {
+ drop(SignalToken::cast_from_usize(ptr));
+ SelCanceled
+ }
+ DISCONNECTED => {
+ match ptr::replace(self.upgrade.get(), SendUsed) {
+ // The other end sent us an upgrade, so we need to
+ // propagate upwards whether the upgrade can receive
+ // data
+ GoUp(upgrade) => {
+ SelUpgraded(SignalToken::cast_from_usize(ptr), upgrade)
+ }
+
+ // If the other end disconnected without sending an
+ // upgrade, then we have data to receive (the channel is
+ // disconnected).
+ up => {
+ ptr::write(self.upgrade.get(), up);
+ drop(SignalToken::cast_from_usize(ptr));
+ SelCanceled
+ }
+ }
+ }
+ _ => unreachable!(), // we're the "one blocker"
+ }
+ }
+ }
+
+ // Remove a previous selecting thread from this port. This ensures that the
+ // blocked thread will no longer be visible to any other threads.
+ //
+ // The return value indicates whether there's data on this port.
+ pub fn abort_selection(&self) -> Result<bool, Receiver<T>> {
+ let state = match self.state.load(Ordering::SeqCst) {
+ // Each of these states means that no further activity will happen
+ // with regard to abortion selection
+ s @ EMPTY |
+ s @ DATA |
+ s @ DISCONNECTED => s,
+
+ // If we've got a blocked thread, then use an atomic to gain ownership
+ // of it (may fail)
+ ptr => self.state.compare_and_swap(ptr, EMPTY, Ordering::SeqCst)
+ };
+
+ // Now that we've got ownership of our state, figure out what to do
+ // about it.
+ match state {
+ EMPTY => unreachable!(),
+ // our thread used for select was stolen
+ DATA => Ok(true),
+
+ // If the other end has hung up, then we have complete ownership
+ // of the port. First, check if there was data waiting for us. This
+ // is possible if the other end sent something and then hung up.
+ //
+ // We then need to check to see if there was an upgrade requested,
+ // and if so, the upgraded port needs to have its selection aborted.
+ DISCONNECTED => unsafe {
+ if (*self.data.get()).is_some() {
+ Ok(true)
+ } else {
+ match ptr::replace(self.upgrade.get(), SendUsed) {
+ GoUp(port) => Err(port),
+ _ => Ok(true),
+ }
+ }
+ },
+
+ // We woke ourselves up from select.
+ ptr => unsafe {
+ drop(SignalToken::cast_from_usize(ptr));
+ Ok(false)
+ }
+ }
+ }
+}
+
+impl<T> Drop for Packet<T> {
+ fn drop(&mut self) {
+ assert_eq!(self.state.load(Ordering::SeqCst), DISCONNECTED);
+ }
+}
diff --git a/src/libstd/sync/mpsc/select.rs b/src/libstd/sync/mpsc/select.rs
new file mode 100644
index 0000000..d1b5f2d
--- /dev/null
+++ b/src/libstd/sync/mpsc/select.rs
@@ -0,0 +1,352 @@
+//! Selection over an array of receivers
+//!
+//! This module contains the implementation machinery necessary for selecting
+//! over a number of receivers. One large goal of this module is to provide an
+//! efficient interface to selecting over any receiver of any type.
+//!
+//! This is achieved through an architecture of a "receiver set" in which
+//! receivers are added to a set and then the entire set is waited on at once.
+//! The set can be waited on multiple times to prevent re-adding each receiver
+//! to the set.
+//!
+//! Usage of this module is currently encouraged to go through the use of the
+//! `select!` macro. This macro allows naturally binding of variables to the
+//! received values of receivers in a much more natural syntax then usage of the
+//! `Select` structure directly.
+//!
+//! # Examples
+//!
+//! ```rust
+//! #![feature(mpsc_select)]
+//!
+//! use std::sync::mpsc::channel;
+//!
+//! let (tx1, rx1) = channel();
+//! let (tx2, rx2) = channel();
+//!
+//! tx1.send(1).unwrap();
+//! tx2.send(2).unwrap();
+//!
+//! select! {
+//! val = rx1.recv() => {
+//! assert_eq!(val.unwrap(), 1);
+//! },
+//! val = rx2.recv() => {
+//! assert_eq!(val.unwrap(), 2);
+//! }
+//! }
+//! ```
+
+#![allow(dead_code)]
+#![unstable(feature = "mpsc_select",
+ reason = "This implementation, while likely sufficient, is unsafe and \
+ likely to be error prone. At some point in the future this \
+ module will be removed.",
+ issue = "27800")]
+#![rustc_deprecated(since = "1.32.0",
+ reason = "channel selection will be removed in a future release")]
+
+use core::cell::{Cell, UnsafeCell};
+use core::marker;
+use core::ptr;
+use core::usize;
+
+use crate::fmt;
+use crate::sync::mpsc::{Receiver, RecvError};
+use crate::sync::mpsc::blocking::{self, SignalToken};
+
+/// The "receiver set" of the select interface. This structure is used to manage
+/// a set of receivers which are being selected over.
+pub struct Select {
+ inner: UnsafeCell<SelectInner>,
+ next_id: Cell<usize>,
+}
+
+struct SelectInner {
+ head: *mut Handle<'static, ()>,
+ tail: *mut Handle<'static, ()>,
+}
+
+impl !marker::Send for Select {}
+
+/// A handle to a receiver which is currently a member of a `Select` set of
+/// receivers. This handle is used to keep the receiver in the set as well as
+/// interact with the underlying receiver.
+pub struct Handle<'rx, T:Send+'rx> {
+ /// The ID of this handle, used to compare against the return value of
+ /// `Select::wait()`.
+ id: usize,
+ selector: *mut SelectInner,
+ next: *mut Handle<'static, ()>,
+ prev: *mut Handle<'static, ()>,
+ added: bool,
+ packet: &'rx (dyn Packet+'rx),
+
+ // due to our fun transmutes, we be sure to place this at the end. (nothing
+ // previous relies on T)
+ rx: &'rx Receiver<T>,
+}
+
+struct Packets { cur: *mut Handle<'static, ()> }
+
+#[doc(hidden)]
+#[derive(PartialEq, Eq)]
+pub enum StartResult {
+ Installed,
+ Abort,
+}
+
+#[doc(hidden)]
+pub trait Packet {
+ fn can_recv(&self) -> bool;
+ fn start_selection(&self, token: SignalToken) -> StartResult;
+ fn abort_selection(&self) -> bool;
+}
+
+impl Select {
+ /// Creates a new selection structure. This set is initially empty.
+ ///
+ /// Usage of this struct directly can sometimes be burdensome, and usage is much easier through
+ /// the `select!` macro.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(mpsc_select)]
+ ///
+ /// use std::sync::mpsc::Select;
+ ///
+ /// let select = Select::new();
+ /// ```
+ pub fn new() -> Select {
+ Select {
+ inner: UnsafeCell::new(SelectInner {
+ head: ptr::null_mut(),
+ tail: ptr::null_mut(),
+ }),
+ next_id: Cell::new(1),
+ }
+ }
+
+ /// Creates a new handle into this receiver set for a new receiver. Note
+ /// that this does *not* add the receiver to the receiver set, for that you
+ /// must call the `add` method on the handle itself.
+ pub fn handle<'a, T: Send>(&'a self, rx: &'a Receiver<T>) -> Handle<'a, T> {
+ let id = self.next_id.get();
+ self.next_id.set(id + 1);
+ Handle {
+ id,
+ selector: self.inner.get(),
+ next: ptr::null_mut(),
+ prev: ptr::null_mut(),
+ added: false,
+ rx,
+ packet: rx,
+ }
+ }
+
+ /// Waits for an event on this receiver set. The returned value is *not* an
+ /// index, but rather an ID. This ID can be queried against any active
+ /// `Handle` structures (each one has an `id` method). The handle with
+ /// the matching `id` will have some sort of event available on it. The
+ /// event could either be that data is available or the corresponding
+ /// channel has been closed.
+ pub fn wait(&self) -> usize {
+ self.wait2(true)
+ }
+
+ /// Helper method for skipping the preflight checks during testing
+ pub(super) fn wait2(&self, do_preflight_checks: bool) -> usize {
+ // Note that this is currently an inefficient implementation. We in
+ // theory have knowledge about all receivers in the set ahead of time,
+ // so this method shouldn't really have to iterate over all of them yet
+ // again. The idea with this "receiver set" interface is to get the
+ // interface right this time around, and later this implementation can
+ // be optimized.
+ //
+ // This implementation can be summarized by:
+ //
+ // fn select(receivers) {
+ // if any receiver ready { return ready index }
+ // deschedule {
+ // block on all receivers
+ // }
+ // unblock on all receivers
+ // return ready index
+ // }
+ //
+ // Most notably, the iterations over all of the receivers shouldn't be
+ // necessary.
+ unsafe {
+ // Stage 1: preflight checks. Look for any packets ready to receive
+ if do_preflight_checks {
+ for handle in self.iter() {
+ if (*handle).packet.can_recv() {
+ return (*handle).id();
+ }
+ }
+ }
+
+ // Stage 2: begin the blocking process
+ //
+ // Create a number of signal tokens, and install each one
+ // sequentially until one fails. If one fails, then abort the
+ // selection on the already-installed tokens.
+ let (wait_token, signal_token) = blocking::tokens();
+ for (i, handle) in self.iter().enumerate() {
+ match (*handle).packet.start_selection(signal_token.clone()) {
+ StartResult::Installed => {}
+ StartResult::Abort => {
+ // Go back and abort the already-begun selections
+ for handle in self.iter().take(i) {
+ (*handle).packet.abort_selection();
+ }
+ return (*handle).id;
+ }
+ }
+ }
+
+ // Stage 3: no messages available, actually block
+ wait_token.wait();
+
+ // Stage 4: there *must* be message available; find it.
+ //
+ // Abort the selection process on each receiver. If the abort
+ // process returns `true`, then that means that the receiver is
+ // ready to receive some data. Note that this also means that the
+ // receiver may have yet to have fully read the `to_wake` field and
+ // woken us up (although the wakeup is guaranteed to fail).
+ //
+ // This situation happens in the window of where a sender invokes
+ // increment(), sees -1, and then decides to wake up the thread. After
+ // all this is done, the sending thread will set `selecting` to
+ // `false`. Until this is done, we cannot return. If we were to
+ // return, then a sender could wake up a receiver which has gone
+ // back to sleep after this call to `select`.
+ //
+ // Note that it is a "fairly small window" in which an increment()
+ // views that it should wake a thread up until the `selecting` bit
+ // is set to false. For now, the implementation currently just spins
+ // in a yield loop. This is very distasteful, but this
+ // implementation is already nowhere near what it should ideally be.
+ // A rewrite should focus on avoiding a yield loop, and for now this
+ // implementation is tying us over to a more efficient "don't
+ // iterate over everything every time" implementation.
+ let mut ready_id = usize::MAX;
+ for handle in self.iter() {
+ if (*handle).packet.abort_selection() {
+ ready_id = (*handle).id;
+ }
+ }
+
+ // We must have found a ready receiver
+ assert!(ready_id != usize::MAX);
+ return ready_id;
+ }
+ }
+
+ fn iter(&self) -> Packets { Packets { cur: unsafe { &*self.inner.get() }.head } }
+}
+
+impl<'rx, T: Send> Handle<'rx, T> {
+ /// Retrieves the ID of this handle.
+ #[inline]
+ pub fn id(&self) -> usize { self.id }
+
+ /// Blocks to receive a value on the underlying receiver, returning `Some` on
+ /// success or `None` if the channel disconnects. This function has the same
+ /// semantics as `Receiver.recv`
+ pub fn recv(&mut self) -> Result<T, RecvError> { self.rx.recv() }
+
+ /// Adds this handle to the receiver set that the handle was created from. This
+ /// method can be called multiple times, but it has no effect if `add` was
+ /// called previously.
+ ///
+ /// This method is unsafe because it requires that the `Handle` is not moved
+ /// while it is added to the `Select` set.
+ pub unsafe fn add(&mut self) {
+ if self.added { return }
+ let selector = &mut *self.selector;
+ let me = self as *mut Handle<'rx, T> as *mut Handle<'static, ()>;
+
+ if selector.head.is_null() {
+ selector.head = me;
+ selector.tail = me;
+ } else {
+ (*me).prev = selector.tail;
+ assert!((*me).next.is_null());
+ (*selector.tail).next = me;
+ selector.tail = me;
+ }
+ self.added = true;
+ }
+
+ /// Removes this handle from the `Select` set. This method is unsafe because
+ /// it has no guarantee that the `Handle` was not moved since `add` was
+ /// called.
+ pub unsafe fn remove(&mut self) {
+ if !self.added { return }
+
+ let selector = &mut *self.selector;
+ let me = self as *mut Handle<'rx, T> as *mut Handle<'static, ()>;
+
+ if self.prev.is_null() {
+ assert_eq!(selector.head, me);
+ selector.head = self.next;
+ } else {
+ (*self.prev).next = self.next;
+ }
+ if self.next.is_null() {
+ assert_eq!(selector.tail, me);
+ selector.tail = self.prev;
+ } else {
+ (*self.next).prev = self.prev;
+ }
+
+ self.next = ptr::null_mut();
+ self.prev = ptr::null_mut();
+
+ self.added = false;
+ }
+}
+
+impl Drop for Select {
+ fn drop(&mut self) {
+ unsafe {
+ assert!((&*self.inner.get()).head.is_null());
+ assert!((&*self.inner.get()).tail.is_null());
+ }
+ }
+}
+
+impl<T: Send> Drop for Handle<'_, T> {
+ fn drop(&mut self) {
+ unsafe { self.remove() }
+ }
+}
+
+impl Iterator for Packets {
+ type Item = *mut Handle<'static, ()>;
+
+ fn next(&mut self) -> Option<*mut Handle<'static, ()>> {
+ if self.cur.is_null() {
+ None
+ } else {
+ let ret = Some(self.cur);
+ unsafe { self.cur = (*self.cur).next; }
+ ret
+ }
+ }
+}
+
+impl fmt::Debug for Select {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("Select").finish()
+ }
+}
+
+impl<T: Send> fmt::Debug for Handle<'_, T> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("Handle").finish()
+ }
+}
diff --git a/src/libstd/sync/mpsc/select_tests.rs b/src/libstd/sync/mpsc/select_tests.rs
new file mode 100644
index 0000000..18d9346
--- /dev/null
+++ b/src/libstd/sync/mpsc/select_tests.rs
@@ -0,0 +1,413 @@
+#![allow(unused_imports)]
+
+/// This file exists to hack around https://github.com/rust-lang/rust/issues/47238
+
+use crate::thread;
+use crate::sync::mpsc::*;
+
+// Don't use the libstd version so we can pull in the right Select structure
+// (std::comm points at the wrong one)
+macro_rules! select {
+ (
+ $($name:pat = $rx:ident.$meth:ident() => $code:expr),+
+ ) => ({
+ let sel = Select::new();
+ $( let mut $rx = sel.handle(&$rx); )+
+ unsafe {
+ $( $rx.add(); )+
+ }
+ let ret = sel.wait();
+ $( if ret == $rx.id() { let $name = $rx.$meth(); $code } else )+
+ { unreachable!() }
+ })
+}
+
+#[test]
+fn smoke() {
+ let (tx1, rx1) = channel::<i32>();
+ let (tx2, rx2) = channel::<i32>();
+ tx1.send(1).unwrap();
+ select! {
+ foo = rx1.recv() => { assert_eq!(foo.unwrap(), 1); },
+ _bar = rx2.recv() => { panic!() }
+ }
+ tx2.send(2).unwrap();
+ select! {
+ _foo = rx1.recv() => { panic!() },
+ bar = rx2.recv() => { assert_eq!(bar.unwrap(), 2) }
+ }
+ drop(tx1);
+ select! {
+ foo = rx1.recv() => { assert!(foo.is_err()); },
+ _bar = rx2.recv() => { panic!() }
+ }
+ drop(tx2);
+ select! {
+ bar = rx2.recv() => { assert!(bar.is_err()); }
+ }
+}
+
+#[test]
+fn smoke2() {
+ let (_tx1, rx1) = channel::<i32>();
+ let (_tx2, rx2) = channel::<i32>();
+ let (_tx3, rx3) = channel::<i32>();
+ let (_tx4, rx4) = channel::<i32>();
+ let (tx5, rx5) = channel::<i32>();
+ tx5.send(4).unwrap();
+ select! {
+ _foo = rx1.recv() => { panic!("1") },
+ _foo = rx2.recv() => { panic!("2") },
+ _foo = rx3.recv() => { panic!("3") },
+ _foo = rx4.recv() => { panic!("4") },
+ foo = rx5.recv() => { assert_eq!(foo.unwrap(), 4); }
+ }
+}
+
+#[test]
+fn closed() {
+ let (_tx1, rx1) = channel::<i32>();
+ let (tx2, rx2) = channel::<i32>();
+ drop(tx2);
+
+ select! {
+ _a1 = rx1.recv() => { panic!() },
+ a2 = rx2.recv() => { assert!(a2.is_err()); }
+ }
+}
+
+#[test]
+fn unblocks() {
+ let (tx1, rx1) = channel::<i32>();
+ let (_tx2, rx2) = channel::<i32>();
+ let (tx3, rx3) = channel::<i32>();
+
+ let _t = thread::spawn(move|| {
+ for _ in 0..20 { thread::yield_now(); }
+ tx1.send(1).unwrap();
+ rx3.recv().unwrap();
+ for _ in 0..20 { thread::yield_now(); }
+ });
+
+ select! {
+ a = rx1.recv() => { assert_eq!(a.unwrap(), 1); },
+ _b = rx2.recv() => { panic!() }
+ }
+ tx3.send(1).unwrap();
+ select! {
+ a = rx1.recv() => { assert!(a.is_err()) },
+ _b = rx2.recv() => { panic!() }
+ }
+}
+
+#[test]
+fn both_ready() {
+ let (tx1, rx1) = channel::<i32>();
+ let (tx2, rx2) = channel::<i32>();
+ let (tx3, rx3) = channel::<()>();
+
+ let _t = thread::spawn(move|| {
+ for _ in 0..20 { thread::yield_now(); }
+ tx1.send(1).unwrap();
+ tx2.send(2).unwrap();
+ rx3.recv().unwrap();
+ });
+
+ select! {
+ a = rx1.recv() => { assert_eq!(a.unwrap(), 1); },
+ a = rx2.recv() => { assert_eq!(a.unwrap(), 2); }
+ }
+ select! {
+ a = rx1.recv() => { assert_eq!(a.unwrap(), 1); },
+ a = rx2.recv() => { assert_eq!(a.unwrap(), 2); }
+ }
+ assert_eq!(rx1.try_recv(), Err(TryRecvError::Empty));
+ assert_eq!(rx2.try_recv(), Err(TryRecvError::Empty));
+ tx3.send(()).unwrap();
+}
+
+#[test]
+fn stress() {
+ const AMT: i32 = 10000;
+ let (tx1, rx1) = channel::<i32>();
+ let (tx2, rx2) = channel::<i32>();
+ let (tx3, rx3) = channel::<()>();
+
+ let _t = thread::spawn(move|| {
+ for i in 0..AMT {
+ if i % 2 == 0 {
+ tx1.send(i).unwrap();
+ } else {
+ tx2.send(i).unwrap();
+ }
+ rx3.recv().unwrap();
+ }
+ });
+
+ for i in 0..AMT {
+ select! {
+ i1 = rx1.recv() => { assert!(i % 2 == 0 && i == i1.unwrap()); },
+ i2 = rx2.recv() => { assert!(i % 2 == 1 && i == i2.unwrap()); }
+ }
+ tx3.send(()).unwrap();
+ }
+}
+
+#[allow(unused_must_use)]
+#[test]
+fn cloning() {
+ let (tx1, rx1) = channel::<i32>();
+ let (_tx2, rx2) = channel::<i32>();
+ let (tx3, rx3) = channel::<()>();
+
+ let _t = thread::spawn(move|| {
+ rx3.recv().unwrap();
+ tx1.clone();
+ assert_eq!(rx3.try_recv(), Err(TryRecvError::Empty));
+ tx1.send(2).unwrap();
+ rx3.recv().unwrap();
+ });
+
+ tx3.send(()).unwrap();
+ select! {
+ _i1 = rx1.recv() => {},
+ _i2 = rx2.recv() => panic!()
+ }
+ tx3.send(()).unwrap();
+}
+
+#[allow(unused_must_use)]
+#[test]
+fn cloning2() {
+ let (tx1, rx1) = channel::<i32>();
+ let (_tx2, rx2) = channel::<i32>();
+ let (tx3, rx3) = channel::<()>();
+
+ let _t = thread::spawn(move|| {
+ rx3.recv().unwrap();
+ tx1.clone();
+ assert_eq!(rx3.try_recv(), Err(TryRecvError::Empty));
+ tx1.send(2).unwrap();
+ rx3.recv().unwrap();
+ });
+
+ tx3.send(()).unwrap();
+ select! {
+ _i1 = rx1.recv() => {},
+ _i2 = rx2.recv() => panic!()
+ }
+ tx3.send(()).unwrap();
+}
+
+#[test]
+fn cloning3() {
+ let (tx1, rx1) = channel::<()>();
+ let (tx2, rx2) = channel::<()>();
+ let (tx3, rx3) = channel::<()>();
+ let _t = thread::spawn(move|| {
+ let s = Select::new();
+ let mut h1 = s.handle(&rx1);
+ let mut h2 = s.handle(&rx2);
+ unsafe { h2.add(); }
+ unsafe { h1.add(); }
+ assert_eq!(s.wait(), h2.id());
+ tx3.send(()).unwrap();
+ });
+
+ for _ in 0..1000 { thread::yield_now(); }
+ drop(tx1.clone());
+ tx2.send(()).unwrap();
+ rx3.recv().unwrap();
+}
+
+#[test]
+fn preflight1() {
+ let (tx, rx) = channel();
+ tx.send(()).unwrap();
+ select! {
+ _n = rx.recv() => {}
+ }
+}
+
+#[test]
+fn preflight2() {
+ let (tx, rx) = channel();
+ tx.send(()).unwrap();
+ tx.send(()).unwrap();
+ select! {
+ _n = rx.recv() => {}
+ }
+}
+
+#[test]
+fn preflight3() {
+ let (tx, rx) = channel();
+ drop(tx.clone());
+ tx.send(()).unwrap();
+ select! {
+ _n = rx.recv() => {}
+ }
+}
+
+#[test]
+fn preflight4() {
+ let (tx, rx) = channel();
+ tx.send(()).unwrap();
+ let s = Select::new();
+ let mut h = s.handle(&rx);
+ unsafe { h.add(); }
+ assert_eq!(s.wait2(false), h.id());
+}
+
+#[test]
+fn preflight5() {
+ let (tx, rx) = channel();
+ tx.send(()).unwrap();
+ tx.send(()).unwrap();
+ let s = Select::new();
+ let mut h = s.handle(&rx);
+ unsafe { h.add(); }
+ assert_eq!(s.wait2(false), h.id());
+}
+
+#[test]
+fn preflight6() {
+ let (tx, rx) = channel();
+ drop(tx.clone());
+ tx.send(()).unwrap();
+ let s = Select::new();
+ let mut h = s.handle(&rx);
+ unsafe { h.add(); }
+ assert_eq!(s.wait2(false), h.id());
+}
+
+#[test]
+fn preflight7() {
+ let (tx, rx) = channel::<()>();
+ drop(tx);
+ let s = Select::new();
+ let mut h = s.handle(&rx);
+ unsafe { h.add(); }
+ assert_eq!(s.wait2(false), h.id());
+}
+
+#[test]
+fn preflight8() {
+ let (tx, rx) = channel();
+ tx.send(()).unwrap();
+ drop(tx);
+ rx.recv().unwrap();
+ let s = Select::new();
+ let mut h = s.handle(&rx);
+ unsafe { h.add(); }
+ assert_eq!(s.wait2(false), h.id());
+}
+
+#[test]
+fn preflight9() {
+ let (tx, rx) = channel();
+ drop(tx.clone());
+ tx.send(()).unwrap();
+ drop(tx);
+ rx.recv().unwrap();
+ let s = Select::new();
+ let mut h = s.handle(&rx);
+ unsafe { h.add(); }
+ assert_eq!(s.wait2(false), h.id());
+}
+
+#[test]
+fn oneshot_data_waiting() {
+ let (tx1, rx1) = channel();
+ let (tx2, rx2) = channel();
+ let _t = thread::spawn(move|| {
+ select! {
+ _n = rx1.recv() => {}
+ }
+ tx2.send(()).unwrap();
+ });
+
+ for _ in 0..100 { thread::yield_now() }
+ tx1.send(()).unwrap();
+ rx2.recv().unwrap();
+}
+
+#[test]
+fn stream_data_waiting() {
+ let (tx1, rx1) = channel();
+ let (tx2, rx2) = channel();
+ tx1.send(()).unwrap();
+ tx1.send(()).unwrap();
+ rx1.recv().unwrap();
+ rx1.recv().unwrap();
+ let _t = thread::spawn(move|| {
+ select! {
+ _n = rx1.recv() => {}
+ }
+ tx2.send(()).unwrap();
+ });
+
+ for _ in 0..100 { thread::yield_now() }
+ tx1.send(()).unwrap();
+ rx2.recv().unwrap();
+}
+
+#[test]
+fn shared_data_waiting() {
+ let (tx1, rx1) = channel();
+ let (tx2, rx2) = channel();
+ drop(tx1.clone());
+ tx1.send(()).unwrap();
+ rx1.recv().unwrap();
+ let _t = thread::spawn(move|| {
+ select! {
+ _n = rx1.recv() => {}
+ }
+ tx2.send(()).unwrap();
+ });
+
+ for _ in 0..100 { thread::yield_now() }
+ tx1.send(()).unwrap();
+ rx2.recv().unwrap();
+}
+
+#[test]
+fn sync1() {
+ let (tx, rx) = sync_channel::<i32>(1);
+ tx.send(1).unwrap();
+ select! {
+ n = rx.recv() => { assert_eq!(n.unwrap(), 1); }
+ }
+}
+
+#[test]
+fn sync2() {
+ let (tx, rx) = sync_channel::<i32>(0);
+ let _t = thread::spawn(move|| {
+ for _ in 0..100 { thread::yield_now() }
+ tx.send(1).unwrap();
+ });
+ select! {
+ n = rx.recv() => { assert_eq!(n.unwrap(), 1); }
+ }
+}
+
+#[test]
+fn sync3() {
+ let (tx1, rx1) = sync_channel::<i32>(0);
+ let (tx2, rx2): (Sender<i32>, Receiver<i32>) = channel();
+ let _t = thread::spawn(move|| { tx1.send(1).unwrap(); });
+ let _t = thread::spawn(move|| { tx2.send(2).unwrap(); });
+ select! {
+ n = rx1.recv() => {
+ let n = n.unwrap();
+ assert_eq!(n, 1);
+ assert_eq!(rx2.recv().unwrap(), 2);
+ },
+ n = rx2.recv() => {
+ let n = n.unwrap();
+ assert_eq!(n, 2);
+ assert_eq!(rx1.recv().unwrap(), 1);
+ }
+ }
+}
diff --git a/src/libstd/sync/mpsc/shared.rs b/src/libstd/sync/mpsc/shared.rs
new file mode 100644
index 0000000..cc70a62
--- /dev/null
+++ b/src/libstd/sync/mpsc/shared.rs
@@ -0,0 +1,496 @@
+/// Shared channels.
+///
+/// This is the flavor of channels which are not necessarily optimized for any
+/// particular use case, but are the most general in how they are used. Shared
+/// channels are cloneable allowing for multiple senders.
+///
+/// High level implementation details can be found in the comment of the parent
+/// module. You'll also note that the implementation of the shared and stream
+/// channels are quite similar, and this is no coincidence!
+
+pub use self::Failure::*;
+
+use core::cmp;
+use core::intrinsics::abort;
+use core::isize;
+
+use crate::cell::UnsafeCell;
+use crate::ptr;
+use crate::sync::atomic::{AtomicUsize, AtomicIsize, AtomicBool, Ordering};
+use crate::sync::mpsc::blocking::{self, SignalToken};
+use crate::sync::mpsc::mpsc_queue as mpsc;
+use crate::sync::mpsc::select::StartResult::*;
+use crate::sync::mpsc::select::StartResult;
+use crate::sync::{Mutex, MutexGuard};
+use crate::thread;
+use crate::time::Instant;
+
+const DISCONNECTED: isize = isize::MIN;
+const FUDGE: isize = 1024;
+const MAX_REFCOUNT: usize = (isize::MAX) as usize;
+#[cfg(test)]
+const MAX_STEALS: isize = 5;
+#[cfg(not(test))]
+const MAX_STEALS: isize = 1 << 20;
+
+pub struct Packet<T> {
+ queue: mpsc::Queue<T>,
+ cnt: AtomicIsize, // How many items are on this channel
+ steals: UnsafeCell<isize>, // How many times has a port received without blocking?
+ to_wake: AtomicUsize, // SignalToken for wake up
+
+ // The number of channels which are currently using this packet.
+ channels: AtomicUsize,
+
+ // See the discussion in Port::drop and the channel send methods for what
+ // these are used for
+ port_dropped: AtomicBool,
+ sender_drain: AtomicIsize,
+
+ // this lock protects various portions of this implementation during
+ // select()
+ select_lock: Mutex<()>,
+}
+
+pub enum Failure {
+ Empty,
+ Disconnected,
+}
+
+impl<T> Packet<T> {
+ // Creation of a packet *must* be followed by a call to postinit_lock
+ // and later by inherit_blocker
+ pub fn new() -> Packet<T> {
+ Packet {
+ queue: mpsc::Queue::new(),
+ cnt: AtomicIsize::new(0),
+ steals: UnsafeCell::new(0),
+ to_wake: AtomicUsize::new(0),
+ channels: AtomicUsize::new(2),
+ port_dropped: AtomicBool::new(false),
+ sender_drain: AtomicIsize::new(0),
+ select_lock: Mutex::new(()),
+ }
+ }
+
+ // This function should be used after newly created Packet
+ // was wrapped with an Arc
+ // In other case mutex data will be duplicated while cloning
+ // and that could cause problems on platforms where it is
+ // represented by opaque data structure
+ pub fn postinit_lock(&self) -> MutexGuard<'_, ()> {
+ self.select_lock.lock().unwrap()
+ }
+
+ // This function is used at the creation of a shared packet to inherit a
+ // previously blocked thread. This is done to prevent spurious wakeups of
+ // threads in select().
+ //
+ // This can only be called at channel-creation time
+ pub fn inherit_blocker(&self,
+ token: Option<SignalToken>,
+ guard: MutexGuard<'_, ()>) {
+ token.map(|token| {
+ assert_eq!(self.cnt.load(Ordering::SeqCst), 0);
+ assert_eq!(self.to_wake.load(Ordering::SeqCst), 0);
+ self.to_wake.store(unsafe { token.cast_to_usize() }, Ordering::SeqCst);
+ self.cnt.store(-1, Ordering::SeqCst);
+
+ // This store is a little sketchy. What's happening here is that
+ // we're transferring a blocker from a oneshot or stream channel to
+ // this shared channel. In doing so, we never spuriously wake them
+ // up and rather only wake them up at the appropriate time. This
+ // implementation of shared channels assumes that any blocking
+ // recv() will undo the increment of steals performed in try_recv()
+ // once the recv is complete. This thread that we're inheriting,
+ // however, is not in the middle of recv. Hence, the first time we
+ // wake them up, they're going to wake up from their old port, move
+ // on to the upgraded port, and then call the block recv() function.
+ //
+ // When calling this function, they'll find there's data immediately
+ // available, counting it as a steal. This in fact wasn't a steal
+ // because we appropriately blocked them waiting for data.
+ //
+ // To offset this bad increment, we initially set the steal count to
+ // -1. You'll find some special code in abort_selection() as well to
+ // ensure that this -1 steal count doesn't escape too far.
+ unsafe { *self.steals.get() = -1; }
+ });
+
+ // When the shared packet is constructed, we grabbed this lock. The
+ // purpose of this lock is to ensure that abort_selection() doesn't
+ // interfere with this method. After we unlock this lock, we're
+ // signifying that we're done modifying self.cnt and self.to_wake and
+ // the port is ready for the world to continue using it.
+ drop(guard);
+ }
+
+ pub fn send(&self, t: T) -> Result<(), T> {
+ // See Port::drop for what's going on
+ if self.port_dropped.load(Ordering::SeqCst) { return Err(t) }
+
+ // Note that the multiple sender case is a little trickier
+ // semantically than the single sender case. The logic for
+ // incrementing is "add and if disconnected store disconnected".
+ // This could end up leading some senders to believe that there
+ // wasn't a disconnect if in fact there was a disconnect. This means
+ // that while one thread is attempting to re-store the disconnected
+ // states, other threads could walk through merrily incrementing
+ // this very-negative disconnected count. To prevent senders from
+ // spuriously attempting to send when the channels is actually
+ // disconnected, the count has a ranged check here.
+ //
+ // This is also done for another reason. Remember that the return
+ // value of this function is:
+ //
+ // `true` == the data *may* be received, this essentially has no
+ // meaning
+ // `false` == the data will *never* be received, this has a lot of
+ // meaning
+ //
+ // In the SPSC case, we have a check of 'queue.is_empty()' to see
+ // whether the data was actually received, but this same condition
+ // means nothing in a multi-producer context. As a result, this
+ // preflight check serves as the definitive "this will never be
+ // received". Once we get beyond this check, we have permanently
+ // entered the realm of "this may be received"
+ if self.cnt.load(Ordering::SeqCst) < DISCONNECTED + FUDGE {
+ return Err(t)
+ }
+
+ self.queue.push(t);
+ match self.cnt.fetch_add(1, Ordering::SeqCst) {
+ -1 => {
+ self.take_to_wake().signal();
+ }
+
+ // In this case, we have possibly failed to send our data, and
+ // we need to consider re-popping the data in order to fully
+ // destroy it. We must arbitrate among the multiple senders,
+ // however, because the queues that we're using are
+ // single-consumer queues. In order to do this, all exiting
+ // pushers will use an atomic count in order to count those
+ // flowing through. Pushers who see 0 are required to drain as
+ // much as possible, and then can only exit when they are the
+ // only pusher (otherwise they must try again).
+ n if n < DISCONNECTED + FUDGE => {
+ // see the comment in 'try' for a shared channel for why this
+ // window of "not disconnected" is ok.
+ self.cnt.store(DISCONNECTED, Ordering::SeqCst);
+
+ if self.sender_drain.fetch_add(1, Ordering::SeqCst) == 0 {
+ loop {
+ // drain the queue, for info on the thread yield see the
+ // discussion in try_recv
+ loop {
+ match self.queue.pop() {
+ mpsc::Data(..) => {}
+ mpsc::Empty => break,
+ mpsc::Inconsistent => thread::yield_now(),
+ }
+ }
+ // maybe we're done, if we're not the last ones
+ // here, then we need to go try again.
+ if self.sender_drain.fetch_sub(1, Ordering::SeqCst) == 1 {
+ break
+ }
+ }
+
+ // At this point, there may still be data on the queue,
+ // but only if the count hasn't been incremented and
+ // some other sender hasn't finished pushing data just
+ // yet. That sender in question will drain its own data.
+ }
+ }
+
+ // Can't make any assumptions about this case like in the SPSC case.
+ _ => {}
+ }
+
+ Ok(())
+ }
+
+ pub fn recv(&self, deadline: Option<Instant>) -> Result<T, Failure> {
+ // This code is essentially the exact same as that found in the stream
+ // case (see stream.rs)
+ match self.try_recv() {
+ Err(Empty) => {}
+ data => return data,
+ }
+
+ let (wait_token, signal_token) = blocking::tokens();
+ if self.decrement(signal_token) == Installed {
+ if let Some(deadline) = deadline {
+ let timed_out = !wait_token.wait_max_until(deadline);
+ if timed_out {
+ self.abort_selection(false);
+ }
+ } else {
+ wait_token.wait();
+ }
+ }
+
+ match self.try_recv() {
+ data @ Ok(..) => unsafe { *self.steals.get() -= 1; data },
+ data => data,
+ }
+ }
+
+ // Essentially the exact same thing as the stream decrement function.
+ // Returns true if blocking should proceed.
+ fn decrement(&self, token: SignalToken) -> StartResult {
+ unsafe {
+ assert_eq!(self.to_wake.load(Ordering::SeqCst), 0);
+ let ptr = token.cast_to_usize();
+ self.to_wake.store(ptr, Ordering::SeqCst);
+
+ let steals = ptr::replace(self.steals.get(), 0);
+
+ match self.cnt.fetch_sub(1 + steals, Ordering::SeqCst) {
+ DISCONNECTED => { self.cnt.store(DISCONNECTED, Ordering::SeqCst); }
+ // If we factor in our steals and notice that the channel has no
+ // data, we successfully sleep
+ n => {
+ assert!(n >= 0);
+ if n - steals <= 0 { return Installed }
+ }
+ }
+
+ self.to_wake.store(0, Ordering::SeqCst);
+ drop(SignalToken::cast_from_usize(ptr));
+ Abort
+ }
+ }
+
+ pub fn try_recv(&self) -> Result<T, Failure> {
+ let ret = match self.queue.pop() {
+ mpsc::Data(t) => Some(t),
+ mpsc::Empty => None,
+
+ // This is a bit of an interesting case. The channel is reported as
+ // having data available, but our pop() has failed due to the queue
+ // being in an inconsistent state. This means that there is some
+ // pusher somewhere which has yet to complete, but we are guaranteed
+ // that a pop will eventually succeed. In this case, we spin in a
+ // yield loop because the remote sender should finish their enqueue
+ // operation "very quickly".
+ //
+ // Avoiding this yield loop would require a different queue
+ // abstraction which provides the guarantee that after M pushes have
+ // succeeded, at least M pops will succeed. The current queues
+ // guarantee that if there are N active pushes, you can pop N times
+ // once all N have finished.
+ mpsc::Inconsistent => {
+ let data;
+ loop {
+ thread::yield_now();
+ match self.queue.pop() {
+ mpsc::Data(t) => { data = t; break }
+ mpsc::Empty => panic!("inconsistent => empty"),
+ mpsc::Inconsistent => {}
+ }
+ }
+ Some(data)
+ }
+ };
+ match ret {
+ // See the discussion in the stream implementation for why we
+ // might decrement steals.
+ Some(data) => unsafe {
+ if *self.steals.get() > MAX_STEALS {
+ match self.cnt.swap(0, Ordering::SeqCst) {
+ DISCONNECTED => {
+ self.cnt.store(DISCONNECTED, Ordering::SeqCst);
+ }
+ n => {
+ let m = cmp::min(n, *self.steals.get());
+ *self.steals.get() -= m;
+ self.bump(n - m);
+ }
+ }
+ assert!(*self.steals.get() >= 0);
+ }
+ *self.steals.get() += 1;
+ Ok(data)
+ },
+
+ // See the discussion in the stream implementation for why we try
+ // again.
+ None => {
+ match self.cnt.load(Ordering::SeqCst) {
+ n if n != DISCONNECTED => Err(Empty),
+ _ => {
+ match self.queue.pop() {
+ mpsc::Data(t) => Ok(t),
+ mpsc::Empty => Err(Disconnected),
+ // with no senders, an inconsistency is impossible.
+ mpsc::Inconsistent => unreachable!(),
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // Prepares this shared packet for a channel clone, essentially just bumping
+ // a refcount.
+ pub fn clone_chan(&self) {
+ let old_count = self.channels.fetch_add(1, Ordering::SeqCst);
+
+ // See comments on Arc::clone() on why we do this (for `mem::forget`).
+ if old_count > MAX_REFCOUNT {
+ unsafe {
+ abort();
+ }
+ }
+ }
+
+ // Decrement the reference count on a channel. This is called whenever a
+ // Chan is dropped and may end up waking up a receiver. It's the receiver's
+ // responsibility on the other end to figure out that we've disconnected.
+ pub fn drop_chan(&self) {
+ match self.channels.fetch_sub(1, Ordering::SeqCst) {
+ 1 => {}
+ n if n > 1 => return,
+ n => panic!("bad number of channels left {}", n),
+ }
+
+ match self.cnt.swap(DISCONNECTED, Ordering::SeqCst) {
+ -1 => { self.take_to_wake().signal(); }
+ DISCONNECTED => {}
+ n => { assert!(n >= 0); }
+ }
+ }
+
+ // See the long discussion inside of stream.rs for why the queue is drained,
+ // and why it is done in this fashion.
+ pub fn drop_port(&self) {
+ self.port_dropped.store(true, Ordering::SeqCst);
+ let mut steals = unsafe { *self.steals.get() };
+ while {
+ let cnt = self.cnt.compare_and_swap(steals, DISCONNECTED, Ordering::SeqCst);
+ cnt != DISCONNECTED && cnt != steals
+ } {
+ // See the discussion in 'try_recv' for why we yield
+ // control of this thread.
+ loop {
+ match self.queue.pop() {
+ mpsc::Data(..) => { steals += 1; }
+ mpsc::Empty | mpsc::Inconsistent => break,
+ }
+ }
+ }
+ }
+
+ // Consumes ownership of the 'to_wake' field.
+ fn take_to_wake(&self) -> SignalToken {
+ let ptr = self.to_wake.load(Ordering::SeqCst);
+ self.to_wake.store(0, Ordering::SeqCst);
+ assert!(ptr != 0);
+ unsafe { SignalToken::cast_from_usize(ptr) }
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ // select implementation
+ ////////////////////////////////////////////////////////////////////////////
+
+ // Helper function for select, tests whether this port can receive without
+ // blocking (obviously not an atomic decision).
+ //
+ // This is different than the stream version because there's no need to peek
+ // at the queue, we can just look at the local count.
+ pub fn can_recv(&self) -> bool {
+ let cnt = self.cnt.load(Ordering::SeqCst);
+ cnt == DISCONNECTED || cnt - unsafe { *self.steals.get() } > 0
+ }
+
+ // increment the count on the channel (used for selection)
+ fn bump(&self, amt: isize) -> isize {
+ match self.cnt.fetch_add(amt, Ordering::SeqCst) {
+ DISCONNECTED => {
+ self.cnt.store(DISCONNECTED, Ordering::SeqCst);
+ DISCONNECTED
+ }
+ n => n
+ }
+ }
+
+ // Inserts the signal token for selection on this port, returning true if
+ // blocking should proceed.
+ //
+ // The code here is the same as in stream.rs, except that it doesn't need to
+ // peek at the channel to see if an upgrade is pending.
+ pub fn start_selection(&self, token: SignalToken) -> StartResult {
+ match self.decrement(token) {
+ Installed => Installed,
+ Abort => {
+ let prev = self.bump(1);
+ assert!(prev == DISCONNECTED || prev >= 0);
+ Abort
+ }
+ }
+ }
+
+ // Cancels a previous thread waiting on this port, returning whether there's
+ // data on the port.
+ //
+ // This is similar to the stream implementation (hence fewer comments), but
+ // uses a different value for the "steals" variable.
+ pub fn abort_selection(&self, _was_upgrade: bool) -> bool {
+ // Before we do anything else, we bounce on this lock. The reason for
+ // doing this is to ensure that any upgrade-in-progress is gone and
+ // done with. Without this bounce, we can race with inherit_blocker
+ // about looking at and dealing with to_wake. Once we have acquired the
+ // lock, we are guaranteed that inherit_blocker is done.
+ {
+ let _guard = self.select_lock.lock().unwrap();
+ }
+
+ // Like the stream implementation, we want to make sure that the count
+ // on the channel goes non-negative. We don't know how negative the
+ // stream currently is, so instead of using a steal value of 1, we load
+ // the channel count and figure out what we should do to make it
+ // positive.
+ let steals = {
+ let cnt = self.cnt.load(Ordering::SeqCst);
+ if cnt < 0 && cnt != DISCONNECTED {-cnt} else {0}
+ };
+ let prev = self.bump(steals + 1);
+
+ if prev == DISCONNECTED {
+ assert_eq!(self.to_wake.load(Ordering::SeqCst), 0);
+ true
+ } else {
+ let cur = prev + steals + 1;
+ assert!(cur >= 0);
+ if prev < 0 {
+ drop(self.take_to_wake());
+ } else {
+ while self.to_wake.load(Ordering::SeqCst) != 0 {
+ thread::yield_now();
+ }
+ }
+ unsafe {
+ // if the number of steals is -1, it was the pre-emptive -1 steal
+ // count from when we inherited a blocker. This is fine because
+ // we're just going to overwrite it with a real value.
+ let old = self.steals.get();
+ assert!(*old == 0 || *old == -1);
+ *old = steals;
+ prev >= 0
+ }
+ }
+ }
+}
+
+impl<T> Drop for Packet<T> {
+ fn drop(&mut self) {
+ // Note that this load is not only an assert for correctness about
+ // disconnection, but also a proper fence before the read of
+ // `to_wake`, so this assert cannot be removed with also removing
+ // the `to_wake` assert.
+ assert_eq!(self.cnt.load(Ordering::SeqCst), DISCONNECTED);
+ assert_eq!(self.to_wake.load(Ordering::SeqCst), 0);
+ assert_eq!(self.channels.load(Ordering::SeqCst), 0);
+ }
+}
diff --git a/src/libstd/sync/mpsc/spsc_queue.rs b/src/libstd/sync/mpsc/spsc_queue.rs
new file mode 100644
index 0000000..0edb1c2
--- /dev/null
+++ b/src/libstd/sync/mpsc/spsc_queue.rs
@@ -0,0 +1,337 @@
+//! A single-producer single-consumer concurrent queue
+//!
+//! This module contains the implementation of an SPSC queue which can be used
+//! concurrently between two threads. This data structure is safe to use and
+//! enforces the semantics that there is one pusher and one popper.
+
+// http://www.1024cores.net/home/lock-free-algorithms/queues/unbounded-spsc-queue
+
+use core::ptr;
+use core::cell::UnsafeCell;
+
+use crate::boxed::Box;
+use crate::sync::atomic::{AtomicPtr, AtomicUsize, Ordering};
+
+use super::cache_aligned::CacheAligned;
+
+// Node within the linked list queue of messages to send
+struct Node<T> {
+ // FIXME: this could be an uninitialized T if we're careful enough, and
+ // that would reduce memory usage (and be a bit faster).
+ // is it worth it?
+ value: Option<T>, // nullable for re-use of nodes
+ cached: bool, // This node goes into the node cache
+ next: AtomicPtr<Node<T>>, // next node in the queue
+}
+
+/// The single-producer single-consumer queue. This structure is not cloneable,
+/// but it can be safely shared in an Arc if it is guaranteed that there
+/// is only one popper and one pusher touching the queue at any one point in
+/// time.
+pub struct Queue<T, ProducerAddition=(), ConsumerAddition=()> {
+ // consumer fields
+ consumer: CacheAligned<Consumer<T, ConsumerAddition>>,
+
+ // producer fields
+ producer: CacheAligned<Producer<T, ProducerAddition>>,
+}
+
+struct Consumer<T, Addition> {
+ tail: UnsafeCell<*mut Node<T>>, // where to pop from
+ tail_prev: AtomicPtr<Node<T>>, // where to pop from
+ cache_bound: usize, // maximum cache size
+ cached_nodes: AtomicUsize, // number of nodes marked as cachable
+ addition: Addition,
+}
+
+struct Producer<T, Addition> {
+ head: UnsafeCell<*mut Node<T>>, // where to push to
+ first: UnsafeCell<*mut Node<T>>, // where to get new nodes from
+ tail_copy: UnsafeCell<*mut Node<T>>, // between first/tail
+ addition: Addition,
+}
+
+unsafe impl<T: Send, P: Send + Sync, C: Send + Sync> Send for Queue<T, P, C> { }
+
+unsafe impl<T: Send, P: Send + Sync, C: Send + Sync> Sync for Queue<T, P, C> { }
+
+impl<T> Node<T> {
+ fn new() -> *mut Node<T> {
+ Box::into_raw(box Node {
+ value: None,
+ cached: false,
+ next: AtomicPtr::new(ptr::null_mut::<Node<T>>()),
+ })
+ }
+}
+
+impl<T, ProducerAddition, ConsumerAddition> Queue<T, ProducerAddition, ConsumerAddition> {
+
+ /// Creates a new queue. With given additional elements in the producer and
+ /// consumer portions of the queue.
+ ///
+ /// Due to the performance implications of cache-contention,
+ /// we wish to keep fields used mainly by the producer on a separate cache
+ /// line than those used by the consumer.
+ /// Since cache lines are usually 64 bytes, it is unreasonably expensive to
+ /// allocate one for small fields, so we allow users to insert additional
+ /// fields into the cache lines already allocated by this for the producer
+ /// and consumer.
+ ///
+ /// This is unsafe as the type system doesn't enforce a single
+ /// consumer-producer relationship. It also allows the consumer to `pop`
+ /// items while there is a `peek` active due to all methods having a
+ /// non-mutable receiver.
+ ///
+ /// # Arguments
+ ///
+ /// * `bound` - This queue implementation is implemented with a linked
+ /// list, and this means that a push is always a malloc. In
+ /// order to amortize this cost, an internal cache of nodes is
+ /// maintained to prevent a malloc from always being
+ /// necessary. This bound is the limit on the size of the
+ /// cache (if desired). If the value is 0, then the cache has
+ /// no bound. Otherwise, the cache will never grow larger than
+ /// `bound` (although the queue itself could be much larger.
+ pub unsafe fn with_additions(
+ bound: usize,
+ producer_addition: ProducerAddition,
+ consumer_addition: ConsumerAddition,
+ ) -> Self {
+ let n1 = Node::new();
+ let n2 = Node::new();
+ (*n1).next.store(n2, Ordering::Relaxed);
+ Queue {
+ consumer: CacheAligned::new(Consumer {
+ tail: UnsafeCell::new(n2),
+ tail_prev: AtomicPtr::new(n1),
+ cache_bound: bound,
+ cached_nodes: AtomicUsize::new(0),
+ addition: consumer_addition
+ }),
+ producer: CacheAligned::new(Producer {
+ head: UnsafeCell::new(n2),
+ first: UnsafeCell::new(n1),
+ tail_copy: UnsafeCell::new(n1),
+ addition: producer_addition
+ }),
+ }
+ }
+
+ /// Pushes a new value onto this queue. Note that to use this function
+ /// safely, it must be externally guaranteed that there is only one pusher.
+ pub fn push(&self, t: T) {
+ unsafe {
+ // Acquire a node (which either uses a cached one or allocates a new
+ // one), and then append this to the 'head' node.
+ let n = self.alloc();
+ assert!((*n).value.is_none());
+ (*n).value = Some(t);
+ (*n).next.store(ptr::null_mut(), Ordering::Relaxed);
+ (**self.producer.head.get()).next.store(n, Ordering::Release);
+ *(&self.producer.head).get() = n;
+ }
+ }
+
+ unsafe fn alloc(&self) -> *mut Node<T> {
+ // First try to see if we can consume the 'first' node for our uses.
+ if *self.producer.first.get() != *self.producer.tail_copy.get() {
+ let ret = *self.producer.first.get();
+ *self.producer.0.first.get() = (*ret).next.load(Ordering::Relaxed);
+ return ret;
+ }
+ // If the above fails, then update our copy of the tail and try
+ // again.
+ *self.producer.0.tail_copy.get() =
+ self.consumer.tail_prev.load(Ordering::Acquire);
+ if *self.producer.first.get() != *self.producer.tail_copy.get() {
+ let ret = *self.producer.first.get();
+ *self.producer.0.first.get() = (*ret).next.load(Ordering::Relaxed);
+ return ret;
+ }
+ // If all of that fails, then we have to allocate a new node
+ // (there's nothing in the node cache).
+ Node::new()
+ }
+
+ /// Attempts to pop a value from this queue. Remember that to use this type
+ /// safely you must ensure that there is only one popper at a time.
+ pub fn pop(&self) -> Option<T> {
+ unsafe {
+ // The `tail` node is not actually a used node, but rather a
+ // sentinel from where we should start popping from. Hence, look at
+ // tail's next field and see if we can use it. If we do a pop, then
+ // the current tail node is a candidate for going into the cache.
+ let tail = *self.consumer.tail.get();
+ let next = (*tail).next.load(Ordering::Acquire);
+ if next.is_null() { return None }
+ assert!((*next).value.is_some());
+ let ret = (*next).value.take();
+
+ *self.consumer.0.tail.get() = next;
+ if self.consumer.cache_bound == 0 {
+ self.consumer.tail_prev.store(tail, Ordering::Release);
+ } else {
+ let cached_nodes = self.consumer.cached_nodes.load(Ordering::Relaxed);
+ if cached_nodes < self.consumer.cache_bound && !(*tail).cached {
+ self.consumer.cached_nodes.store(cached_nodes, Ordering::Relaxed);
+ (*tail).cached = true;
+ }
+
+ if (*tail).cached {
+ self.consumer.tail_prev.store(tail, Ordering::Release);
+ } else {
+ (*self.consumer.tail_prev.load(Ordering::Relaxed))
+ .next.store(next, Ordering::Relaxed);
+ // We have successfully erased all references to 'tail', so
+ // now we can safely drop it.
+ let _: Box<Node<T>> = Box::from_raw(tail);
+ }
+ }
+ ret
+ }
+ }
+
+ /// Attempts to peek at the head of the queue, returning `None` if the queue
+ /// has no data currently
+ ///
+ /// # Warning
+ /// The reference returned is invalid if it is not used before the consumer
+ /// pops the value off the queue. If the producer then pushes another value
+ /// onto the queue, it will overwrite the value pointed to by the reference.
+ pub fn peek(&self) -> Option<&mut T> {
+ // This is essentially the same as above with all the popping bits
+ // stripped out.
+ unsafe {
+ let tail = *self.consumer.tail.get();
+ let next = (*tail).next.load(Ordering::Acquire);
+ if next.is_null() { None } else { (*next).value.as_mut() }
+ }
+ }
+
+ pub fn producer_addition(&self) -> &ProducerAddition {
+ &self.producer.addition
+ }
+
+ pub fn consumer_addition(&self) -> &ConsumerAddition {
+ &self.consumer.addition
+ }
+}
+
+impl<T, ProducerAddition, ConsumerAddition> Drop for Queue<T, ProducerAddition, ConsumerAddition> {
+ fn drop(&mut self) {
+ unsafe {
+ let mut cur = *self.producer.first.get();
+ while !cur.is_null() {
+ let next = (*cur).next.load(Ordering::Relaxed);
+ let _n: Box<Node<T>> = Box::from_raw(cur);
+ cur = next;
+ }
+ }
+ }
+}
+
+#[cfg(all(test, not(target_os = "emscripten")))]
+mod tests {
+ use super::Queue;
+ use crate::sync::Arc;
+ use crate::thread;
+ use crate::sync::mpsc::channel;
+
+ #[test]
+ fn smoke() {
+ unsafe {
+ let queue = Queue::with_additions(0, (), ());
+ queue.push(1);
+ queue.push(2);
+ assert_eq!(queue.pop(), Some(1));
+ assert_eq!(queue.pop(), Some(2));
+ assert_eq!(queue.pop(), None);
+ queue.push(3);
+ queue.push(4);
+ assert_eq!(queue.pop(), Some(3));
+ assert_eq!(queue.pop(), Some(4));
+ assert_eq!(queue.pop(), None);
+ }
+ }
+
+ #[test]
+ fn peek() {
+ unsafe {
+ let queue = Queue::with_additions(0, (), ());
+ queue.push(vec![1]);
+
+ // Ensure the borrowchecker works
+ match queue.peek() {
+ Some(vec) => {
+ assert_eq!(&*vec, &[1]);
+ },
+ None => unreachable!()
+ }
+
+ match queue.pop() {
+ Some(vec) => {
+ assert_eq!(&*vec, &[1]);
+ },
+ None => unreachable!()
+ }
+ }
+ }
+
+ #[test]
+ fn drop_full() {
+ unsafe {
+ let q: Queue<Box<_>> = Queue::with_additions(0, (), ());
+ q.push(box 1);
+ q.push(box 2);
+ }
+ }
+
+ #[test]
+ fn smoke_bound() {
+ unsafe {
+ let q = Queue::with_additions(0, (), ());
+ q.push(1);
+ q.push(2);
+ assert_eq!(q.pop(), Some(1));
+ assert_eq!(q.pop(), Some(2));
+ assert_eq!(q.pop(), None);
+ q.push(3);
+ q.push(4);
+ assert_eq!(q.pop(), Some(3));
+ assert_eq!(q.pop(), Some(4));
+ assert_eq!(q.pop(), None);
+ }
+ }
+
+ #[test]
+ fn stress() {
+ unsafe {
+ stress_bound(0);
+ stress_bound(1);
+ }
+
+ unsafe fn stress_bound(bound: usize) {
+ let q = Arc::new(Queue::with_additions(bound, (), ()));
+
+ let (tx, rx) = channel();
+ let q2 = q.clone();
+ let _t = thread::spawn(move|| {
+ for _ in 0..100000 {
+ loop {
+ match q2.pop() {
+ Some(1) => break,
+ Some(_) => panic!(),
+ None => {}
+ }
+ }
+ }
+ tx.send(()).unwrap();
+ });
+ for _ in 0..100000 {
+ q.push(1);
+ }
+ rx.recv().unwrap();
+ }
+ }
+}
diff --git a/src/libstd/sync/mpsc/stream.rs b/src/libstd/sync/mpsc/stream.rs
new file mode 100644
index 0000000..7ae6f68
--- /dev/null
+++ b/src/libstd/sync/mpsc/stream.rs
@@ -0,0 +1,495 @@
+/// Stream channels
+///
+/// This is the flavor of channels which are optimized for one sender and one
+/// receiver. The sender will be upgraded to a shared channel if the channel is
+/// cloned.
+///
+/// High level implementation details can be found in the comment of the parent
+/// module.
+
+pub use self::Failure::*;
+pub use self::UpgradeResult::*;
+pub use self::SelectionResult::*;
+use self::Message::*;
+
+use core::cmp;
+use core::isize;
+
+use crate::cell::UnsafeCell;
+use crate::ptr;
+use crate::thread;
+use crate::time::Instant;
+
+use crate::sync::atomic::{AtomicIsize, AtomicUsize, Ordering, AtomicBool};
+use crate::sync::mpsc::Receiver;
+use crate::sync::mpsc::blocking::{self, SignalToken};
+use crate::sync::mpsc::spsc_queue as spsc;
+
+const DISCONNECTED: isize = isize::MIN;
+#[cfg(test)]
+const MAX_STEALS: isize = 5;
+#[cfg(not(test))]
+const MAX_STEALS: isize = 1 << 20;
+
+pub struct Packet<T> {
+ // internal queue for all messages
+ queue: spsc::Queue<Message<T>, ProducerAddition, ConsumerAddition>,
+}
+
+struct ProducerAddition {
+ cnt: AtomicIsize, // How many items are on this channel
+ to_wake: AtomicUsize, // SignalToken for the blocked thread to wake up
+
+ port_dropped: AtomicBool, // flag if the channel has been destroyed.
+}
+
+struct ConsumerAddition {
+ steals: UnsafeCell<isize>, // How many times has a port received without blocking?
+}
+
+
+pub enum Failure<T> {
+ Empty,
+ Disconnected,
+ Upgraded(Receiver<T>),
+}
+
+pub enum UpgradeResult {
+ UpSuccess,
+ UpDisconnected,
+ UpWoke(SignalToken),
+}
+
+pub enum SelectionResult<T> {
+ SelSuccess,
+ SelCanceled,
+ SelUpgraded(SignalToken, Receiver<T>),
+}
+
+// Any message could contain an "upgrade request" to a new shared port, so the
+// internal queue it's a queue of T, but rather Message<T>
+enum Message<T> {
+ Data(T),
+ GoUp(Receiver<T>),
+}
+
+impl<T> Packet<T> {
+ pub fn new() -> Packet<T> {
+ Packet {
+ queue: unsafe { spsc::Queue::with_additions(
+ 128,
+ ProducerAddition {
+ cnt: AtomicIsize::new(0),
+ to_wake: AtomicUsize::new(0),
+
+ port_dropped: AtomicBool::new(false),
+ },
+ ConsumerAddition {
+ steals: UnsafeCell::new(0),
+ }
+ )},
+ }
+ }
+
+ pub fn send(&self, t: T) -> Result<(), T> {
+ // If the other port has deterministically gone away, then definitely
+ // must return the data back up the stack. Otherwise, the data is
+ // considered as being sent.
+ if self.queue.producer_addition().port_dropped.load(Ordering::SeqCst) { return Err(t) }
+
+ match self.do_send(Data(t)) {
+ UpSuccess | UpDisconnected => {},
+ UpWoke(token) => { token.signal(); }
+ }
+ Ok(())
+ }
+
+ pub fn upgrade(&self, up: Receiver<T>) -> UpgradeResult {
+ // If the port has gone away, then there's no need to proceed any
+ // further.
+ if self.queue.producer_addition().port_dropped.load(Ordering::SeqCst) {
+ return UpDisconnected
+ }
+
+ self.do_send(GoUp(up))
+ }
+
+ fn do_send(&self, t: Message<T>) -> UpgradeResult {
+ self.queue.push(t);
+ match self.queue.producer_addition().cnt.fetch_add(1, Ordering::SeqCst) {
+ // As described in the mod's doc comment, -1 == wakeup
+ -1 => UpWoke(self.take_to_wake()),
+ // As as described before, SPSC queues must be >= -2
+ -2 => UpSuccess,
+
+ // Be sure to preserve the disconnected state, and the return value
+ // in this case is going to be whether our data was received or not.
+ // This manifests itself on whether we have an empty queue or not.
+ //
+ // Primarily, are required to drain the queue here because the port
+ // will never remove this data. We can only have at most one item to
+ // drain (the port drains the rest).
+ DISCONNECTED => {
+ self.queue.producer_addition().cnt.store(DISCONNECTED, Ordering::SeqCst);
+ let first = self.queue.pop();
+ let second = self.queue.pop();
+ assert!(second.is_none());
+
+ match first {
+ Some(..) => UpSuccess, // we failed to send the data
+ None => UpDisconnected, // we successfully sent data
+ }
+ }
+
+ // Otherwise we just sent some data on a non-waiting queue, so just
+ // make sure the world is sane and carry on!
+ n => { assert!(n >= 0); UpSuccess }
+ }
+ }
+
+ // Consumes ownership of the 'to_wake' field.
+ fn take_to_wake(&self) -> SignalToken {
+ let ptr = self.queue.producer_addition().to_wake.load(Ordering::SeqCst);
+ self.queue.producer_addition().to_wake.store(0, Ordering::SeqCst);
+ assert!(ptr != 0);
+ unsafe { SignalToken::cast_from_usize(ptr) }
+ }
+
+ // Decrements the count on the channel for a sleeper, returning the sleeper
+ // back if it shouldn't sleep. Note that this is the location where we take
+ // steals into account.
+ fn decrement(&self, token: SignalToken) -> Result<(), SignalToken> {
+ assert_eq!(self.queue.producer_addition().to_wake.load(Ordering::SeqCst), 0);
+ let ptr = unsafe { token.cast_to_usize() };
+ self.queue.producer_addition().to_wake.store(ptr, Ordering::SeqCst);
+
+ let steals = unsafe { ptr::replace(self.queue.consumer_addition().steals.get(), 0) };
+
+ match self.queue.producer_addition().cnt.fetch_sub(1 + steals, Ordering::SeqCst) {
+ DISCONNECTED => {
+ self.queue.producer_addition().cnt.store(DISCONNECTED, Ordering::SeqCst);
+ }
+ // If we factor in our steals and notice that the channel has no
+ // data, we successfully sleep
+ n => {
+ assert!(n >= 0);
+ if n - steals <= 0 { return Ok(()) }
+ }
+ }
+
+ self.queue.producer_addition().to_wake.store(0, Ordering::SeqCst);
+ Err(unsafe { SignalToken::cast_from_usize(ptr) })
+ }
+
+ pub fn recv(&self, deadline: Option<Instant>) -> Result<T, Failure<T>> {
+ // Optimistic preflight check (scheduling is expensive).
+ match self.try_recv() {
+ Err(Empty) => {}
+ data => return data,
+ }
+
+ // Welp, our channel has no data. Deschedule the current thread and
+ // initiate the blocking protocol.
+ let (wait_token, signal_token) = blocking::tokens();
+ if self.decrement(signal_token).is_ok() {
+ if let Some(deadline) = deadline {
+ let timed_out = !wait_token.wait_max_until(deadline);
+ if timed_out {
+ self.abort_selection(/* was_upgrade = */ false).map_err(Upgraded)?;
+ }
+ } else {
+ wait_token.wait();
+ }
+ }
+
+ match self.try_recv() {
+ // Messages which actually popped from the queue shouldn't count as
+ // a steal, so offset the decrement here (we already have our
+ // "steal" factored into the channel count above).
+ data @ Ok(..) |
+ data @ Err(Upgraded(..)) => unsafe {
+ *self.queue.consumer_addition().steals.get() -= 1;
+ data
+ },
+
+ data => data,
+ }
+ }
+
+ pub fn try_recv(&self) -> Result<T, Failure<T>> {
+ match self.queue.pop() {
+ // If we stole some data, record to that effect (this will be
+ // factored into cnt later on).
+ //
+ // Note that we don't allow steals to grow without bound in order to
+ // prevent eventual overflow of either steals or cnt as an overflow
+ // would have catastrophic results. Sometimes, steals > cnt, but
+ // other times cnt > steals, so we don't know the relation between
+ // steals and cnt. This code path is executed only rarely, so we do
+ // a pretty slow operation, of swapping 0 into cnt, taking steals
+ // down as much as possible (without going negative), and then
+ // adding back in whatever we couldn't factor into steals.
+ Some(data) => unsafe {
+ if *self.queue.consumer_addition().steals.get() > MAX_STEALS {
+ match self.queue.producer_addition().cnt.swap(0, Ordering::SeqCst) {
+ DISCONNECTED => {
+ self.queue.producer_addition().cnt.store(
+ DISCONNECTED, Ordering::SeqCst);
+ }
+ n => {
+ let m = cmp::min(n, *self.queue.consumer_addition().steals.get());
+ *self.queue.consumer_addition().steals.get() -= m;
+ self.bump(n - m);
+ }
+ }
+ assert!(*self.queue.consumer_addition().steals.get() >= 0);
+ }
+ *self.queue.consumer_addition().steals.get() += 1;
+ match data {
+ Data(t) => Ok(t),
+ GoUp(up) => Err(Upgraded(up)),
+ }
+ },
+
+ None => {
+ match self.queue.producer_addition().cnt.load(Ordering::SeqCst) {
+ n if n != DISCONNECTED => Err(Empty),
+
+ // This is a little bit of a tricky case. We failed to pop
+ // data above, and then we have viewed that the channel is
+ // disconnected. In this window more data could have been
+ // sent on the channel. It doesn't really make sense to
+ // return that the channel is disconnected when there's
+ // actually data on it, so be extra sure there's no data by
+ // popping one more time.
+ //
+ // We can ignore steals because the other end is
+ // disconnected and we'll never need to really factor in our
+ // steals again.
+ _ => {
+ match self.queue.pop() {
+ Some(Data(t)) => Ok(t),
+ Some(GoUp(up)) => Err(Upgraded(up)),
+ None => Err(Disconnected),
+ }
+ }
+ }
+ }
+ }
+ }
+
+ pub fn drop_chan(&self) {
+ // Dropping a channel is pretty simple, we just flag it as disconnected
+ // and then wakeup a blocker if there is one.
+ match self.queue.producer_addition().cnt.swap(DISCONNECTED, Ordering::SeqCst) {
+ -1 => { self.take_to_wake().signal(); }
+ DISCONNECTED => {}
+ n => { assert!(n >= 0); }
+ }
+ }
+
+ pub fn drop_port(&self) {
+ // Dropping a port seems like a fairly trivial thing. In theory all we
+ // need to do is flag that we're disconnected and then everything else
+ // can take over (we don't have anyone to wake up).
+ //
+ // The catch for Ports is that we want to drop the entire contents of
+ // the queue. There are multiple reasons for having this property, the
+ // largest of which is that if another chan is waiting in this channel
+ // (but not received yet), then waiting on that port will cause a
+ // deadlock.
+ //
+ // So if we accept that we must now destroy the entire contents of the
+ // queue, this code may make a bit more sense. The tricky part is that
+ // we can't let any in-flight sends go un-dropped, we have to make sure
+ // *everything* is dropped and nothing new will come onto the channel.
+
+ // The first thing we do is set a flag saying that we're done for. All
+ // sends are gated on this flag, so we're immediately guaranteed that
+ // there are a bounded number of active sends that we'll have to deal
+ // with.
+ self.queue.producer_addition().port_dropped.store(true, Ordering::SeqCst);
+
+ // Now that we're guaranteed to deal with a bounded number of senders,
+ // we need to drain the queue. This draining process happens atomically
+ // with respect to the "count" of the channel. If the count is nonzero
+ // (with steals taken into account), then there must be data on the
+ // channel. In this case we drain everything and then try again. We will
+ // continue to fail while active senders send data while we're dropping
+ // data, but eventually we're guaranteed to break out of this loop
+ // (because there is a bounded number of senders).
+ let mut steals = unsafe { *self.queue.consumer_addition().steals.get() };
+ while {
+ let cnt = self.queue.producer_addition().cnt.compare_and_swap(
+ steals, DISCONNECTED, Ordering::SeqCst);
+ cnt != DISCONNECTED && cnt != steals
+ } {
+ while let Some(_) = self.queue.pop() { steals += 1; }
+ }
+
+ // At this point in time, we have gated all future senders from sending,
+ // and we have flagged the channel as being disconnected. The senders
+ // still have some responsibility, however, because some sends may not
+ // complete until after we flag the disconnection. There are more
+ // details in the sending methods that see DISCONNECTED
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ // select implementation
+ ////////////////////////////////////////////////////////////////////////////
+
+ // Tests to see whether this port can receive without blocking. If Ok is
+ // returned, then that's the answer. If Err is returned, then the returned
+ // port needs to be queried instead (an upgrade happened)
+ pub fn can_recv(&self) -> Result<bool, Receiver<T>> {
+ // We peek at the queue to see if there's anything on it, and we use
+ // this return value to determine if we should pop from the queue and
+ // upgrade this channel immediately. If it looks like we've got an
+ // upgrade pending, then go through the whole recv rigamarole to update
+ // the internal state.
+ match self.queue.peek() {
+ Some(&mut GoUp(..)) => {
+ match self.recv(None) {
+ Err(Upgraded(port)) => Err(port),
+ _ => unreachable!(),
+ }
+ }
+ Some(..) => Ok(true),
+ None => Ok(false)
+ }
+ }
+
+ // increment the count on the channel (used for selection)
+ fn bump(&self, amt: isize) -> isize {
+ match self.queue.producer_addition().cnt.fetch_add(amt, Ordering::SeqCst) {
+ DISCONNECTED => {
+ self.queue.producer_addition().cnt.store(DISCONNECTED, Ordering::SeqCst);
+ DISCONNECTED
+ }
+ n => n
+ }
+ }
+
+ // Attempts to start selecting on this port. Like a oneshot, this can fail
+ // immediately because of an upgrade.
+ pub fn start_selection(&self, token: SignalToken) -> SelectionResult<T> {
+ match self.decrement(token) {
+ Ok(()) => SelSuccess,
+ Err(token) => {
+ let ret = match self.queue.peek() {
+ Some(&mut GoUp(..)) => {
+ match self.queue.pop() {
+ Some(GoUp(port)) => SelUpgraded(token, port),
+ _ => unreachable!(),
+ }
+ }
+ Some(..) => SelCanceled,
+ None => SelCanceled,
+ };
+ // Undo our decrement above, and we should be guaranteed that the
+ // previous value is positive because we're not going to sleep
+ let prev = self.bump(1);
+ assert!(prev == DISCONNECTED || prev >= 0);
+ ret
+ }
+ }
+ }
+
+ // Removes a previous thread from being blocked in this port
+ pub fn abort_selection(&self,
+ was_upgrade: bool) -> Result<bool, Receiver<T>> {
+ // If we're aborting selection after upgrading from a oneshot, then
+ // we're guarantee that no one is waiting. The only way that we could
+ // have seen the upgrade is if data was actually sent on the channel
+ // half again. For us, this means that there is guaranteed to be data on
+ // this channel. Furthermore, we're guaranteed that there was no
+ // start_selection previously, so there's no need to modify `self.cnt`
+ // at all.
+ //
+ // Hence, because of these invariants, we immediately return `Ok(true)`.
+ // Note that the data may not actually be sent on the channel just yet.
+ // The other end could have flagged the upgrade but not sent data to
+ // this end. This is fine because we know it's a small bounded windows
+ // of time until the data is actually sent.
+ if was_upgrade {
+ assert_eq!(unsafe { *self.queue.consumer_addition().steals.get() }, 0);
+ assert_eq!(self.queue.producer_addition().to_wake.load(Ordering::SeqCst), 0);
+ return Ok(true)
+ }
+
+ // We want to make sure that the count on the channel goes non-negative,
+ // and in the stream case we can have at most one steal, so just assume
+ // that we had one steal.
+ let steals = 1;
+ let prev = self.bump(steals + 1);
+
+ // If we were previously disconnected, then we know for sure that there
+ // is no thread in to_wake, so just keep going
+ let has_data = if prev == DISCONNECTED {
+ assert_eq!(self.queue.producer_addition().to_wake.load(Ordering::SeqCst), 0);
+ true // there is data, that data is that we're disconnected
+ } else {
+ let cur = prev + steals + 1;
+ assert!(cur >= 0);
+
+ // If the previous count was negative, then we just made things go
+ // positive, hence we passed the -1 boundary and we're responsible
+ // for removing the to_wake() field and trashing it.
+ //
+ // If the previous count was positive then we're in a tougher
+ // situation. A possible race is that a sender just incremented
+ // through -1 (meaning it's going to try to wake a thread up), but it
+ // hasn't yet read the to_wake. In order to prevent a future recv()
+ // from waking up too early (this sender picking up the plastered
+ // over to_wake), we spin loop here waiting for to_wake to be 0.
+ // Note that this entire select() implementation needs an overhaul,
+ // and this is *not* the worst part of it, so this is not done as a
+ // final solution but rather out of necessity for now to get
+ // something working.
+ if prev < 0 {
+ drop(self.take_to_wake());
+ } else {
+ while self.queue.producer_addition().to_wake.load(Ordering::SeqCst) != 0 {
+ thread::yield_now();
+ }
+ }
+ unsafe {
+ assert_eq!(*self.queue.consumer_addition().steals.get(), 0);
+ *self.queue.consumer_addition().steals.get() = steals;
+ }
+
+ // if we were previously positive, then there's surely data to
+ // receive
+ prev >= 0
+ };
+
+ // Now that we've determined that this queue "has data", we peek at the
+ // queue to see if the data is an upgrade or not. If it's an upgrade,
+ // then we need to destroy this port and abort selection on the
+ // upgraded port.
+ if has_data {
+ match self.queue.peek() {
+ Some(&mut GoUp(..)) => {
+ match self.queue.pop() {
+ Some(GoUp(port)) => Err(port),
+ _ => unreachable!(),
+ }
+ }
+ _ => Ok(true),
+ }
+ } else {
+ Ok(false)
+ }
+ }
+}
+
+impl<T> Drop for Packet<T> {
+ fn drop(&mut self) {
+ // Note that this load is not only an assert for correctness about
+ // disconnection, but also a proper fence before the read of
+ // `to_wake`, so this assert cannot be removed with also removing
+ // the `to_wake` assert.
+ assert_eq!(self.queue.producer_addition().cnt.load(Ordering::SeqCst), DISCONNECTED);
+ assert_eq!(self.queue.producer_addition().to_wake.load(Ordering::SeqCst), 0);
+ }
+}
diff --git a/src/libstd/sync/mpsc/sync.rs b/src/libstd/sync/mpsc/sync.rs
new file mode 100644
index 0000000..b2d9f4c
--- /dev/null
+++ b/src/libstd/sync/mpsc/sync.rs
@@ -0,0 +1,518 @@
+/// Synchronous channels/ports
+///
+/// This channel implementation differs significantly from the asynchronous
+/// implementations found next to it (oneshot/stream/share). This is an
+/// implementation of a synchronous, bounded buffer channel.
+///
+/// Each channel is created with some amount of backing buffer, and sends will
+/// *block* until buffer space becomes available. A buffer size of 0 is valid,
+/// which means that every successful send is paired with a successful recv.
+///
+/// This flavor of channels defines a new `send_opt` method for channels which
+/// is the method by which a message is sent but the thread does not panic if it
+/// cannot be delivered.
+///
+/// Another major difference is that send() will *always* return back the data
+/// if it couldn't be sent. This is because it is deterministically known when
+/// the data is received and when it is not received.
+///
+/// Implementation-wise, it can all be summed up with "use a mutex plus some
+/// logic". The mutex used here is an OS native mutex, meaning that no user code
+/// is run inside of the mutex (to prevent context switching). This
+/// implementation shares almost all code for the buffered and unbuffered cases
+/// of a synchronous channel. There are a few branches for the unbuffered case,
+/// but they're mostly just relevant to blocking senders.
+
+pub use self::Failure::*;
+use self::Blocker::*;
+
+use core::intrinsics::abort;
+use core::isize;
+use core::mem;
+use core::ptr;
+
+use crate::sync::atomic::{Ordering, AtomicUsize};
+use crate::sync::mpsc::blocking::{self, WaitToken, SignalToken};
+use crate::sync::mpsc::select::StartResult::{self, Installed, Abort};
+use crate::sync::{Mutex, MutexGuard};
+use crate::time::Instant;
+
+const MAX_REFCOUNT: usize = (isize::MAX) as usize;
+
+pub struct Packet<T> {
+ /// Only field outside of the mutex. Just done for kicks, but mainly because
+ /// the other shared channel already had the code implemented
+ channels: AtomicUsize,
+
+ lock: Mutex<State<T>>,
+}
+
+unsafe impl<T: Send> Send for Packet<T> { }
+
+unsafe impl<T: Send> Sync for Packet<T> { }
+
+struct State<T> {
+ disconnected: bool, // Is the channel disconnected yet?
+ queue: Queue, // queue of senders waiting to send data
+ blocker: Blocker, // currently blocked thread on this channel
+ buf: Buffer<T>, // storage for buffered messages
+ cap: usize, // capacity of this channel
+
+ /// A curious flag used to indicate whether a sender failed or succeeded in
+ /// blocking. This is used to transmit information back to the thread that it
+ /// must dequeue its message from the buffer because it was not received.
+ /// This is only relevant in the 0-buffer case. This obviously cannot be
+ /// safely constructed, but it's guaranteed to always have a valid pointer
+ /// value.
+ canceled: Option<&'static mut bool>,
+}
+
+unsafe impl<T: Send> Send for State<T> {}
+
+/// Possible flavors of threads who can be blocked on this channel.
+enum Blocker {
+ BlockedSender(SignalToken),
+ BlockedReceiver(SignalToken),
+ NoneBlocked
+}
+
+/// Simple queue for threading threads together. Nodes are stack-allocated, so
+/// this structure is not safe at all
+struct Queue {
+ head: *mut Node,
+ tail: *mut Node,
+}
+
+struct Node {
+ token: Option<SignalToken>,
+ next: *mut Node,
+}
+
+unsafe impl Send for Node {}
+
+/// A simple ring-buffer
+struct Buffer<T> {
+ buf: Vec<Option<T>>,
+ start: usize,
+ size: usize,
+}
+
+#[derive(Debug)]
+pub enum Failure {
+ Empty,
+ Disconnected,
+}
+
+/// Atomically blocks the current thread, placing it into `slot`, unlocking `lock`
+/// in the meantime. This re-locks the mutex upon returning.
+fn wait<'a, 'b, T>(lock: &'a Mutex<State<T>>,
+ mut guard: MutexGuard<'b, State<T>>,
+ f: fn(SignalToken) -> Blocker)
+ -> MutexGuard<'a, State<T>>
+{
+ let (wait_token, signal_token) = blocking::tokens();
+ match mem::replace(&mut guard.blocker, f(signal_token)) {
+ NoneBlocked => {}
+ _ => unreachable!(),
+ }
+ drop(guard); // unlock
+ wait_token.wait(); // block
+ lock.lock().unwrap() // relock
+}
+
+/// Same as wait, but waiting at most until `deadline`.
+fn wait_timeout_receiver<'a, 'b, T>(lock: &'a Mutex<State<T>>,
+ deadline: Instant,
+ mut guard: MutexGuard<'b, State<T>>,
+ success: &mut bool)
+ -> MutexGuard<'a, State<T>>
+{
+ let (wait_token, signal_token) = blocking::tokens();
+ match mem::replace(&mut guard.blocker, BlockedReceiver(signal_token)) {
+ NoneBlocked => {}
+ _ => unreachable!(),
+ }
+ drop(guard); // unlock
+ *success = wait_token.wait_max_until(deadline); // block
+ let mut new_guard = lock.lock().unwrap(); // relock
+ if !*success {
+ abort_selection(&mut new_guard);
+ }
+ new_guard
+}
+
+fn abort_selection<'a, T>(guard: &mut MutexGuard<'a , State<T>>) -> bool {
+ match mem::replace(&mut guard.blocker, NoneBlocked) {
+ NoneBlocked => true,
+ BlockedSender(token) => {
+ guard.blocker = BlockedSender(token);
+ true
+ }
+ BlockedReceiver(token) => { drop(token); false }
+ }
+}
+
+/// Wakes up a thread, dropping the lock at the correct time
+fn wakeup<T>(token: SignalToken, guard: MutexGuard<'_, State<T>>) {
+ // We need to be careful to wake up the waiting thread *outside* of the mutex
+ // in case it incurs a context switch.
+ drop(guard);
+ token.signal();
+}
+
+impl<T> Packet<T> {
+ pub fn new(cap: usize) -> Packet<T> {
+ Packet {
+ channels: AtomicUsize::new(1),
+ lock: Mutex::new(State {
+ disconnected: false,
+ blocker: NoneBlocked,
+ cap,
+ canceled: None,
+ queue: Queue {
+ head: ptr::null_mut(),
+ tail: ptr::null_mut(),
+ },
+ buf: Buffer {
+ buf: (0..cap + if cap == 0 {1} else {0}).map(|_| None).collect(),
+ start: 0,
+ size: 0,
+ },
+ }),
+ }
+ }
+
+ // wait until a send slot is available, returning locked access to
+ // the channel state.
+ fn acquire_send_slot(&self) -> MutexGuard<'_, State<T>> {
+ let mut node = Node { token: None, next: ptr::null_mut() };
+ loop {
+ let mut guard = self.lock.lock().unwrap();
+ // are we ready to go?
+ if guard.disconnected || guard.buf.size() < guard.buf.cap() {
+ return guard;
+ }
+ // no room; actually block
+ let wait_token = guard.queue.enqueue(&mut node);
+ drop(guard);
+ wait_token.wait();
+ }
+ }
+
+ pub fn send(&self, t: T) -> Result<(), T> {
+ let mut guard = self.acquire_send_slot();
+ if guard.disconnected { return Err(t) }
+ guard.buf.enqueue(t);
+
+ match mem::replace(&mut guard.blocker, NoneBlocked) {
+ // if our capacity is 0, then we need to wait for a receiver to be
+ // available to take our data. After waiting, we check again to make
+ // sure the port didn't go away in the meantime. If it did, we need
+ // to hand back our data.
+ NoneBlocked if guard.cap == 0 => {
+ let mut canceled = false;
+ assert!(guard.canceled.is_none());
+ guard.canceled = Some(unsafe { mem::transmute(&mut canceled) });
+ let mut guard = wait(&self.lock, guard, BlockedSender);
+ if canceled {Err(guard.buf.dequeue())} else {Ok(())}
+ }
+
+ // success, we buffered some data
+ NoneBlocked => Ok(()),
+
+ // success, someone's about to receive our buffered data.
+ BlockedReceiver(token) => { wakeup(token, guard); Ok(()) }
+
+ BlockedSender(..) => panic!("lolwut"),
+ }
+ }
+
+ pub fn try_send(&self, t: T) -> Result<(), super::TrySendError<T>> {
+ let mut guard = self.lock.lock().unwrap();
+ if guard.disconnected {
+ Err(super::TrySendError::Disconnected(t))
+ } else if guard.buf.size() == guard.buf.cap() {
+ Err(super::TrySendError::Full(t))
+ } else if guard.cap == 0 {
+ // With capacity 0, even though we have buffer space we can't
+ // transfer the data unless there's a receiver waiting.
+ match mem::replace(&mut guard.blocker, NoneBlocked) {
+ NoneBlocked => Err(super::TrySendError::Full(t)),
+ BlockedSender(..) => unreachable!(),
+ BlockedReceiver(token) => {
+ guard.buf.enqueue(t);
+ wakeup(token, guard);
+ Ok(())
+ }
+ }
+ } else {
+ // If the buffer has some space and the capacity isn't 0, then we
+ // just enqueue the data for later retrieval, ensuring to wake up
+ // any blocked receiver if there is one.
+ assert!(guard.buf.size() < guard.buf.cap());
+ guard.buf.enqueue(t);
+ match mem::replace(&mut guard.blocker, NoneBlocked) {
+ BlockedReceiver(token) => wakeup(token, guard),
+ NoneBlocked => {}
+ BlockedSender(..) => unreachable!(),
+ }
+ Ok(())
+ }
+ }
+
+ // Receives a message from this channel
+ //
+ // When reading this, remember that there can only ever be one receiver at
+ // time.
+ pub fn recv(&self, deadline: Option<Instant>) -> Result<T, Failure> {
+ let mut guard = self.lock.lock().unwrap();
+
+ let mut woke_up_after_waiting = false;
+ // Wait for the buffer to have something in it. No need for a
+ // while loop because we're the only receiver.
+ if !guard.disconnected && guard.buf.size() == 0 {
+ if let Some(deadline) = deadline {
+ guard = wait_timeout_receiver(&self.lock,
+ deadline,
+ guard,
+ &mut woke_up_after_waiting);
+ } else {
+ guard = wait(&self.lock, guard, BlockedReceiver);
+ woke_up_after_waiting = true;
+ }
+ }
+
+ // N.B., channel could be disconnected while waiting, so the order of
+ // these conditionals is important.
+ if guard.disconnected && guard.buf.size() == 0 {
+ return Err(Disconnected);
+ }
+
+ // Pick up the data, wake up our neighbors, and carry on
+ assert!(guard.buf.size() > 0 || (deadline.is_some() && !woke_up_after_waiting));
+
+ if guard.buf.size() == 0 { return Err(Empty); }
+
+ let ret = guard.buf.dequeue();
+ self.wakeup_senders(woke_up_after_waiting, guard);
+ Ok(ret)
+ }
+
+ pub fn try_recv(&self) -> Result<T, Failure> {
+ let mut guard = self.lock.lock().unwrap();
+
+ // Easy cases first
+ if guard.disconnected && guard.buf.size() == 0 { return Err(Disconnected) }
+ if guard.buf.size() == 0 { return Err(Empty) }
+
+ // Be sure to wake up neighbors
+ let ret = Ok(guard.buf.dequeue());
+ self.wakeup_senders(false, guard);
+ ret
+ }
+
+ // Wake up pending senders after some data has been received
+ //
+ // * `waited` - flag if the receiver blocked to receive some data, or if it
+ // just picked up some data on the way out
+ // * `guard` - the lock guard that is held over this channel's lock
+ fn wakeup_senders(&self, waited: bool, mut guard: MutexGuard<'_, State<T>>) {
+ let pending_sender1: Option<SignalToken> = guard.queue.dequeue();
+
+ // If this is a no-buffer channel (cap == 0), then if we didn't wait we
+ // need to ACK the sender. If we waited, then the sender waking us up
+ // was already the ACK.
+ let pending_sender2 = if guard.cap == 0 && !waited {
+ match mem::replace(&mut guard.blocker, NoneBlocked) {
+ NoneBlocked => None,
+ BlockedReceiver(..) => unreachable!(),
+ BlockedSender(token) => {
+ guard.canceled.take();
+ Some(token)
+ }
+ }
+ } else {
+ None
+ };
+ mem::drop(guard);
+
+ // only outside of the lock do we wake up the pending threads
+ pending_sender1.map(|t| t.signal());
+ pending_sender2.map(|t| t.signal());
+ }
+
+ // Prepares this shared packet for a channel clone, essentially just bumping
+ // a refcount.
+ pub fn clone_chan(&self) {
+ let old_count = self.channels.fetch_add(1, Ordering::SeqCst);
+
+ // See comments on Arc::clone() on why we do this (for `mem::forget`).
+ if old_count > MAX_REFCOUNT {
+ unsafe {
+ abort();
+ }
+ }
+ }
+
+ pub fn drop_chan(&self) {
+ // Only flag the channel as disconnected if we're the last channel
+ match self.channels.fetch_sub(1, Ordering::SeqCst) {
+ 1 => {}
+ _ => return
+ }
+
+ // Not much to do other than wake up a receiver if one's there
+ let mut guard = self.lock.lock().unwrap();
+ if guard.disconnected { return }
+ guard.disconnected = true;
+ match mem::replace(&mut guard.blocker, NoneBlocked) {
+ NoneBlocked => {}
+ BlockedSender(..) => unreachable!(),
+ BlockedReceiver(token) => wakeup(token, guard),
+ }
+ }
+
+ pub fn drop_port(&self) {
+ let mut guard = self.lock.lock().unwrap();
+
+ if guard.disconnected { return }
+ guard.disconnected = true;
+
+ // If the capacity is 0, then the sender may want its data back after
+ // we're disconnected. Otherwise it's now our responsibility to destroy
+ // the buffered data. As with many other portions of this code, this
+ // needs to be careful to destroy the data *outside* of the lock to
+ // prevent deadlock.
+ let _data = if guard.cap != 0 {
+ mem::replace(&mut guard.buf.buf, Vec::new())
+ } else {
+ Vec::new()
+ };
+ let mut queue = mem::replace(&mut guard.queue, Queue {
+ head: ptr::null_mut(),
+ tail: ptr::null_mut(),
+ });
+
+ let waiter = match mem::replace(&mut guard.blocker, NoneBlocked) {
+ NoneBlocked => None,
+ BlockedSender(token) => {
+ *guard.canceled.take().unwrap() = true;
+ Some(token)
+ }
+ BlockedReceiver(..) => unreachable!(),
+ };
+ mem::drop(guard);
+
+ while let Some(token) = queue.dequeue() { token.signal(); }
+ waiter.map(|t| t.signal());
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ // select implementation
+ ////////////////////////////////////////////////////////////////////////////
+
+ // If Ok, the value is whether this port has data, if Err, then the upgraded
+ // port needs to be checked instead of this one.
+ pub fn can_recv(&self) -> bool {
+ let guard = self.lock.lock().unwrap();
+ guard.disconnected || guard.buf.size() > 0
+ }
+
+ // Attempts to start selection on this port. This can either succeed or fail
+ // because there is data waiting.
+ pub fn start_selection(&self, token: SignalToken) -> StartResult {
+ let mut guard = self.lock.lock().unwrap();
+ if guard.disconnected || guard.buf.size() > 0 {
+ Abort
+ } else {
+ match mem::replace(&mut guard.blocker, BlockedReceiver(token)) {
+ NoneBlocked => {}
+ BlockedSender(..) => unreachable!(),
+ BlockedReceiver(..) => unreachable!(),
+ }
+ Installed
+ }
+ }
+
+ // Remove a previous selecting thread from this port. This ensures that the
+ // blocked thread will no longer be visible to any other threads.
+ //
+ // The return value indicates whether there's data on this port.
+ pub fn abort_selection(&self) -> bool {
+ let mut guard = self.lock.lock().unwrap();
+ abort_selection(&mut guard)
+ }
+}
+
+impl<T> Drop for Packet<T> {
+ fn drop(&mut self) {
+ assert_eq!(self.channels.load(Ordering::SeqCst), 0);
+ let mut guard = self.lock.lock().unwrap();
+ assert!(guard.queue.dequeue().is_none());
+ assert!(guard.canceled.is_none());
+ }
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+// Buffer, a simple ring buffer backed by Vec<T>
+////////////////////////////////////////////////////////////////////////////////
+
+impl<T> Buffer<T> {
+ fn enqueue(&mut self, t: T) {
+ let pos = (self.start + self.size) % self.buf.len();
+ self.size += 1;
+ let prev = mem::replace(&mut self.buf[pos], Some(t));
+ assert!(prev.is_none());
+ }
+
+ fn dequeue(&mut self) -> T {
+ let start = self.start;
+ self.size -= 1;
+ self.start = (self.start + 1) % self.buf.len();
+ let result = &mut self.buf[start];
+ result.take().unwrap()
+ }
+
+ fn size(&self) -> usize { self.size }
+ fn cap(&self) -> usize { self.buf.len() }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Queue, a simple queue to enqueue threads with (stack-allocated nodes)
+////////////////////////////////////////////////////////////////////////////////
+
+impl Queue {
+ fn enqueue(&mut self, node: &mut Node) -> WaitToken {
+ let (wait_token, signal_token) = blocking::tokens();
+ node.token = Some(signal_token);
+ node.next = ptr::null_mut();
+
+ if self.tail.is_null() {
+ self.head = node as *mut Node;
+ self.tail = node as *mut Node;
+ } else {
+ unsafe {
+ (*self.tail).next = node as *mut Node;
+ self.tail = node as *mut Node;
+ }
+ }
+
+ wait_token
+ }
+
+ fn dequeue(&mut self) -> Option<SignalToken> {
+ if self.head.is_null() {
+ return None
+ }
+ let node = self.head;
+ self.head = unsafe { (*node).next };
+ if self.head.is_null() {
+ self.tail = ptr::null_mut();
+ }
+ unsafe {
+ (*node).next = ptr::null_mut();
+ Some((*node).token.take().unwrap())
+ }
+ }
+}
diff --git a/src/libstd/sync/mutex.rs b/src/libstd/sync/mutex.rs
new file mode 100644
index 0000000..11ac34f
--- /dev/null
+++ b/src/libstd/sync/mutex.rs
@@ -0,0 +1,704 @@
+use crate::cell::UnsafeCell;
+use crate::fmt;
+use crate::mem;
+use crate::ops::{Deref, DerefMut};
+use crate::ptr;
+use crate::sys_common::mutex as sys;
+use crate::sys_common::poison::{self, TryLockError, TryLockResult, LockResult};
+
+/// A mutual exclusion primitive useful for protecting shared data
+///
+/// This mutex will block threads waiting for the lock to become available. The
+/// mutex can also be statically initialized or created via a [`new`]
+/// constructor. Each mutex has a type parameter which represents the data that
+/// it is protecting. The data can only be accessed through the RAII guards
+/// returned from [`lock`] and [`try_lock`], which guarantees that the data is only
+/// ever accessed when the mutex is locked.
+///
+/// # Poisoning
+///
+/// The mutexes in this module implement a strategy called "poisoning" where a
+/// mutex is considered poisoned whenever a thread panics while holding the
+/// mutex. Once a mutex is poisoned, all other threads are unable to access the
+/// data by default as it is likely tainted (some invariant is not being
+/// upheld).
+///
+/// For a mutex, this means that the [`lock`] and [`try_lock`] methods return a
+/// [`Result`] which indicates whether a mutex has been poisoned or not. Most
+/// usage of a mutex will simply [`unwrap()`] these results, propagating panics
+/// among threads to ensure that a possibly invalid invariant is not witnessed.
+///
+/// A poisoned mutex, however, does not prevent all access to the underlying
+/// data. The [`PoisonError`] type has an [`into_inner`] method which will return
+/// the guard that would have otherwise been returned on a successful lock. This
+/// allows access to the data, despite the lock being poisoned.
+///
+/// [`new`]: #method.new
+/// [`lock`]: #method.lock
+/// [`try_lock`]: #method.try_lock
+/// [`Result`]: ../../std/result/enum.Result.html
+/// [`unwrap()`]: ../../std/result/enum.Result.html#method.unwrap
+/// [`PoisonError`]: ../../std/sync/struct.PoisonError.html
+/// [`into_inner`]: ../../std/sync/struct.PoisonError.html#method.into_inner
+///
+/// # Examples
+///
+/// ```
+/// use std::sync::{Arc, Mutex};
+/// use std::thread;
+/// use std::sync::mpsc::channel;
+///
+/// const N: usize = 10;
+///
+/// // Spawn a few threads to increment a shared variable (non-atomically), and
+/// // let the main thread know once all increments are done.
+/// //
+/// // Here we're using an Arc to share memory among threads, and the data inside
+/// // the Arc is protected with a mutex.
+/// let data = Arc::new(Mutex::new(0));
+///
+/// let (tx, rx) = channel();
+/// for _ in 0..N {
+/// let (data, tx) = (Arc::clone(&data), tx.clone());
+/// thread::spawn(move || {
+/// // The shared state can only be accessed once the lock is held.
+/// // Our non-atomic increment is safe because we're the only thread
+/// // which can access the shared state when the lock is held.
+/// //
+/// // We unwrap() the return value to assert that we are not expecting
+/// // threads to ever fail while holding the lock.
+/// let mut data = data.lock().unwrap();
+/// *data += 1;
+/// if *data == N {
+/// tx.send(()).unwrap();
+/// }
+/// // the lock is unlocked here when `data` goes out of scope.
+/// });
+/// }
+///
+/// rx.recv().unwrap();
+/// ```
+///
+/// To recover from a poisoned mutex:
+///
+/// ```
+/// use std::sync::{Arc, Mutex};
+/// use std::thread;
+///
+/// let lock = Arc::new(Mutex::new(0_u32));
+/// let lock2 = lock.clone();
+///
+/// let _ = thread::spawn(move || -> () {
+/// // This thread will acquire the mutex first, unwrapping the result of
+/// // `lock` because the lock has not been poisoned.
+/// let _guard = lock2.lock().unwrap();
+///
+/// // This panic while holding the lock (`_guard` is in scope) will poison
+/// // the mutex.
+/// panic!();
+/// }).join();
+///
+/// // The lock is poisoned by this point, but the returned result can be
+/// // pattern matched on to return the underlying guard on both branches.
+/// let mut guard = match lock.lock() {
+/// Ok(guard) => guard,
+/// Err(poisoned) => poisoned.into_inner(),
+/// };
+///
+/// *guard += 1;
+/// ```
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct Mutex<T: ?Sized> {
+ // Note that this mutex is in a *box*, not inlined into the struct itself.
+ // Once a native mutex has been used once, its address can never change (it
+ // can't be moved). This mutex type can be safely moved at any time, so to
+ // ensure that the native mutex is used correctly we box the inner mutex to
+ // give it a constant address.
+ inner: Box<sys::Mutex>,
+ poison: poison::Flag,
+ data: UnsafeCell<T>,
+}
+
+// these are the only places where `T: Send` matters; all other
+// functionality works fine on a single thread.
+#[stable(feature = "rust1", since = "1.0.0")]
+unsafe impl<T: ?Sized + Send> Send for Mutex<T> { }
+#[stable(feature = "rust1", since = "1.0.0")]
+unsafe impl<T: ?Sized + Send> Sync for Mutex<T> { }
+
+/// An RAII implementation of a "scoped lock" of a mutex. When this structure is
+/// dropped (falls out of scope), the lock will be unlocked.
+///
+/// The data protected by the mutex can be accessed through this guard via its
+/// [`Deref`] and [`DerefMut`] implementations.
+///
+/// This structure is created by the [`lock`] and [`try_lock`] methods on
+/// [`Mutex`].
+///
+/// [`Deref`]: ../../std/ops/trait.Deref.html
+/// [`DerefMut`]: ../../std/ops/trait.DerefMut.html
+/// [`lock`]: struct.Mutex.html#method.lock
+/// [`try_lock`]: struct.Mutex.html#method.try_lock
+/// [`Mutex`]: struct.Mutex.html
+#[must_use = "if unused the Mutex will immediately unlock"]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct MutexGuard<'a, T: ?Sized + 'a> {
+ // funny underscores due to how Deref/DerefMut currently work (they
+ // disregard field privacy).
+ __lock: &'a Mutex<T>,
+ __poison: poison::Guard,
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T: ?Sized> !Send for MutexGuard<'_, T> { }
+#[stable(feature = "mutexguard", since = "1.19.0")]
+unsafe impl<T: ?Sized + Sync> Sync for MutexGuard<'_, T> { }
+
+impl<T> Mutex<T> {
+ /// Creates a new mutex in an unlocked state ready for use.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::sync::Mutex;
+ ///
+ /// let mutex = Mutex::new(0);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn new(t: T) -> Mutex<T> {
+ let mut m = Mutex {
+ inner: box sys::Mutex::new(),
+ poison: poison::Flag::new(),
+ data: UnsafeCell::new(t),
+ };
+ unsafe {
+ m.inner.init();
+ }
+ m
+ }
+}
+
+impl<T: ?Sized> Mutex<T> {
+ /// Acquires a mutex, blocking the current thread until it is able to do so.
+ ///
+ /// This function will block the local thread until it is available to acquire
+ /// the mutex. Upon returning, the thread is the only thread with the lock
+ /// held. An RAII guard is returned to allow scoped unlock of the lock. When
+ /// the guard goes out of scope, the mutex will be unlocked.
+ ///
+ /// The exact behavior on locking a mutex in the thread which already holds
+ /// the lock is left unspecified. However, this function will not return on
+ /// the second call (it might panic or deadlock, for example).
+ ///
+ /// # Errors
+ ///
+ /// If another user of this mutex panicked while holding the mutex, then
+ /// this call will return an error once the mutex is acquired.
+ ///
+ /// # Panics
+ ///
+ /// This function might panic when called if the lock is already held by
+ /// the current thread.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::sync::{Arc, Mutex};
+ /// use std::thread;
+ ///
+ /// let mutex = Arc::new(Mutex::new(0));
+ /// let c_mutex = mutex.clone();
+ ///
+ /// thread::spawn(move || {
+ /// *c_mutex.lock().unwrap() = 10;
+ /// }).join().expect("thread::spawn failed");
+ /// assert_eq!(*mutex.lock().unwrap(), 10);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn lock(&self) -> LockResult<MutexGuard<'_, T>> {
+ unsafe {
+ self.inner.raw_lock();
+ MutexGuard::new(self)
+ }
+ }
+
+ /// Attempts to acquire this lock.
+ ///
+ /// If the lock could not be acquired at this time, then [`Err`] is returned.
+ /// Otherwise, an RAII guard is returned. The lock will be unlocked when the
+ /// guard is dropped.
+ ///
+ /// This function does not block.
+ ///
+ /// # Errors
+ ///
+ /// If another user of this mutex panicked while holding the mutex, then
+ /// this call will return failure if the mutex would otherwise be
+ /// acquired.
+ ///
+ /// [`Err`]: ../../std/result/enum.Result.html#variant.Err
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::sync::{Arc, Mutex};
+ /// use std::thread;
+ ///
+ /// let mutex = Arc::new(Mutex::new(0));
+ /// let c_mutex = mutex.clone();
+ ///
+ /// thread::spawn(move || {
+ /// let mut lock = c_mutex.try_lock();
+ /// if let Ok(ref mut mutex) = lock {
+ /// **mutex = 10;
+ /// } else {
+ /// println!("try_lock failed");
+ /// }
+ /// }).join().expect("thread::spawn failed");
+ /// assert_eq!(*mutex.lock().unwrap(), 10);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn try_lock(&self) -> TryLockResult<MutexGuard<'_, T>> {
+ unsafe {
+ if self.inner.try_lock() {
+ Ok(MutexGuard::new(self)?)
+ } else {
+ Err(TryLockError::WouldBlock)
+ }
+ }
+ }
+
+ /// Determines whether the mutex is poisoned.
+ ///
+ /// If another thread is active, the mutex can still become poisoned at any
+ /// time. You should not trust a `false` value for program correctness
+ /// without additional synchronization.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::sync::{Arc, Mutex};
+ /// use std::thread;
+ ///
+ /// let mutex = Arc::new(Mutex::new(0));
+ /// let c_mutex = mutex.clone();
+ ///
+ /// let _ = thread::spawn(move || {
+ /// let _lock = c_mutex.lock().unwrap();
+ /// panic!(); // the mutex gets poisoned
+ /// }).join();
+ /// assert_eq!(mutex.is_poisoned(), true);
+ /// ```
+ #[inline]
+ #[stable(feature = "sync_poison", since = "1.2.0")]
+ pub fn is_poisoned(&self) -> bool {
+ self.poison.get()
+ }
+
+ /// Consumes this mutex, returning the underlying data.
+ ///
+ /// # Errors
+ ///
+ /// If another user of this mutex panicked while holding the mutex, then
+ /// this call will return an error instead.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::sync::Mutex;
+ ///
+ /// let mutex = Mutex::new(0);
+ /// assert_eq!(mutex.into_inner().unwrap(), 0);
+ /// ```
+ #[stable(feature = "mutex_into_inner", since = "1.6.0")]
+ pub fn into_inner(self) -> LockResult<T> where T: Sized {
+ // We know statically that there are no outstanding references to
+ // `self` so there's no need to lock the inner mutex.
+ //
+ // To get the inner value, we'd like to call `data.into_inner()`,
+ // but because `Mutex` impl-s `Drop`, we can't move out of it, so
+ // we'll have to destructure it manually instead.
+ unsafe {
+ // Like `let Mutex { inner, poison, data } = self`.
+ let (inner, poison, data) = {
+ let Mutex { ref inner, ref poison, ref data } = self;
+ (ptr::read(inner), ptr::read(poison), ptr::read(data))
+ };
+ mem::forget(self);
+ inner.destroy(); // Keep in sync with the `Drop` impl.
+ drop(inner);
+
+ poison::map_result(poison.borrow(), |_| data.into_inner())
+ }
+ }
+
+ /// Returns a mutable reference to the underlying data.
+ ///
+ /// Since this call borrows the `Mutex` mutably, no actual locking needs to
+ /// take place -- the mutable borrow statically guarantees no locks exist.
+ ///
+ /// # Errors
+ ///
+ /// If another user of this mutex panicked while holding the mutex, then
+ /// this call will return an error instead.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::sync::Mutex;
+ ///
+ /// let mut mutex = Mutex::new(0);
+ /// *mutex.get_mut().unwrap() = 10;
+ /// assert_eq!(*mutex.lock().unwrap(), 10);
+ /// ```
+ #[stable(feature = "mutex_get_mut", since = "1.6.0")]
+ pub fn get_mut(&mut self) -> LockResult<&mut T> {
+ // We know statically that there are no other references to `self`, so
+ // there's no need to lock the inner mutex.
+ let data = unsafe { &mut *self.data.get() };
+ poison::map_result(self.poison.borrow(), |_| data )
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+unsafe impl<#[may_dangle] T: ?Sized> Drop for Mutex<T> {
+ fn drop(&mut self) {
+ // This is actually safe b/c we know that there is no further usage of
+ // this mutex (it's up to the user to arrange for a mutex to get
+ // dropped, that's not our job)
+ //
+ // IMPORTANT: This code must be kept in sync with `Mutex::into_inner`.
+ unsafe { self.inner.destroy() }
+ }
+}
+
+#[stable(feature = "mutex_from", since = "1.24.0")]
+impl<T> From<T> for Mutex<T> {
+ /// Creates a new mutex in an unlocked state ready for use.
+ /// This is equivalent to [`Mutex::new`].
+ fn from(t: T) -> Self {
+ Mutex::new(t)
+ }
+}
+
+#[stable(feature = "mutex_default", since = "1.10.0")]
+impl<T: ?Sized + Default> Default for Mutex<T> {
+ /// Creates a `Mutex<T>`, with the `Default` value for T.
+ fn default() -> Mutex<T> {
+ Mutex::new(Default::default())
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T: ?Sized + fmt::Debug> fmt::Debug for Mutex<T> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self.try_lock() {
+ Ok(guard) => f.debug_struct("Mutex").field("data", &&*guard).finish(),
+ Err(TryLockError::Poisoned(err)) => {
+ f.debug_struct("Mutex").field("data", &&**err.get_ref()).finish()
+ },
+ Err(TryLockError::WouldBlock) => {
+ struct LockedPlaceholder;
+ impl fmt::Debug for LockedPlaceholder {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.write_str("<locked>")
+ }
+ }
+
+ f.debug_struct("Mutex").field("data", &LockedPlaceholder).finish()
+ }
+ }
+ }
+}
+
+impl<'mutex, T: ?Sized> MutexGuard<'mutex, T> {
+ unsafe fn new(lock: &'mutex Mutex<T>) -> LockResult<MutexGuard<'mutex, T>> {
+ poison::map_result(lock.poison.borrow(), |guard| {
+ MutexGuard {
+ __lock: lock,
+ __poison: guard,
+ }
+ })
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T: ?Sized> Deref for MutexGuard<'_, T> {
+ type Target = T;
+
+ fn deref(&self) -> &T {
+ unsafe { &*self.__lock.data.get() }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T: ?Sized> DerefMut for MutexGuard<'_, T> {
+ fn deref_mut(&mut self) -> &mut T {
+ unsafe { &mut *self.__lock.data.get() }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T: ?Sized> Drop for MutexGuard<'_, T> {
+ #[inline]
+ fn drop(&mut self) {
+ unsafe {
+ self.__lock.poison.done(&self.__poison);
+ self.__lock.inner.raw_unlock();
+ }
+ }
+}
+
+#[stable(feature = "std_debug", since = "1.16.0")]
+impl<T: ?Sized + fmt::Debug> fmt::Debug for MutexGuard<'_, T> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt::Debug::fmt(&**self, f)
+ }
+}
+
+#[stable(feature = "std_guard_impls", since = "1.20.0")]
+impl<T: ?Sized + fmt::Display> fmt::Display for MutexGuard<'_, T> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ (**self).fmt(f)
+ }
+}
+
+pub fn guard_lock<'a, T: ?Sized>(guard: &MutexGuard<'a, T>) -> &'a sys::Mutex {
+ &guard.__lock.inner
+}
+
+pub fn guard_poison<'a, T: ?Sized>(guard: &MutexGuard<'a, T>) -> &'a poison::Flag {
+ &guard.__lock.poison
+}
+
+#[cfg(all(test, not(target_os = "emscripten")))]
+mod tests {
+ use crate::sync::mpsc::channel;
+ use crate::sync::{Arc, Mutex, Condvar};
+ use crate::sync::atomic::{AtomicUsize, Ordering};
+ use crate::thread;
+
+ struct Packet<T>(Arc<(Mutex<T>, Condvar)>);
+
+ #[derive(Eq, PartialEq, Debug)]
+ struct NonCopy(i32);
+
+ #[test]
+ fn smoke() {
+ let m = Mutex::new(());
+ drop(m.lock().unwrap());
+ drop(m.lock().unwrap());
+ }
+
+ #[test]
+ fn lots_and_lots() {
+ const J: u32 = 1000;
+ const K: u32 = 3;
+
+ let m = Arc::new(Mutex::new(0));
+
+ fn inc(m: &Mutex<u32>) {
+ for _ in 0..J {
+ *m.lock().unwrap() += 1;
+ }
+ }
+
+ let (tx, rx) = channel();
+ for _ in 0..K {
+ let tx2 = tx.clone();
+ let m2 = m.clone();
+ thread::spawn(move|| { inc(&m2); tx2.send(()).unwrap(); });
+ let tx2 = tx.clone();
+ let m2 = m.clone();
+ thread::spawn(move|| { inc(&m2); tx2.send(()).unwrap(); });
+ }
+
+ drop(tx);
+ for _ in 0..2 * K {
+ rx.recv().unwrap();
+ }
+ assert_eq!(*m.lock().unwrap(), J * K * 2);
+ }
+
+ #[test]
+ fn try_lock() {
+ let m = Mutex::new(());
+ *m.try_lock().unwrap() = ();
+ }
+
+ #[test]
+ fn test_into_inner() {
+ let m = Mutex::new(NonCopy(10));
+ assert_eq!(m.into_inner().unwrap(), NonCopy(10));
+ }
+
+ #[test]
+ fn test_into_inner_drop() {
+ struct Foo(Arc<AtomicUsize>);
+ impl Drop for Foo {
+ fn drop(&mut self) {
+ self.0.fetch_add(1, Ordering::SeqCst);
+ }
+ }
+ let num_drops = Arc::new(AtomicUsize::new(0));
+ let m = Mutex::new(Foo(num_drops.clone()));
+ assert_eq!(num_drops.load(Ordering::SeqCst), 0);
+ {
+ let _inner = m.into_inner().unwrap();
+ assert_eq!(num_drops.load(Ordering::SeqCst), 0);
+ }
+ assert_eq!(num_drops.load(Ordering::SeqCst), 1);
+ }
+
+ #[test]
+ fn test_into_inner_poison() {
+ let m = Arc::new(Mutex::new(NonCopy(10)));
+ let m2 = m.clone();
+ let _ = thread::spawn(move || {
+ let _lock = m2.lock().unwrap();
+ panic!("test panic in inner thread to poison mutex");
+ }).join();
+
+ assert!(m.is_poisoned());
+ match Arc::try_unwrap(m).unwrap().into_inner() {
+ Err(e) => assert_eq!(e.into_inner(), NonCopy(10)),
+ Ok(x) => panic!("into_inner of poisoned Mutex is Ok: {:?}", x),
+ }
+ }
+
+ #[test]
+ fn test_get_mut() {
+ let mut m = Mutex::new(NonCopy(10));
+ *m.get_mut().unwrap() = NonCopy(20);
+ assert_eq!(m.into_inner().unwrap(), NonCopy(20));
+ }
+
+ #[test]
+ fn test_get_mut_poison() {
+ let m = Arc::new(Mutex::new(NonCopy(10)));
+ let m2 = m.clone();
+ let _ = thread::spawn(move || {
+ let _lock = m2.lock().unwrap();
+ panic!("test panic in inner thread to poison mutex");
+ }).join();
+
+ assert!(m.is_poisoned());
+ match Arc::try_unwrap(m).unwrap().get_mut() {
+ Err(e) => assert_eq!(*e.into_inner(), NonCopy(10)),
+ Ok(x) => panic!("get_mut of poisoned Mutex is Ok: {:?}", x),
+ }
+ }
+
+ #[test]
+ fn test_mutex_arc_condvar() {
+ let packet = Packet(Arc::new((Mutex::new(false), Condvar::new())));
+ let packet2 = Packet(packet.0.clone());
+ let (tx, rx) = channel();
+ let _t = thread::spawn(move|| {
+ // wait until parent gets in
+ rx.recv().unwrap();
+ let &(ref lock, ref cvar) = &*packet2.0;
+ let mut lock = lock.lock().unwrap();
+ *lock = true;
+ cvar.notify_one();
+ });
+
+ let &(ref lock, ref cvar) = &*packet.0;
+ let mut lock = lock.lock().unwrap();
+ tx.send(()).unwrap();
+ assert!(!*lock);
+ while !*lock {
+ lock = cvar.wait(lock).unwrap();
+ }
+ }
+
+ #[test]
+ fn test_arc_condvar_poison() {
+ let packet = Packet(Arc::new((Mutex::new(1), Condvar::new())));
+ let packet2 = Packet(packet.0.clone());
+ let (tx, rx) = channel();
+
+ let _t = thread::spawn(move || -> () {
+ rx.recv().unwrap();
+ let &(ref lock, ref cvar) = &*packet2.0;
+ let _g = lock.lock().unwrap();
+ cvar.notify_one();
+ // Parent should fail when it wakes up.
+ panic!();
+ });
+
+ let &(ref lock, ref cvar) = &*packet.0;
+ let mut lock = lock.lock().unwrap();
+ tx.send(()).unwrap();
+ while *lock == 1 {
+ match cvar.wait(lock) {
+ Ok(l) => {
+ lock = l;
+ assert_eq!(*lock, 1);
+ }
+ Err(..) => break,
+ }
+ }
+ }
+
+ #[test]
+ fn test_mutex_arc_poison() {
+ let arc = Arc::new(Mutex::new(1));
+ assert!(!arc.is_poisoned());
+ let arc2 = arc.clone();
+ let _ = thread::spawn(move|| {
+ let lock = arc2.lock().unwrap();
+ assert_eq!(*lock, 2);
+ }).join();
+ assert!(arc.lock().is_err());
+ assert!(arc.is_poisoned());
+ }
+
+ #[test]
+ fn test_mutex_arc_nested() {
+ // Tests nested mutexes and access
+ // to underlying data.
+ let arc = Arc::new(Mutex::new(1));
+ let arc2 = Arc::new(Mutex::new(arc));
+ let (tx, rx) = channel();
+ let _t = thread::spawn(move|| {
+ let lock = arc2.lock().unwrap();
+ let lock2 = lock.lock().unwrap();
+ assert_eq!(*lock2, 1);
+ tx.send(()).unwrap();
+ });
+ rx.recv().unwrap();
+ }
+
+ #[test]
+ fn test_mutex_arc_access_in_unwind() {
+ let arc = Arc::new(Mutex::new(1));
+ let arc2 = arc.clone();
+ let _ = thread::spawn(move|| -> () {
+ struct Unwinder {
+ i: Arc<Mutex<i32>>,
+ }
+ impl Drop for Unwinder {
+ fn drop(&mut self) {
+ *self.i.lock().unwrap() += 1;
+ }
+ }
+ let _u = Unwinder { i: arc2 };
+ panic!();
+ }).join();
+ let lock = arc.lock().unwrap();
+ assert_eq!(*lock, 2);
+ }
+
+ #[test]
+ fn test_mutex_unsized() {
+ let mutex: &Mutex<[i32]> = &Mutex::new([1, 2, 3]);
+ {
+ let b = &mut *mutex.lock().unwrap();
+ b[0] = 4;
+ b[2] = 5;
+ }
+ let comp: &[i32] = &[4, 2, 5];
+ assert_eq!(&*mutex.lock().unwrap(), comp);
+ }
+}
diff --git a/src/libstd/sync/once.rs b/src/libstd/sync/once.rs
new file mode 100644
index 0000000..0c91249
--- /dev/null
+++ b/src/libstd/sync/once.rs
@@ -0,0 +1,632 @@
+//! A "once initialization" primitive
+//!
+//! This primitive is meant to be used to run one-time initialization. An
+//! example use case would be for initializing an FFI library.
+
+// A "once" is a relatively simple primitive, and it's also typically provided
+// by the OS as well (see `pthread_once` or `InitOnceExecuteOnce`). The OS
+// primitives, however, tend to have surprising restrictions, such as the Unix
+// one doesn't allow an argument to be passed to the function.
+//
+// As a result, we end up implementing it ourselves in the standard library.
+// This also gives us the opportunity to optimize the implementation a bit which
+// should help the fast path on call sites. Consequently, let's explain how this
+// primitive works now!
+//
+// So to recap, the guarantees of a Once are that it will call the
+// initialization closure at most once, and it will never return until the one
+// that's running has finished running. This means that we need some form of
+// blocking here while the custom callback is running at the very least.
+// Additionally, we add on the restriction of **poisoning**. Whenever an
+// initialization closure panics, the Once enters a "poisoned" state which means
+// that all future calls will immediately panic as well.
+//
+// So to implement this, one might first reach for a `Mutex`, but those cannot
+// be put into a `static`. It also gets a lot harder with poisoning to figure
+// out when the mutex needs to be deallocated because it's not after the closure
+// finishes, but after the first successful closure finishes.
+//
+// All in all, this is instead implemented with atomics and lock-free
+// operations! Whee! Each `Once` has one word of atomic state, and this state is
+// CAS'd on to determine what to do. There are four possible state of a `Once`:
+//
+// * Incomplete - no initialization has run yet, and no thread is currently
+// using the Once.
+// * Poisoned - some thread has previously attempted to initialize the Once, but
+// it panicked, so the Once is now poisoned. There are no other
+// threads currently accessing this Once.
+// * Running - some thread is currently attempting to run initialization. It may
+// succeed, so all future threads need to wait for it to finish.
+// Note that this state is accompanied with a payload, described
+// below.
+// * Complete - initialization has completed and all future calls should finish
+// immediately.
+//
+// With 4 states we need 2 bits to encode this, and we use the remaining bits
+// in the word we have allocated as a queue of threads waiting for the thread
+// responsible for entering the RUNNING state. This queue is just a linked list
+// of Waiter nodes which is monotonically increasing in size. Each node is
+// allocated on the stack, and whenever the running closure finishes it will
+// consume the entire queue and notify all waiters they should try again.
+//
+// You'll find a few more details in the implementation, but that's the gist of
+// it!
+
+use crate::fmt;
+use crate::marker;
+use crate::ptr;
+use crate::sync::atomic::{AtomicUsize, AtomicBool, Ordering};
+use crate::thread::{self, Thread};
+
+/// A synchronization primitive which can be used to run a one-time global
+/// initialization. Useful for one-time initialization for FFI or related
+/// functionality. This type can only be constructed with the [`ONCE_INIT`]
+/// value or the equivalent [`Once::new`] constructor.
+///
+/// [`ONCE_INIT`]: constant.ONCE_INIT.html
+/// [`Once::new`]: struct.Once.html#method.new
+///
+/// # Examples
+///
+/// ```
+/// use std::sync::Once;
+///
+/// static START: Once = Once::new();
+///
+/// START.call_once(|| {
+/// // run initialization here
+/// });
+/// ```
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct Once {
+ // This `state` word is actually an encoded version of just a pointer to a
+ // `Waiter`, so we add the `PhantomData` appropriately.
+ state: AtomicUsize,
+ _marker: marker::PhantomData<*mut Waiter>,
+}
+
+// The `PhantomData` of a raw pointer removes these two auto traits, but we
+// enforce both below in the implementation so this should be safe to add.
+#[stable(feature = "rust1", since = "1.0.0")]
+unsafe impl Sync for Once {}
+#[stable(feature = "rust1", since = "1.0.0")]
+unsafe impl Send for Once {}
+
+/// State yielded to [`call_once_force`]’s closure parameter. The state can be
+/// used to query the poison status of the [`Once`].
+///
+/// [`call_once_force`]: struct.Once.html#method.call_once_force
+/// [`Once`]: struct.Once.html
+#[unstable(feature = "once_poison", issue = "33577")]
+#[derive(Debug)]
+pub struct OnceState {
+ poisoned: bool,
+}
+
+/// Initialization value for static [`Once`] values.
+///
+/// [`Once`]: struct.Once.html
+///
+/// # Examples
+///
+/// ```
+/// use std::sync::{Once, ONCE_INIT};
+///
+/// static START: Once = ONCE_INIT;
+/// ```
+#[stable(feature = "rust1", since = "1.0.0")]
+pub const ONCE_INIT: Once = Once::new();
+
+// Four states that a Once can be in, encoded into the lower bits of `state` in
+// the Once structure.
+const INCOMPLETE: usize = 0x0;
+const POISONED: usize = 0x1;
+const RUNNING: usize = 0x2;
+const COMPLETE: usize = 0x3;
+
+// Mask to learn about the state. All other bits are the queue of waiters if
+// this is in the RUNNING state.
+const STATE_MASK: usize = 0x3;
+
+// Representation of a node in the linked list of waiters in the RUNNING state.
+struct Waiter {
+ thread: Option<Thread>,
+ signaled: AtomicBool,
+ next: *mut Waiter,
+}
+
+// Helper struct used to clean up after a closure call with a `Drop`
+// implementation to also run on panic.
+struct Finish<'a> {
+ panicked: bool,
+ me: &'a Once,
+}
+
+impl Once {
+ /// Creates a new `Once` value.
+ #[stable(feature = "once_new", since = "1.2.0")]
+ pub const fn new() -> Once {
+ Once {
+ state: AtomicUsize::new(INCOMPLETE),
+ _marker: marker::PhantomData,
+ }
+ }
+
+ /// Performs an initialization routine once and only once. The given closure
+ /// will be executed if this is the first time `call_once` has been called,
+ /// and otherwise the routine will *not* be invoked.
+ ///
+ /// This method will block the calling thread if another initialization
+ /// routine is currently running.
+ ///
+ /// When this function returns, it is guaranteed that some initialization
+ /// has run and completed (it may not be the closure specified). It is also
+ /// guaranteed that any memory writes performed by the executed closure can
+ /// be reliably observed by other threads at this point (there is a
+ /// happens-before relation between the closure and code executing after the
+ /// return).
+ ///
+ /// If the given closure recursively invokes `call_once` on the same `Once`
+ /// instance the exact behavior is not specified, allowed outcomes are
+ /// a panic or a deadlock.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::sync::Once;
+ ///
+ /// static mut VAL: usize = 0;
+ /// static INIT: Once = Once::new();
+ ///
+ /// // Accessing a `static mut` is unsafe much of the time, but if we do so
+ /// // in a synchronized fashion (e.g., write once or read all) then we're
+ /// // good to go!
+ /// //
+ /// // This function will only call `expensive_computation` once, and will
+ /// // otherwise always return the value returned from the first invocation.
+ /// fn get_cached_val() -> usize {
+ /// unsafe {
+ /// INIT.call_once(|| {
+ /// VAL = expensive_computation();
+ /// });
+ /// VAL
+ /// }
+ /// }
+ ///
+ /// fn expensive_computation() -> usize {
+ /// // ...
+ /// # 2
+ /// }
+ /// ```
+ ///
+ /// # Panics
+ ///
+ /// The closure `f` will only be executed once if this is called
+ /// concurrently amongst many threads. If that closure panics, however, then
+ /// it will *poison* this `Once` instance, causing all future invocations of
+ /// `call_once` to also panic.
+ ///
+ /// This is similar to [poisoning with mutexes][poison].
+ ///
+ /// [poison]: struct.Mutex.html#poisoning
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn call_once<F>(&self, f: F) where F: FnOnce() {
+ // Fast path check
+ if self.is_completed() {
+ return;
+ }
+
+ let mut f = Some(f);
+ self.call_inner(false, &mut |_| f.take().unwrap()());
+ }
+
+ /// Performs the same function as [`call_once`] except ignores poisoning.
+ ///
+ /// Unlike [`call_once`], if this `Once` has been poisoned (i.e., a previous
+ /// call to `call_once` or `call_once_force` caused a panic), calling
+ /// `call_once_force` will still invoke the closure `f` and will _not_
+ /// result in an immediate panic. If `f` panics, the `Once` will remain
+ /// in a poison state. If `f` does _not_ panic, the `Once` will no
+ /// longer be in a poison state and all future calls to `call_once` or
+ /// `call_one_force` will be no-ops.
+ ///
+ /// The closure `f` is yielded a [`OnceState`] structure which can be used
+ /// to query the poison status of the `Once`.
+ ///
+ /// [`call_once`]: struct.Once.html#method.call_once
+ /// [`OnceState`]: struct.OnceState.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(once_poison)]
+ ///
+ /// use std::sync::Once;
+ /// use std::thread;
+ ///
+ /// static INIT: Once = Once::new();
+ ///
+ /// // poison the once
+ /// let handle = thread::spawn(|| {
+ /// INIT.call_once(|| panic!());
+ /// });
+ /// assert!(handle.join().is_err());
+ ///
+ /// // poisoning propagates
+ /// let handle = thread::spawn(|| {
+ /// INIT.call_once(|| {});
+ /// });
+ /// assert!(handle.join().is_err());
+ ///
+ /// // call_once_force will still run and reset the poisoned state
+ /// INIT.call_once_force(|state| {
+ /// assert!(state.poisoned());
+ /// });
+ ///
+ /// // once any success happens, we stop propagating the poison
+ /// INIT.call_once(|| {});
+ /// ```
+ #[unstable(feature = "once_poison", issue = "33577")]
+ pub fn call_once_force<F>(&self, f: F) where F: FnOnce(&OnceState) {
+ // Fast path check
+ if self.is_completed() {
+ return;
+ }
+
+ let mut f = Some(f);
+ self.call_inner(true, &mut |p| {
+ f.take().unwrap()(&OnceState { poisoned: p })
+ });
+ }
+
+ /// Returns `true` if some `call_once` call has completed
+ /// successfully. Specifically, `is_completed` will return false in
+ /// the following situations:
+ /// * `call_once` was not called at all,
+ /// * `call_once` was called, but has not yet completed,
+ /// * the `Once` instance is poisoned
+ ///
+ /// It is also possible that immediately after `is_completed`
+ /// returns false, some other thread finishes executing
+ /// `call_once`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(once_is_completed)]
+ /// use std::sync::Once;
+ ///
+ /// static INIT: Once = Once::new();
+ ///
+ /// assert_eq!(INIT.is_completed(), false);
+ /// INIT.call_once(|| {
+ /// assert_eq!(INIT.is_completed(), false);
+ /// });
+ /// assert_eq!(INIT.is_completed(), true);
+ /// ```
+ ///
+ /// ```
+ /// #![feature(once_is_completed)]
+ /// use std::sync::Once;
+ /// use std::thread;
+ ///
+ /// static INIT: Once = Once::new();
+ ///
+ /// assert_eq!(INIT.is_completed(), false);
+ /// let handle = thread::spawn(|| {
+ /// INIT.call_once(|| panic!());
+ /// });
+ /// assert!(handle.join().is_err());
+ /// assert_eq!(INIT.is_completed(), false);
+ /// ```
+ #[unstable(feature = "once_is_completed", issue = "54890")]
+ #[inline]
+ pub fn is_completed(&self) -> bool {
+ // An `Acquire` load is enough because that makes all the initialization
+ // operations visible to us, and, this being a fast path, weaker
+ // ordering helps with performance. This `Acquire` synchronizes with
+ // `SeqCst` operations on the slow path.
+ self.state.load(Ordering::Acquire) == COMPLETE
+ }
+
+ // This is a non-generic function to reduce the monomorphization cost of
+ // using `call_once` (this isn't exactly a trivial or small implementation).
+ //
+ // Additionally, this is tagged with `#[cold]` as it should indeed be cold
+ // and it helps let LLVM know that calls to this function should be off the
+ // fast path. Essentially, this should help generate more straight line code
+ // in LLVM.
+ //
+ // Finally, this takes an `FnMut` instead of a `FnOnce` because there's
+ // currently no way to take an `FnOnce` and call it via virtual dispatch
+ // without some allocation overhead.
+ #[cold]
+ fn call_inner(&self,
+ ignore_poisoning: bool,
+ init: &mut dyn FnMut(bool)) {
+
+ // This cold path uses SeqCst consistently because the
+ // performance difference really does not matter there, and
+ // SeqCst minimizes the chances of something going wrong.
+ let mut state = self.state.load(Ordering::SeqCst);
+
+ 'outer: loop {
+ match state {
+ // If we're complete, then there's nothing to do, we just
+ // jettison out as we shouldn't run the closure.
+ COMPLETE => return,
+
+ // If we're poisoned and we're not in a mode to ignore
+ // poisoning, then we panic here to propagate the poison.
+ POISONED if !ignore_poisoning => {
+ panic!("Once instance has previously been poisoned");
+ }
+
+ // Otherwise if we see a poisoned or otherwise incomplete state
+ // we will attempt to move ourselves into the RUNNING state. If
+ // we succeed, then the queue of waiters starts at null (all 0
+ // bits).
+ POISONED |
+ INCOMPLETE => {
+ let old = self.state.compare_and_swap(state, RUNNING,
+ Ordering::SeqCst);
+ if old != state {
+ state = old;
+ continue
+ }
+
+ // Run the initialization routine, letting it know if we're
+ // poisoned or not. The `Finish` struct is then dropped, and
+ // the `Drop` implementation here is responsible for waking
+ // up other waiters both in the normal return and panicking
+ // case.
+ let mut complete = Finish {
+ panicked: true,
+ me: self,
+ };
+ init(state == POISONED);
+ complete.panicked = false;
+ return
+ }
+
+ // All other values we find should correspond to the RUNNING
+ // state with an encoded waiter list in the more significant
+ // bits. We attempt to enqueue ourselves by moving us to the
+ // head of the list and bail out if we ever see a state that's
+ // not RUNNING.
+ _ => {
+ assert!(state & STATE_MASK == RUNNING);
+ let mut node = Waiter {
+ thread: Some(thread::current()),
+ signaled: AtomicBool::new(false),
+ next: ptr::null_mut(),
+ };
+ let me = &mut node as *mut Waiter as usize;
+ assert!(me & STATE_MASK == 0);
+
+ while state & STATE_MASK == RUNNING {
+ node.next = (state & !STATE_MASK) as *mut Waiter;
+ let old = self.state.compare_and_swap(state,
+ me | RUNNING,
+ Ordering::SeqCst);
+ if old != state {
+ state = old;
+ continue
+ }
+
+ // Once we've enqueued ourselves, wait in a loop.
+ // Afterwards reload the state and continue with what we
+ // were doing from before.
+ while !node.signaled.load(Ordering::SeqCst) {
+ thread::park();
+ }
+ state = self.state.load(Ordering::SeqCst);
+ continue 'outer
+ }
+ }
+ }
+ }
+ }
+}
+
+#[stable(feature = "std_debug", since = "1.16.0")]
+impl fmt::Debug for Once {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.pad("Once { .. }")
+ }
+}
+
+impl Drop for Finish<'_> {
+ fn drop(&mut self) {
+ // Swap out our state with however we finished. We should only ever see
+ // an old state which was RUNNING.
+ let queue = if self.panicked {
+ self.me.state.swap(POISONED, Ordering::SeqCst)
+ } else {
+ self.me.state.swap(COMPLETE, Ordering::SeqCst)
+ };
+ assert_eq!(queue & STATE_MASK, RUNNING);
+
+ // Decode the RUNNING to a list of waiters, then walk that entire list
+ // and wake them up. Note that it is crucial that after we store `true`
+ // in the node it can be free'd! As a result we load the `thread` to
+ // signal ahead of time and then unpark it after the store.
+ unsafe {
+ let mut queue = (queue & !STATE_MASK) as *mut Waiter;
+ while !queue.is_null() {
+ let next = (*queue).next;
+ let thread = (*queue).thread.take().unwrap();
+ (*queue).signaled.store(true, Ordering::SeqCst);
+ thread.unpark();
+ queue = next;
+ }
+ }
+ }
+}
+
+impl OnceState {
+ /// Returns `true` if the associated [`Once`] was poisoned prior to the
+ /// invocation of the closure passed to [`call_once_force`].
+ ///
+ /// [`call_once_force`]: struct.Once.html#method.call_once_force
+ /// [`Once`]: struct.Once.html
+ ///
+ /// # Examples
+ ///
+ /// A poisoned `Once`:
+ ///
+ /// ```
+ /// #![feature(once_poison)]
+ ///
+ /// use std::sync::Once;
+ /// use std::thread;
+ ///
+ /// static INIT: Once = Once::new();
+ ///
+ /// // poison the once
+ /// let handle = thread::spawn(|| {
+ /// INIT.call_once(|| panic!());
+ /// });
+ /// assert!(handle.join().is_err());
+ ///
+ /// INIT.call_once_force(|state| {
+ /// assert!(state.poisoned());
+ /// });
+ /// ```
+ ///
+ /// An unpoisoned `Once`:
+ ///
+ /// ```
+ /// #![feature(once_poison)]
+ ///
+ /// use std::sync::Once;
+ ///
+ /// static INIT: Once = Once::new();
+ ///
+ /// INIT.call_once_force(|state| {
+ /// assert!(!state.poisoned());
+ /// });
+ #[unstable(feature = "once_poison", issue = "33577")]
+ pub fn poisoned(&self) -> bool {
+ self.poisoned
+ }
+}
+
+#[cfg(all(test, not(target_os = "emscripten")))]
+mod tests {
+ use crate::panic;
+ use crate::sync::mpsc::channel;
+ use crate::thread;
+ use super::Once;
+
+ #[test]
+ fn smoke_once() {
+ static O: Once = Once::new();
+ let mut a = 0;
+ O.call_once(|| a += 1);
+ assert_eq!(a, 1);
+ O.call_once(|| a += 1);
+ assert_eq!(a, 1);
+ }
+
+ #[test]
+ fn stampede_once() {
+ static O: Once = Once::new();
+ static mut RUN: bool = false;
+
+ let (tx, rx) = channel();
+ for _ in 0..10 {
+ let tx = tx.clone();
+ thread::spawn(move|| {
+ for _ in 0..4 { thread::yield_now() }
+ unsafe {
+ O.call_once(|| {
+ assert!(!RUN);
+ RUN = true;
+ });
+ assert!(RUN);
+ }
+ tx.send(()).unwrap();
+ });
+ }
+
+ unsafe {
+ O.call_once(|| {
+ assert!(!RUN);
+ RUN = true;
+ });
+ assert!(RUN);
+ }
+
+ for _ in 0..10 {
+ rx.recv().unwrap();
+ }
+ }
+
+ #[test]
+ fn poison_bad() {
+ static O: Once = Once::new();
+
+ // poison the once
+ let t = panic::catch_unwind(|| {
+ O.call_once(|| panic!());
+ });
+ assert!(t.is_err());
+
+ // poisoning propagates
+ let t = panic::catch_unwind(|| {
+ O.call_once(|| {});
+ });
+ assert!(t.is_err());
+
+ // we can subvert poisoning, however
+ let mut called = false;
+ O.call_once_force(|p| {
+ called = true;
+ assert!(p.poisoned())
+ });
+ assert!(called);
+
+ // once any success happens, we stop propagating the poison
+ O.call_once(|| {});
+ }
+
+ #[test]
+ fn wait_for_force_to_finish() {
+ static O: Once = Once::new();
+
+ // poison the once
+ let t = panic::catch_unwind(|| {
+ O.call_once(|| panic!());
+ });
+ assert!(t.is_err());
+
+ // make sure someone's waiting inside the once via a force
+ let (tx1, rx1) = channel();
+ let (tx2, rx2) = channel();
+ let t1 = thread::spawn(move || {
+ O.call_once_force(|p| {
+ assert!(p.poisoned());
+ tx1.send(()).unwrap();
+ rx2.recv().unwrap();
+ });
+ });
+
+ rx1.recv().unwrap();
+
+ // put another waiter on the once
+ let t2 = thread::spawn(|| {
+ let mut called = false;
+ O.call_once(|| {
+ called = true;
+ });
+ assert!(!called);
+ });
+
+ tx2.send(()).unwrap();
+
+ assert!(t1.join().is_ok());
+ assert!(t2.join().is_ok());
+
+ }
+}
diff --git a/src/libstd/sync/rwlock.rs b/src/libstd/sync/rwlock.rs
new file mode 100644
index 0000000..1299a74
--- /dev/null
+++ b/src/libstd/sync/rwlock.rs
@@ -0,0 +1,798 @@
+use crate::cell::UnsafeCell;
+use crate::fmt;
+use crate::mem;
+use crate::ops::{Deref, DerefMut};
+use crate::ptr;
+use crate::sys_common::poison::{self, LockResult, TryLockError, TryLockResult};
+use crate::sys_common::rwlock as sys;
+
+/// A reader-writer lock
+///
+/// This type of lock allows a number of readers or at most one writer at any
+/// point in time. The write portion of this lock typically allows modification
+/// of the underlying data (exclusive access) and the read portion of this lock
+/// typically allows for read-only access (shared access).
+///
+/// In comparison, a [`Mutex`] does not distinguish between readers or writers
+/// that acquire the lock, therefore blocking any threads waiting for the lock to
+/// become available. An `RwLock` will allow any number of readers to acquire the
+/// lock as long as a writer is not holding the lock.
+///
+/// The priority policy of the lock is dependent on the underlying operating
+/// system's implementation, and this type does not guarantee that any
+/// particular policy will be used.
+///
+/// The type parameter `T` represents the data that this lock protects. It is
+/// required that `T` satisfies [`Send`] to be shared across threads and
+/// [`Sync`] to allow concurrent access through readers. The RAII guards
+/// returned from the locking methods implement [`Deref`][] (and [`DerefMut`]
+/// for the `write` methods) to allow access to the content of the lock.
+///
+/// # Poisoning
+///
+/// An `RwLock`, like [`Mutex`], will become poisoned on a panic. Note, however,
+/// that an `RwLock` may only be poisoned if a panic occurs while it is locked
+/// exclusively (write mode). If a panic occurs in any reader, then the lock
+/// will not be poisoned.
+///
+/// # Examples
+///
+/// ```
+/// use std::sync::RwLock;
+///
+/// let lock = RwLock::new(5);
+///
+/// // many reader locks can be held at once
+/// {
+/// let r1 = lock.read().unwrap();
+/// let r2 = lock.read().unwrap();
+/// assert_eq!(*r1, 5);
+/// assert_eq!(*r2, 5);
+/// } // read locks are dropped at this point
+///
+/// // only one write lock may be held, however
+/// {
+/// let mut w = lock.write().unwrap();
+/// *w += 1;
+/// assert_eq!(*w, 6);
+/// } // write lock is dropped here
+/// ```
+///
+/// [`Deref`]: ../../std/ops/trait.Deref.html
+/// [`DerefMut`]: ../../std/ops/trait.DerefMut.html
+/// [`Send`]: ../../std/marker/trait.Send.html
+/// [`Sync`]: ../../std/marker/trait.Sync.html
+/// [`Mutex`]: struct.Mutex.html
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct RwLock<T: ?Sized> {
+ inner: Box<sys::RWLock>,
+ poison: poison::Flag,
+ data: UnsafeCell<T>,
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+unsafe impl<T: ?Sized + Send> Send for RwLock<T> {}
+#[stable(feature = "rust1", since = "1.0.0")]
+unsafe impl<T: ?Sized + Send + Sync> Sync for RwLock<T> {}
+
+/// RAII structure used to release the shared read access of a lock when
+/// dropped.
+///
+/// This structure is created by the [`read`] and [`try_read`] methods on
+/// [`RwLock`].
+///
+/// [`read`]: struct.RwLock.html#method.read
+/// [`try_read`]: struct.RwLock.html#method.try_read
+/// [`RwLock`]: struct.RwLock.html
+#[must_use = "if unused the RwLock will immediately unlock"]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct RwLockReadGuard<'a, T: ?Sized + 'a> {
+ __lock: &'a RwLock<T>,
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T: ?Sized> !Send for RwLockReadGuard<'_, T> {}
+
+#[stable(feature = "rwlock_guard_sync", since = "1.23.0")]
+unsafe impl<T: ?Sized + Sync> Sync for RwLockReadGuard<'_, T> {}
+
+/// RAII structure used to release the exclusive write access of a lock when
+/// dropped.
+///
+/// This structure is created by the [`write`] and [`try_write`] methods
+/// on [`RwLock`].
+///
+/// [`write`]: struct.RwLock.html#method.write
+/// [`try_write`]: struct.RwLock.html#method.try_write
+/// [`RwLock`]: struct.RwLock.html
+#[must_use = "if unused the RwLock will immediately unlock"]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct RwLockWriteGuard<'a, T: ?Sized + 'a> {
+ __lock: &'a RwLock<T>,
+ __poison: poison::Guard,
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T: ?Sized> !Send for RwLockWriteGuard<'_, T> {}
+
+#[stable(feature = "rwlock_guard_sync", since = "1.23.0")]
+unsafe impl<T: ?Sized + Sync> Sync for RwLockWriteGuard<'_, T> {}
+
+impl<T> RwLock<T> {
+ /// Creates a new instance of an `RwLock<T>` which is unlocked.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::sync::RwLock;
+ ///
+ /// let lock = RwLock::new(5);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn new(t: T) -> RwLock<T> {
+ RwLock {
+ inner: box sys::RWLock::new(),
+ poison: poison::Flag::new(),
+ data: UnsafeCell::new(t),
+ }
+ }
+}
+
+impl<T: ?Sized> RwLock<T> {
+ /// Locks this rwlock with shared read access, blocking the current thread
+ /// until it can be acquired.
+ ///
+ /// The calling thread will be blocked until there are no more writers which
+ /// hold the lock. There may be other readers currently inside the lock when
+ /// this method returns. This method does not provide any guarantees with
+ /// respect to the ordering of whether contentious readers or writers will
+ /// acquire the lock first.
+ ///
+ /// Returns an RAII guard which will release this thread's shared access
+ /// once it is dropped.
+ ///
+ /// # Errors
+ ///
+ /// This function will return an error if the RwLock is poisoned. An RwLock
+ /// is poisoned whenever a writer panics while holding an exclusive lock.
+ /// The failure will occur immediately after the lock has been acquired.
+ ///
+ /// # Panics
+ ///
+ /// This function might panic when called if the lock is already held by the current thread.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::sync::{Arc, RwLock};
+ /// use std::thread;
+ ///
+ /// let lock = Arc::new(RwLock::new(1));
+ /// let c_lock = lock.clone();
+ ///
+ /// let n = lock.read().unwrap();
+ /// assert_eq!(*n, 1);
+ ///
+ /// thread::spawn(move || {
+ /// let r = c_lock.read();
+ /// assert!(r.is_ok());
+ /// }).join().unwrap();
+ /// ```
+ #[inline]
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn read(&self) -> LockResult<RwLockReadGuard<'_, T>> {
+ unsafe {
+ self.inner.read();
+ RwLockReadGuard::new(self)
+ }
+ }
+
+ /// Attempts to acquire this rwlock with shared read access.
+ ///
+ /// If the access could not be granted at this time, then `Err` is returned.
+ /// Otherwise, an RAII guard is returned which will release the shared access
+ /// when it is dropped.
+ ///
+ /// This function does not block.
+ ///
+ /// This function does not provide any guarantees with respect to the ordering
+ /// of whether contentious readers or writers will acquire the lock first.
+ ///
+ /// # Errors
+ ///
+ /// This function will return an error if the RwLock is poisoned. An RwLock
+ /// is poisoned whenever a writer panics while holding an exclusive lock. An
+ /// error will only be returned if the lock would have otherwise been
+ /// acquired.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::sync::RwLock;
+ ///
+ /// let lock = RwLock::new(1);
+ ///
+ /// match lock.try_read() {
+ /// Ok(n) => assert_eq!(*n, 1),
+ /// Err(_) => unreachable!(),
+ /// };
+ /// ```
+ #[inline]
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn try_read(&self) -> TryLockResult<RwLockReadGuard<'_, T>> {
+ unsafe {
+ if self.inner.try_read() {
+ Ok(RwLockReadGuard::new(self)?)
+ } else {
+ Err(TryLockError::WouldBlock)
+ }
+ }
+ }
+
+ /// Locks this rwlock with exclusive write access, blocking the current
+ /// thread until it can be acquired.
+ ///
+ /// This function will not return while other writers or other readers
+ /// currently have access to the lock.
+ ///
+ /// Returns an RAII guard which will drop the write access of this rwlock
+ /// when dropped.
+ ///
+ /// # Errors
+ ///
+ /// This function will return an error if the RwLock is poisoned. An RwLock
+ /// is poisoned whenever a writer panics while holding an exclusive lock.
+ /// An error will be returned when the lock is acquired.
+ ///
+ /// # Panics
+ ///
+ /// This function might panic when called if the lock is already held by the current thread.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::sync::RwLock;
+ ///
+ /// let lock = RwLock::new(1);
+ ///
+ /// let mut n = lock.write().unwrap();
+ /// *n = 2;
+ ///
+ /// assert!(lock.try_read().is_err());
+ /// ```
+ #[inline]
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn write(&self) -> LockResult<RwLockWriteGuard<'_, T>> {
+ unsafe {
+ self.inner.write();
+ RwLockWriteGuard::new(self)
+ }
+ }
+
+ /// Attempts to lock this rwlock with exclusive write access.
+ ///
+ /// If the lock could not be acquired at this time, then `Err` is returned.
+ /// Otherwise, an RAII guard is returned which will release the lock when
+ /// it is dropped.
+ ///
+ /// This function does not block.
+ ///
+ /// This function does not provide any guarantees with respect to the ordering
+ /// of whether contentious readers or writers will acquire the lock first.
+ ///
+ /// # Errors
+ ///
+ /// This function will return an error if the RwLock is poisoned. An RwLock
+ /// is poisoned whenever a writer panics while holding an exclusive lock. An
+ /// error will only be returned if the lock would have otherwise been
+ /// acquired.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::sync::RwLock;
+ ///
+ /// let lock = RwLock::new(1);
+ ///
+ /// let n = lock.read().unwrap();
+ /// assert_eq!(*n, 1);
+ ///
+ /// assert!(lock.try_write().is_err());
+ /// ```
+ #[inline]
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn try_write(&self) -> TryLockResult<RwLockWriteGuard<'_, T>> {
+ unsafe {
+ if self.inner.try_write() {
+ Ok(RwLockWriteGuard::new(self)?)
+ } else {
+ Err(TryLockError::WouldBlock)
+ }
+ }
+ }
+
+ /// Determines whether the lock is poisoned.
+ ///
+ /// If another thread is active, the lock can still become poisoned at any
+ /// time. You should not trust a `false` value for program correctness
+ /// without additional synchronization.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::sync::{Arc, RwLock};
+ /// use std::thread;
+ ///
+ /// let lock = Arc::new(RwLock::new(0));
+ /// let c_lock = lock.clone();
+ ///
+ /// let _ = thread::spawn(move || {
+ /// let _lock = c_lock.write().unwrap();
+ /// panic!(); // the lock gets poisoned
+ /// }).join();
+ /// assert_eq!(lock.is_poisoned(), true);
+ /// ```
+ #[inline]
+ #[stable(feature = "sync_poison", since = "1.2.0")]
+ pub fn is_poisoned(&self) -> bool {
+ self.poison.get()
+ }
+
+ /// Consumes this `RwLock`, returning the underlying data.
+ ///
+ /// # Errors
+ ///
+ /// This function will return an error if the RwLock is poisoned. An RwLock
+ /// is poisoned whenever a writer panics while holding an exclusive lock. An
+ /// error will only be returned if the lock would have otherwise been
+ /// acquired.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::sync::RwLock;
+ ///
+ /// let lock = RwLock::new(String::new());
+ /// {
+ /// let mut s = lock.write().unwrap();
+ /// *s = "modified".to_owned();
+ /// }
+ /// assert_eq!(lock.into_inner().unwrap(), "modified");
+ /// ```
+ #[stable(feature = "rwlock_into_inner", since = "1.6.0")]
+ pub fn into_inner(self) -> LockResult<T> where T: Sized {
+ // We know statically that there are no outstanding references to
+ // `self` so there's no need to lock the inner lock.
+ //
+ // To get the inner value, we'd like to call `data.into_inner()`,
+ // but because `RwLock` impl-s `Drop`, we can't move out of it, so
+ // we'll have to destructure it manually instead.
+ unsafe {
+ // Like `let RwLock { inner, poison, data } = self`.
+ let (inner, poison, data) = {
+ let RwLock { ref inner, ref poison, ref data } = self;
+ (ptr::read(inner), ptr::read(poison), ptr::read(data))
+ };
+ mem::forget(self);
+ inner.destroy(); // Keep in sync with the `Drop` impl.
+ drop(inner);
+
+ poison::map_result(poison.borrow(), |_| data.into_inner())
+ }
+ }
+
+ /// Returns a mutable reference to the underlying data.
+ ///
+ /// Since this call borrows the `RwLock` mutably, no actual locking needs to
+ /// take place -- the mutable borrow statically guarantees no locks exist.
+ ///
+ /// # Errors
+ ///
+ /// This function will return an error if the RwLock is poisoned. An RwLock
+ /// is poisoned whenever a writer panics while holding an exclusive lock. An
+ /// error will only be returned if the lock would have otherwise been
+ /// acquired.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::sync::RwLock;
+ ///
+ /// let mut lock = RwLock::new(0);
+ /// *lock.get_mut().unwrap() = 10;
+ /// assert_eq!(*lock.read().unwrap(), 10);
+ /// ```
+ #[stable(feature = "rwlock_get_mut", since = "1.6.0")]
+ pub fn get_mut(&mut self) -> LockResult<&mut T> {
+ // We know statically that there are no other references to `self`, so
+ // there's no need to lock the inner lock.
+ let data = unsafe { &mut *self.data.get() };
+ poison::map_result(self.poison.borrow(), |_| data)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+unsafe impl<#[may_dangle] T: ?Sized> Drop for RwLock<T> {
+ fn drop(&mut self) {
+ // IMPORTANT: This code needs to be kept in sync with `RwLock::into_inner`.
+ unsafe { self.inner.destroy() }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T: ?Sized + fmt::Debug> fmt::Debug for RwLock<T> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self.try_read() {
+ Ok(guard) => f.debug_struct("RwLock").field("data", &&*guard).finish(),
+ Err(TryLockError::Poisoned(err)) => {
+ f.debug_struct("RwLock").field("data", &&**err.get_ref()).finish()
+ },
+ Err(TryLockError::WouldBlock) => {
+ struct LockedPlaceholder;
+ impl fmt::Debug for LockedPlaceholder {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.write_str("<locked>")
+ }
+ }
+
+ f.debug_struct("RwLock").field("data", &LockedPlaceholder).finish()
+ }
+ }
+ }
+}
+
+#[stable(feature = "rw_lock_default", since = "1.10.0")]
+impl<T: Default> Default for RwLock<T> {
+ /// Creates a new `RwLock<T>`, with the `Default` value for T.
+ fn default() -> RwLock<T> {
+ RwLock::new(Default::default())
+ }
+}
+
+#[stable(feature = "rw_lock_from", since = "1.24.0")]
+impl<T> From<T> for RwLock<T> {
+ /// Creates a new instance of an `RwLock<T>` which is unlocked.
+ /// This is equivalent to [`RwLock::new`].
+ fn from(t: T) -> Self {
+ RwLock::new(t)
+ }
+}
+
+impl<'rwlock, T: ?Sized> RwLockReadGuard<'rwlock, T> {
+ unsafe fn new(lock: &'rwlock RwLock<T>)
+ -> LockResult<RwLockReadGuard<'rwlock, T>> {
+ poison::map_result(lock.poison.borrow(), |_| {
+ RwLockReadGuard {
+ __lock: lock,
+ }
+ })
+ }
+}
+
+impl<'rwlock, T: ?Sized> RwLockWriteGuard<'rwlock, T> {
+ unsafe fn new(lock: &'rwlock RwLock<T>)
+ -> LockResult<RwLockWriteGuard<'rwlock, T>> {
+ poison::map_result(lock.poison.borrow(), |guard| {
+ RwLockWriteGuard {
+ __lock: lock,
+ __poison: guard,
+ }
+ })
+ }
+}
+
+#[stable(feature = "std_debug", since = "1.16.0")]
+impl<T: fmt::Debug> fmt::Debug for RwLockReadGuard<'_, T> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("RwLockReadGuard")
+ .field("lock", &self.__lock)
+ .finish()
+ }
+}
+
+#[stable(feature = "std_guard_impls", since = "1.20.0")]
+impl<T: ?Sized + fmt::Display> fmt::Display for RwLockReadGuard<'_, T> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ (**self).fmt(f)
+ }
+}
+
+#[stable(feature = "std_debug", since = "1.16.0")]
+impl<T: fmt::Debug> fmt::Debug for RwLockWriteGuard<'_, T> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("RwLockWriteGuard")
+ .field("lock", &self.__lock)
+ .finish()
+ }
+}
+
+#[stable(feature = "std_guard_impls", since = "1.20.0")]
+impl<T: ?Sized + fmt::Display> fmt::Display for RwLockWriteGuard<'_, T> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ (**self).fmt(f)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T: ?Sized> Deref for RwLockReadGuard<'_, T> {
+ type Target = T;
+
+ fn deref(&self) -> &T {
+ unsafe { &*self.__lock.data.get() }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T: ?Sized> Deref for RwLockWriteGuard<'_, T> {
+ type Target = T;
+
+ fn deref(&self) -> &T {
+ unsafe { &*self.__lock.data.get() }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T: ?Sized> DerefMut for RwLockWriteGuard<'_, T> {
+ fn deref_mut(&mut self) -> &mut T {
+ unsafe { &mut *self.__lock.data.get() }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T: ?Sized> Drop for RwLockReadGuard<'_, T> {
+ fn drop(&mut self) {
+ unsafe { self.__lock.inner.read_unlock(); }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T: ?Sized> Drop for RwLockWriteGuard<'_, T> {
+ fn drop(&mut self) {
+ self.__lock.poison.done(&self.__poison);
+ unsafe { self.__lock.inner.write_unlock(); }
+ }
+}
+
+#[cfg(all(test, not(target_os = "emscripten")))]
+mod tests {
+ use rand::{self, Rng};
+ use crate::sync::mpsc::channel;
+ use crate::thread;
+ use crate::sync::{Arc, RwLock, TryLockError};
+ use crate::sync::atomic::{AtomicUsize, Ordering};
+
+ #[derive(Eq, PartialEq, Debug)]
+ struct NonCopy(i32);
+
+ #[test]
+ fn smoke() {
+ let l = RwLock::new(());
+ drop(l.read().unwrap());
+ drop(l.write().unwrap());
+ drop((l.read().unwrap(), l.read().unwrap()));
+ drop(l.write().unwrap());
+ }
+
+ #[test]
+ fn frob() {
+ const N: u32 = 10;
+ const M: usize = 1000;
+
+ let r = Arc::new(RwLock::new(()));
+
+ let (tx, rx) = channel::<()>();
+ for _ in 0..N {
+ let tx = tx.clone();
+ let r = r.clone();
+ thread::spawn(move || {
+ let mut rng = rand::thread_rng();
+ for _ in 0..M {
+ if rng.gen_bool(1.0 / (N as f64)) {
+ drop(r.write().unwrap());
+ } else {
+ drop(r.read().unwrap());
+ }
+ }
+ drop(tx);
+ });
+ }
+ drop(tx);
+ let _ = rx.recv();
+ }
+
+ #[test]
+ fn test_rw_arc_poison_wr() {
+ let arc = Arc::new(RwLock::new(1));
+ let arc2 = arc.clone();
+ let _: Result<(), _> = thread::spawn(move || {
+ let _lock = arc2.write().unwrap();
+ panic!();
+ }).join();
+ assert!(arc.read().is_err());
+ }
+
+ #[test]
+ fn test_rw_arc_poison_ww() {
+ let arc = Arc::new(RwLock::new(1));
+ assert!(!arc.is_poisoned());
+ let arc2 = arc.clone();
+ let _: Result<(), _> = thread::spawn(move || {
+ let _lock = arc2.write().unwrap();
+ panic!();
+ }).join();
+ assert!(arc.write().is_err());
+ assert!(arc.is_poisoned());
+ }
+
+ #[test]
+ fn test_rw_arc_no_poison_rr() {
+ let arc = Arc::new(RwLock::new(1));
+ let arc2 = arc.clone();
+ let _: Result<(), _> = thread::spawn(move || {
+ let _lock = arc2.read().unwrap();
+ panic!();
+ }).join();
+ let lock = arc.read().unwrap();
+ assert_eq!(*lock, 1);
+ }
+ #[test]
+ fn test_rw_arc_no_poison_rw() {
+ let arc = Arc::new(RwLock::new(1));
+ let arc2 = arc.clone();
+ let _: Result<(), _> = thread::spawn(move || {
+ let _lock = arc2.read().unwrap();
+ panic!()
+ }).join();
+ let lock = arc.write().unwrap();
+ assert_eq!(*lock, 1);
+ }
+
+ #[test]
+ fn test_rw_arc() {
+ let arc = Arc::new(RwLock::new(0));
+ let arc2 = arc.clone();
+ let (tx, rx) = channel();
+
+ thread::spawn(move || {
+ let mut lock = arc2.write().unwrap();
+ for _ in 0..10 {
+ let tmp = *lock;
+ *lock = -1;
+ thread::yield_now();
+ *lock = tmp + 1;
+ }
+ tx.send(()).unwrap();
+ });
+
+ // Readers try to catch the writer in the act
+ let mut children = Vec::new();
+ for _ in 0..5 {
+ let arc3 = arc.clone();
+ children.push(thread::spawn(move || {
+ let lock = arc3.read().unwrap();
+ assert!(*lock >= 0);
+ }));
+ }
+
+ // Wait for children to pass their asserts
+ for r in children {
+ assert!(r.join().is_ok());
+ }
+
+ // Wait for writer to finish
+ rx.recv().unwrap();
+ let lock = arc.read().unwrap();
+ assert_eq!(*lock, 10);
+ }
+
+ #[test]
+ fn test_rw_arc_access_in_unwind() {
+ let arc = Arc::new(RwLock::new(1));
+ let arc2 = arc.clone();
+ let _ = thread::spawn(move || -> () {
+ struct Unwinder {
+ i: Arc<RwLock<isize>>,
+ }
+ impl Drop for Unwinder {
+ fn drop(&mut self) {
+ let mut lock = self.i.write().unwrap();
+ *lock += 1;
+ }
+ }
+ let _u = Unwinder { i: arc2 };
+ panic!();
+ }).join();
+ let lock = arc.read().unwrap();
+ assert_eq!(*lock, 2);
+ }
+
+ #[test]
+ fn test_rwlock_unsized() {
+ let rw: &RwLock<[i32]> = &RwLock::new([1, 2, 3]);
+ {
+ let b = &mut *rw.write().unwrap();
+ b[0] = 4;
+ b[2] = 5;
+ }
+ let comp: &[i32] = &[4, 2, 5];
+ assert_eq!(&*rw.read().unwrap(), comp);
+ }
+
+ #[test]
+ fn test_rwlock_try_write() {
+ let lock = RwLock::new(0isize);
+ let read_guard = lock.read().unwrap();
+
+ let write_result = lock.try_write();
+ match write_result {
+ Err(TryLockError::WouldBlock) => (),
+ Ok(_) => assert!(false, "try_write should not succeed while read_guard is in scope"),
+ Err(_) => assert!(false, "unexpected error"),
+ }
+
+ drop(read_guard);
+ }
+
+ #[test]
+ fn test_into_inner() {
+ let m = RwLock::new(NonCopy(10));
+ assert_eq!(m.into_inner().unwrap(), NonCopy(10));
+ }
+
+ #[test]
+ fn test_into_inner_drop() {
+ struct Foo(Arc<AtomicUsize>);
+ impl Drop for Foo {
+ fn drop(&mut self) {
+ self.0.fetch_add(1, Ordering::SeqCst);
+ }
+ }
+ let num_drops = Arc::new(AtomicUsize::new(0));
+ let m = RwLock::new(Foo(num_drops.clone()));
+ assert_eq!(num_drops.load(Ordering::SeqCst), 0);
+ {
+ let _inner = m.into_inner().unwrap();
+ assert_eq!(num_drops.load(Ordering::SeqCst), 0);
+ }
+ assert_eq!(num_drops.load(Ordering::SeqCst), 1);
+ }
+
+ #[test]
+ fn test_into_inner_poison() {
+ let m = Arc::new(RwLock::new(NonCopy(10)));
+ let m2 = m.clone();
+ let _ = thread::spawn(move || {
+ let _lock = m2.write().unwrap();
+ panic!("test panic in inner thread to poison RwLock");
+ }).join();
+
+ assert!(m.is_poisoned());
+ match Arc::try_unwrap(m).unwrap().into_inner() {
+ Err(e) => assert_eq!(e.into_inner(), NonCopy(10)),
+ Ok(x) => panic!("into_inner of poisoned RwLock is Ok: {:?}", x),
+ }
+ }
+
+ #[test]
+ fn test_get_mut() {
+ let mut m = RwLock::new(NonCopy(10));
+ *m.get_mut().unwrap() = NonCopy(20);
+ assert_eq!(m.into_inner().unwrap(), NonCopy(20));
+ }
+
+ #[test]
+ fn test_get_mut_poison() {
+ let m = Arc::new(RwLock::new(NonCopy(10)));
+ let m2 = m.clone();
+ let _ = thread::spawn(move || {
+ let _lock = m2.write().unwrap();
+ panic!("test panic in inner thread to poison RwLock");
+ }).join();
+
+ assert!(m.is_poisoned());
+ match Arc::try_unwrap(m).unwrap().get_mut() {
+ Err(e) => assert_eq!(*e.into_inner(), NonCopy(10)),
+ Ok(x) => panic!("get_mut of poisoned RwLock is Ok: {:?}", x),
+ }
+ }
+}
diff --git a/src/libstd/sys/cloudabi/abi/bitflags.rs b/src/libstd/sys/cloudabi/abi/bitflags.rs
new file mode 100644
index 0000000..3069362
--- /dev/null
+++ b/src/libstd/sys/cloudabi/abi/bitflags.rs
@@ -0,0 +1,50 @@
+// Copyright (c) 2018 Nuxi (https://nuxi.nl/) and contributors.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+// 1. Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// 2. Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+// SUCH DAMAGE.
+
+// Appease Rust's tidy.
+// ignore-license
+
+#[cfg(feature = "bitflags")]
+use bitflags::bitflags;
+
+// Minimal implementation of bitflags! in case we can't depend on the bitflags
+// crate. Only implements `bits()` and a `from_bits_truncate()` that doesn't
+// actually truncate.
+#[cfg(not(feature = "bitflags"))]
+macro_rules! bitflags {
+ (
+ $(#[$attr:meta])*
+ pub struct $name:ident: $type:ty {
+ $($(#[$const_attr:meta])* const $const:ident = $val:expr;)*
+ }
+ ) => {
+ $(#[$attr])*
+ #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+ pub struct $name { bits: $type }
+ impl $name {
+ $($(#[$const_attr])* pub const $const: $name = $name{ bits: $val };)*
+ pub fn bits(&self) -> $type { self.bits }
+ pub fn from_bits_truncate(bits: $type) -> Self { $name{ bits } }
+ }
+ }
+}
diff --git a/src/libstd/sys/cloudabi/abi/cloudabi.rs b/src/libstd/sys/cloudabi/abi/cloudabi.rs
new file mode 100644
index 0000000..2307e21
--- /dev/null
+++ b/src/libstd/sys/cloudabi/abi/cloudabi.rs
@@ -0,0 +1,2845 @@
+// Copyright (c) 2016-2017 Nuxi <https://nuxi.nl/> and contributors.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+// 1. Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// 2. Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+// SUCH DAMAGE.
+//
+// This file is automatically generated. Do not edit.
+//
+// Source: https://github.com/NuxiNL/cloudabi
+
+// Appease Rust's tidy.
+// ignore-license
+// ignore-tidy-linelength
+
+//! **PLEASE NOTE: This entire crate including this
+//! documentation is automatically generated from
+//! [`cloudabi.txt`](https://github.com/NuxiNL/cloudabi/blob/master/cloudabi.txt)**
+//!
+//! # Nuxi CloudABI
+//!
+//! CloudABI is what you get if you take POSIX, add capability-based
+//! security, and remove everything that's incompatible with that. The
+//! result is a minimal ABI consisting of only 49 syscalls.
+//!
+//! CloudABI doesn't have its own kernel, but instead is implemented in existing
+//! kernels: FreeBSD has CloudABI support for x86-64 and arm64, and [a patch-set
+//! for NetBSD](https://github.com/NuxiNL/netbsd) and [a patch-set for
+//! Linux](https://github.com/NuxiNL/linux) are available as well. This means that
+//! CloudABI binaries can be executed on different operating systems, without any
+//! modification.
+//!
+//! ## Capability-Based Security
+//!
+//! Capability-based security means that processes can only perform
+//! actions that have no global impact. Processes cannot open files by
+//! their absolute path, cannot open network connections, and cannot
+//! observe global system state such as the process table.
+//!
+//! The capabilities of a process are fully determined by its set of open
+//! file descriptors (fds). For example, files can only be opened if the
+//! process already has a file descriptor to a directory the file is in.
+//!
+//! Unlike in POSIX, where processes are normally started with file
+//! descriptors 0, 1, and 2 reserved for standard input, output, and
+//! error, CloudABI does not reserve any file descriptor numbers for
+//! specific purposes.
+//!
+//! In CloudABI, a process depends on its parent process to launch it with
+//! the right set of resources, since the process will not be able to open
+//! any new resources. For example, a simple static web server would need
+//! to be started with a file descriptor to a [TCP
+//! listener](https://github.com/NuxiNL/flower), and a file descriptor to
+//! the directory for which to serve files. The web server will then be
+//! unable to do anything other than reading files in that directory, and
+//! process incoming network connections.
+//!
+//! So, unknown CloudABI binaries can safely be executed without the need
+//! for containers, virtual machines, or other sandboxing technologies.
+//!
+//! Watch [Ed Schouten's Talk at
+//! 32C3](https://www.youtube.com/watch?v=3N29vrPoDv8) for more
+//! information about what capability-based security for UNIX means.
+//!
+//! ## Cloudlibc
+//!
+//! [Cloudlibc](https://github.com/NuxiNL/cloudlibc) is an implementation
+//! of the C standard library, without all CloudABI-incompatible
+//! functions. For example, Cloudlibc does not have `printf`, but does
+//! have `fprintf`. It does not have `open`, but does have `openat`.
+//!
+//! ## CloudABI-Ports
+//!
+//! [CloudABI-Ports](https://github.com/NuxiNL/cloudabi-ports) is a
+//! collection of ports of commonly used libraries and applications to
+//! CloudABI. It contains software such as `zlib`, `libpng`, `boost`,
+//! `memcached`, and much more. The software is patched to not depend on
+//! any global state, such as files in `/etc` or `/dev`, using `open()`,
+//! etc.
+//!
+//! ## Using CloudABI
+//!
+//! Instructions for using CloudABI (including kernel modules/patches,
+//! toolchain, and ports) are available for several operating systems:
+//!
+//! - [Arch Linux](https://nuxi.nl/cloudabi/archlinux/)
+//! - [Debian, Ubuntu, and other Debian derivatives](https://nuxi.nl/cloudabi/debian/)
+//! - [FreeBSD, PC-BSD and DragonFly BSD](https://nuxi.nl/cloudabi/freebsd/)
+//! - [Mac OS X](https://nuxi.nl/cloudabi/mac/)
+//! - [NetBSD](https://nuxi.nl/cloudabi/netbsd/)
+//!
+//! ## Specification of the ABI
+//!
+//! The entire ABI is specified in a file called
+//! [`cloudabi.txt`](https://github.com/NuxiNL/cloudabi/blob/master/cloudabi.txt),
+//! from which all
+//! [headers](https://github.com/NuxiNL/cloudabi/tree/master/headers)
+//! and documentation (including the one you're reading now) is generated.
+
+#![no_std]
+#![allow(non_camel_case_types)]
+
+include!("bitflags.rs");
+
+/// File or memory access pattern advisory information.
+#[repr(u8)]
+#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+#[non_exhaustive]
+pub enum advice {
+ /// The application expects that it will not access the
+ /// specified data in the near future.
+ DONTNEED = 1,
+ /// The application expects to access the specified data
+ /// once and then not reuse it thereafter.
+ NOREUSE = 2,
+ /// The application has no advice to give on its behavior
+ /// with respect to the specified data.
+ NORMAL = 3,
+ /// The application expects to access the specified data
+ /// in a random order.
+ RANDOM = 4,
+ /// The application expects to access the specified data
+ /// sequentially from lower offsets to higher offsets.
+ SEQUENTIAL = 5,
+ /// The application expects to access the specified data
+ /// in the near future.
+ WILLNEED = 6,
+}
+
+/// Enumeration describing the kind of value stored in [`auxv`](struct.auxv.html).
+#[repr(u32)]
+#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+#[non_exhaustive]
+pub enum auxtype {
+ /// Base address of the binary argument data provided to
+ /// [`proc_exec()`](fn.proc_exec.html).
+ ARGDATA = 256,
+ /// Length of the binary argument data provided to
+ /// [`proc_exec()`](fn.proc_exec.html).
+ ARGDATALEN = 257,
+ /// Base address at which the executable is placed in
+ /// memory.
+ BASE = 7,
+ /// Base address of a buffer of random data that may be
+ /// used for non-cryptographic purposes, for example as a
+ /// canary for stack smashing protection.
+ CANARY = 258,
+ /// Length of a buffer of random data that may be used
+ /// for non-cryptographic purposes, for example as a
+ /// canary for stack smashing protection.
+ CANARYLEN = 259,
+ /// Number of CPUs that the system this process is running
+ /// on has.
+ NCPUS = 260,
+ /// Terminator of the auxiliary vector.
+ NULL = 0,
+ /// Smallest memory object size for which individual
+ /// memory protection controls can be configured.
+ PAGESZ = 6,
+ /// Address of the first ELF program header of the
+ /// executable.
+ PHDR = 3,
+ /// Number of ELF program headers of the executable.
+ PHNUM = 4,
+ /// Identifier of the process.
+ ///
+ /// This environment does not provide any simple numerical
+ /// process identifiers, for the reason that these are not
+ /// useful in distributed contexts. Instead, processes are
+ /// identified by a UUID.
+ ///
+ /// This record should point to sixteen bytes of binary
+ /// data, containing a version 4 UUID (fully random).
+ PID = 263,
+ /// Address of the ELF header of the vDSO.
+ ///
+ /// The vDSO is a shared library that is mapped in the
+ /// address space of the process. It provides entry points
+ /// for every system call supported by the environment,
+ /// all having a corresponding symbol that is prefixed
+ /// with `cloudabi_sys_`. System calls should be invoked
+ /// through these entry points.
+ ///
+ /// The first advantage of letting processes call into a
+ /// vDSO to perform system calls instead of raising
+ /// hardware traps is that it allows for easy emulation of
+ /// executables on top of existing operating systems. The
+ /// second advantage is that in cases where an operating
+ /// system provides native support for CloudABI executables,
+ /// it may still implement partial userspace
+ /// implementations of these system calls to improve
+ /// performance (e.g., [`clock_time_get()`](fn.clock_time_get.html)). It also provides
+ /// a more dynamic way of adding, removing or replacing
+ /// system calls.
+ SYSINFO_EHDR = 262,
+ /// Thread ID of the initial thread of the process.
+ TID = 261,
+}
+
+/// Identifiers for clocks.
+#[repr(u32)]
+#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+#[non_exhaustive]
+pub enum clockid {
+ /// The system-wide monotonic clock, which is defined as a
+ /// clock measuring real time, whose value cannot be
+ /// adjusted and which cannot have negative clock jumps.
+ ///
+ /// The epoch of this clock is undefined. The absolute
+ /// time value of this clock therefore has no meaning.
+ MONOTONIC = 1,
+ /// The CPU-time clock associated with the current
+ /// process.
+ PROCESS_CPUTIME_ID = 2,
+ /// The system-wide clock measuring real time. Time value
+ /// zero corresponds with 1970-01-01T00:00:00Z.
+ REALTIME = 3,
+ /// The CPU-time clock associated with the current thread.
+ THREAD_CPUTIME_ID = 4,
+}
+
+/// A userspace condition variable.
+#[repr(C)]
+#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+pub struct condvar(pub u32);
+/// The condition variable is in its initial state. There
+/// are no threads waiting to be woken up. If the
+/// condition variable has any other value, the kernel
+/// must be called to wake up any sleeping threads.
+pub const CONDVAR_HAS_NO_WAITERS: condvar = condvar(0);
+
+/// Identifier for a device containing a file system. Can be used
+/// in combination with [`inode`](struct.inode.html) to uniquely identify a file on the
+/// local system.
+#[repr(C)]
+#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+pub struct device(pub u64);
+
+/// A reference to the offset of a directory entry.
+#[repr(C)]
+#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+pub struct dircookie(pub u64);
+/// Permanent reference to the first directory entry
+/// within a directory.
+pub const DIRCOOKIE_START: dircookie = dircookie(0);
+
+/// Error codes returned by system calls.
+///
+/// Not all of these error codes are returned by the system calls
+/// provided by this environment, but are either used in userspace
+/// exclusively or merely provided for alignment with POSIX.
+#[repr(u16)]
+#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+#[non_exhaustive]
+pub enum errno {
+ /// No error occurred. System call completed successfully.
+ SUCCESS = 0,
+ /// Argument list too long.
+ TOOBIG = 1,
+ /// Permission denied.
+ ACCES = 2,
+ /// Address in use.
+ ADDRINUSE = 3,
+ /// Address not available.
+ ADDRNOTAVAIL = 4,
+ /// Address family not supported.
+ AFNOSUPPORT = 5,
+ /// Resource unavailable, or operation would block.
+ AGAIN = 6,
+ /// Connection already in progress.
+ ALREADY = 7,
+ /// Bad file descriptor.
+ BADF = 8,
+ /// Bad message.
+ BADMSG = 9,
+ /// Device or resource busy.
+ BUSY = 10,
+ /// Operation canceled.
+ CANCELED = 11,
+ /// No child processes.
+ CHILD = 12,
+ /// Connection aborted.
+ CONNABORTED = 13,
+ /// Connection refused.
+ CONNREFUSED = 14,
+ /// Connection reset.
+ CONNRESET = 15,
+ /// Resource deadlock would occur.
+ DEADLK = 16,
+ /// Destination address required.
+ DESTADDRREQ = 17,
+ /// Mathematics argument out of domain of function.
+ DOM = 18,
+ /// Reserved.
+ DQUOT = 19,
+ /// File exists.
+ EXIST = 20,
+ /// Bad address.
+ FAULT = 21,
+ /// File too large.
+ FBIG = 22,
+ /// Host is unreachable.
+ HOSTUNREACH = 23,
+ /// Identifier removed.
+ IDRM = 24,
+ /// Illegal byte sequence.
+ ILSEQ = 25,
+ /// Operation in progress.
+ INPROGRESS = 26,
+ /// Interrupted function.
+ INTR = 27,
+ /// Invalid argument.
+ INVAL = 28,
+ /// I/O error.
+ IO = 29,
+ /// Socket is connected.
+ ISCONN = 30,
+ /// Is a directory.
+ ISDIR = 31,
+ /// Too many levels of symbolic links.
+ LOOP = 32,
+ /// File descriptor value too large.
+ MFILE = 33,
+ /// Too many links.
+ MLINK = 34,
+ /// Message too large.
+ MSGSIZE = 35,
+ /// Reserved.
+ MULTIHOP = 36,
+ /// Filename too long.
+ NAMETOOLONG = 37,
+ /// Network is down.
+ NETDOWN = 38,
+ /// Connection aborted by network.
+ NETRESET = 39,
+ /// Network unreachable.
+ NETUNREACH = 40,
+ /// Too many files open in system.
+ NFILE = 41,
+ /// No buffer space available.
+ NOBUFS = 42,
+ /// No such device.
+ NODEV = 43,
+ /// No such file or directory.
+ NOENT = 44,
+ /// Executable file format error.
+ NOEXEC = 45,
+ /// No locks available.
+ NOLCK = 46,
+ /// Reserved.
+ NOLINK = 47,
+ /// Not enough space.
+ NOMEM = 48,
+ /// No message of the desired type.
+ NOMSG = 49,
+ /// Protocol not available.
+ NOPROTOOPT = 50,
+ /// No space left on device.
+ NOSPC = 51,
+ /// Function not supported.
+ NOSYS = 52,
+ /// The socket is not connected.
+ NOTCONN = 53,
+ /// Not a directory or a symbolic link to a directory.
+ NOTDIR = 54,
+ /// Directory not empty.
+ NOTEMPTY = 55,
+ /// State not recoverable.
+ NOTRECOVERABLE = 56,
+ /// Not a socket.
+ NOTSOCK = 57,
+ /// Not supported, or operation not supported on socket.
+ NOTSUP = 58,
+ /// Inappropriate I/O control operation.
+ NOTTY = 59,
+ /// No such device or address.
+ NXIO = 60,
+ /// Value too large to be stored in data type.
+ OVERFLOW = 61,
+ /// Previous owner died.
+ OWNERDEAD = 62,
+ /// Operation not permitted.
+ PERM = 63,
+ /// Broken pipe.
+ PIPE = 64,
+ /// Protocol error.
+ PROTO = 65,
+ /// Protocol not supported.
+ PROTONOSUPPORT = 66,
+ /// Protocol wrong type for socket.
+ PROTOTYPE = 67,
+ /// Result too large.
+ RANGE = 68,
+ /// Read-only file system.
+ ROFS = 69,
+ /// Invalid seek.
+ SPIPE = 70,
+ /// No such process.
+ SRCH = 71,
+ /// Reserved.
+ STALE = 72,
+ /// Connection timed out.
+ TIMEDOUT = 73,
+ /// Text file busy.
+ TXTBSY = 74,
+ /// Cross-device link.
+ XDEV = 75,
+ /// Extension: Capabilities insufficient.
+ NOTCAPABLE = 76,
+}
+
+bitflags! {
+ /// The state of the file descriptor subscribed to with
+ /// [`FD_READ`](enum.eventtype.html#variant.FD_READ) or [`FD_WRITE`](enum.eventtype.html#variant.FD_WRITE).
+ #[repr(C)]
+ pub struct eventrwflags: u16 {
+ /// The peer of this socket has closed or disconnected.
+ const HANGUP = 0x0001;
+ }
+}
+
+/// Type of a subscription to an event or its occurrence.
+#[repr(u8)]
+#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+#[non_exhaustive]
+pub enum eventtype {
+ /// The time value of clock [`subscription.union.clock.clock_id`](struct.subscription_clock.html#structfield.clock_id)
+ /// has reached timestamp [`subscription.union.clock.timeout`](struct.subscription_clock.html#structfield.timeout).
+ CLOCK = 1,
+ /// Condition variable [`subscription.union.condvar.condvar`](struct.subscription_condvar.html#structfield.condvar) has
+ /// been woken up and [`subscription.union.condvar.lock`](struct.subscription_condvar.html#structfield.lock) has been
+ /// acquired for writing.
+ CONDVAR = 2,
+ /// File descriptor [`subscription.union.fd_readwrite.fd`](struct.subscription_fd_readwrite.html#structfield.fd) has
+ /// data available for reading. This event always triggers
+ /// for regular files.
+ FD_READ = 3,
+ /// File descriptor [`subscription.union.fd_readwrite.fd`](struct.subscription_fd_readwrite.html#structfield.fd) has
+ /// capacity available for writing. This event always
+ /// triggers for regular files.
+ FD_WRITE = 4,
+ /// Lock [`subscription.union.lock.lock`](struct.subscription_lock.html#structfield.lock) has been acquired for
+ /// reading.
+ LOCK_RDLOCK = 5,
+ /// Lock [`subscription.union.lock.lock`](struct.subscription_lock.html#structfield.lock) has been acquired for
+ /// writing.
+ LOCK_WRLOCK = 6,
+ /// The process associated with process descriptor
+ /// [`subscription.union.proc_terminate.fd`](struct.subscription_proc_terminate.html#structfield.fd) has terminated.
+ PROC_TERMINATE = 7,
+}
+
+/// Exit code generated by a process when exiting.
+pub type exitcode = u32;
+
+/// A file descriptor number.
+///
+/// Unlike on POSIX-compliant systems, none of the file descriptor
+/// numbers are reserved for a purpose (e.g., stdin, stdout,
+/// stderr). Operating systems are not required to allocate new
+/// file descriptors in ascending order.
+#[repr(C)]
+#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+pub struct fd(pub u32);
+/// Returned to the child process by [`proc_fork()`](fn.proc_fork.html).
+pub const PROCESS_CHILD: fd = fd(0xffffffff);
+/// Passed to [`mem_map()`](fn.mem_map.html) when creating a mapping to
+/// anonymous memory.
+pub const MAP_ANON_FD : fd = fd(0xffffffff);
+
+bitflags! {
+ /// File descriptor flags.
+ #[repr(C)]
+ pub struct fdflags: u16 {
+ /// Append mode: Data written to the file is always
+ /// appended to the file's end.
+ const APPEND = 0x0001;
+ /// Write according to synchronized I/O data integrity
+ /// completion. Only the data stored in the file is
+ /// synchronized.
+ const DSYNC = 0x0002;
+ /// Non-blocking mode.
+ const NONBLOCK = 0x0004;
+ /// Synchronized read I/O operations.
+ const RSYNC = 0x0008;
+ /// Write according to synchronized I/O file integrity
+ /// completion. In addition to synchronizing the data
+ /// stored in the file, the system may also synchronously
+ /// update the file's metadata.
+ const SYNC = 0x0010;
+ }
+}
+
+bitflags! {
+ /// Which file descriptor attributes to adjust.
+ #[repr(C)]
+ pub struct fdsflags: u16 {
+ /// Adjust the file descriptor flags stored in
+ /// [`fdstat.fs_flags`](struct.fdstat.html#structfield.fs_flags).
+ const FLAGS = 0x0001;
+ /// Restrict the rights of the file descriptor to the
+ /// rights stored in [`fdstat.fs_rights_base`](struct.fdstat.html#structfield.fs_rights_base) and
+ /// [`fdstat.fs_rights_inheriting`](struct.fdstat.html#structfield.fs_rights_inheriting).
+ const RIGHTS = 0x0002;
+ }
+}
+
+/// Relative offset within a file.
+pub type filedelta = i64;
+
+/// Non-negative file size or length of a region within a file.
+pub type filesize = u64;
+
+/// The type of a file descriptor or file.
+#[repr(u8)]
+#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+#[non_exhaustive]
+pub enum filetype {
+ /// The type of the file descriptor or file is unknown or
+ /// is different from any of the other types specified.
+ UNKNOWN = 0,
+ /// The file descriptor or file refers to a block device
+ /// inode.
+ BLOCK_DEVICE = 16,
+ /// The file descriptor or file refers to a character
+ /// device inode.
+ CHARACTER_DEVICE = 17,
+ /// The file descriptor or file refers to a directory
+ /// inode.
+ DIRECTORY = 32,
+ /// The file descriptor refers to a process handle.
+ PROCESS = 80,
+ /// The file descriptor or file refers to a regular file
+ /// inode.
+ REGULAR_FILE = 96,
+ /// The file descriptor refers to a shared memory object.
+ SHARED_MEMORY = 112,
+ /// The file descriptor or file refers to a datagram
+ /// socket.
+ SOCKET_DGRAM = 128,
+ /// The file descriptor or file refers to a byte-stream
+ /// socket.
+ SOCKET_STREAM = 130,
+ /// The file refers to a symbolic link inode.
+ SYMBOLIC_LINK = 144,
+}
+
+bitflags! {
+ /// Which file attributes to adjust.
+ #[repr(C)]
+ pub struct fsflags: u16 {
+ /// Adjust the last data access timestamp to the value
+ /// stored in [`filestat.st_atim`](struct.filestat.html#structfield.st_atim).
+ const ATIM = 0x0001;
+ /// Adjust the last data access timestamp to the time
+ /// of clock [`REALTIME`](enum.clockid.html#variant.REALTIME).
+ const ATIM_NOW = 0x0002;
+ /// Adjust the last data modification timestamp to the
+ /// value stored in [`filestat.st_mtim`](struct.filestat.html#structfield.st_mtim).
+ const MTIM = 0x0004;
+ /// Adjust the last data modification timestamp to the
+ /// time of clock [`REALTIME`](enum.clockid.html#variant.REALTIME).
+ const MTIM_NOW = 0x0008;
+ /// Truncate or extend the file to the size stored in
+ /// [`filestat.st_size`](struct.filestat.html#structfield.st_size).
+ const SIZE = 0x0010;
+ }
+}
+
+/// File serial number that is unique within its file system.
+#[repr(C)]
+#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+pub struct inode(pub u64);
+
+/// Number of hard links to an inode.
+pub type linkcount = u32;
+
+/// A userspace read-recursive readers-writer lock, similar to a
+/// Linux futex or a FreeBSD umtx.
+#[repr(C)]
+#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+pub struct lock(pub u32);
+/// Value indicating that the lock is in its initial
+/// unlocked state.
+pub const LOCK_UNLOCKED : lock = lock(0x00000000);
+/// Bitmask indicating that the lock is write-locked. If
+/// set, the lower 30 bits of the lock contain the
+/// identifier of the thread that owns the write lock.
+/// Otherwise, the lower 30 bits of the lock contain the
+/// number of acquired read locks.
+pub const LOCK_WRLOCKED : lock = lock(0x40000000);
+/// Bitmask indicating that the lock is either read locked
+/// or write locked, and that one or more threads have
+/// their execution suspended, waiting to acquire the
+/// lock. The last owner of the lock must call the
+/// kernel to unlock.
+///
+/// When the lock is acquired for reading and this bit is
+/// set, it means that one or more threads are attempting
+/// to acquire this lock for writing. In that case, other
+/// threads should only acquire additional read locks if
+/// suspending execution would cause a deadlock. It is
+/// preferred to suspend execution, as this prevents
+/// starvation of writers.
+pub const LOCK_KERNEL_MANAGED: lock = lock(0x80000000);
+/// Value indicating that the lock is in an incorrect
+/// state. A lock cannot be in its initial unlocked state,
+/// while also managed by the kernel.
+pub const LOCK_BOGUS : lock = lock(0x80000000);
+
+bitflags! {
+ /// Flags determining the method of how paths are resolved.
+ #[repr(C)]
+ pub struct lookupflags: u32 {
+ /// As long as the resolved path corresponds to a symbolic
+ /// link, it is expanded.
+ const SYMLINK_FOLLOW = 0x00000001;
+ }
+}
+
+bitflags! {
+ /// Memory mapping flags.
+ #[repr(C)]
+ pub struct mflags: u8 {
+ /// Instead of mapping the contents of the file provided,
+ /// create a mapping to anonymous memory. The file
+ /// descriptor argument must be set to [`MAP_ANON_FD`](constant.MAP_ANON_FD.html),
+ /// and the offset must be set to zero.
+ const ANON = 0x01;
+ /// Require that the mapping is performed at the base
+ /// address provided.
+ const FIXED = 0x02;
+ /// Changes are private.
+ const PRIVATE = 0x04;
+ /// Changes are shared.
+ const SHARED = 0x08;
+ }
+}
+
+bitflags! {
+ /// Memory page protection options.
+ ///
+ /// This implementation enforces the `W^X` property: Pages cannot be
+ /// mapped for execution while also mapped for writing.
+ #[repr(C)]
+ pub struct mprot: u8 {
+ /// Page can be executed.
+ const EXEC = 0x01;
+ /// Page can be written.
+ const WRITE = 0x02;
+ /// Page can be read.
+ const READ = 0x04;
+ }
+}
+
+bitflags! {
+ /// Methods of synchronizing memory with physical storage.
+ #[repr(C)]
+ pub struct msflags: u8 {
+ /// Performs asynchronous writes.
+ const ASYNC = 0x01;
+ /// Invalidates cached data.
+ const INVALIDATE = 0x02;
+ /// Performs synchronous writes.
+ const SYNC = 0x04;
+ }
+}
+
+/// Specifies the number of threads sleeping on a condition
+/// variable that should be woken up.
+pub type nthreads = u32;
+
+bitflags! {
+ /// Open flags used by [`file_open()`](fn.file_open.html).
+ #[repr(C)]
+ pub struct oflags: u16 {
+ /// Create file if it does not exist.
+ const CREAT = 0x0001;
+ /// Fail if not a directory.
+ const DIRECTORY = 0x0002;
+ /// Fail if file already exists.
+ const EXCL = 0x0004;
+ /// Truncate file to size 0.
+ const TRUNC = 0x0008;
+ }
+}
+
+bitflags! {
+ /// Flags provided to [`sock_recv()`](fn.sock_recv.html).
+ #[repr(C)]
+ pub struct riflags: u16 {
+ /// Returns the message without removing it from the
+ /// socket's receive queue.
+ const PEEK = 0x0004;
+ /// On byte-stream sockets, block until the full amount
+ /// of data can be returned.
+ const WAITALL = 0x0010;
+ }
+}
+
+bitflags! {
+ /// File descriptor rights, determining which actions may be
+ /// performed.
+ #[repr(C)]
+ pub struct rights: u64 {
+ /// The right to invoke [`fd_datasync()`](fn.fd_datasync.html).
+ ///
+ /// If [`FILE_OPEN`](struct.rights.html#associatedconstant.FILE_OPEN) is set, includes the right to
+ /// invoke [`file_open()`](fn.file_open.html) with [`DSYNC`](struct.fdflags.html#associatedconstant.DSYNC).
+ const FD_DATASYNC = 0x0000000000000001;
+ /// The right to invoke [`fd_read()`](fn.fd_read.html) and [`sock_recv()`](fn.sock_recv.html).
+ ///
+ /// If [`MEM_MAP`](struct.rights.html#associatedconstant.MEM_MAP) is set, includes the right to
+ /// invoke [`mem_map()`](fn.mem_map.html) with memory protection option
+ /// [`READ`](struct.mprot.html#associatedconstant.READ).
+ ///
+ /// If [`FD_SEEK`](struct.rights.html#associatedconstant.FD_SEEK) is set, includes the right to invoke
+ /// [`fd_pread()`](fn.fd_pread.html).
+ const FD_READ = 0x0000000000000002;
+ /// The right to invoke [`fd_seek()`](fn.fd_seek.html). This flag implies
+ /// [`FD_TELL`](struct.rights.html#associatedconstant.FD_TELL).
+ const FD_SEEK = 0x0000000000000004;
+ /// The right to invoke [`fd_stat_put()`](fn.fd_stat_put.html) with
+ /// [`FLAGS`](struct.fdsflags.html#associatedconstant.FLAGS).
+ const FD_STAT_PUT_FLAGS = 0x0000000000000008;
+ /// The right to invoke [`fd_sync()`](fn.fd_sync.html).
+ ///
+ /// If [`FILE_OPEN`](struct.rights.html#associatedconstant.FILE_OPEN) is set, includes the right to
+ /// invoke [`file_open()`](fn.file_open.html) with [`RSYNC`](struct.fdflags.html#associatedconstant.RSYNC) and
+ /// [`DSYNC`](struct.fdflags.html#associatedconstant.DSYNC).
+ const FD_SYNC = 0x0000000000000010;
+ /// The right to invoke [`fd_seek()`](fn.fd_seek.html) in such a way that the
+ /// file offset remains unaltered (i.e., [`CUR`](enum.whence.html#variant.CUR) with
+ /// offset zero).
+ const FD_TELL = 0x0000000000000020;
+ /// The right to invoke [`fd_write()`](fn.fd_write.html) and [`sock_send()`](fn.sock_send.html).
+ ///
+ /// If [`MEM_MAP`](struct.rights.html#associatedconstant.MEM_MAP) is set, includes the right to
+ /// invoke [`mem_map()`](fn.mem_map.html) with memory protection option
+ /// [`WRITE`](struct.mprot.html#associatedconstant.WRITE).
+ ///
+ /// If [`FD_SEEK`](struct.rights.html#associatedconstant.FD_SEEK) is set, includes the right to
+ /// invoke [`fd_pwrite()`](fn.fd_pwrite.html).
+ const FD_WRITE = 0x0000000000000040;
+ /// The right to invoke [`file_advise()`](fn.file_advise.html).
+ const FILE_ADVISE = 0x0000000000000080;
+ /// The right to invoke [`file_allocate()`](fn.file_allocate.html).
+ const FILE_ALLOCATE = 0x0000000000000100;
+ /// The right to invoke [`file_create()`](fn.file_create.html) with
+ /// [`DIRECTORY`](enum.filetype.html#variant.DIRECTORY).
+ const FILE_CREATE_DIRECTORY = 0x0000000000000200;
+ /// If [`FILE_OPEN`](struct.rights.html#associatedconstant.FILE_OPEN) is set, the right to invoke
+ /// [`file_open()`](fn.file_open.html) with [`CREAT`](struct.oflags.html#associatedconstant.CREAT).
+ const FILE_CREATE_FILE = 0x0000000000000400;
+ /// The right to invoke [`file_link()`](fn.file_link.html) with the file
+ /// descriptor as the source directory.
+ const FILE_LINK_SOURCE = 0x0000000000001000;
+ /// The right to invoke [`file_link()`](fn.file_link.html) with the file
+ /// descriptor as the target directory.
+ const FILE_LINK_TARGET = 0x0000000000002000;
+ /// The right to invoke [`file_open()`](fn.file_open.html).
+ const FILE_OPEN = 0x0000000000004000;
+ /// The right to invoke [`file_readdir()`](fn.file_readdir.html).
+ const FILE_READDIR = 0x0000000000008000;
+ /// The right to invoke [`file_readlink()`](fn.file_readlink.html).
+ const FILE_READLINK = 0x0000000000010000;
+ /// The right to invoke [`file_rename()`](fn.file_rename.html) with the file
+ /// descriptor as the source directory.
+ const FILE_RENAME_SOURCE = 0x0000000000020000;
+ /// The right to invoke [`file_rename()`](fn.file_rename.html) with the file
+ /// descriptor as the target directory.
+ const FILE_RENAME_TARGET = 0x0000000000040000;
+ /// The right to invoke [`file_stat_fget()`](fn.file_stat_fget.html).
+ const FILE_STAT_FGET = 0x0000000000080000;
+ /// The right to invoke [`file_stat_fput()`](fn.file_stat_fput.html) with
+ /// [`SIZE`](struct.fsflags.html#associatedconstant.SIZE).
+ ///
+ /// If [`FILE_OPEN`](struct.rights.html#associatedconstant.FILE_OPEN) is set, includes the right to
+ /// invoke [`file_open()`](fn.file_open.html) with [`TRUNC`](struct.oflags.html#associatedconstant.TRUNC).
+ const FILE_STAT_FPUT_SIZE = 0x0000000000100000;
+ /// The right to invoke [`file_stat_fput()`](fn.file_stat_fput.html) with
+ /// [`ATIM`](struct.fsflags.html#associatedconstant.ATIM), [`ATIM_NOW`](struct.fsflags.html#associatedconstant.ATIM_NOW), [`MTIM`](struct.fsflags.html#associatedconstant.MTIM),
+ /// and [`MTIM_NOW`](struct.fsflags.html#associatedconstant.MTIM_NOW).
+ const FILE_STAT_FPUT_TIMES = 0x0000000000200000;
+ /// The right to invoke [`file_stat_get()`](fn.file_stat_get.html).
+ const FILE_STAT_GET = 0x0000000000400000;
+ /// The right to invoke [`file_stat_put()`](fn.file_stat_put.html) with
+ /// [`ATIM`](struct.fsflags.html#associatedconstant.ATIM), [`ATIM_NOW`](struct.fsflags.html#associatedconstant.ATIM_NOW), [`MTIM`](struct.fsflags.html#associatedconstant.MTIM),
+ /// and [`MTIM_NOW`](struct.fsflags.html#associatedconstant.MTIM_NOW).
+ const FILE_STAT_PUT_TIMES = 0x0000000000800000;
+ /// The right to invoke [`file_symlink()`](fn.file_symlink.html).
+ const FILE_SYMLINK = 0x0000000001000000;
+ /// The right to invoke [`file_unlink()`](fn.file_unlink.html).
+ const FILE_UNLINK = 0x0000000002000000;
+ /// The right to invoke [`mem_map()`](fn.mem_map.html) with [`mprot`](struct.mprot.html) set to
+ /// zero.
+ const MEM_MAP = 0x0000000004000000;
+ /// If [`MEM_MAP`](struct.rights.html#associatedconstant.MEM_MAP) is set, the right to invoke
+ /// [`mem_map()`](fn.mem_map.html) with [`EXEC`](struct.mprot.html#associatedconstant.EXEC).
+ const MEM_MAP_EXEC = 0x0000000008000000;
+ /// If [`FD_READ`](struct.rights.html#associatedconstant.FD_READ) is set, includes the right to
+ /// invoke [`poll()`](fn.poll.html) to subscribe to [`FD_READ`](enum.eventtype.html#variant.FD_READ).
+ ///
+ /// If [`FD_WRITE`](struct.rights.html#associatedconstant.FD_WRITE) is set, includes the right to
+ /// invoke [`poll()`](fn.poll.html) to subscribe to [`FD_WRITE`](enum.eventtype.html#variant.FD_WRITE).
+ const POLL_FD_READWRITE = 0x0000000010000000;
+ /// The right to invoke [`poll()`](fn.poll.html) to subscribe to
+ /// [`PROC_TERMINATE`](enum.eventtype.html#variant.PROC_TERMINATE).
+ const POLL_PROC_TERMINATE = 0x0000000040000000;
+ /// The right to invoke [`proc_exec()`](fn.proc_exec.html).
+ const PROC_EXEC = 0x0000000100000000;
+ /// The right to invoke [`sock_shutdown()`](fn.sock_shutdown.html).
+ const SOCK_SHUTDOWN = 0x0000008000000000;
+ }
+}
+
+bitflags! {
+ /// Flags returned by [`sock_recv()`](fn.sock_recv.html).
+ #[repr(C)]
+ pub struct roflags: u16 {
+ /// Returned by [`sock_recv()`](fn.sock_recv.html): List of file descriptors
+ /// has been truncated.
+ const FDS_TRUNCATED = 0x0001;
+ /// Returned by [`sock_recv()`](fn.sock_recv.html): Message data has been
+ /// truncated.
+ const DATA_TRUNCATED = 0x0008;
+ }
+}
+
+/// Indicates whether an object is stored in private or shared
+/// memory.
+#[repr(u8)]
+#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+#[non_exhaustive]
+pub enum scope {
+ /// The object is stored in private memory.
+ PRIVATE = 4,
+ /// The object is stored in shared memory.
+ SHARED = 8,
+}
+
+bitflags! {
+ /// Which channels on a socket need to be shut down.
+ #[repr(C)]
+ pub struct sdflags: u8 {
+ /// Disables further receive operations.
+ const RD = 0x01;
+ /// Disables further send operations.
+ const WR = 0x02;
+ }
+}
+
+bitflags! {
+ /// Flags provided to [`sock_send()`](fn.sock_send.html). As there are currently no flags
+ /// defined, it must be set to zero.
+ #[repr(C)]
+ pub struct siflags: u16 {
+ const DEFAULT = 0;
+ }
+}
+
+/// Signal condition.
+#[repr(u8)]
+#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+#[non_exhaustive]
+pub enum signal {
+ /// Process abort signal.
+ ///
+ /// Action: Terminates the process.
+ ABRT = 1,
+ /// Alarm clock.
+ ///
+ /// Action: Terminates the process.
+ ALRM = 2,
+ /// Access to an undefined portion of a memory object.
+ ///
+ /// Action: Terminates the process.
+ BUS = 3,
+ /// Child process terminated, stopped, or continued.
+ ///
+ /// Action: Ignored.
+ CHLD = 4,
+ /// Continue executing, if stopped.
+ ///
+ /// Action: Continues executing, if stopped.
+ CONT = 5,
+ /// Erroneous arithmetic operation.
+ ///
+ /// Action: Terminates the process.
+ FPE = 6,
+ /// Hangup.
+ ///
+ /// Action: Terminates the process.
+ HUP = 7,
+ /// Illegal instruction.
+ ///
+ /// Action: Terminates the process.
+ ILL = 8,
+ /// Terminate interrupt signal.
+ ///
+ /// Action: Terminates the process.
+ INT = 9,
+ /// Kill.
+ ///
+ /// Action: Terminates the process.
+ KILL = 10,
+ /// Write on a pipe with no one to read it.
+ ///
+ /// Action: Ignored.
+ PIPE = 11,
+ /// Terminal quit signal.
+ ///
+ /// Action: Terminates the process.
+ QUIT = 12,
+ /// Invalid memory reference.
+ ///
+ /// Action: Terminates the process.
+ SEGV = 13,
+ /// Stop executing.
+ ///
+ /// Action: Stops executing.
+ STOP = 14,
+ /// Bad system call.
+ ///
+ /// Action: Terminates the process.
+ SYS = 15,
+ /// Termination signal.
+ ///
+ /// Action: Terminates the process.
+ TERM = 16,
+ /// Trace/breakpoint trap.
+ ///
+ /// Action: Terminates the process.
+ TRAP = 17,
+ /// Terminal stop signal.
+ ///
+ /// Action: Stops executing.
+ TSTP = 18,
+ /// Background process attempting read.
+ ///
+ /// Action: Stops executing.
+ TTIN = 19,
+ /// Background process attempting write.
+ ///
+ /// Action: Stops executing.
+ TTOU = 20,
+ /// High bandwidth data is available at a socket.
+ ///
+ /// Action: Ignored.
+ URG = 21,
+ /// User-defined signal 1.
+ ///
+ /// Action: Terminates the process.
+ USR1 = 22,
+ /// User-defined signal 2.
+ ///
+ /// Action: Terminates the process.
+ USR2 = 23,
+ /// Virtual timer expired.
+ ///
+ /// Action: Terminates the process.
+ VTALRM = 24,
+ /// CPU time limit exceeded.
+ ///
+ /// Action: Terminates the process.
+ XCPU = 25,
+ /// File size limit exceeded.
+ ///
+ /// Action: Terminates the process.
+ XFSZ = 26,
+}
+
+bitflags! {
+ /// Flags determining how the timestamp provided in
+ /// [`subscription.union.clock.timeout`](struct.subscription_clock.html#structfield.timeout) should be interpreted.
+ #[repr(C)]
+ pub struct subclockflags: u16 {
+ /// If set, treat the timestamp provided in
+ /// [`subscription.union.clock.timeout`](struct.subscription_clock.html#structfield.timeout) as an absolute timestamp
+ /// of clock [`subscription.union.clock.clock_id`](struct.subscription_clock.html#structfield.clock_id).
+ ///
+ /// If clear, treat the timestamp provided in
+ /// [`subscription.union.clock.timeout`](struct.subscription_clock.html#structfield.timeout) relative to the current
+ /// time value of clock [`subscription.union.clock.clock_id`](struct.subscription_clock.html#structfield.clock_id).
+ const ABSTIME = 0x0001;
+ }
+}
+
+bitflags! {
+ /// Flags influencing the method of polling for read or writing on
+ /// a file descriptor.
+ #[repr(C)]
+ pub struct subrwflags: u16 {
+ /// Deprecated. Must be set by callers and ignored by
+ /// implementations.
+ const POLL = 0x0001;
+ }
+}
+
+/// Unique system-local identifier of a thread. This identifier is
+/// only valid during the lifetime of the thread.
+///
+/// Threads must be aware of their thread identifier, as it is
+/// written it into locks when acquiring them for writing. It is
+/// not advised to use these identifiers for any other purpose.
+///
+/// As the thread identifier is also stored in [`lock`](struct.lock.html) when
+/// [`LOCK_WRLOCKED`](constant.LOCK_WRLOCKED.html) is set, the top two bits of the thread
+/// must always be set to zero.
+#[repr(C)]
+#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+pub struct tid(pub u32);
+
+/// Timestamp in nanoseconds.
+pub type timestamp = u64;
+
+bitflags! {
+ /// Specifies whether files are unlinked or directories are
+ /// removed.
+ #[repr(C)]
+ pub struct ulflags: u8 {
+ /// If set, removes a directory. Otherwise, unlinks any
+ /// non-directory file.
+ const REMOVEDIR = 0x01;
+ }
+}
+
+/// User-provided value that can be attached to objects that is
+/// retained when extracted from the kernel.
+pub type userdata = u64;
+
+/// Relative to which position the offset of the file descriptor
+/// should be set.
+#[repr(u8)]
+#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+#[non_exhaustive]
+pub enum whence {
+ /// Seek relative to current position.
+ CUR = 1,
+ /// Seek relative to end-of-file.
+ END = 2,
+ /// Seek relative to start-of-file.
+ SET = 3,
+}
+
+/// Auxiliary vector entry.
+///
+/// The auxiliary vector is a list of key-value pairs that is
+/// provided to the process on startup. Unlike structures, it is
+/// extensible, as it is possible to add new records later on.
+/// The auxiliary vector is always terminated by an entry having
+/// type [`NULL`](enum.auxtype.html#variant.NULL).
+///
+/// The auxiliary vector is part of the x86-64 ABI, but is used by
+/// this environment on all architectures.
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct auxv {
+ /// The type of the auxiliary vector entry.
+ pub a_type: auxtype,
+ pub union: auxv_union
+}
+/// A union inside `auxv`.
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub union auxv_union {
+ /// Used when `a_type` is [`ARGDATALEN`](enum.auxtype.html#variant.ARGDATALEN), [`CANARYLEN`](enum.auxtype.html#variant.CANARYLEN), [`NCPUS`](enum.auxtype.html#variant.NCPUS), [`PAGESZ`](enum.auxtype.html#variant.PAGESZ), [`PHNUM`](enum.auxtype.html#variant.PHNUM), or [`TID`](enum.auxtype.html#variant.TID).
+/// A numerical value.
+ pub a_val: usize,
+ /// Used when `a_type` is [`ARGDATA`](enum.auxtype.html#variant.ARGDATA), [`BASE`](enum.auxtype.html#variant.BASE), [`CANARY`](enum.auxtype.html#variant.CANARY), [`PHDR`](enum.auxtype.html#variant.PHDR), [`PID`](enum.auxtype.html#variant.PID), or [`SYSINFO_EHDR`](enum.auxtype.html#variant.SYSINFO_EHDR).
+/// A pointer value.
+ pub a_ptr: *mut (),
+}
+#[test]
+#[cfg(target_pointer_width = "32")]
+fn auxv_layout_test_32() {
+ assert_eq!(core::mem::size_of::<auxv>(), 8);
+ assert_eq!(core::mem::align_of::<auxv>(), 4);
+ unsafe {
+ let obj: auxv = core::mem::uninitialized();
+ let base = &obj as *const _ as usize;
+ assert_eq!(&obj.a_type as *const _ as usize - base, 0);
+ assert_eq!(&obj.union.a_val as *const _ as usize - base, 4);
+ assert_eq!(&obj.union.a_ptr as *const _ as usize - base, 4);
+ }
+}
+#[test]
+#[cfg(target_pointer_width = "64")]
+fn auxv_layout_test_64() {
+ assert_eq!(core::mem::size_of::<auxv>(), 16);
+ assert_eq!(core::mem::align_of::<auxv>(), 8);
+ unsafe {
+ let obj: auxv = core::mem::uninitialized();
+ let base = &obj as *const _ as usize;
+ assert_eq!(&obj.a_type as *const _ as usize - base, 0);
+ assert_eq!(&obj.union.a_val as *const _ as usize - base, 8);
+ assert_eq!(&obj.union.a_ptr as *const _ as usize - base, 8);
+ }
+}
+
+/// A region of memory for scatter/gather writes.
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct ciovec {
+ /// The address and length of the buffer to be written.
+ pub buf: (*const (), usize),
+}
+#[test]
+#[cfg(target_pointer_width = "32")]
+fn ciovec_layout_test_32() {
+ assert_eq!(core::mem::size_of::<ciovec>(), 8);
+ assert_eq!(core::mem::align_of::<ciovec>(), 4);
+ unsafe {
+ let obj: ciovec = core::mem::uninitialized();
+ let base = &obj as *const _ as usize;
+ assert_eq!(&obj.buf.0 as *const _ as usize - base, 0);
+ assert_eq!(&obj.buf.1 as *const _ as usize - base, 4);
+ }
+}
+#[test]
+#[cfg(target_pointer_width = "64")]
+fn ciovec_layout_test_64() {
+ assert_eq!(core::mem::size_of::<ciovec>(), 16);
+ assert_eq!(core::mem::align_of::<ciovec>(), 8);
+ unsafe {
+ let obj: ciovec = core::mem::uninitialized();
+ let base = &obj as *const _ as usize;
+ assert_eq!(&obj.buf.0 as *const _ as usize - base, 0);
+ assert_eq!(&obj.buf.1 as *const _ as usize - base, 8);
+ }
+}
+
+/// A directory entry.
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct dirent {
+ /// The offset of the next directory entry stored in this
+ /// directory.
+ pub d_next: dircookie,
+ /// The serial number of the file referred to by this
+ /// directory entry.
+ pub d_ino: inode,
+ /// The length of the name of the directory entry.
+ pub d_namlen: u32,
+ /// The type of the file referred to by this directory
+ /// entry.
+ pub d_type: filetype,
+}
+#[test]
+fn dirent_layout_test() {
+ assert_eq!(core::mem::size_of::<dirent>(), 24);
+ assert_eq!(core::mem::align_of::<dirent>(), 8);
+ unsafe {
+ let obj: dirent = core::mem::uninitialized();
+ let base = &obj as *const _ as usize;
+ assert_eq!(&obj.d_next as *const _ as usize - base, 0);
+ assert_eq!(&obj.d_ino as *const _ as usize - base, 8);
+ assert_eq!(&obj.d_namlen as *const _ as usize - base, 16);
+ assert_eq!(&obj.d_type as *const _ as usize - base, 20);
+ }
+}
+
+/// An event that occurred.
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct event {
+ /// User-provided value that got attached to
+ /// [`subscription.userdata`](struct.subscription.html#structfield.userdata).
+ pub userdata: userdata,
+ /// If non-zero, an error that occurred while processing
+ /// the subscription request.
+ pub error: errno,
+ /// The type of the event that occurred.
+ pub type_: eventtype,
+ pub union: event_union
+}
+/// A union inside `event`.
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub union event_union {
+ /// Used when `type_` is [`FD_READ`](enum.eventtype.html#variant.FD_READ) or [`FD_WRITE`](enum.eventtype.html#variant.FD_WRITE).
+ pub fd_readwrite: event_fd_readwrite,
+ /// Used when `type_` is [`PROC_TERMINATE`](enum.eventtype.html#variant.PROC_TERMINATE).
+ pub proc_terminate: event_proc_terminate,
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct event_fd_readwrite {
+ /// The number of bytes available
+ /// for reading or writing.
+ pub nbytes: filesize,
+ /// Obsolete.
+ pub unused: [u8; 4],
+ /// The state of the file
+ /// descriptor.
+ pub flags: eventrwflags,
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct event_proc_terminate {
+ /// Obsolete.
+ pub unused: [u8; 4],
+ /// If zero, the process has
+ /// exited.
+ /// Otherwise, the signal
+ /// condition causing it to
+ /// terminated.
+ pub signal: signal,
+ /// If exited, the exit code of
+ /// the process.
+ pub exitcode: exitcode,
+}
+#[test]
+fn event_layout_test() {
+ assert_eq!(core::mem::size_of::<event>(), 32);
+ assert_eq!(core::mem::align_of::<event>(), 8);
+ unsafe {
+ let obj: event = core::mem::uninitialized();
+ let base = &obj as *const _ as usize;
+ assert_eq!(&obj.userdata as *const _ as usize - base, 0);
+ assert_eq!(&obj.error as *const _ as usize - base, 8);
+ assert_eq!(&obj.type_ as *const _ as usize - base, 10);
+ assert_eq!(&obj.union.fd_readwrite.nbytes as *const _ as usize - base, 16);
+ assert_eq!(&obj.union.fd_readwrite.unused as *const _ as usize - base, 24);
+ assert_eq!(&obj.union.fd_readwrite.flags as *const _ as usize - base, 28);
+ assert_eq!(&obj.union.proc_terminate.unused as *const _ as usize - base, 16);
+ assert_eq!(&obj.union.proc_terminate.signal as *const _ as usize - base, 20);
+ assert_eq!(&obj.union.proc_terminate.exitcode as *const _ as usize - base, 24);
+ }
+}
+
+/// File descriptor attributes.
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct fdstat {
+ /// File type.
+ pub fs_filetype: filetype,
+ /// File descriptor flags.
+ pub fs_flags: fdflags,
+ /// Rights that apply to this file descriptor.
+ pub fs_rights_base: rights,
+ /// Maximum set of rights that can be installed on new
+ /// file descriptors that are created through this file
+ /// descriptor, e.g., through [`file_open()`](fn.file_open.html).
+ pub fs_rights_inheriting: rights,
+}
+#[test]
+fn fdstat_layout_test() {
+ assert_eq!(core::mem::size_of::<fdstat>(), 24);
+ assert_eq!(core::mem::align_of::<fdstat>(), 8);
+ unsafe {
+ let obj: fdstat = core::mem::uninitialized();
+ let base = &obj as *const _ as usize;
+ assert_eq!(&obj.fs_filetype as *const _ as usize - base, 0);
+ assert_eq!(&obj.fs_flags as *const _ as usize - base, 2);
+ assert_eq!(&obj.fs_rights_base as *const _ as usize - base, 8);
+ assert_eq!(&obj.fs_rights_inheriting as *const _ as usize - base, 16);
+ }
+}
+
+/// File attributes.
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct filestat {
+ /// Device ID of device containing the file.
+ pub st_dev: device,
+ /// File serial number.
+ pub st_ino: inode,
+ /// File type.
+ pub st_filetype: filetype,
+ /// Number of hard links to the file.
+ pub st_nlink: linkcount,
+ /// For regular files, the file size in bytes. For
+ /// symbolic links, the length in bytes of the pathname
+ /// contained in the symbolic link.
+ pub st_size: filesize,
+ /// Last data access timestamp.
+ pub st_atim: timestamp,
+ /// Last data modification timestamp.
+ pub st_mtim: timestamp,
+ /// Last file status change timestamp.
+ pub st_ctim: timestamp,
+}
+#[test]
+fn filestat_layout_test() {
+ assert_eq!(core::mem::size_of::<filestat>(), 56);
+ assert_eq!(core::mem::align_of::<filestat>(), 8);
+ unsafe {
+ let obj: filestat = core::mem::uninitialized();
+ let base = &obj as *const _ as usize;
+ assert_eq!(&obj.st_dev as *const _ as usize - base, 0);
+ assert_eq!(&obj.st_ino as *const _ as usize - base, 8);
+ assert_eq!(&obj.st_filetype as *const _ as usize - base, 16);
+ assert_eq!(&obj.st_nlink as *const _ as usize - base, 20);
+ assert_eq!(&obj.st_size as *const _ as usize - base, 24);
+ assert_eq!(&obj.st_atim as *const _ as usize - base, 32);
+ assert_eq!(&obj.st_mtim as *const _ as usize - base, 40);
+ assert_eq!(&obj.st_ctim as *const _ as usize - base, 48);
+ }
+}
+
+/// A region of memory for scatter/gather reads.
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct iovec {
+ /// The address and length of the buffer to be filled.
+ pub buf: (*mut (), usize),
+}
+#[test]
+#[cfg(target_pointer_width = "32")]
+fn iovec_layout_test_32() {
+ assert_eq!(core::mem::size_of::<iovec>(), 8);
+ assert_eq!(core::mem::align_of::<iovec>(), 4);
+ unsafe {
+ let obj: iovec = core::mem::uninitialized();
+ let base = &obj as *const _ as usize;
+ assert_eq!(&obj.buf.0 as *const _ as usize - base, 0);
+ assert_eq!(&obj.buf.1 as *const _ as usize - base, 4);
+ }
+}
+#[test]
+#[cfg(target_pointer_width = "64")]
+fn iovec_layout_test_64() {
+ assert_eq!(core::mem::size_of::<iovec>(), 16);
+ assert_eq!(core::mem::align_of::<iovec>(), 8);
+ unsafe {
+ let obj: iovec = core::mem::uninitialized();
+ let base = &obj as *const _ as usize;
+ assert_eq!(&obj.buf.0 as *const _ as usize - base, 0);
+ assert_eq!(&obj.buf.1 as *const _ as usize - base, 8);
+ }
+}
+
+/// Path lookup properties.
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct lookup {
+ /// The working directory at which the resolution of the
+ /// path starts.
+ pub fd: fd,
+ /// Flags determining the method of how the path is
+ /// resolved.
+ pub flags: lookupflags,
+}
+#[test]
+fn lookup_layout_test() {
+ assert_eq!(core::mem::size_of::<lookup>(), 8);
+ assert_eq!(core::mem::align_of::<lookup>(), 4);
+ unsafe {
+ let obj: lookup = core::mem::uninitialized();
+ let base = &obj as *const _ as usize;
+ assert_eq!(&obj.fd as *const _ as usize - base, 0);
+ assert_eq!(&obj.flags as *const _ as usize - base, 4);
+ }
+}
+
+/// Entry point for a process (`_start`).
+///
+/// **auxv**:
+/// The auxiliary vector. See [`auxv`](struct.auxv.html).
+pub type processentry = unsafe extern "C" fn(
+ auxv: *const auxv,
+) -> ();
+
+/// Arguments of [`sock_recv()`](fn.sock_recv.html).
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct recv_in {
+ /// List of scatter/gather vectors where message data
+ /// should be stored.
+ pub ri_data: (*const iovec, usize),
+ /// Buffer where numbers of incoming file descriptors
+ /// should be stored.
+ pub ri_fds: (*mut fd, usize),
+ /// Message flags.
+ pub ri_flags: riflags,
+}
+#[test]
+#[cfg(target_pointer_width = "32")]
+fn recv_in_layout_test_32() {
+ assert_eq!(core::mem::size_of::<recv_in>(), 20);
+ assert_eq!(core::mem::align_of::<recv_in>(), 4);
+ unsafe {
+ let obj: recv_in = core::mem::uninitialized();
+ let base = &obj as *const _ as usize;
+ assert_eq!(&obj.ri_data.0 as *const _ as usize - base, 0);
+ assert_eq!(&obj.ri_data.1 as *const _ as usize - base, 4);
+ assert_eq!(&obj.ri_fds.0 as *const _ as usize - base, 8);
+ assert_eq!(&obj.ri_fds.1 as *const _ as usize - base, 12);
+ assert_eq!(&obj.ri_flags as *const _ as usize - base, 16);
+ }
+}
+#[test]
+#[cfg(target_pointer_width = "64")]
+fn recv_in_layout_test_64() {
+ assert_eq!(core::mem::size_of::<recv_in>(), 40);
+ assert_eq!(core::mem::align_of::<recv_in>(), 8);
+ unsafe {
+ let obj: recv_in = core::mem::uninitialized();
+ let base = &obj as *const _ as usize;
+ assert_eq!(&obj.ri_data.0 as *const _ as usize - base, 0);
+ assert_eq!(&obj.ri_data.1 as *const _ as usize - base, 8);
+ assert_eq!(&obj.ri_fds.0 as *const _ as usize - base, 16);
+ assert_eq!(&obj.ri_fds.1 as *const _ as usize - base, 24);
+ assert_eq!(&obj.ri_flags as *const _ as usize - base, 32);
+ }
+}
+
+/// Results of [`sock_recv()`](fn.sock_recv.html).
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct recv_out {
+ /// Number of bytes stored in [`recv_in.ri_data`](struct.recv_in.html#structfield.ri_data).
+ pub ro_datalen: usize,
+ /// Number of file descriptors stored in [`recv_in.ri_fds`](struct.recv_in.html#structfield.ri_fds).
+ pub ro_fdslen: usize,
+ /// Fields that were used by previous implementations.
+ pub ro_unused: [u8; 40],
+ /// Message flags.
+ pub ro_flags: roflags,
+}
+#[test]
+#[cfg(target_pointer_width = "32")]
+fn recv_out_layout_test_32() {
+ assert_eq!(core::mem::size_of::<recv_out>(), 52);
+ assert_eq!(core::mem::align_of::<recv_out>(), 4);
+ unsafe {
+ let obj: recv_out = core::mem::uninitialized();
+ let base = &obj as *const _ as usize;
+ assert_eq!(&obj.ro_datalen as *const _ as usize - base, 0);
+ assert_eq!(&obj.ro_fdslen as *const _ as usize - base, 4);
+ assert_eq!(&obj.ro_unused as *const _ as usize - base, 8);
+ assert_eq!(&obj.ro_flags as *const _ as usize - base, 48);
+ }
+}
+#[test]
+#[cfg(target_pointer_width = "64")]
+fn recv_out_layout_test_64() {
+ assert_eq!(core::mem::size_of::<recv_out>(), 64);
+ assert_eq!(core::mem::align_of::<recv_out>(), 8);
+ unsafe {
+ let obj: recv_out = core::mem::uninitialized();
+ let base = &obj as *const _ as usize;
+ assert_eq!(&obj.ro_datalen as *const _ as usize - base, 0);
+ assert_eq!(&obj.ro_fdslen as *const _ as usize - base, 8);
+ assert_eq!(&obj.ro_unused as *const _ as usize - base, 16);
+ assert_eq!(&obj.ro_flags as *const _ as usize - base, 56);
+ }
+}
+
+/// Arguments of [`sock_send()`](fn.sock_send.html).
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct send_in {
+ /// List of scatter/gather vectors where message data
+ /// should be retrieved.
+ pub si_data: (*const ciovec, usize),
+ /// File descriptors that need to be attached to the
+ /// message.
+ pub si_fds: (*const fd, usize),
+ /// Message flags.
+ pub si_flags: siflags,
+}
+#[test]
+#[cfg(target_pointer_width = "32")]
+fn send_in_layout_test_32() {
+ assert_eq!(core::mem::size_of::<send_in>(), 20);
+ assert_eq!(core::mem::align_of::<send_in>(), 4);
+ unsafe {
+ let obj: send_in = core::mem::uninitialized();
+ let base = &obj as *const _ as usize;
+ assert_eq!(&obj.si_data.0 as *const _ as usize - base, 0);
+ assert_eq!(&obj.si_data.1 as *const _ as usize - base, 4);
+ assert_eq!(&obj.si_fds.0 as *const _ as usize - base, 8);
+ assert_eq!(&obj.si_fds.1 as *const _ as usize - base, 12);
+ assert_eq!(&obj.si_flags as *const _ as usize - base, 16);
+ }
+}
+#[test]
+#[cfg(target_pointer_width = "64")]
+fn send_in_layout_test_64() {
+ assert_eq!(core::mem::size_of::<send_in>(), 40);
+ assert_eq!(core::mem::align_of::<send_in>(), 8);
+ unsafe {
+ let obj: send_in = core::mem::uninitialized();
+ let base = &obj as *const _ as usize;
+ assert_eq!(&obj.si_data.0 as *const _ as usize - base, 0);
+ assert_eq!(&obj.si_data.1 as *const _ as usize - base, 8);
+ assert_eq!(&obj.si_fds.0 as *const _ as usize - base, 16);
+ assert_eq!(&obj.si_fds.1 as *const _ as usize - base, 24);
+ assert_eq!(&obj.si_flags as *const _ as usize - base, 32);
+ }
+}
+
+/// Results of [`sock_send()`](fn.sock_send.html).
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct send_out {
+ /// Number of bytes transmitted.
+ pub so_datalen: usize,
+}
+#[test]
+#[cfg(target_pointer_width = "32")]
+fn send_out_layout_test_32() {
+ assert_eq!(core::mem::size_of::<send_out>(), 4);
+ assert_eq!(core::mem::align_of::<send_out>(), 4);
+ unsafe {
+ let obj: send_out = core::mem::uninitialized();
+ let base = &obj as *const _ as usize;
+ assert_eq!(&obj.so_datalen as *const _ as usize - base, 0);
+ }
+}
+#[test]
+#[cfg(target_pointer_width = "64")]
+fn send_out_layout_test_64() {
+ assert_eq!(core::mem::size_of::<send_out>(), 8);
+ assert_eq!(core::mem::align_of::<send_out>(), 8);
+ unsafe {
+ let obj: send_out = core::mem::uninitialized();
+ let base = &obj as *const _ as usize;
+ assert_eq!(&obj.so_datalen as *const _ as usize - base, 0);
+ }
+}
+
+/// Subscription to an event.
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct subscription {
+ /// User-provided value that is attached to the
+ /// subscription in the kernel and returned through
+ /// [`event.userdata`](struct.event.html#structfield.userdata).
+ pub userdata: userdata,
+ /// Used by previous implementations. Ignored.
+ pub unused: u16,
+ /// The type of the event to which to subscribe.
+ ///
+ /// Currently, [`CONDVAR`](enum.eventtype.html#variant.CONDVAR),
+ /// [`LOCK_RDLOCK`](enum.eventtype.html#variant.LOCK_RDLOCK), and [`LOCK_WRLOCK`](enum.eventtype.html#variant.LOCK_WRLOCK)
+ /// must be provided as the first subscription and may
+ /// only be followed by up to one other subscription,
+ /// having type [`CLOCK`](enum.eventtype.html#variant.CLOCK).
+ pub type_: eventtype,
+ pub union: subscription_union
+}
+/// A union inside `subscription`.
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub union subscription_union {
+ /// Used when `type_` is [`CLOCK`](enum.eventtype.html#variant.CLOCK).
+ pub clock: subscription_clock,
+ /// Used when `type_` is [`CONDVAR`](enum.eventtype.html#variant.CONDVAR).
+ pub condvar: subscription_condvar,
+ /// Used when `type_` is [`FD_READ`](enum.eventtype.html#variant.FD_READ) or [`FD_WRITE`](enum.eventtype.html#variant.FD_WRITE).
+ pub fd_readwrite: subscription_fd_readwrite,
+ /// Used when `type_` is [`LOCK_RDLOCK`](enum.eventtype.html#variant.LOCK_RDLOCK) or [`LOCK_WRLOCK`](enum.eventtype.html#variant.LOCK_WRLOCK).
+ pub lock: subscription_lock,
+ /// Used when `type_` is [`PROC_TERMINATE`](enum.eventtype.html#variant.PROC_TERMINATE).
+ pub proc_terminate: subscription_proc_terminate,
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct subscription_clock {
+ /// The user-defined unique
+ /// identifier of the clock.
+ pub identifier: userdata,
+ /// The clock against which the
+ /// timestamp should be compared.
+ pub clock_id: clockid,
+ /// The absolute or relative
+ /// timestamp.
+ pub timeout: timestamp,
+ /// The amount of time that the
+ /// kernel may wait additionally
+ /// to coalesce with other events.
+ pub precision: timestamp,
+ /// Flags specifying whether the
+ /// timeout is absolute or
+ /// relative.
+ pub flags: subclockflags,
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct subscription_condvar {
+ /// The condition variable on
+ /// which to wait to be woken up.
+ pub condvar: *mut condvar,
+ /// The lock that will be
+ /// released while waiting.
+ ///
+ /// The lock will be reacquired
+ /// for writing when the condition
+ /// variable triggers.
+ pub lock: *mut lock,
+ /// Whether the condition variable
+ /// is stored in private or shared
+ /// memory.
+ pub condvar_scope: scope,
+ /// Whether the lock is stored in
+ /// private or shared memory.
+ pub lock_scope: scope,
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct subscription_fd_readwrite {
+ /// The file descriptor on which
+ /// to wait for it to become ready
+ /// for reading or writing.
+ pub fd: fd,
+ /// Under which conditions to
+ /// trigger.
+ pub flags: subrwflags,
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct subscription_lock {
+ /// The lock that will be acquired
+ /// for reading or writing.
+ pub lock: *mut lock,
+ /// Whether the lock is stored in
+ /// private or shared memory.
+ pub lock_scope: scope,
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct subscription_proc_terminate {
+ /// The process descriptor on
+ /// which to wait for process
+ /// termination.
+ pub fd: fd,
+}
+#[test]
+#[cfg(target_pointer_width = "32")]
+fn subscription_layout_test_32() {
+ assert_eq!(core::mem::size_of::<subscription>(), 56);
+ assert_eq!(core::mem::align_of::<subscription>(), 8);
+ unsafe {
+ let obj: subscription = core::mem::uninitialized();
+ let base = &obj as *const _ as usize;
+ assert_eq!(&obj.userdata as *const _ as usize - base, 0);
+ assert_eq!(&obj.unused as *const _ as usize - base, 8);
+ assert_eq!(&obj.type_ as *const _ as usize - base, 10);
+ assert_eq!(&obj.union.clock.identifier as *const _ as usize - base, 16);
+ assert_eq!(&obj.union.clock.clock_id as *const _ as usize - base, 24);
+ assert_eq!(&obj.union.clock.timeout as *const _ as usize - base, 32);
+ assert_eq!(&obj.union.clock.precision as *const _ as usize - base, 40);
+ assert_eq!(&obj.union.clock.flags as *const _ as usize - base, 48);
+ assert_eq!(&obj.union.condvar.condvar as *const _ as usize - base, 16);
+ assert_eq!(&obj.union.condvar.lock as *const _ as usize - base, 20);
+ assert_eq!(&obj.union.condvar.condvar_scope as *const _ as usize - base, 24);
+ assert_eq!(&obj.union.condvar.lock_scope as *const _ as usize - base, 25);
+ assert_eq!(&obj.union.fd_readwrite.fd as *const _ as usize - base, 16);
+ assert_eq!(&obj.union.fd_readwrite.flags as *const _ as usize - base, 20);
+ assert_eq!(&obj.union.lock.lock as *const _ as usize - base, 16);
+ assert_eq!(&obj.union.lock.lock_scope as *const _ as usize - base, 20);
+ assert_eq!(&obj.union.proc_terminate.fd as *const _ as usize - base, 16);
+ }
+}
+#[test]
+#[cfg(target_pointer_width = "64")]
+fn subscription_layout_test_64() {
+ assert_eq!(core::mem::size_of::<subscription>(), 56);
+ assert_eq!(core::mem::align_of::<subscription>(), 8);
+ unsafe {
+ let obj: subscription = core::mem::uninitialized();
+ let base = &obj as *const _ as usize;
+ assert_eq!(&obj.userdata as *const _ as usize - base, 0);
+ assert_eq!(&obj.unused as *const _ as usize - base, 8);
+ assert_eq!(&obj.type_ as *const _ as usize - base, 10);
+ assert_eq!(&obj.union.clock.identifier as *const _ as usize - base, 16);
+ assert_eq!(&obj.union.clock.clock_id as *const _ as usize - base, 24);
+ assert_eq!(&obj.union.clock.timeout as *const _ as usize - base, 32);
+ assert_eq!(&obj.union.clock.precision as *const _ as usize - base, 40);
+ assert_eq!(&obj.union.clock.flags as *const _ as usize - base, 48);
+ assert_eq!(&obj.union.condvar.condvar as *const _ as usize - base, 16);
+ assert_eq!(&obj.union.condvar.lock as *const _ as usize - base, 24);
+ assert_eq!(&obj.union.condvar.condvar_scope as *const _ as usize - base, 32);
+ assert_eq!(&obj.union.condvar.lock_scope as *const _ as usize - base, 33);
+ assert_eq!(&obj.union.fd_readwrite.fd as *const _ as usize - base, 16);
+ assert_eq!(&obj.union.fd_readwrite.flags as *const _ as usize - base, 20);
+ assert_eq!(&obj.union.lock.lock as *const _ as usize - base, 16);
+ assert_eq!(&obj.union.lock.lock_scope as *const _ as usize - base, 24);
+ assert_eq!(&obj.union.proc_terminate.fd as *const _ as usize - base, 16);
+ }
+}
+
+/// The Thread Control Block (TCB).
+///
+/// After a thread begins execution (at program startup or when
+/// created through [`thread_create()`](fn.thread_create.html)), the CPU's registers
+/// controlling Thread-Local Storage (TLS) will already be
+/// initialized. They will point to an area only containing the
+/// TCB.
+///
+/// If the thread needs space for storing thread-specific
+/// variables, the thread may allocate a larger area and adjust
+/// the CPU's registers to point to that area instead. However, it
+/// does need to make sure that the TCB is copied over to the new
+/// TLS area.
+///
+/// The purpose of the TCB is that it allows light-weight
+/// emulators to store information related to individual threads.
+/// For example, it may be used to store a copy of the CPU
+/// registers prior emulation, so that TLS for the host system
+/// can be restored if needed.
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct tcb {
+ /// Pointer that may be freely assigned by the system. Its
+ /// value cannot be interpreted by the application.
+ pub parent: *mut (),
+}
+#[test]
+#[cfg(target_pointer_width = "32")]
+fn tcb_layout_test_32() {
+ assert_eq!(core::mem::size_of::<tcb>(), 4);
+ assert_eq!(core::mem::align_of::<tcb>(), 4);
+ unsafe {
+ let obj: tcb = core::mem::uninitialized();
+ let base = &obj as *const _ as usize;
+ assert_eq!(&obj.parent as *const _ as usize - base, 0);
+ }
+}
+#[test]
+#[cfg(target_pointer_width = "64")]
+fn tcb_layout_test_64() {
+ assert_eq!(core::mem::size_of::<tcb>(), 8);
+ assert_eq!(core::mem::align_of::<tcb>(), 8);
+ unsafe {
+ let obj: tcb = core::mem::uninitialized();
+ let base = &obj as *const _ as usize;
+ assert_eq!(&obj.parent as *const _ as usize - base, 0);
+ }
+}
+
+/// Entry point for additionally created threads.
+///
+/// `tid`: thread ID of the current thread.
+///
+/// `aux`: copy of the value stored in
+/// [`threadattr.argument`](struct.threadattr.html#structfield.argument).
+pub type threadentry = unsafe extern "C" fn(
+ tid: tid,
+ aux: *mut (),
+) -> ();
+
+/// Attributes for thread creation.
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct threadattr {
+ /// Initial program counter value.
+ pub entry_point: threadentry,
+ /// Region allocated to serve as stack space.
+ pub stack: (*mut (), usize),
+ /// Argument to be forwarded to the entry point function.
+ pub argument: *mut (),
+}
+#[test]
+#[cfg(target_pointer_width = "32")]
+fn threadattr_layout_test_32() {
+ assert_eq!(core::mem::size_of::<threadattr>(), 16);
+ assert_eq!(core::mem::align_of::<threadattr>(), 4);
+ unsafe {
+ let obj: threadattr = core::mem::uninitialized();
+ let base = &obj as *const _ as usize;
+ assert_eq!(&obj.entry_point as *const _ as usize - base, 0);
+ assert_eq!(&obj.stack.0 as *const _ as usize - base, 4);
+ assert_eq!(&obj.stack.1 as *const _ as usize - base, 8);
+ assert_eq!(&obj.argument as *const _ as usize - base, 12);
+ }
+}
+#[test]
+#[cfg(target_pointer_width = "64")]
+fn threadattr_layout_test_64() {
+ assert_eq!(core::mem::size_of::<threadattr>(), 32);
+ assert_eq!(core::mem::align_of::<threadattr>(), 8);
+ unsafe {
+ let obj: threadattr = core::mem::uninitialized();
+ let base = &obj as *const _ as usize;
+ assert_eq!(&obj.entry_point as *const _ as usize - base, 0);
+ assert_eq!(&obj.stack.0 as *const _ as usize - base, 8);
+ assert_eq!(&obj.stack.1 as *const _ as usize - base, 16);
+ assert_eq!(&obj.argument as *const _ as usize - base, 24);
+ }
+}
+
+/// The table with pointers to all syscall implementations.
+#[allow(improper_ctypes)]
+extern "C" {
+ fn cloudabi_sys_clock_res_get(_: clockid, _: *mut timestamp) -> errno;
+ fn cloudabi_sys_clock_time_get(_: clockid, _: timestamp, _: *mut timestamp) -> errno;
+ fn cloudabi_sys_condvar_signal(_: *mut condvar, _: scope, _: nthreads) -> errno;
+ fn cloudabi_sys_fd_close(_: fd) -> errno;
+ fn cloudabi_sys_fd_create1(_: filetype, _: *mut fd) -> errno;
+ fn cloudabi_sys_fd_create2(_: filetype, _: *mut fd, _: *mut fd) -> errno;
+ fn cloudabi_sys_fd_datasync(_: fd) -> errno;
+ fn cloudabi_sys_fd_dup(_: fd, _: *mut fd) -> errno;
+ fn cloudabi_sys_fd_pread(_: fd, _: *const iovec, _: usize, _: filesize, _: *mut usize) -> errno;
+ fn cloudabi_sys_fd_pwrite(_: fd, _: *const ciovec, _: usize, _: filesize, _: *mut usize) -> errno;
+ fn cloudabi_sys_fd_read(_: fd, _: *const iovec, _: usize, _: *mut usize) -> errno;
+ fn cloudabi_sys_fd_replace(_: fd, _: fd) -> errno;
+ fn cloudabi_sys_fd_seek(_: fd, _: filedelta, _: whence, _: *mut filesize) -> errno;
+ fn cloudabi_sys_fd_stat_get(_: fd, _: *mut fdstat) -> errno;
+ fn cloudabi_sys_fd_stat_put(_: fd, _: *const fdstat, _: fdsflags) -> errno;
+ fn cloudabi_sys_fd_sync(_: fd) -> errno;
+ fn cloudabi_sys_fd_write(_: fd, _: *const ciovec, _: usize, _: *mut usize) -> errno;
+ fn cloudabi_sys_file_advise(_: fd, _: filesize, _: filesize, _: advice) -> errno;
+ fn cloudabi_sys_file_allocate(_: fd, _: filesize, _: filesize) -> errno;
+ fn cloudabi_sys_file_create(_: fd, _: *const u8, _: usize, _: filetype) -> errno;
+ fn cloudabi_sys_file_link(_: lookup, _: *const u8, _: usize, _: fd, _: *const u8, _: usize) -> errno;
+ fn cloudabi_sys_file_open(_: lookup, _: *const u8, _: usize, _: oflags, _: *const fdstat, _: *mut fd) -> errno;
+ fn cloudabi_sys_file_readdir(_: fd, _: *mut (), _: usize, _: dircookie, _: *mut usize) -> errno;
+ fn cloudabi_sys_file_readlink(_: fd, _: *const u8, _: usize, _: *mut u8, _: usize, _: *mut usize) -> errno;
+ fn cloudabi_sys_file_rename(_: fd, _: *const u8, _: usize, _: fd, _: *const u8, _: usize) -> errno;
+ fn cloudabi_sys_file_stat_fget(_: fd, _: *mut filestat) -> errno;
+ fn cloudabi_sys_file_stat_fput(_: fd, _: *const filestat, _: fsflags) -> errno;
+ fn cloudabi_sys_file_stat_get(_: lookup, _: *const u8, _: usize, _: *mut filestat) -> errno;
+ fn cloudabi_sys_file_stat_put(_: lookup, _: *const u8, _: usize, _: *const filestat, _: fsflags) -> errno;
+ fn cloudabi_sys_file_symlink(_: *const u8, _: usize, _: fd, _: *const u8, _: usize) -> errno;
+ fn cloudabi_sys_file_unlink(_: fd, _: *const u8, _: usize, _: ulflags) -> errno;
+ fn cloudabi_sys_lock_unlock(_: *mut lock, _: scope) -> errno;
+ fn cloudabi_sys_mem_advise(_: *mut (), _: usize, _: advice) -> errno;
+ fn cloudabi_sys_mem_map(_: *mut (), _: usize, _: mprot, _: mflags, _: fd, _: filesize, _: *mut *mut ()) -> errno;
+ fn cloudabi_sys_mem_protect(_: *mut (), _: usize, _: mprot) -> errno;
+ fn cloudabi_sys_mem_sync(_: *mut (), _: usize, _: msflags) -> errno;
+ fn cloudabi_sys_mem_unmap(_: *mut (), _: usize) -> errno;
+ fn cloudabi_sys_poll(_: *const subscription, _: *mut event, _: usize, _: *mut usize) -> errno;
+ fn cloudabi_sys_proc_exec(_: fd, _: *const (), _: usize, _: *const fd, _: usize) -> errno;
+ fn cloudabi_sys_proc_exit(_: exitcode) -> !;
+ fn cloudabi_sys_proc_fork(_: *mut fd, _: *mut tid) -> errno;
+ fn cloudabi_sys_proc_raise(_: signal) -> errno;
+ fn cloudabi_sys_random_get(_: *mut (), _: usize) -> errno;
+ fn cloudabi_sys_sock_recv(_: fd, _: *const recv_in, _: *mut recv_out) -> errno;
+ fn cloudabi_sys_sock_send(_: fd, _: *const send_in, _: *mut send_out) -> errno;
+ fn cloudabi_sys_sock_shutdown(_: fd, _: sdflags) -> errno;
+ fn cloudabi_sys_thread_create(_: *mut threadattr, _: *mut tid) -> errno;
+ fn cloudabi_sys_thread_exit(_: *mut lock, _: scope) -> !;
+ fn cloudabi_sys_thread_yield() -> errno;
+}
+
+/// Obtains the resolution of a clock.
+///
+/// ## Parameters
+///
+/// **clock_id**:
+/// The clock for which the resolution needs to be
+/// returned.
+///
+/// **resolution**:
+/// The resolution of the clock.
+#[inline]
+pub unsafe fn clock_res_get(clock_id_: clockid, resolution_: &mut timestamp) -> errno {
+ cloudabi_sys_clock_res_get(clock_id_, resolution_)
+}
+
+/// Obtains the time value of a clock.
+///
+/// ## Parameters
+///
+/// **clock_id**:
+/// The clock for which the time needs to be
+/// returned.
+///
+/// **precision**:
+/// The maximum lag (exclusive) that the returned
+/// time value may have, compared to its actual
+/// value.
+///
+/// **time**:
+/// The time value of the clock.
+#[inline]
+pub unsafe fn clock_time_get(clock_id_: clockid, precision_: timestamp, time_: &mut timestamp) -> errno {
+ cloudabi_sys_clock_time_get(clock_id_, precision_, time_)
+}
+
+/// Wakes up threads waiting on a userspace condition variable.
+///
+/// If an invocation of this system call causes all waiting
+/// threads to be woken up, the value of the condition variable
+/// is set to [`CONDVAR_HAS_NO_WAITERS`](constant.CONDVAR_HAS_NO_WAITERS.html). As long as the condition
+/// variable is set to this value, it is not needed to invoke this
+/// system call.
+///
+/// ## Parameters
+///
+/// **condvar**:
+/// The userspace condition variable that has
+/// waiting threads.
+///
+/// **scope**:
+/// Whether the condition variable is stored in
+/// private or shared memory.
+///
+/// **nwaiters**:
+/// The number of threads that need to be woken
+/// up. If it exceeds the number of waiting
+/// threads, all threads are woken up.
+#[inline]
+pub unsafe fn condvar_signal(condvar_: *mut condvar, scope_: scope, nwaiters_: nthreads) -> errno {
+ cloudabi_sys_condvar_signal(condvar_, scope_, nwaiters_)
+}
+
+/// Closes a file descriptor.
+///
+/// ## Parameters
+///
+/// **fd**:
+/// The file descriptor that needs to be closed.
+#[inline]
+pub unsafe fn fd_close(fd_: fd) -> errno {
+ cloudabi_sys_fd_close(fd_)
+}
+
+/// Creates a file descriptor.
+///
+/// ## Parameters
+///
+/// **type**:
+/// Possible values:
+///
+/// - [`SHARED_MEMORY`](enum.filetype.html#variant.SHARED_MEMORY):
+/// Creates an anonymous shared memory
+/// object.
+///
+/// **fd**:
+/// The file descriptor that has been created.
+#[inline]
+pub unsafe fn fd_create1(type_: filetype, fd_: &mut fd) -> errno {
+ cloudabi_sys_fd_create1(type_, fd_)
+}
+
+/// Creates a pair of file descriptors.
+///
+/// ## Parameters
+///
+/// **type**:
+/// Possible values:
+///
+/// - [`SOCKET_DGRAM`](enum.filetype.html#variant.SOCKET_DGRAM):
+/// Creates a UNIX datagram socket pair.
+/// - [`SOCKET_STREAM`](enum.filetype.html#variant.SOCKET_STREAM):
+/// Creates a UNIX byte-stream socket
+/// pair.
+///
+/// **fd1**:
+/// The first file descriptor of the pair.
+///
+/// **fd2**:
+/// The second file descriptor of the pair.
+#[inline]
+pub unsafe fn fd_create2(type_: filetype, fd1_: &mut fd, fd2_: &mut fd) -> errno {
+ cloudabi_sys_fd_create2(type_, fd1_, fd2_)
+}
+
+/// Synchronizes the data of a file to disk.
+///
+/// ## Parameters
+///
+/// **fd**:
+/// The file descriptor of the file whose data
+/// needs to be synchronized to disk.
+#[inline]
+pub unsafe fn fd_datasync(fd_: fd) -> errno {
+ cloudabi_sys_fd_datasync(fd_)
+}
+
+/// Duplicates a file descriptor.
+///
+/// ## Parameters
+///
+/// **from**:
+/// The file descriptor that needs to be
+/// duplicated.
+///
+/// **fd**:
+/// The new file descriptor.
+#[inline]
+pub unsafe fn fd_dup(from_: fd, fd_: &mut fd) -> errno {
+ cloudabi_sys_fd_dup(from_, fd_)
+}
+
+/// Reads from a file descriptor, without using and updating the
+/// file descriptor's offset.
+///
+/// ## Parameters
+///
+/// **fd**:
+/// The file descriptor from which data should be
+/// read.
+///
+/// **iovs**:
+/// List of scatter/gather vectors where data
+/// should be stored.
+///
+/// **offset**:
+/// The offset within the file at which reading
+/// should start.
+///
+/// **nread**:
+/// The number of bytes read.
+#[inline]
+pub unsafe fn fd_pread(fd_: fd, iovs_: &[iovec], offset_: filesize, nread_: &mut usize) -> errno {
+ cloudabi_sys_fd_pread(fd_, iovs_.as_ptr(), iovs_.len(), offset_, nread_)
+}
+
+/// Writes to a file descriptor, without using and updating the
+/// file descriptor's offset.
+///
+/// ## Parameters
+///
+/// **fd**:
+/// The file descriptor to which data should be
+/// written.
+///
+/// **iovs**:
+/// List of scatter/gather vectors where data
+/// should be retrieved.
+///
+/// **offset**:
+/// The offset within the file at which writing
+/// should start.
+///
+/// **nwritten**:
+/// The number of bytes written.
+#[inline]
+pub unsafe fn fd_pwrite(fd_: fd, iovs_: &[ciovec], offset_: filesize, nwritten_: &mut usize) -> errno {
+ cloudabi_sys_fd_pwrite(fd_, iovs_.as_ptr(), iovs_.len(), offset_, nwritten_)
+}
+
+/// Reads from a file descriptor.
+///
+/// ## Parameters
+///
+/// **fd**:
+/// The file descriptor from which data should be
+/// read.
+///
+/// **iovs**:
+/// List of scatter/gather vectors where data
+/// should be stored.
+///
+/// **nread**:
+/// The number of bytes read.
+#[inline]
+pub unsafe fn fd_read(fd_: fd, iovs_: &[iovec], nread_: &mut usize) -> errno {
+ cloudabi_sys_fd_read(fd_, iovs_.as_ptr(), iovs_.len(), nread_)
+}
+
+/// Atomically replaces a file descriptor by a copy of another
+/// file descriptor.
+///
+/// Due to the strong focus on thread safety, this environment
+/// does not provide a mechanism to duplicate a file descriptor to
+/// an arbitrary number, like dup2(). This would be prone to race
+/// conditions, as an actual file descriptor with the same number
+/// could be allocated by a different thread at the same time.
+///
+/// This system call provides a way to atomically replace file
+/// descriptors, which would disappear if dup2() were to be
+/// removed entirely.
+///
+/// ## Parameters
+///
+/// **from**:
+/// The file descriptor that needs to be copied.
+///
+/// **to**:
+/// The file descriptor that needs to be
+/// overwritten.
+#[inline]
+pub unsafe fn fd_replace(from_: fd, to_: fd) -> errno {
+ cloudabi_sys_fd_replace(from_, to_)
+}
+
+/// Moves the offset of the file descriptor.
+///
+/// ## Parameters
+///
+/// **fd**:
+/// The file descriptor whose offset has to be
+/// moved.
+///
+/// **offset**:
+/// The number of bytes to move.
+///
+/// **whence**:
+/// Relative to which position the move should
+/// take place.
+///
+/// **newoffset**:
+/// The new offset of the file descriptor,
+/// relative to the start of the file.
+#[inline]
+pub unsafe fn fd_seek(fd_: fd, offset_: filedelta, whence_: whence, newoffset_: &mut filesize) -> errno {
+ cloudabi_sys_fd_seek(fd_, offset_, whence_, newoffset_)
+}
+
+/// Gets attributes of a file descriptor.
+///
+/// ## Parameters
+///
+/// **fd**:
+/// The file descriptor whose attributes have to
+/// be obtained.
+///
+/// **buf**:
+/// The buffer where the file descriptor's
+/// attributes are stored.
+#[inline]
+pub unsafe fn fd_stat_get(fd_: fd, buf_: *mut fdstat) -> errno {
+ cloudabi_sys_fd_stat_get(fd_, buf_)
+}
+
+/// Adjusts attributes of a file descriptor.
+///
+/// ## Parameters
+///
+/// **fd**:
+/// The file descriptor whose attributes have to
+/// be adjusted.
+///
+/// **buf**:
+/// The desired values of the file descriptor
+/// attributes that are adjusted.
+///
+/// **flags**:
+/// A bitmask indicating which attributes have to
+/// be adjusted.
+#[inline]
+pub unsafe fn fd_stat_put(fd_: fd, buf_: *const fdstat, flags_: fdsflags) -> errno {
+ cloudabi_sys_fd_stat_put(fd_, buf_, flags_)
+}
+
+/// Synchronizes the data and metadata of a file to disk.
+///
+/// ## Parameters
+///
+/// **fd**:
+/// The file descriptor of the file whose data
+/// and metadata needs to be synchronized to disk.
+#[inline]
+pub unsafe fn fd_sync(fd_: fd) -> errno {
+ cloudabi_sys_fd_sync(fd_)
+}
+
+/// Writes to a file descriptor.
+///
+/// ## Parameters
+///
+/// **fd**:
+/// The file descriptor to which data should be
+/// written.
+///
+/// **iovs**:
+/// List of scatter/gather vectors where data
+/// should be retrieved.
+///
+/// **nwritten**:
+/// The number of bytes written.
+#[inline]
+pub unsafe fn fd_write(fd_: fd, iovs_: &[ciovec], nwritten_: &mut usize) -> errno {
+ cloudabi_sys_fd_write(fd_, iovs_.as_ptr(), iovs_.len(), nwritten_)
+}
+
+/// Provides file advisory information on a file descriptor.
+///
+/// ## Parameters
+///
+/// **fd**:
+/// The file descriptor for which to provide file
+/// advisory information.
+///
+/// **offset**:
+/// The offset within the file to which the
+/// advisory applies.
+///
+/// **len**:
+/// The length of the region to which the advisory
+/// applies.
+///
+/// **advice**:
+/// The advice.
+#[inline]
+pub unsafe fn file_advise(fd_: fd, offset_: filesize, len_: filesize, advice_: advice) -> errno {
+ cloudabi_sys_file_advise(fd_, offset_, len_, advice_)
+}
+
+/// Forces the allocation of space in a file.
+///
+/// ## Parameters
+///
+/// **fd**:
+/// The file in which the space should be
+/// allocated.
+///
+/// **offset**:
+/// The offset at which the allocation should
+/// start.
+///
+/// **len**:
+/// The length of the area that is allocated.
+#[inline]
+pub unsafe fn file_allocate(fd_: fd, offset_: filesize, len_: filesize) -> errno {
+ cloudabi_sys_file_allocate(fd_, offset_, len_)
+}
+
+/// Creates a file of a specified type.
+///
+/// ## Parameters
+///
+/// **fd**:
+/// The working directory at which the resolution
+/// of the file to be created starts.
+///
+/// **path**:
+/// The path at which the file should be created.
+///
+/// **type**:
+/// Possible values:
+///
+/// - [`DIRECTORY`](enum.filetype.html#variant.DIRECTORY):
+/// Creates a directory.
+#[inline]
+pub unsafe fn file_create(fd_: fd, path_: &[u8], type_: filetype) -> errno {
+ cloudabi_sys_file_create(fd_, path_.as_ptr(), path_.len(), type_)
+}
+
+/// Creates a hard link.
+///
+/// ## Parameters
+///
+/// **fd1**:
+/// The working directory at which the resolution
+/// of the source path starts.
+///
+/// **path1**:
+/// The source path of the file that should be
+/// hard linked.
+///
+/// **fd2**:
+/// The working directory at which the resolution
+/// of the destination path starts.
+///
+/// **path2**:
+/// The destination path at which the hard link
+/// should be created.
+#[inline]
+pub unsafe fn file_link(fd1_: lookup, path1_: &[u8], fd2_: fd, path2_: &[u8]) -> errno {
+ cloudabi_sys_file_link(fd1_, path1_.as_ptr(), path1_.len(), fd2_, path2_.as_ptr(), path2_.len())
+}
+
+/// Opens a file.
+///
+/// ## Parameters
+///
+/// **dirfd**:
+/// The working directory at which the resolution
+/// of the file to be opened starts.
+///
+/// **path**:
+/// The path of the file that should be opened.
+///
+/// **oflags**:
+/// The method at which the file should be opened.
+///
+/// **fds**:
+/// [`fdstat.fs_rights_base`](struct.fdstat.html#structfield.fs_rights_base) and
+/// [`fdstat.fs_rights_inheriting`](struct.fdstat.html#structfield.fs_rights_inheriting) specify the
+/// initial rights of the newly created file
+/// descriptor. The operating system is allowed to
+/// return a file descriptor with fewer rights
+/// than specified, if and only if those rights do
+/// not apply to the type of file being opened.
+///
+/// [`fdstat.fs_flags`](struct.fdstat.html#structfield.fs_flags) specifies the initial flags
+/// of the file descriptor.
+///
+/// [`fdstat.fs_filetype`](struct.fdstat.html#structfield.fs_filetype) is ignored.
+///
+/// **fd**:
+/// The file descriptor of the file that has been
+/// opened.
+#[inline]
+pub unsafe fn file_open(dirfd_: lookup, path_: &[u8], oflags_: oflags, fds_: *const fdstat, fd_: &mut fd) -> errno {
+ cloudabi_sys_file_open(dirfd_, path_.as_ptr(), path_.len(), oflags_, fds_, fd_)
+}
+
+/// Reads directory entries from a directory.
+///
+/// When successful, the contents of the output buffer consist of
+/// a sequence of directory entries. Each directory entry consists
+/// of a [`dirent`](struct.dirent.html) object, followed by [`dirent.d_namlen`](struct.dirent.html#structfield.d_namlen) bytes
+/// holding the name of the directory entry.
+///
+/// This system call fills the output buffer as much as possible,
+/// potentially truncating the last directory entry. This allows
+/// the caller to grow its read buffer size in case it's too small
+/// to fit a single large directory entry, or skip the oversized
+/// directory entry.
+///
+/// ## Parameters
+///
+/// **fd**:
+/// The directory from which to read the directory
+/// entries.
+///
+/// **buf**:
+/// The buffer where directory entries are stored.
+///
+/// **cookie**:
+/// The location within the directory to start
+/// reading.
+///
+/// **bufused**:
+/// The number of bytes stored in the read buffer.
+/// If less than the size of the read buffer, the
+/// end of the directory has been reached.
+#[inline]
+pub unsafe fn file_readdir(fd_: fd, buf_: &mut [u8], cookie_: dircookie, bufused_: &mut usize) -> errno {
+ cloudabi_sys_file_readdir(fd_, buf_.as_mut_ptr() as *mut (), buf_.len(), cookie_, bufused_)
+}
+
+/// Reads the contents of a symbolic link.
+///
+/// ## Parameters
+///
+/// **fd**:
+/// The working directory at which the resolution
+/// of the path of the symbolic starts.
+///
+/// **path**:
+/// The path of the symbolic link whose contents
+/// should be read.
+///
+/// **buf**:
+/// The buffer where the contents of the symbolic
+/// link should be stored.
+///
+/// **bufused**:
+/// The number of bytes placed in the buffer.
+#[inline]
+pub unsafe fn file_readlink(fd_: fd, path_: &[u8], buf_: &mut [u8], bufused_: &mut usize) -> errno {
+ cloudabi_sys_file_readlink(fd_, path_.as_ptr(), path_.len(), buf_.as_mut_ptr(), buf_.len(), bufused_)
+}
+
+/// Renames a file.
+///
+/// ## Parameters
+///
+/// **fd1**:
+/// The working directory at which the resolution
+/// of the source path starts.
+///
+/// **path1**:
+/// The source path of the file that should be
+/// renamed.
+///
+/// **fd2**:
+/// The working directory at which the resolution
+/// of the destination path starts.
+///
+/// **path2**:
+/// The destination path to which the file should
+/// be renamed.
+#[inline]
+pub unsafe fn file_rename(fd1_: fd, path1_: &[u8], fd2_: fd, path2_: &[u8]) -> errno {
+ cloudabi_sys_file_rename(fd1_, path1_.as_ptr(), path1_.len(), fd2_, path2_.as_ptr(), path2_.len())
+}
+
+/// Gets attributes of a file by file descriptor.
+///
+/// ## Parameters
+///
+/// **fd**:
+/// The file descriptor whose attributes have to
+/// be obtained.
+///
+/// **buf**:
+/// The buffer where the file's attributes are
+/// stored.
+#[inline]
+pub unsafe fn file_stat_fget(fd_: fd, buf_: *mut filestat) -> errno {
+ cloudabi_sys_file_stat_fget(fd_, buf_)
+}
+
+/// Adjusts attributes of a file by file descriptor.
+///
+/// ## Parameters
+///
+/// **fd**:
+/// The file descriptor whose attributes have to
+/// be adjusted.
+///
+/// **buf**:
+/// The desired values of the file attributes that
+/// are adjusted.
+///
+/// **flags**:
+/// A bitmask indicating which attributes have to
+/// be adjusted.
+#[inline]
+pub unsafe fn file_stat_fput(fd_: fd, buf_: *const filestat, flags_: fsflags) -> errno {
+ cloudabi_sys_file_stat_fput(fd_, buf_, flags_)
+}
+
+/// Gets attributes of a file by path.
+///
+/// ## Parameters
+///
+/// **fd**:
+/// The working directory at which the resolution
+/// of the path whose attributes have to be
+/// obtained starts.
+///
+/// **path**:
+/// The path of the file whose attributes have to
+/// be obtained.
+///
+/// **buf**:
+/// The buffer where the file's attributes are
+/// stored.
+#[inline]
+pub unsafe fn file_stat_get(fd_: lookup, path_: &[u8], buf_: *mut filestat) -> errno {
+ cloudabi_sys_file_stat_get(fd_, path_.as_ptr(), path_.len(), buf_)
+}
+
+/// Adjusts attributes of a file by path.
+///
+/// ## Parameters
+///
+/// **fd**:
+/// The working directory at which the resolution
+/// of the path whose attributes have to be
+/// adjusted starts.
+///
+/// **path**:
+/// The path of the file whose attributes have to
+/// be adjusted.
+///
+/// **buf**:
+/// The desired values of the file attributes that
+/// are adjusted.
+///
+/// **flags**:
+/// A bitmask indicating which attributes have to
+/// be adjusted.
+#[inline]
+pub unsafe fn file_stat_put(fd_: lookup, path_: &[u8], buf_: *const filestat, flags_: fsflags) -> errno {
+ cloudabi_sys_file_stat_put(fd_, path_.as_ptr(), path_.len(), buf_, flags_)
+}
+
+/// Creates a symbolic link.
+///
+/// ## Parameters
+///
+/// **path1**:
+/// The contents of the symbolic link.
+///
+/// **fd**:
+/// The working directory at which the resolution
+/// of the destination path starts.
+///
+/// **path2**:
+/// The destination path at which the symbolic
+/// link should be created.
+#[inline]
+pub unsafe fn file_symlink(path1_: &[u8], fd_: fd, path2_: &[u8]) -> errno {
+ cloudabi_sys_file_symlink(path1_.as_ptr(), path1_.len(), fd_, path2_.as_ptr(), path2_.len())
+}
+
+/// Unlinks a file, or removes a directory.
+///
+/// ## Parameters
+///
+/// **fd**:
+/// The working directory at which the resolution
+/// of the path starts.
+///
+/// **path**:
+/// The path that needs to be unlinked or removed.
+///
+/// **flags**:
+/// Possible values:
+///
+/// - [`REMOVEDIR`](struct.ulflags.html#associatedconstant.REMOVEDIR):
+/// If set, attempt to remove a directory.
+/// Otherwise, unlink a file.
+#[inline]
+pub unsafe fn file_unlink(fd_: fd, path_: &[u8], flags_: ulflags) -> errno {
+ cloudabi_sys_file_unlink(fd_, path_.as_ptr(), path_.len(), flags_)
+}
+
+/// Unlocks a write-locked userspace lock.
+///
+/// If a userspace lock is unlocked while having its
+/// [`LOCK_KERNEL_MANAGED`](constant.LOCK_KERNEL_MANAGED.html) flag set, the lock cannot be unlocked in
+/// userspace directly. This system call needs to be performed
+/// instead, so that any waiting threads can be woken up.
+///
+/// To prevent spurious invocations of this system call, the lock
+/// must be locked for writing. This prevents other threads from
+/// acquiring additional read locks while the system call is in
+/// progress. If the lock is acquired for reading, it must first
+/// be upgraded to a write lock.
+///
+/// ## Parameters
+///
+/// **lock**:
+/// The userspace lock that is locked for writing
+/// by the calling thread.
+///
+/// **scope**:
+/// Whether the lock is stored in private or
+/// shared memory.
+#[inline]
+pub unsafe fn lock_unlock(lock_: *mut lock, scope_: scope) -> errno {
+ cloudabi_sys_lock_unlock(lock_, scope_)
+}
+
+/// Provides memory advisory information on a region of memory.
+///
+/// ## Parameters
+///
+/// **mapping**:
+/// The pages for which to provide memory advisory
+/// information.
+///
+/// **advice**:
+/// The advice.
+#[inline]
+pub unsafe fn mem_advise(mapping_: &mut [u8], advice_: advice) -> errno {
+ cloudabi_sys_mem_advise(mapping_.as_mut_ptr() as *mut (), mapping_.len(), advice_)
+}
+
+/// Creates a memory mapping, making the contents of a file
+/// accessible through memory.
+///
+/// ## Parameters
+///
+/// **addr**:
+/// If [`FIXED`](struct.mflags.html#associatedconstant.FIXED) is set, specifies to which
+/// address the file region is mapped. Otherwise,
+/// the mapping is performed at an unused
+/// location.
+///
+/// **len**:
+/// The length of the memory mapping to be
+/// created.
+///
+/// **prot**:
+/// Initial memory protection options for the
+/// memory mapping.
+///
+/// **flags**:
+/// Memory mapping flags.
+///
+/// **fd**:
+/// If [`ANON`](struct.mflags.html#associatedconstant.ANON) is set, this argument must be
+/// [`MAP_ANON_FD`](constant.MAP_ANON_FD.html). Otherwise, this argument
+/// specifies the file whose contents need to be
+/// mapped.
+///
+/// **off**:
+/// If [`ANON`](struct.mflags.html#associatedconstant.ANON) is set, this argument must be
+/// zero. Otherwise, this argument specifies the
+/// offset within the file at which the mapping
+/// starts.
+///
+/// **mem**:
+/// The starting address of the memory mapping.
+#[inline]
+pub unsafe fn mem_map(addr_: *mut (), len_: usize, prot_: mprot, flags_: mflags, fd_: fd, off_: filesize, mem_: &mut *mut ()) -> errno {
+ cloudabi_sys_mem_map(addr_, len_, prot_, flags_, fd_, off_, mem_)
+}
+
+/// Changes the protection of a memory mapping.
+///
+/// ## Parameters
+///
+/// **mapping**:
+/// The pages that need their protection changed.
+///
+/// **prot**:
+/// New protection options.
+#[inline]
+pub unsafe fn mem_protect(mapping_: &mut [u8], prot_: mprot) -> errno {
+ cloudabi_sys_mem_protect(mapping_.as_mut_ptr() as *mut (), mapping_.len(), prot_)
+}
+
+/// Synchronizes a region of memory with its physical storage.
+///
+/// ## Parameters
+///
+/// **mapping**:
+/// The pages that need to be synchronized.
+///
+/// **flags**:
+/// The method of synchronization.
+#[inline]
+pub unsafe fn mem_sync(mapping_: &mut [u8], flags_: msflags) -> errno {
+ cloudabi_sys_mem_sync(mapping_.as_mut_ptr() as *mut (), mapping_.len(), flags_)
+}
+
+/// Unmaps a region of memory.
+///
+/// ## Parameters
+///
+/// **mapping**:
+/// The pages that needs to be unmapped.
+#[inline]
+pub unsafe fn mem_unmap(mapping_: &mut [u8]) -> errno {
+ cloudabi_sys_mem_unmap(mapping_.as_mut_ptr() as *mut (), mapping_.len())
+}
+
+/// Concurrently polls for the occurrence of a set of events.
+///
+/// ## Parameters
+///
+/// **in**:
+/// The events to which to subscribe.
+///
+/// **out**:
+/// The events that have occurred.
+///
+/// **nsubscriptions**:
+/// Both the number of subscriptions and events.
+///
+/// **nevents**:
+/// The number of events stored.
+#[inline]
+pub unsafe fn poll(in_: *const subscription, out_: *mut event, nsubscriptions_: usize, nevents_: &mut usize) -> errno {
+ cloudabi_sys_poll(in_, out_, nsubscriptions_, nevents_)
+}
+
+/// Replaces the process by a new executable.
+///
+/// Process execution in CloudABI differs from POSIX in two ways:
+/// handling of arguments and inheritance of file descriptors.
+///
+/// CloudABI does not use string command line arguments. Instead,
+/// a buffer with binary data is copied into the address space of
+/// the new executable. The kernel does not enforce any specific
+/// structure to this data, although CloudABI's C library uses it
+/// to store a tree structure that is semantically identical to
+/// YAML.
+///
+/// Due to the strong focus on thread safety, file descriptors
+/// aren't inherited through close-on-exec flags. An explicit
+/// list of file descriptors that need to be retained needs to be
+/// provided. After execution, file descriptors are placed in the
+/// order in which they are stored in the array. This not only
+/// makes the execution process deterministic. It also prevents
+/// potential information disclosures about the layout of the
+/// original process.
+///
+/// ## Parameters
+///
+/// **fd**:
+/// A file descriptor of the new executable.
+///
+/// **data**:
+/// Binary argument data that is passed on to the
+/// new executable.
+///
+/// **fds**:
+/// The layout of the file descriptor table after
+/// execution.
+#[inline]
+pub unsafe fn proc_exec(fd_: fd, data_: &[u8], fds_: &[fd]) -> errno {
+ cloudabi_sys_proc_exec(fd_, data_.as_ptr() as *const (), data_.len(), fds_.as_ptr(), fds_.len())
+}
+
+/// Terminates the process normally.
+///
+/// ## Parameters
+///
+/// **rval**:
+/// The exit code returned by the process. The
+/// exit code can be obtained by other processes
+/// through [`event.union.proc_terminate.exitcode`](struct.event_proc_terminate.html#structfield.exitcode).
+#[inline]
+pub unsafe fn proc_exit(rval_: exitcode) -> ! {
+ cloudabi_sys_proc_exit(rval_)
+}
+
+/// Forks the process of the calling thread.
+///
+/// After forking, a new process shall be created, having only a
+/// copy of the calling thread. The parent process will obtain a
+/// process descriptor. When closed, the child process is
+/// automatically signaled with [`KILL`](enum.signal.html#variant.KILL).
+///
+/// ## Parameters
+///
+/// **fd**:
+/// In the parent process: the file descriptor
+/// number of the process descriptor.
+///
+/// In the child process: [`PROCESS_CHILD`](constant.PROCESS_CHILD.html).
+///
+/// **tid**:
+/// In the parent process: undefined.
+///
+/// In the child process: the thread ID of the
+/// initial thread of the child process.
+#[inline]
+pub unsafe fn proc_fork(fd_: &mut fd, tid_: &mut tid) -> errno {
+ cloudabi_sys_proc_fork(fd_, tid_)
+}
+
+/// Sends a signal to the process of the calling thread.
+///
+/// ## Parameters
+///
+/// **sig**:
+/// The signal condition that should be triggered.
+/// If the signal causes the process to terminate,
+/// its condition can be obtained by other
+/// processes through
+/// [`event.union.proc_terminate.signal`](struct.event_proc_terminate.html#structfield.signal).
+#[inline]
+pub unsafe fn proc_raise(sig_: signal) -> errno {
+ cloudabi_sys_proc_raise(sig_)
+}
+
+/// Obtains random data from the kernel random number generator.
+///
+/// As this interface is not guaranteed to be fast, it is advised
+/// that the random data obtained through this system call is used
+/// as the seed for a userspace pseudo-random number generator.
+///
+/// ## Parameters
+///
+/// **buf**:
+/// The buffer that needs to be filled with random
+/// data.
+#[inline]
+pub unsafe fn random_get(buf_: &mut [u8]) -> errno {
+ cloudabi_sys_random_get(buf_.as_mut_ptr() as *mut (), buf_.len())
+}
+
+/// Receives a message on a socket.
+///
+/// ## Parameters
+///
+/// **sock**:
+/// The socket on which a message should be
+/// received.
+///
+/// **in**:
+/// Input parameters.
+///
+/// **out**:
+/// Output parameters.
+#[inline]
+pub unsafe fn sock_recv(sock_: fd, in_: *const recv_in, out_: *mut recv_out) -> errno {
+ cloudabi_sys_sock_recv(sock_, in_, out_)
+}
+
+/// Sends a message on a socket.
+///
+/// ## Parameters
+///
+/// **sock**:
+/// The socket on which a message should be sent.
+///
+/// **in**:
+/// Input parameters.
+///
+/// **out**:
+/// Output parameters.
+#[inline]
+pub unsafe fn sock_send(sock_: fd, in_: *const send_in, out_: *mut send_out) -> errno {
+ cloudabi_sys_sock_send(sock_, in_, out_)
+}
+
+/// Shuts down socket send and receive channels.
+///
+/// ## Parameters
+///
+/// **sock**:
+/// The socket that needs its channels shut down.
+///
+/// **how**:
+/// Which channels on the socket need to be shut
+/// down.
+#[inline]
+pub unsafe fn sock_shutdown(sock_: fd, how_: sdflags) -> errno {
+ cloudabi_sys_sock_shutdown(sock_, how_)
+}
+
+/// Creates a new thread within the current process.
+///
+/// ## Parameters
+///
+/// **attr**:
+/// The desired attributes of the new thread.
+///
+/// **tid**:
+/// The thread ID of the new thread.
+#[inline]
+pub unsafe fn thread_create(attr_: *mut threadattr, tid_: &mut tid) -> errno {
+ cloudabi_sys_thread_create(attr_, tid_)
+}
+
+/// Terminates the calling thread.
+///
+/// This system call can also unlock a single userspace lock
+/// after termination, which can be used to implement thread
+/// joining.
+///
+/// ## Parameters
+///
+/// **lock**:
+/// Userspace lock that is locked for writing by
+/// the calling thread.
+///
+/// **scope**:
+/// Whether the lock is stored in private or
+/// shared memory.
+#[inline]
+pub unsafe fn thread_exit(lock_: *mut lock, scope_: scope) -> ! {
+ cloudabi_sys_thread_exit(lock_, scope_)
+}
+
+/// Temporarily yields execution of the calling thread.
+#[inline]
+pub unsafe fn thread_yield() -> errno {
+ cloudabi_sys_thread_yield()
+}
diff --git a/src/libstd/sys/cloudabi/abi/mod.rs b/src/libstd/sys/cloudabi/abi/mod.rs
new file mode 100644
index 0000000..9d01d24
--- /dev/null
+++ b/src/libstd/sys/cloudabi/abi/mod.rs
@@ -0,0 +1,3 @@
+#[allow(warnings)]
+mod cloudabi;
+pub use self::cloudabi::*;
diff --git a/src/libstd/sys/cloudabi/args.rs b/src/libstd/sys/cloudabi/args.rs
new file mode 100644
index 0000000..dea562a
--- /dev/null
+++ b/src/libstd/sys/cloudabi/args.rs
@@ -0,0 +1,7 @@
+pub use crate::sys::cloudabi::shims::args::*;
+
+#[allow(dead_code)]
+pub fn init(_: isize, _: *const *const u8) {}
+
+#[allow(dead_code)]
+pub fn cleanup() {}
diff --git a/src/libstd/sys/cloudabi/backtrace.rs b/src/libstd/sys/cloudabi/backtrace.rs
new file mode 100644
index 0000000..17719a2
--- /dev/null
+++ b/src/libstd/sys/cloudabi/backtrace.rs
@@ -0,0 +1,116 @@
+use crate::error::Error;
+use crate::ffi::CStr;
+use crate::fmt;
+use crate::intrinsics;
+use crate::io;
+use crate::sys_common::backtrace::Frame;
+
+use unwind as uw;
+
+pub struct BacktraceContext;
+
+struct Context<'a> {
+ idx: usize,
+ frames: &'a mut [Frame],
+}
+
+#[derive(Debug)]
+struct UnwindError(uw::_Unwind_Reason_Code);
+
+impl Error for UnwindError {
+ fn description(&self) -> &'static str {
+ "unexpected return value while unwinding"
+ }
+}
+
+impl fmt::Display for UnwindError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "{}: {:?}", self.description(), self.0)
+ }
+}
+
+#[inline(never)] // if we know this is a function call, we can skip it when
+ // tracing
+pub fn unwind_backtrace(frames: &mut [Frame]) -> io::Result<(usize, BacktraceContext)> {
+ let mut cx = Context { idx: 0, frames };
+ let result_unwind = unsafe {
+ uw::_Unwind_Backtrace(trace_fn, &mut cx as *mut Context<'_> as *mut libc::c_void)
+ };
+ // See libunwind:src/unwind/Backtrace.c for the return values.
+ // No, there is no doc.
+ match result_unwind {
+ // These return codes seem to be benign and need to be ignored for backtraces
+ // to show up properly on all tested platforms.
+ uw::_URC_END_OF_STACK | uw::_URC_FATAL_PHASE1_ERROR | uw::_URC_FAILURE => {
+ Ok((cx.idx, BacktraceContext))
+ }
+ _ => Err(io::Error::new(
+ io::ErrorKind::Other,
+ UnwindError(result_unwind),
+ )),
+ }
+}
+
+extern "C" fn trace_fn(
+ ctx: *mut uw::_Unwind_Context,
+ arg: *mut libc::c_void,
+) -> uw::_Unwind_Reason_Code {
+ let cx = unsafe { &mut *(arg as *mut Context<'_>) };
+ if cx.idx >= cx.frames.len() {
+ return uw::_URC_NORMAL_STOP;
+ }
+
+ let mut ip_before_insn = 0;
+ let mut ip = unsafe { uw::_Unwind_GetIPInfo(ctx, &mut ip_before_insn) as *mut libc::c_void };
+ if !ip.is_null() && ip_before_insn == 0 {
+ // this is a non-signaling frame, so `ip` refers to the address
+ // after the calling instruction. account for that.
+ ip = (ip as usize - 1) as *mut _;
+ }
+
+ let symaddr = unsafe { uw::_Unwind_FindEnclosingFunction(ip) };
+ cx.frames[cx.idx] = Frame {
+ symbol_addr: symaddr as *mut u8,
+ exact_position: ip as *mut u8,
+ inline_context: 0,
+ };
+ cx.idx += 1;
+
+ uw::_URC_NO_REASON
+}
+
+pub fn foreach_symbol_fileline<F>(_: Frame, _: F, _: &BacktraceContext) -> io::Result<bool>
+where
+ F: FnMut(&[u8], u32) -> io::Result<()>,
+{
+ // No way to obtain this information on CloudABI.
+ Ok(false)
+}
+
+pub fn resolve_symname<F>(frame: Frame, callback: F, _: &BacktraceContext) -> io::Result<()>
+where
+ F: FnOnce(Option<&str>) -> io::Result<()>,
+{
+ unsafe {
+ let mut info: Dl_info = intrinsics::init();
+ let symname =
+ if dladdr(frame.exact_position as *mut _, &mut info) == 0 || info.dli_sname.is_null() {
+ None
+ } else {
+ CStr::from_ptr(info.dli_sname).to_str().ok()
+ };
+ callback(symname)
+ }
+}
+
+#[repr(C)]
+struct Dl_info {
+ dli_fname: *const libc::c_char,
+ dli_fbase: *mut libc::c_void,
+ dli_sname: *const libc::c_char,
+ dli_saddr: *mut libc::c_void,
+}
+
+extern "C" {
+ fn dladdr(addr: *const libc::c_void, info: *mut Dl_info) -> libc::c_int;
+}
diff --git a/src/libstd/sys/cloudabi/condvar.rs b/src/libstd/sys/cloudabi/condvar.rs
new file mode 100644
index 0000000..7aa0b0b
--- /dev/null
+++ b/src/libstd/sys/cloudabi/condvar.rs
@@ -0,0 +1,163 @@
+use crate::cell::UnsafeCell;
+use crate::mem;
+use crate::sync::atomic::{AtomicU32, Ordering};
+use crate::sys::cloudabi::abi;
+use crate::sys::mutex::{self, Mutex};
+use crate::sys::time::checked_dur2intervals;
+use crate::time::Duration;
+
+extern "C" {
+ #[thread_local]
+ static __pthread_thread_id: abi::tid;
+}
+
+pub struct Condvar {
+ condvar: UnsafeCell<AtomicU32>,
+}
+
+unsafe impl Send for Condvar {}
+unsafe impl Sync for Condvar {}
+
+const NEW: Condvar = Condvar {
+ condvar: UnsafeCell::new(AtomicU32::new(abi::CONDVAR_HAS_NO_WAITERS.0)),
+};
+
+impl Condvar {
+ pub const fn new() -> Condvar {
+ NEW
+ }
+
+ pub unsafe fn init(&mut self) {}
+
+ pub unsafe fn notify_one(&self) {
+ let condvar = self.condvar.get();
+ if (*condvar).load(Ordering::Relaxed) != abi::CONDVAR_HAS_NO_WAITERS.0 {
+ let ret = abi::condvar_signal(condvar as *mut abi::condvar, abi::scope::PRIVATE, 1);
+ assert_eq!(
+ ret,
+ abi::errno::SUCCESS,
+ "Failed to signal on condition variable"
+ );
+ }
+ }
+
+ pub unsafe fn notify_all(&self) {
+ let condvar = self.condvar.get();
+ if (*condvar).load(Ordering::Relaxed) != abi::CONDVAR_HAS_NO_WAITERS.0 {
+ let ret = abi::condvar_signal(
+ condvar as *mut abi::condvar,
+ abi::scope::PRIVATE,
+ abi::nthreads::max_value(),
+ );
+ assert_eq!(
+ ret,
+ abi::errno::SUCCESS,
+ "Failed to broadcast on condition variable"
+ );
+ }
+ }
+
+ pub unsafe fn wait(&self, mutex: &Mutex) {
+ let mutex = mutex::raw(mutex);
+ assert_eq!(
+ (*mutex).load(Ordering::Relaxed) & !abi::LOCK_KERNEL_MANAGED.0,
+ __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0,
+ "This lock is not write-locked by this thread"
+ );
+
+ // Call into the kernel to wait on the condition variable.
+ let condvar = self.condvar.get();
+ let subscription = abi::subscription {
+ type_: abi::eventtype::CONDVAR,
+ union: abi::subscription_union {
+ condvar: abi::subscription_condvar {
+ condvar: condvar as *mut abi::condvar,
+ condvar_scope: abi::scope::PRIVATE,
+ lock: mutex as *mut abi::lock,
+ lock_scope: abi::scope::PRIVATE,
+ },
+ },
+ ..mem::zeroed()
+ };
+ let mut event: abi::event = mem::uninitialized();
+ let mut nevents: usize = mem::uninitialized();
+ let ret = abi::poll(&subscription, &mut event, 1, &mut nevents);
+ assert_eq!(
+ ret,
+ abi::errno::SUCCESS,
+ "Failed to wait on condition variable"
+ );
+ assert_eq!(
+ event.error,
+ abi::errno::SUCCESS,
+ "Failed to wait on condition variable"
+ );
+ }
+
+ pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
+ let mutex = mutex::raw(mutex);
+ assert_eq!(
+ (*mutex).load(Ordering::Relaxed) & !abi::LOCK_KERNEL_MANAGED.0,
+ __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0,
+ "This lock is not write-locked by this thread"
+ );
+
+ // Call into the kernel to wait on the condition variable.
+ let condvar = self.condvar.get();
+ let timeout = checked_dur2intervals(&dur)
+ .expect("overflow converting duration to nanoseconds");
+ let subscriptions = [
+ abi::subscription {
+ type_: abi::eventtype::CONDVAR,
+ union: abi::subscription_union {
+ condvar: abi::subscription_condvar {
+ condvar: condvar as *mut abi::condvar,
+ condvar_scope: abi::scope::PRIVATE,
+ lock: mutex as *mut abi::lock,
+ lock_scope: abi::scope::PRIVATE,
+ },
+ },
+ ..mem::zeroed()
+ },
+ abi::subscription {
+ type_: abi::eventtype::CLOCK,
+ union: abi::subscription_union {
+ clock: abi::subscription_clock {
+ clock_id: abi::clockid::MONOTONIC,
+ timeout,
+ ..mem::zeroed()
+ },
+ },
+ ..mem::zeroed()
+ },
+ ];
+ let mut events: [abi::event; 2] = mem::uninitialized();
+ let mut nevents: usize = mem::uninitialized();
+ let ret = abi::poll(subscriptions.as_ptr(), events.as_mut_ptr(), 2, &mut nevents);
+ assert_eq!(
+ ret,
+ abi::errno::SUCCESS,
+ "Failed to wait on condition variable"
+ );
+ for i in 0..nevents {
+ assert_eq!(
+ events[i].error,
+ abi::errno::SUCCESS,
+ "Failed to wait on condition variable"
+ );
+ if events[i].type_ == abi::eventtype::CONDVAR {
+ return true;
+ }
+ }
+ false
+ }
+
+ pub unsafe fn destroy(&self) {
+ let condvar = self.condvar.get();
+ assert_eq!(
+ (*condvar).load(Ordering::Relaxed),
+ abi::CONDVAR_HAS_NO_WAITERS.0,
+ "Attempted to destroy a condition variable with blocked threads"
+ );
+ }
+}
diff --git a/src/libstd/sys/cloudabi/io.rs b/src/libstd/sys/cloudabi/io.rs
new file mode 100644
index 0000000..8b02d3f
--- /dev/null
+++ b/src/libstd/sys/cloudabi/io.rs
@@ -0,0 +1,32 @@
+pub struct IoVec<'a>(&'a [u8]);
+
+impl<'a> IoVec<'a> {
+ #[inline]
+ pub fn new(buf: &'a [u8]) -> IoVec<'a> {
+ IoVec(buf)
+ }
+
+ #[inline]
+ pub fn as_slice(&self) -> &[u8] {
+ self.0
+ }
+}
+
+pub struct IoVecMut<'a>(&'a mut [u8]);
+
+impl<'a> IoVecMut<'a> {
+ #[inline]
+ pub fn new(buf: &'a mut [u8]) -> IoVecMut<'a> {
+ IoVecMut(buf)
+ }
+
+ #[inline]
+ pub fn as_slice(&self) -> &[u8] {
+ self.0
+ }
+
+ #[inline]
+ pub fn as_mut_slice(&mut self) -> &mut [u8] {
+ self.0
+ }
+}
diff --git a/src/libstd/sys/cloudabi/mod.rs b/src/libstd/sys/cloudabi/mod.rs
new file mode 100644
index 0000000..3f8e67a
--- /dev/null
+++ b/src/libstd/sys/cloudabi/mod.rs
@@ -0,0 +1,68 @@
+use crate::io::ErrorKind;
+use crate::mem;
+
+#[path = "../unix/alloc.rs"]
+pub mod alloc;
+pub mod args;
+#[cfg(feature = "backtrace")]
+pub mod backtrace;
+#[path = "../unix/cmath.rs"]
+pub mod cmath;
+pub mod condvar;
+pub mod io;
+#[path = "../unix/memchr.rs"]
+pub mod memchr;
+pub mod mutex;
+pub mod os;
+pub mod rwlock;
+pub mod stack_overflow;
+pub mod stdio;
+pub mod thread;
+#[path = "../unix/thread_local.rs"]
+pub mod thread_local;
+pub mod time;
+
+pub use crate::sys_common::os_str_bytes as os_str;
+
+mod abi;
+
+mod shims;
+pub use self::shims::*;
+
+#[allow(dead_code)]
+pub fn init() {}
+
+pub fn decode_error_kind(errno: i32) -> ErrorKind {
+ match errno {
+ x if x == abi::errno::ACCES as i32 => ErrorKind::PermissionDenied,
+ x if x == abi::errno::ADDRINUSE as i32 => ErrorKind::AddrInUse,
+ x if x == abi::errno::ADDRNOTAVAIL as i32 => ErrorKind::AddrNotAvailable,
+ x if x == abi::errno::AGAIN as i32 => ErrorKind::WouldBlock,
+ x if x == abi::errno::CONNABORTED as i32 => ErrorKind::ConnectionAborted,
+ x if x == abi::errno::CONNREFUSED as i32 => ErrorKind::ConnectionRefused,
+ x if x == abi::errno::CONNRESET as i32 => ErrorKind::ConnectionReset,
+ x if x == abi::errno::EXIST as i32 => ErrorKind::AlreadyExists,
+ x if x == abi::errno::INTR as i32 => ErrorKind::Interrupted,
+ x if x == abi::errno::INVAL as i32 => ErrorKind::InvalidInput,
+ x if x == abi::errno::NOENT as i32 => ErrorKind::NotFound,
+ x if x == abi::errno::NOTCONN as i32 => ErrorKind::NotConnected,
+ x if x == abi::errno::PERM as i32 => ErrorKind::PermissionDenied,
+ x if x == abi::errno::PIPE as i32 => ErrorKind::BrokenPipe,
+ x if x == abi::errno::TIMEDOUT as i32 => ErrorKind::TimedOut,
+ _ => ErrorKind::Other,
+ }
+}
+
+pub unsafe fn abort_internal() -> ! {
+ core::intrinsics::abort();
+}
+
+pub use libc::strlen;
+
+pub fn hashmap_random_keys() -> (u64, u64) {
+ unsafe {
+ let mut v = mem::uninitialized();
+ libc::arc4random_buf(&mut v as *mut _ as *mut libc::c_void, mem::size_of_val(&v));
+ v
+ }
+}
diff --git a/src/libstd/sys/cloudabi/mutex.rs b/src/libstd/sys/cloudabi/mutex.rs
new file mode 100644
index 0000000..5e191e3
--- /dev/null
+++ b/src/libstd/sys/cloudabi/mutex.rs
@@ -0,0 +1,148 @@
+use crate::cell::UnsafeCell;
+use crate::mem;
+use crate::sync::atomic::{AtomicU32, Ordering};
+use crate::sys::cloudabi::abi;
+use crate::sys::rwlock::{self, RWLock};
+
+extern "C" {
+ #[thread_local]
+ static __pthread_thread_id: abi::tid;
+}
+
+// Implement Mutex using an RWLock. This doesn't introduce any
+// performance overhead in this environment, as the operations would be
+// implemented identically.
+pub struct Mutex(RWLock);
+
+pub unsafe fn raw(m: &Mutex) -> *mut AtomicU32 {
+ rwlock::raw(&m.0)
+}
+
+impl Mutex {
+ pub const fn new() -> Mutex {
+ Mutex(RWLock::new())
+ }
+
+ pub unsafe fn init(&mut self) {
+ // This function should normally reinitialize the mutex after
+ // moving it to a different memory address. This implementation
+ // does not require adjustments after moving.
+ }
+
+ pub unsafe fn try_lock(&self) -> bool {
+ self.0.try_write()
+ }
+
+ pub unsafe fn lock(&self) {
+ self.0.write()
+ }
+
+ pub unsafe fn unlock(&self) {
+ self.0.write_unlock()
+ }
+
+ pub unsafe fn destroy(&self) {
+ self.0.destroy()
+ }
+}
+
+pub struct ReentrantMutex {
+ lock: UnsafeCell<AtomicU32>,
+ recursion: UnsafeCell<u32>,
+}
+
+impl ReentrantMutex {
+ pub unsafe fn uninitialized() -> ReentrantMutex {
+ mem::uninitialized()
+ }
+
+ pub unsafe fn init(&mut self) {
+ self.lock = UnsafeCell::new(AtomicU32::new(abi::LOCK_UNLOCKED.0));
+ self.recursion = UnsafeCell::new(0);
+ }
+
+ pub unsafe fn try_lock(&self) -> bool {
+ // Attempt to acquire the lock.
+ let lock = self.lock.get();
+ let recursion = self.recursion.get();
+ if let Err(old) = (*lock).compare_exchange(
+ abi::LOCK_UNLOCKED.0,
+ __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0,
+ Ordering::Acquire,
+ Ordering::Relaxed,
+ ) {
+ // If we fail to acquire the lock, it may be the case
+ // that we've already acquired it and may need to recurse.
+ if old & !abi::LOCK_KERNEL_MANAGED.0 == __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0 {
+ *recursion += 1;
+ true
+ } else {
+ false
+ }
+ } else {
+ // Success.
+ assert_eq!(*recursion, 0, "Mutex has invalid recursion count");
+ true
+ }
+ }
+
+ pub unsafe fn lock(&self) {
+ if !self.try_lock() {
+ // Call into the kernel to acquire a write lock.
+ let lock = self.lock.get();
+ let subscription = abi::subscription {
+ type_: abi::eventtype::LOCK_WRLOCK,
+ union: abi::subscription_union {
+ lock: abi::subscription_lock {
+ lock: lock as *mut abi::lock,
+ lock_scope: abi::scope::PRIVATE,
+ },
+ },
+ ..mem::zeroed()
+ };
+ let mut event: abi::event = mem::uninitialized();
+ let mut nevents: usize = mem::uninitialized();
+ let ret = abi::poll(&subscription, &mut event, 1, &mut nevents);
+ assert_eq!(ret, abi::errno::SUCCESS, "Failed to acquire mutex");
+ assert_eq!(event.error, abi::errno::SUCCESS, "Failed to acquire mutex");
+ }
+ }
+
+ pub unsafe fn unlock(&self) {
+ let lock = self.lock.get();
+ let recursion = self.recursion.get();
+ assert_eq!(
+ (*lock).load(Ordering::Relaxed) & !abi::LOCK_KERNEL_MANAGED.0,
+ __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0,
+ "This mutex is locked by a different thread"
+ );
+
+ if *recursion > 0 {
+ *recursion -= 1;
+ } else if !(*lock)
+ .compare_exchange(
+ __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0,
+ abi::LOCK_UNLOCKED.0,
+ Ordering::Release,
+ Ordering::Relaxed,
+ )
+ .is_ok()
+ {
+ // Lock is managed by kernelspace. Call into the kernel
+ // to unblock waiting threads.
+ let ret = abi::lock_unlock(lock as *mut abi::lock, abi::scope::PRIVATE);
+ assert_eq!(ret, abi::errno::SUCCESS, "Failed to unlock a mutex");
+ }
+ }
+
+ pub unsafe fn destroy(&self) {
+ let lock = self.lock.get();
+ let recursion = self.recursion.get();
+ assert_eq!(
+ (*lock).load(Ordering::Relaxed),
+ abi::LOCK_UNLOCKED.0,
+ "Attempted to destroy locked mutex"
+ );
+ assert_eq!(*recursion, 0, "Recursion counter invalid");
+ }
+}
diff --git a/src/libstd/sys/cloudabi/os.rs b/src/libstd/sys/cloudabi/os.rs
new file mode 100644
index 0000000..7db7808
--- /dev/null
+++ b/src/libstd/sys/cloudabi/os.rs
@@ -0,0 +1,28 @@
+use crate::ffi::CStr;
+use crate::str;
+
+use libc::c_int;
+
+pub use crate::sys::cloudabi::shims::os::*;
+
+pub fn errno() -> i32 {
+ extern "C" {
+ #[thread_local]
+ static errno: c_int;
+ }
+
+ unsafe { errno as i32 }
+}
+
+/// Gets a detailed string description for the given error number.
+pub fn error_string(errno: i32) -> String {
+ // cloudlibc's strerror() is guaranteed to be thread-safe. There is
+ // thus no need to use strerror_r().
+ str::from_utf8(unsafe { CStr::from_ptr(libc::strerror(errno)) }.to_bytes())
+ .unwrap()
+ .to_owned()
+}
+
+pub fn exit(code: i32) -> ! {
+ unsafe { libc::exit(code as c_int) }
+}
diff --git a/src/libstd/sys/cloudabi/rwlock.rs b/src/libstd/sys/cloudabi/rwlock.rs
new file mode 100644
index 0000000..6da3f38
--- /dev/null
+++ b/src/libstd/sys/cloudabi/rwlock.rs
@@ -0,0 +1,229 @@
+use crate::cell::UnsafeCell;
+use crate::mem;
+use crate::sync::atomic::{AtomicU32, Ordering};
+use crate::sys::cloudabi::abi;
+
+extern "C" {
+ #[thread_local]
+ static __pthread_thread_id: abi::tid;
+}
+
+#[thread_local]
+static mut RDLOCKS_ACQUIRED: u32 = 0;
+
+pub struct RWLock {
+ lock: UnsafeCell<AtomicU32>,
+}
+
+pub unsafe fn raw(r: &RWLock) -> *mut AtomicU32 {
+ r.lock.get()
+}
+
+unsafe impl Send for RWLock {}
+unsafe impl Sync for RWLock {}
+
+const NEW: RWLock = RWLock {
+ lock: UnsafeCell::new(AtomicU32::new(abi::LOCK_UNLOCKED.0)),
+};
+
+impl RWLock {
+ pub const fn new() -> RWLock {
+ NEW
+ }
+
+ pub unsafe fn try_read(&self) -> bool {
+ let lock = self.lock.get();
+ let mut old = abi::LOCK_UNLOCKED.0;
+ while let Err(cur) =
+ (*lock).compare_exchange_weak(old, old + 1, Ordering::Acquire, Ordering::Relaxed)
+ {
+ if (cur & abi::LOCK_WRLOCKED.0) != 0 {
+ // Another thread already has a write lock.
+ assert_ne!(
+ old & !abi::LOCK_KERNEL_MANAGED.0,
+ __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0,
+ "Attempted to acquire a read lock while holding a write lock"
+ );
+ return false;
+ } else if (old & abi::LOCK_KERNEL_MANAGED.0) != 0 && RDLOCKS_ACQUIRED == 0 {
+ // Lock has threads waiting for the lock. Only acquire
+ // the lock if we have already acquired read locks. In
+ // that case, it is justified to acquire this lock to
+ // prevent a deadlock.
+ return false;
+ }
+ old = cur;
+ }
+
+ RDLOCKS_ACQUIRED += 1;
+ true
+ }
+
+ pub unsafe fn read(&self) {
+ if !self.try_read() {
+ // Call into the kernel to acquire a read lock.
+ let lock = self.lock.get();
+ let subscription = abi::subscription {
+ type_: abi::eventtype::LOCK_RDLOCK,
+ union: abi::subscription_union {
+ lock: abi::subscription_lock {
+ lock: lock as *mut abi::lock,
+ lock_scope: abi::scope::PRIVATE,
+ },
+ },
+ ..mem::zeroed()
+ };
+ let mut event: abi::event = mem::uninitialized();
+ let mut nevents: usize = mem::uninitialized();
+ let ret = abi::poll(&subscription, &mut event, 1, &mut nevents);
+ assert_eq!(ret, abi::errno::SUCCESS, "Failed to acquire read lock");
+ assert_eq!(
+ event.error,
+ abi::errno::SUCCESS,
+ "Failed to acquire read lock"
+ );
+
+ RDLOCKS_ACQUIRED += 1;
+ }
+ }
+
+ pub unsafe fn read_unlock(&self) {
+ // Perform a read unlock. We can do this in userspace, except when
+ // other threads are blocked and we are performing the last unlock.
+ // In that case, call into the kernel.
+ //
+ // Other threads may attempt to increment the read lock count,
+ // meaning that the call into the kernel could be spurious. To
+ // prevent this from happening, upgrade to a write lock first. This
+ // allows us to call into the kernel, having the guarantee that the
+ // lock value will not change in the meantime.
+ assert!(RDLOCKS_ACQUIRED > 0, "Bad lock count");
+ let mut old = 1;
+ loop {
+ let lock = self.lock.get();
+ if old == 1 | abi::LOCK_KERNEL_MANAGED.0 {
+ // Last read lock while threads are waiting. Attempt to upgrade
+ // to a write lock before calling into the kernel to unlock.
+ if let Err(cur) = (*lock).compare_exchange_weak(
+ old,
+ __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0 | abi::LOCK_KERNEL_MANAGED.0,
+ Ordering::Acquire,
+ Ordering::Relaxed,
+ ) {
+ old = cur;
+ } else {
+ // Call into the kernel to unlock.
+ let ret = abi::lock_unlock(lock as *mut abi::lock, abi::scope::PRIVATE);
+ assert_eq!(ret, abi::errno::SUCCESS, "Failed to write unlock a rwlock");
+ break;
+ }
+ } else {
+ // No threads waiting or not the last read lock. Just decrement
+ // the read lock count.
+ assert_ne!(
+ old & !abi::LOCK_KERNEL_MANAGED.0,
+ 0,
+ "This rwlock is not locked"
+ );
+ assert_eq!(
+ old & abi::LOCK_WRLOCKED.0,
+ 0,
+ "Attempted to read-unlock a write-locked rwlock"
+ );
+ if let Err(cur) = (*lock).compare_exchange_weak(
+ old,
+ old - 1,
+ Ordering::Acquire,
+ Ordering::Relaxed,
+ ) {
+ old = cur;
+ } else {
+ break;
+ }
+ }
+ }
+
+ RDLOCKS_ACQUIRED -= 1;
+ }
+
+ pub unsafe fn try_write(&self) -> bool {
+ // Attempt to acquire the lock.
+ let lock = self.lock.get();
+ if let Err(old) = (*lock).compare_exchange(
+ abi::LOCK_UNLOCKED.0,
+ __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0,
+ Ordering::Acquire,
+ Ordering::Relaxed,
+ ) {
+ // Failure. Crash upon recursive acquisition.
+ assert_ne!(
+ old & !abi::LOCK_KERNEL_MANAGED.0,
+ __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0,
+ "Attempted to recursive write-lock a rwlock",
+ );
+ false
+ } else {
+ // Success.
+ true
+ }
+ }
+
+ pub unsafe fn write(&self) {
+ if !self.try_write() {
+ // Call into the kernel to acquire a write lock.
+ let lock = self.lock.get();
+ let subscription = abi::subscription {
+ type_: abi::eventtype::LOCK_WRLOCK,
+ union: abi::subscription_union {
+ lock: abi::subscription_lock {
+ lock: lock as *mut abi::lock,
+ lock_scope: abi::scope::PRIVATE,
+ },
+ },
+ ..mem::zeroed()
+ };
+ let mut event: abi::event = mem::uninitialized();
+ let mut nevents: usize = mem::uninitialized();
+ let ret = abi::poll(&subscription, &mut event, 1, &mut nevents);
+ assert_eq!(ret, abi::errno::SUCCESS, "Failed to acquire write lock");
+ assert_eq!(
+ event.error,
+ abi::errno::SUCCESS,
+ "Failed to acquire write lock"
+ );
+ }
+ }
+
+ pub unsafe fn write_unlock(&self) {
+ let lock = self.lock.get();
+ assert_eq!(
+ (*lock).load(Ordering::Relaxed) & !abi::LOCK_KERNEL_MANAGED.0,
+ __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0,
+ "This rwlock is not write-locked by this thread"
+ );
+
+ if !(*lock)
+ .compare_exchange(
+ __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0,
+ abi::LOCK_UNLOCKED.0,
+ Ordering::Release,
+ Ordering::Relaxed,
+ )
+ .is_ok()
+ {
+ // Lock is managed by kernelspace. Call into the kernel
+ // to unblock waiting threads.
+ let ret = abi::lock_unlock(lock as *mut abi::lock, abi::scope::PRIVATE);
+ assert_eq!(ret, abi::errno::SUCCESS, "Failed to write unlock a rwlock");
+ }
+ }
+
+ pub unsafe fn destroy(&self) {
+ let lock = self.lock.get();
+ assert_eq!(
+ (*lock).load(Ordering::Relaxed),
+ abi::LOCK_UNLOCKED.0,
+ "Attempted to destroy locked rwlock"
+ );
+ }
+}
diff --git a/src/libstd/sys/cloudabi/shims/args.rs b/src/libstd/sys/cloudabi/shims/args.rs
new file mode 100644
index 0000000..f5cf71c
--- /dev/null
+++ b/src/libstd/sys/cloudabi/shims/args.rs
@@ -0,0 +1,35 @@
+use crate::ffi::OsString;
+
+pub struct Args(());
+
+impl Args {
+ pub fn inner_debug(&self) -> &[OsString] {
+ &[]
+ }
+}
+
+impl Iterator for Args {
+ type Item = OsString;
+ fn next(&mut self) -> Option<OsString> {
+ None
+ }
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ (0, Some(0))
+ }
+}
+
+impl ExactSizeIterator for Args {
+ fn len(&self) -> usize {
+ 0
+ }
+}
+
+impl DoubleEndedIterator for Args {
+ fn next_back(&mut self) -> Option<OsString> {
+ None
+ }
+}
+
+pub fn args() -> Args {
+ Args(())
+}
diff --git a/src/libstd/sys/cloudabi/shims/env.rs b/src/libstd/sys/cloudabi/shims/env.rs
new file mode 100644
index 0000000..de165a8
--- /dev/null
+++ b/src/libstd/sys/cloudabi/shims/env.rs
@@ -0,0 +1,9 @@
+pub mod os {
+ pub const FAMILY: &str = "cloudabi";
+ pub const OS: &str = "cloudabi";
+ pub const DLL_PREFIX: &str = "lib";
+ pub const DLL_SUFFIX: &str = ".so";
+ pub const DLL_EXTENSION: &str = "so";
+ pub const EXE_SUFFIX: &str = "";
+ pub const EXE_EXTENSION: &str = "";
+}
diff --git a/src/libstd/sys/cloudabi/shims/fs.rs b/src/libstd/sys/cloudabi/shims/fs.rs
new file mode 100644
index 0000000..ee045b8
--- /dev/null
+++ b/src/libstd/sys/cloudabi/shims/fs.rs
@@ -0,0 +1,292 @@
+use crate::ffi::OsString;
+use crate::fmt;
+use crate::hash::{Hash, Hasher};
+use crate::io::{self, SeekFrom};
+use crate::path::{Path, PathBuf};
+use crate::sys::time::SystemTime;
+use crate::sys::{unsupported, Void};
+
+pub struct File(Void);
+
+pub struct FileAttr(Void);
+
+pub struct ReadDir(Void);
+
+pub struct DirEntry(Void);
+
+#[derive(Clone, Debug)]
+pub struct OpenOptions {}
+
+pub struct FilePermissions(Void);
+
+pub struct FileType(Void);
+
+#[derive(Debug)]
+pub struct DirBuilder {}
+
+impl FileAttr {
+ pub fn size(&self) -> u64 {
+ match self.0 {}
+ }
+
+ pub fn perm(&self) -> FilePermissions {
+ match self.0 {}
+ }
+
+ pub fn file_type(&self) -> FileType {
+ match self.0 {}
+ }
+
+ pub fn modified(&self) -> io::Result<SystemTime> {
+ match self.0 {}
+ }
+
+ pub fn accessed(&self) -> io::Result<SystemTime> {
+ match self.0 {}
+ }
+
+ pub fn created(&self) -> io::Result<SystemTime> {
+ match self.0 {}
+ }
+}
+
+impl Clone for FileAttr {
+ fn clone(&self) -> FileAttr {
+ match self.0 {}
+ }
+}
+
+impl FilePermissions {
+ pub fn readonly(&self) -> bool {
+ match self.0 {}
+ }
+
+ pub fn set_readonly(&mut self, _readonly: bool) {
+ match self.0 {}
+ }
+}
+
+impl Clone for FilePermissions {
+ fn clone(&self) -> FilePermissions {
+ match self.0 {}
+ }
+}
+
+impl PartialEq for FilePermissions {
+ fn eq(&self, _other: &FilePermissions) -> bool {
+ match self.0 {}
+ }
+}
+
+impl Eq for FilePermissions {}
+
+impl fmt::Debug for FilePermissions {
+ fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self.0 {}
+ }
+}
+
+impl FileType {
+ pub fn is_dir(&self) -> bool {
+ match self.0 {}
+ }
+
+ pub fn is_file(&self) -> bool {
+ match self.0 {}
+ }
+
+ pub fn is_symlink(&self) -> bool {
+ match self.0 {}
+ }
+}
+
+impl Clone for FileType {
+ fn clone(&self) -> FileType {
+ match self.0 {}
+ }
+}
+
+impl Copy for FileType {}
+
+impl PartialEq for FileType {
+ fn eq(&self, _other: &FileType) -> bool {
+ match self.0 {}
+ }
+}
+
+impl Eq for FileType {}
+
+impl Hash for FileType {
+ fn hash<H: Hasher>(&self, _h: &mut H) {
+ match self.0 {}
+ }
+}
+
+impl fmt::Debug for FileType {
+ fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self.0 {}
+ }
+}
+
+impl fmt::Debug for ReadDir {
+ fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self.0 {}
+ }
+}
+
+impl Iterator for ReadDir {
+ type Item = io::Result<DirEntry>;
+
+ fn next(&mut self) -> Option<io::Result<DirEntry>> {
+ match self.0 {}
+ }
+}
+
+impl DirEntry {
+ pub fn path(&self) -> PathBuf {
+ match self.0 {}
+ }
+
+ pub fn file_name(&self) -> OsString {
+ match self.0 {}
+ }
+
+ pub fn metadata(&self) -> io::Result<FileAttr> {
+ match self.0 {}
+ }
+
+ pub fn file_type(&self) -> io::Result<FileType> {
+ match self.0 {}
+ }
+}
+
+impl OpenOptions {
+ pub fn new() -> OpenOptions {
+ OpenOptions {}
+ }
+
+ pub fn read(&mut self, _read: bool) {}
+ pub fn write(&mut self, _write: bool) {}
+ pub fn append(&mut self, _append: bool) {}
+ pub fn truncate(&mut self, _truncate: bool) {}
+ pub fn create(&mut self, _create: bool) {}
+ pub fn create_new(&mut self, _create_new: bool) {}
+}
+
+impl File {
+ pub fn open(_path: &Path, _opts: &OpenOptions) -> io::Result<File> {
+ unsupported()
+ }
+
+ pub fn file_attr(&self) -> io::Result<FileAttr> {
+ match self.0 {}
+ }
+
+ pub fn fsync(&self) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn datasync(&self) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn truncate(&self, _size: u64) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn read(&self, _buf: &mut [u8]) -> io::Result<usize> {
+ match self.0 {}
+ }
+
+ pub fn write(&self, _buf: &[u8]) -> io::Result<usize> {
+ match self.0 {}
+ }
+
+ pub fn flush(&self) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn seek(&self, _pos: SeekFrom) -> io::Result<u64> {
+ match self.0 {}
+ }
+
+ pub fn duplicate(&self) -> io::Result<File> {
+ match self.0 {}
+ }
+
+ pub fn set_permissions(&self, _perm: FilePermissions) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn diverge(&self) -> ! {
+ match self.0 {}
+ }
+}
+
+impl DirBuilder {
+ pub fn new() -> DirBuilder {
+ DirBuilder {}
+ }
+
+ pub fn mkdir(&self, _p: &Path) -> io::Result<()> {
+ unsupported()
+ }
+}
+
+impl fmt::Debug for File {
+ fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self.0 {}
+ }
+}
+
+pub fn readdir(_p: &Path) -> io::Result<ReadDir> {
+ unsupported()
+}
+
+pub fn unlink(_p: &Path) -> io::Result<()> {
+ unsupported()
+}
+
+pub fn rename(_old: &Path, _new: &Path) -> io::Result<()> {
+ unsupported()
+}
+
+pub fn set_perm(_p: &Path, perm: FilePermissions) -> io::Result<()> {
+ match perm.0 {}
+}
+
+pub fn rmdir(_p: &Path) -> io::Result<()> {
+ unsupported()
+}
+
+pub fn remove_dir_all(_path: &Path) -> io::Result<()> {
+ unsupported()
+}
+
+pub fn readlink(_p: &Path) -> io::Result<PathBuf> {
+ unsupported()
+}
+
+pub fn symlink(_src: &Path, _dst: &Path) -> io::Result<()> {
+ unsupported()
+}
+
+pub fn link(_src: &Path, _dst: &Path) -> io::Result<()> {
+ unsupported()
+}
+
+pub fn stat(_p: &Path) -> io::Result<FileAttr> {
+ unsupported()
+}
+
+pub fn lstat(_p: &Path) -> io::Result<FileAttr> {
+ unsupported()
+}
+
+pub fn canonicalize(_p: &Path) -> io::Result<PathBuf> {
+ unsupported()
+}
+
+pub fn copy(_from: &Path, _to: &Path) -> io::Result<u64> {
+ unsupported()
+}
diff --git a/src/libstd/sys/cloudabi/shims/mod.rs b/src/libstd/sys/cloudabi/shims/mod.rs
new file mode 100644
index 0000000..fbb5ff5
--- /dev/null
+++ b/src/libstd/sys/cloudabi/shims/mod.rs
@@ -0,0 +1,22 @@
+use crate::io;
+
+pub mod args;
+pub mod env;
+pub mod fs;
+pub mod net;
+#[path = "../../unix/path.rs"]
+pub mod path;
+pub mod pipe;
+pub mod process;
+pub mod os;
+
+// This enum is used as the storage for a bunch of types which can't actually exist.
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
+pub enum Void {}
+
+pub fn unsupported<T>() -> io::Result<T> {
+ Err(io::Error::new(
+ io::ErrorKind::Other,
+ "This function is not available on CloudABI.",
+ ))
+}
diff --git a/src/libstd/sys/cloudabi/shims/net.rs b/src/libstd/sys/cloudabi/shims/net.rs
new file mode 100644
index 0000000..7cf2374
--- /dev/null
+++ b/src/libstd/sys/cloudabi/shims/net.rs
@@ -0,0 +1,318 @@
+use crate::fmt;
+use crate::io::{self, IoVec, IoVecMut};
+use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr};
+use crate::time::Duration;
+use crate::sys::{unsupported, Void};
+use crate::convert::TryFrom;
+
+#[allow(unused_extern_crates)]
+pub extern crate libc as netc;
+
+pub struct TcpStream(Void);
+
+impl TcpStream {
+ pub fn connect(_: io::Result<&SocketAddr>) -> io::Result<TcpStream> {
+ unsupported()
+ }
+
+ pub fn connect_timeout(_: &SocketAddr, _: Duration) -> io::Result<TcpStream> {
+ unsupported()
+ }
+
+ pub fn set_read_timeout(&self, _: Option<Duration>) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn set_write_timeout(&self, _: Option<Duration>) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
+ match self.0 {}
+ }
+
+ pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
+ match self.0 {}
+ }
+
+ pub fn peek(&self, _: &mut [u8]) -> io::Result<usize> {
+ match self.0 {}
+ }
+
+ pub fn read(&self, _: &mut [u8]) -> io::Result<usize> {
+ match self.0 {}
+ }
+
+ pub fn read_vectored(&self, _: &mut [IoVecMut<'_>]) -> io::Result<usize> {
+ match self.0 {}
+ }
+
+ pub fn write(&self, _: &[u8]) -> io::Result<usize> {
+ match self.0 {}
+ }
+
+ pub fn write_vectored(&self, _: &[IoVec<'_>]) -> io::Result<usize> {
+ match self.0 {}
+ }
+
+ pub fn peer_addr(&self) -> io::Result<SocketAddr> {
+ match self.0 {}
+ }
+
+ pub fn socket_addr(&self) -> io::Result<SocketAddr> {
+ match self.0 {}
+ }
+
+ pub fn shutdown(&self, _: Shutdown) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn duplicate(&self) -> io::Result<TcpStream> {
+ match self.0 {}
+ }
+
+ pub fn set_nodelay(&self, _: bool) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn nodelay(&self) -> io::Result<bool> {
+ match self.0 {}
+ }
+
+ pub fn set_ttl(&self, _: u32) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn ttl(&self) -> io::Result<u32> {
+ match self.0 {}
+ }
+
+ pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+ match self.0 {}
+ }
+
+ pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
+ match self.0 {}
+ }
+}
+
+impl fmt::Debug for TcpStream {
+ fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self.0 {}
+ }
+}
+
+pub struct TcpListener(Void);
+
+impl TcpListener {
+ pub fn bind(_: io::Result<&SocketAddr>) -> io::Result<TcpListener> {
+ unsupported()
+ }
+
+ pub fn socket_addr(&self) -> io::Result<SocketAddr> {
+ match self.0 {}
+ }
+
+ pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> {
+ match self.0 {}
+ }
+
+ pub fn duplicate(&self) -> io::Result<TcpListener> {
+ match self.0 {}
+ }
+
+ pub fn set_ttl(&self, _: u32) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn ttl(&self) -> io::Result<u32> {
+ match self.0 {}
+ }
+
+ pub fn set_only_v6(&self, _: bool) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn only_v6(&self) -> io::Result<bool> {
+ match self.0 {}
+ }
+
+ pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+ match self.0 {}
+ }
+
+ pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
+ match self.0 {}
+ }
+}
+
+impl fmt::Debug for TcpListener {
+ fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self.0 {}
+ }
+}
+
+pub struct UdpSocket(Void);
+
+impl UdpSocket {
+ pub fn bind(_: io::Result<&SocketAddr>) -> io::Result<UdpSocket> {
+ unsupported()
+ }
+
+ pub fn peer_addr(&self) -> io::Result<SocketAddr> {
+ match self.0 {}
+ }
+
+ pub fn socket_addr(&self) -> io::Result<SocketAddr> {
+ match self.0 {}
+ }
+
+ pub fn recv_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+ match self.0 {}
+ }
+
+ pub fn peek_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+ match self.0 {}
+ }
+
+ pub fn send_to(&self, _: &[u8], _: &SocketAddr) -> io::Result<usize> {
+ match self.0 {}
+ }
+
+ pub fn duplicate(&self) -> io::Result<UdpSocket> {
+ match self.0 {}
+ }
+
+ pub fn set_read_timeout(&self, _: Option<Duration>) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn set_write_timeout(&self, _: Option<Duration>) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
+ match self.0 {}
+ }
+
+ pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
+ match self.0 {}
+ }
+
+ pub fn set_broadcast(&self, _: bool) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn broadcast(&self) -> io::Result<bool> {
+ match self.0 {}
+ }
+
+ pub fn set_multicast_loop_v4(&self, _: bool) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn multicast_loop_v4(&self) -> io::Result<bool> {
+ match self.0 {}
+ }
+
+ pub fn set_multicast_ttl_v4(&self, _: u32) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn multicast_ttl_v4(&self) -> io::Result<u32> {
+ match self.0 {}
+ }
+
+ pub fn set_multicast_loop_v6(&self, _: bool) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn multicast_loop_v6(&self) -> io::Result<bool> {
+ match self.0 {}
+ }
+
+ pub fn join_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn join_multicast_v6(&self, _: &Ipv6Addr, _: u32) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn leave_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn leave_multicast_v6(&self, _: &Ipv6Addr, _: u32) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn set_ttl(&self, _: u32) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn ttl(&self) -> io::Result<u32> {
+ match self.0 {}
+ }
+
+ pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+ match self.0 {}
+ }
+
+ pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn recv(&self, _: &mut [u8]) -> io::Result<usize> {
+ match self.0 {}
+ }
+
+ pub fn peek(&self, _: &mut [u8]) -> io::Result<usize> {
+ match self.0 {}
+ }
+
+ pub fn send(&self, _: &[u8]) -> io::Result<usize> {
+ match self.0 {}
+ }
+
+ pub fn connect(&self, _: io::Result<&SocketAddr>) -> io::Result<()> {
+ match self.0 {}
+ }
+}
+
+impl fmt::Debug for UdpSocket {
+ fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self.0 {}
+ }
+}
+
+pub struct LookupHost(Void);
+
+impl LookupHost {
+ pub fn port(&self) -> u16 {
+ match self.0 {}
+ }
+}
+
+impl Iterator for LookupHost {
+ type Item = SocketAddr;
+ fn next(&mut self) -> Option<SocketAddr> {
+ match self.0 {}
+ }
+}
+
+impl TryFrom<&str> for LookupHost {
+ type Error = io::Error;
+
+ fn try_from(_v: &str) -> io::Result<LookupHost> {
+ unsupported()
+ }
+}
+
+impl<'a> TryFrom<(&'a str, u16)> for LookupHost {
+ type Error = io::Error;
+
+ fn try_from(_v: (&'a str, u16)) -> io::Result<LookupHost> {
+ unsupported()
+ }
+}
diff --git a/src/libstd/sys/cloudabi/shims/os.rs b/src/libstd/sys/cloudabi/shims/os.rs
new file mode 100644
index 0000000..944b952
--- /dev/null
+++ b/src/libstd/sys/cloudabi/shims/os.rs
@@ -0,0 +1,85 @@
+use crate::error::Error as StdError;
+use crate::ffi::{OsStr, OsString};
+use crate::fmt;
+use crate::io;
+use crate::iter;
+use crate::path::{self, PathBuf};
+use crate::sys::{unsupported, Void};
+
+pub fn getcwd() -> io::Result<PathBuf> {
+ unsupported()
+}
+
+pub fn chdir(_: &path::Path) -> io::Result<()> {
+ unsupported()
+}
+
+pub type Env = iter::Empty<(OsString, OsString)>;
+
+pub fn env() -> Env {
+ iter::empty()
+}
+
+pub fn getenv(_: &OsStr) -> io::Result<Option<OsString>> {
+ Ok(None)
+}
+
+pub fn setenv(_: &OsStr, _: &OsStr) -> io::Result<()> {
+ unsupported()
+}
+
+pub fn unsetenv(_: &OsStr) -> io::Result<()> {
+ unsupported()
+}
+
+pub struct SplitPaths<'a>(&'a Void);
+
+pub fn split_paths(_unparsed: &OsStr) -> SplitPaths<'_> {
+ panic!("unsupported")
+}
+
+impl<'a> Iterator for SplitPaths<'a> {
+ type Item = PathBuf;
+ fn next(&mut self) -> Option<PathBuf> {
+ match *self.0 {}
+ }
+}
+
+#[derive(Debug)]
+pub struct JoinPathsError;
+
+pub fn join_paths<I, T>(_paths: I) -> Result<OsString, JoinPathsError>
+where
+ I: Iterator<Item = T>,
+ T: AsRef<OsStr>,
+{
+ Err(JoinPathsError)
+}
+
+impl fmt::Display for JoinPathsError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ "not supported on CloudABI yet".fmt(f)
+ }
+}
+
+impl StdError for JoinPathsError {
+ fn description(&self) -> &str {
+ "not supported on CloudABI yet"
+ }
+}
+
+pub fn home_dir() -> Option<PathBuf> {
+ None
+}
+
+pub fn temp_dir() -> PathBuf {
+ PathBuf::from("/tmp")
+}
+
+pub fn current_exe() -> io::Result<PathBuf> {
+ unsupported()
+}
+
+pub fn getpid() -> u32 {
+ 1
+}
diff --git a/src/libstd/sys/cloudabi/shims/pipe.rs b/src/libstd/sys/cloudabi/shims/pipe.rs
new file mode 100644
index 0000000..f3debb9
--- /dev/null
+++ b/src/libstd/sys/cloudabi/shims/pipe.rs
@@ -0,0 +1,22 @@
+use crate::io;
+use crate::sys::Void;
+
+pub struct AnonPipe(Void);
+
+impl AnonPipe {
+ pub fn read(&self, _buf: &mut [u8]) -> io::Result<usize> {
+ match self.0 {}
+ }
+
+ pub fn write(&self, _buf: &[u8]) -> io::Result<usize> {
+ match self.0 {}
+ }
+
+ pub fn diverge(&self) -> ! {
+ match self.0 {}
+ }
+}
+
+pub fn read2(p1: AnonPipe, _v1: &mut Vec<u8>, _p2: AnonPipe, _v2: &mut Vec<u8>) -> io::Result<()> {
+ match p1.0 {}
+}
diff --git a/src/libstd/sys/cloudabi/shims/process.rs b/src/libstd/sys/cloudabi/shims/process.rs
new file mode 100644
index 0000000..e719b36
--- /dev/null
+++ b/src/libstd/sys/cloudabi/shims/process.rs
@@ -0,0 +1,149 @@
+use crate::ffi::OsStr;
+use crate::fmt;
+use crate::io;
+use crate::sys::fs::File;
+use crate::sys::pipe::AnonPipe;
+use crate::sys::{unsupported, Void};
+use crate::sys_common::process::{CommandEnv, DefaultEnvKey};
+
+////////////////////////////////////////////////////////////////////////////////
+// Command
+////////////////////////////////////////////////////////////////////////////////
+
+pub struct Command {
+ env: CommandEnv<DefaultEnvKey>,
+}
+
+// passed back to std::process with the pipes connected to the child, if any
+// were requested
+pub struct StdioPipes {
+ pub stdin: Option<AnonPipe>,
+ pub stdout: Option<AnonPipe>,
+ pub stderr: Option<AnonPipe>,
+}
+
+pub enum Stdio {
+ Inherit,
+ Null,
+ MakePipe,
+}
+
+impl Command {
+ pub fn new(_program: &OsStr) -> Command {
+ Command {
+ env: Default::default(),
+ }
+ }
+
+ pub fn arg(&mut self, _arg: &OsStr) {}
+
+ pub fn env_mut(&mut self) -> &mut CommandEnv<DefaultEnvKey> {
+ &mut self.env
+ }
+
+ pub fn cwd(&mut self, _dir: &OsStr) {}
+
+ pub fn stdin(&mut self, _stdin: Stdio) {}
+
+ pub fn stdout(&mut self, _stdout: Stdio) {}
+
+ pub fn stderr(&mut self, _stderr: Stdio) {}
+
+ pub fn spawn(
+ &mut self,
+ _default: Stdio,
+ _needs_stdin: bool,
+ ) -> io::Result<(Process, StdioPipes)> {
+ unsupported()
+ }
+}
+
+impl From<AnonPipe> for Stdio {
+ fn from(pipe: AnonPipe) -> Stdio {
+ pipe.diverge()
+ }
+}
+
+impl From<File> for Stdio {
+ fn from(file: File) -> Stdio {
+ file.diverge()
+ }
+}
+
+impl fmt::Debug for Command {
+ fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ Ok(())
+ }
+}
+
+pub struct ExitStatus(Void);
+
+impl ExitStatus {
+ pub fn success(&self) -> bool {
+ match self.0 {}
+ }
+
+ pub fn code(&self) -> Option<i32> {
+ match self.0 {}
+ }
+}
+
+impl Clone for ExitStatus {
+ fn clone(&self) -> ExitStatus {
+ match self.0 {}
+ }
+}
+
+impl Copy for ExitStatus {}
+
+impl PartialEq for ExitStatus {
+ fn eq(&self, _other: &ExitStatus) -> bool {
+ match self.0 {}
+ }
+}
+
+impl Eq for ExitStatus {}
+
+impl fmt::Debug for ExitStatus {
+ fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self.0 {}
+ }
+}
+
+impl fmt::Display for ExitStatus {
+ fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self.0 {}
+ }
+}
+
+#[derive(PartialEq, Eq, Clone, Copy, Debug)]
+pub struct ExitCode(bool);
+
+impl ExitCode {
+ pub const SUCCESS: ExitCode = ExitCode(false);
+ pub const FAILURE: ExitCode = ExitCode(true);
+
+ pub fn as_i32(&self) -> i32 {
+ self.0 as i32
+ }
+}
+
+pub struct Process(Void);
+
+impl Process {
+ pub fn id(&self) -> u32 {
+ match self.0 {}
+ }
+
+ pub fn kill(&mut self) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn wait(&mut self) -> io::Result<ExitStatus> {
+ match self.0 {}
+ }
+
+ pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
+ match self.0 {}
+ }
+}
diff --git a/src/libstd/sys/cloudabi/stack_overflow.rs b/src/libstd/sys/cloudabi/stack_overflow.rs
new file mode 100644
index 0000000..e97831b
--- /dev/null
+++ b/src/libstd/sys/cloudabi/stack_overflow.rs
@@ -0,0 +1,13 @@
+#![cfg_attr(test, allow(dead_code))]
+
+pub struct Handler;
+
+impl Handler {
+ pub unsafe fn new() -> Handler {
+ Handler
+ }
+}
+
+pub unsafe fn init() {}
+
+pub unsafe fn cleanup() {}
diff --git a/src/libstd/sys/cloudabi/stdio.rs b/src/libstd/sys/cloudabi/stdio.rs
new file mode 100644
index 0000000..601563c
--- /dev/null
+++ b/src/libstd/sys/cloudabi/stdio.rs
@@ -0,0 +1,66 @@
+use crate::io;
+use crate::sys::cloudabi::abi;
+
+pub struct Stdin(());
+pub struct Stdout(());
+pub struct Stderr(());
+
+impl Stdin {
+ pub fn new() -> io::Result<Stdin> {
+ Ok(Stdin(()))
+ }
+}
+
+impl io::Read for Stdin {
+ fn read(&mut self, _buf: &mut [u8]) -> io::Result<usize> {
+ Ok(0)
+ }
+}
+
+impl Stdout {
+ pub fn new() -> io::Result<Stdout> {
+ Ok(Stdout(()))
+ }
+}
+
+impl io::Write for Stdout {
+ fn write(&mut self, _buf: &[u8]) -> io::Result<usize> {
+ Err(io::Error::new(
+ io::ErrorKind::BrokenPipe,
+ "Stdout is not connected to any output in this environment",
+ ))
+ }
+
+ fn flush(&mut self) -> io::Result<()> {
+ Ok(())
+ }
+}
+
+impl Stderr {
+ pub fn new() -> io::Result<Stderr> {
+ Ok(Stderr(()))
+ }
+}
+
+impl io::Write for Stderr {
+ fn write(&mut self, _buf: &[u8]) -> io::Result<usize> {
+ Err(io::Error::new(
+ io::ErrorKind::BrokenPipe,
+ "Stderr is not connected to any output in this environment",
+ ))
+ }
+
+ fn flush(&mut self) -> io::Result<()> {
+ Ok(())
+ }
+}
+
+pub fn is_ebadf(err: &io::Error) -> bool {
+ err.raw_os_error() == Some(abi::errno::BADF as i32)
+}
+
+pub const STDIN_BUF_SIZE: usize = crate::sys_common::io::DEFAULT_BUF_SIZE;
+
+pub fn panic_output() -> Option<impl io::Write> {
+ Stderr::new().ok()
+}
diff --git a/src/libstd/sys/cloudabi/thread.rs b/src/libstd/sys/cloudabi/thread.rs
new file mode 100644
index 0000000..f853346
--- /dev/null
+++ b/src/libstd/sys/cloudabi/thread.rs
@@ -0,0 +1,117 @@
+use crate::boxed::FnBox;
+use crate::cmp;
+use crate::ffi::CStr;
+use crate::io;
+use crate::mem;
+use crate::ptr;
+use crate::sys::cloudabi::abi;
+use crate::sys::time::checked_dur2intervals;
+use crate::sys_common::thread::*;
+use crate::time::Duration;
+
+pub const DEFAULT_MIN_STACK_SIZE: usize = 2 * 1024 * 1024;
+
+pub struct Thread {
+ id: libc::pthread_t,
+}
+
+// CloudABI has pthread_t as a pointer in which case we still want
+// a thread to be Send/Sync
+unsafe impl Send for Thread {}
+unsafe impl Sync for Thread {}
+
+impl Thread {
+ // unsafe: see thread::Builder::spawn_unchecked for safety requirements
+ pub unsafe fn new(stack: usize, p: Box<dyn FnBox()>) -> io::Result<Thread> {
+ let p = box p;
+ let mut native: libc::pthread_t = mem::zeroed();
+ let mut attr: libc::pthread_attr_t = mem::zeroed();
+ assert_eq!(libc::pthread_attr_init(&mut attr), 0);
+
+ let stack_size = cmp::max(stack, min_stack_size(&attr));
+ assert_eq!(libc::pthread_attr_setstacksize(&mut attr, stack_size), 0);
+
+ let ret = libc::pthread_create(&mut native, &attr, thread_start, &*p as *const _ as *mut _);
+ assert_eq!(libc::pthread_attr_destroy(&mut attr), 0);
+
+ return if ret != 0 {
+ Err(io::Error::from_raw_os_error(ret))
+ } else {
+ mem::forget(p); // ownership passed to pthread_create
+ Ok(Thread { id: native })
+ };
+
+ extern "C" fn thread_start(main: *mut libc::c_void) -> *mut libc::c_void {
+ unsafe {
+ start_thread(main as *mut u8);
+ }
+ ptr::null_mut()
+ }
+ }
+
+ pub fn yield_now() {
+ let ret = unsafe { abi::thread_yield() };
+ debug_assert_eq!(ret, abi::errno::SUCCESS);
+ }
+
+ pub fn set_name(_name: &CStr) {
+ // CloudABI has no way to set a thread name.
+ }
+
+ pub fn sleep(dur: Duration) {
+ let timeout = checked_dur2intervals(&dur)
+ .expect("overflow converting duration to nanoseconds");
+ unsafe {
+ let subscription = abi::subscription {
+ type_: abi::eventtype::CLOCK,
+ union: abi::subscription_union {
+ clock: abi::subscription_clock {
+ clock_id: abi::clockid::MONOTONIC,
+ timeout,
+ ..mem::zeroed()
+ },
+ },
+ ..mem::zeroed()
+ };
+ let mut event: abi::event = mem::uninitialized();
+ let mut nevents: usize = mem::uninitialized();
+ let ret = abi::poll(&subscription, &mut event, 1, &mut nevents);
+ assert_eq!(ret, abi::errno::SUCCESS);
+ assert_eq!(event.error, abi::errno::SUCCESS);
+ }
+ }
+
+ pub fn join(self) {
+ unsafe {
+ let ret = libc::pthread_join(self.id, ptr::null_mut());
+ mem::forget(self);
+ assert!(
+ ret == 0,
+ "failed to join thread: {}",
+ io::Error::from_raw_os_error(ret)
+ );
+ }
+ }
+}
+
+impl Drop for Thread {
+ fn drop(&mut self) {
+ let ret = unsafe { libc::pthread_detach(self.id) };
+ debug_assert_eq!(ret, 0);
+ }
+}
+
+#[cfg_attr(test, allow(dead_code))]
+pub mod guard {
+ pub type Guard = !;
+ pub unsafe fn current() -> Option<Guard> {
+ None
+ }
+ pub unsafe fn init() -> Option<Guard> {
+ None
+ }
+}
+
+fn min_stack_size(_: *const libc::pthread_attr_t) -> usize {
+ libc::PTHREAD_STACK_MIN
+}
diff --git a/src/libstd/sys/cloudabi/time.rs b/src/libstd/sys/cloudabi/time.rs
new file mode 100644
index 0000000..49a234e
--- /dev/null
+++ b/src/libstd/sys/cloudabi/time.rs
@@ -0,0 +1,98 @@
+use crate::mem;
+use crate::sys::cloudabi::abi;
+use crate::time::Duration;
+
+const NSEC_PER_SEC: abi::timestamp = 1_000_000_000;
+
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
+pub struct Instant {
+ t: abi::timestamp,
+}
+
+pub fn checked_dur2intervals(dur: &Duration) -> Option<abi::timestamp> {
+ dur.as_secs()
+ .checked_mul(NSEC_PER_SEC)?
+ .checked_add(dur.subsec_nanos() as abi::timestamp)
+}
+
+impl Instant {
+ pub fn now() -> Instant {
+ unsafe {
+ let mut t = mem::uninitialized();
+ let ret = abi::clock_time_get(abi::clockid::MONOTONIC, 0, &mut t);
+ assert_eq!(ret, abi::errno::SUCCESS);
+ Instant { t }
+ }
+ }
+
+ pub fn actually_monotonic() -> bool {
+ true
+ }
+
+ pub const fn zero() -> Instant {
+ Instant { t: 0 }
+ }
+
+ pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
+ let diff = self.t.checked_sub(other.t)?;
+ Some(Duration::new(diff / NSEC_PER_SEC, (diff % NSEC_PER_SEC) as u32))
+ }
+
+ pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
+ Some(Instant {
+ t: self.t.checked_add(checked_dur2intervals(other)?)?,
+ })
+ }
+
+ pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
+ Some(Instant {
+ t: self.t.checked_sub(checked_dur2intervals(other)?)?,
+ })
+ }
+}
+
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
+pub struct SystemTime {
+ t: abi::timestamp,
+}
+
+impl SystemTime {
+ pub fn now() -> SystemTime {
+ unsafe {
+ let mut t = mem::uninitialized();
+ let ret = abi::clock_time_get(abi::clockid::REALTIME, 0, &mut t);
+ assert_eq!(ret, abi::errno::SUCCESS);
+ SystemTime { t }
+ }
+ }
+
+ pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
+ if self.t >= other.t {
+ let diff = self.t - other.t;
+ Ok(Duration::new(
+ diff / NSEC_PER_SEC,
+ (diff % NSEC_PER_SEC) as u32,
+ ))
+ } else {
+ let diff = other.t - self.t;
+ Err(Duration::new(
+ diff / NSEC_PER_SEC,
+ (diff % NSEC_PER_SEC) as u32,
+ ))
+ }
+ }
+
+ pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
+ Some(SystemTime {
+ t: self.t.checked_add(checked_dur2intervals(other)?)?,
+ })
+ }
+
+ pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
+ Some(SystemTime {
+ t: self.t.checked_sub(checked_dur2intervals(other)?)?,
+ })
+ }
+}
+
+pub const UNIX_EPOCH: SystemTime = SystemTime { t: 0 };
diff --git a/src/libstd/sys/mod.rs b/src/libstd/sys/mod.rs
new file mode 100644
index 0000000..d7ce6a0
--- /dev/null
+++ b/src/libstd/sys/mod.rs
@@ -0,0 +1,107 @@
+//! Platform-dependent platform abstraction.
+//!
+//! The `std::sys` module is the abstracted interface through which
+//! `std` talks to the underlying operating system. It has different
+//! implementations for different operating system families, today
+//! just Unix and Windows, and initial support for Redox.
+//!
+//! The centralization of platform-specific code in this module is
+//! enforced by the "platform abstraction layer" tidy script in
+//! `tools/tidy/src/pal.rs`.
+//!
+//! This module is closely related to the platform-independent system
+//! integration code in `std::sys_common`. See that module's
+//! documentation for details.
+//!
+//! In the future it would be desirable for the independent
+//! implementations of this module to be extracted to their own crates
+//! that `std` can link to, thus enabling their implementation
+//! out-of-tree via crate replacement. Though due to the complex
+//! inter-dependencies within `std` that will be a challenging goal to
+//! achieve.
+
+#![allow(missing_debug_implementations)]
+
+cfg_if! {
+ if #[cfg(unix)] {
+ mod unix;
+ pub use self::unix::*;
+ } else if #[cfg(windows)] {
+ mod windows;
+ pub use self::windows::*;
+ } else if #[cfg(target_os = "cloudabi")] {
+ mod cloudabi;
+ pub use self::cloudabi::*;
+ } else if #[cfg(target_os = "redox")] {
+ mod redox;
+ pub use self::redox::*;
+ } else if #[cfg(target_env = "wasi")] {
+ mod wasi;
+ pub use self::wasi::*;
+ } else if #[cfg(target_arch = "wasm32")] {
+ mod wasm;
+ pub use self::wasm::*;
+ } else if #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] {
+ mod sgx;
+ pub use self::sgx::*;
+ } else {
+ compile_error!("libstd doesn't compile for this platform yet");
+ }
+}
+
+// Import essential modules from both platforms when documenting. These are
+// then later used in the `std::os` module when documenting, for example,
+// Windows when we're compiling for Linux.
+
+#[cfg(rustdoc)]
+cfg_if! {
+ if #[cfg(any(unix, target_os = "redox"))] {
+ // On unix we'll document what's already available
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub use self::ext as unix_ext;
+ } else if #[cfg(any(target_os = "cloudabi",
+ target_arch = "wasm32",
+ all(target_vendor = "fortanix", target_env = "sgx")))] {
+ // On CloudABI and wasm right now the module below doesn't compile
+ // (missing things in `libc` which is empty) so just omit everything
+ // with an empty module
+ #[unstable(issue = "0", feature = "std_internals")]
+ #[allow(missing_docs)]
+ pub mod unix_ext {}
+ } else {
+ // On other platforms like Windows document the bare bones of unix
+ use crate::os::linux as platform;
+ #[path = "unix/ext/mod.rs"]
+ pub mod unix_ext;
+ }
+}
+
+#[cfg(rustdoc)]
+cfg_if! {
+ if #[cfg(windows)] {
+ // On windows we'll just be documenting what's already available
+ #[allow(missing_docs)]
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub use self::ext as windows_ext;
+ } else if #[cfg(any(target_os = "cloudabi",
+ target_arch = "wasm32",
+ all(target_vendor = "fortanix", target_env = "sgx")))] {
+ // On CloudABI and wasm right now the shim below doesn't compile, so
+ // just omit it
+ #[unstable(issue = "0", feature = "std_internals")]
+ #[allow(missing_docs)]
+ pub mod windows_ext {}
+ } else {
+ // On all other platforms (aka linux/osx/etc) then pull in a "minimal"
+ // amount of windows goop which ends up compiling
+ #[macro_use]
+ #[path = "windows/compat.rs"]
+ mod compat;
+
+ #[path = "windows/c.rs"]
+ mod c;
+
+ #[path = "windows/ext/mod.rs"]
+ pub mod windows_ext;
+ }
+}
diff --git a/src/libstd/sys/redox/args.rs b/src/libstd/sys/redox/args.rs
new file mode 100644
index 0000000..f9e2f5b
--- /dev/null
+++ b/src/libstd/sys/redox/args.rs
@@ -0,0 +1,96 @@
+//! Global initialization and retrieval of command line arguments.
+//!
+//! On some platforms these are stored during runtime startup,
+//! and on some they are retrieved from the system on demand.
+
+#![allow(dead_code)] // runtime init functions not used during testing
+
+use crate::ffi::OsString;
+use crate::marker::PhantomData;
+use crate::vec;
+
+/// One-time global initialization.
+pub unsafe fn init(argc: isize, argv: *const *const u8) { imp::init(argc, argv) }
+
+/// One-time global cleanup.
+pub unsafe fn cleanup() { imp::cleanup() }
+
+/// Returns the command line arguments
+pub fn args() -> Args {
+ imp::args()
+}
+
+pub struct Args {
+ iter: vec::IntoIter<OsString>,
+ _dont_send_or_sync_me: PhantomData<*mut ()>,
+}
+
+impl Args {
+ pub fn inner_debug(&self) -> &[OsString] {
+ self.iter.as_slice()
+ }
+}
+
+impl Iterator for Args {
+ type Item = OsString;
+ fn next(&mut self) -> Option<OsString> { self.iter.next() }
+ fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
+}
+
+impl ExactSizeIterator for Args {
+ fn len(&self) -> usize { self.iter.len() }
+}
+
+impl DoubleEndedIterator for Args {
+ fn next_back(&mut self) -> Option<OsString> { self.iter.next_back() }
+}
+
+mod imp {
+ use crate::os::unix::prelude::*;
+ use crate::mem;
+ use crate::ffi::{CStr, OsString};
+ use crate::marker::PhantomData;
+ use super::Args;
+
+ use crate::sys_common::mutex::Mutex;
+
+ static mut GLOBAL_ARGS_PTR: usize = 0;
+ static LOCK: Mutex = Mutex::new();
+
+ pub unsafe fn init(argc: isize, argv: *const *const u8) {
+ let args = (0..argc).map(|i| {
+ CStr::from_ptr(*argv.offset(i) as *const libc::c_char).to_bytes().to_vec()
+ }).collect();
+
+ let _guard = LOCK.lock();
+ let ptr = get_global_ptr();
+ assert!((*ptr).is_none());
+ (*ptr) = Some(box args);
+ }
+
+ pub unsafe fn cleanup() {
+ let _guard = LOCK.lock();
+ *get_global_ptr() = None;
+ }
+
+ pub fn args() -> Args {
+ let bytes = clone().unwrap_or_default();
+ let v: Vec<OsString> = bytes.into_iter().map(|v| {
+ OsStringExt::from_vec(v)
+ }).collect();
+ Args { iter: v.into_iter(), _dont_send_or_sync_me: PhantomData }
+ }
+
+ fn clone() -> Option<Vec<Vec<u8>>> {
+ unsafe {
+ let _guard = LOCK.lock();
+ let ptr = get_global_ptr();
+ (*ptr).as_ref().map(|s| (**s).clone())
+ }
+ }
+
+ unsafe fn get_global_ptr() -> *mut Option<Box<Vec<Vec<u8>>>> {
+ mem::transmute(&GLOBAL_ARGS_PTR)
+ }
+
+}
diff --git a/src/libstd/sys/redox/backtrace/mod.rs b/src/libstd/sys/redox/backtrace/mod.rs
new file mode 100644
index 0000000..8ea2783
--- /dev/null
+++ b/src/libstd/sys/redox/backtrace/mod.rs
@@ -0,0 +1,32 @@
+/// See sys/unix/backtrace/mod.rs for an explanation of the method used here.
+
+pub use self::tracing::unwind_backtrace;
+pub use self::printing::{foreach_symbol_fileline, resolve_symname};
+
+// tracing impls:
+mod tracing;
+// symbol resolvers:
+mod printing;
+
+pub mod gnu {
+ use crate::io;
+ use crate::fs;
+ use crate::vec::Vec;
+ use crate::ffi::OsStr;
+ use crate::os::unix::ffi::OsStrExt;
+ use crate::io::Read;
+ use libc::c_char;
+
+ pub fn get_executable_filename() -> io::Result<(Vec<c_char>, fs::File)> {
+ let mut exefile = fs::File::open("sys:exe")?;
+ let mut exename = Vec::new();
+ exefile.read_to_end(&mut exename)?;
+ if exename.last() == Some(&b'\n') {
+ exename.pop();
+ }
+ let file = fs::File::open(OsStr::from_bytes(&exename))?;
+ Ok((exename.into_iter().map(|c| c as c_char).collect(), file))
+ }
+}
+
+pub struct BacktraceContext;
diff --git a/src/libstd/sys/redox/backtrace/printing.rs b/src/libstd/sys/redox/backtrace/printing.rs
new file mode 100644
index 0000000..489eed4
--- /dev/null
+++ b/src/libstd/sys/redox/backtrace/printing.rs
@@ -0,0 +1 @@
+pub use crate::sys_common::gnu::libbacktrace::{foreach_symbol_fileline, resolve_symname};
diff --git a/src/libstd/sys/redox/backtrace/tracing.rs b/src/libstd/sys/redox/backtrace/tracing.rs
new file mode 100644
index 0000000..13f3433
--- /dev/null
+++ b/src/libstd/sys/redox/backtrace/tracing.rs
@@ -0,0 +1,99 @@
+use crate::error::Error;
+use crate::fmt;
+use crate::io;
+use crate::sys::backtrace::BacktraceContext;
+use crate::sys_common::backtrace::Frame;
+
+use unwind as uw;
+
+struct Context<'a> {
+ idx: usize,
+ frames: &'a mut [Frame],
+}
+
+#[derive(Debug)]
+struct UnwindError(uw::_Unwind_Reason_Code);
+
+impl Error for UnwindError {
+ fn description(&self) -> &'static str {
+ "unexpected return value while unwinding"
+ }
+}
+
+impl fmt::Display for UnwindError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "{}: {:?}", self.description(), self.0)
+ }
+}
+
+#[inline(never)] // if we know this is a function call, we can skip it when
+ // tracing
+pub fn unwind_backtrace(frames: &mut [Frame])
+ -> io::Result<(usize, BacktraceContext)>
+{
+ let mut cx = Context {
+ idx: 0,
+ frames: frames,
+ };
+ let result_unwind = unsafe {
+ uw::_Unwind_Backtrace(trace_fn,
+ &mut cx as *mut Context<'_>
+ as *mut libc::c_void)
+ };
+ // See libunwind:src/unwind/Backtrace.c for the return values.
+ // No, there is no doc.
+ match result_unwind {
+ // These return codes seem to be benign and need to be ignored for backtraces
+ // to show up properly on all tested platforms.
+ uw::_URC_END_OF_STACK | uw::_URC_FATAL_PHASE1_ERROR | uw::_URC_FAILURE => {
+ Ok((cx.idx, BacktraceContext))
+ }
+ _ => {
+ Err(io::Error::new(io::ErrorKind::Other,
+ UnwindError(result_unwind)))
+ }
+ }
+}
+
+extern fn trace_fn(ctx: *mut uw::_Unwind_Context,
+ arg: *mut libc::c_void) -> uw::_Unwind_Reason_Code {
+ let cx = unsafe { &mut *(arg as *mut Context<'_>) };
+ if cx.idx >= cx.frames.len() {
+ return uw::_URC_NORMAL_STOP;
+ }
+
+ let mut ip_before_insn = 0;
+ let mut ip = unsafe {
+ uw::_Unwind_GetIPInfo(ctx, &mut ip_before_insn) as *mut libc::c_void
+ };
+ if !ip.is_null() && ip_before_insn == 0 {
+ // this is a non-signaling frame, so `ip` refers to the address
+ // after the calling instruction. account for that.
+ ip = (ip as usize - 1) as *mut _;
+ }
+
+ // dladdr() on osx gets whiny when we use FindEnclosingFunction, and
+ // it appears to work fine without it, so we only use
+ // FindEnclosingFunction on non-osx platforms. In doing so, we get a
+ // slightly more accurate stack trace in the process.
+ //
+ // This is often because panic involves the last instruction of a
+ // function being "call std::rt::begin_unwind", with no ret
+ // instructions after it. This means that the return instruction
+ // pointer points *outside* of the calling function, and by
+ // unwinding it we go back to the original function.
+ let symaddr = if cfg!(target_os = "macos") || cfg!(target_os = "ios") {
+ ip
+ } else {
+ unsafe { uw::_Unwind_FindEnclosingFunction(ip) }
+ };
+
+ cx.frames[cx.idx] = Frame {
+ symbol_addr: symaddr as *mut u8,
+ exact_position: ip as *mut u8,
+ inline_context: 0,
+ };
+ cx.idx += 1;
+
+ uw::_URC_NO_REASON
+}
diff --git a/src/libstd/sys/redox/cmath.rs b/src/libstd/sys/redox/cmath.rs
new file mode 100644
index 0000000..f6bb589
--- /dev/null
+++ b/src/libstd/sys/redox/cmath.rs
@@ -0,0 +1,33 @@
+#![cfg(not(test))]
+
+use libc::{c_float, c_double};
+
+#[link_name = "m"]
+extern {
+ pub fn acos(n: c_double) -> c_double;
+ pub fn acosf(n: c_float) -> c_float;
+ pub fn asin(n: c_double) -> c_double;
+ pub fn asinf(n: c_float) -> c_float;
+ pub fn atan(n: c_double) -> c_double;
+ pub fn atan2(a: c_double, b: c_double) -> c_double;
+ pub fn atan2f(a: c_float, b: c_float) -> c_float;
+ pub fn atanf(n: c_float) -> c_float;
+ pub fn cbrt(n: c_double) -> c_double;
+ pub fn cbrtf(n: c_float) -> c_float;
+ pub fn cosh(n: c_double) -> c_double;
+ pub fn coshf(n: c_float) -> c_float;
+ pub fn expm1(n: c_double) -> c_double;
+ pub fn expm1f(n: c_float) -> c_float;
+ pub fn fdim(a: c_double, b: c_double) -> c_double;
+ pub fn fdimf(a: c_float, b: c_float) -> c_float;
+ pub fn hypot(x: c_double, y: c_double) -> c_double;
+ pub fn hypotf(x: c_float, y: c_float) -> c_float;
+ pub fn log1p(n: c_double) -> c_double;
+ pub fn log1pf(n: c_float) -> c_float;
+ pub fn sinh(n: c_double) -> c_double;
+ pub fn sinhf(n: c_float) -> c_float;
+ pub fn tan(n: c_double) -> c_double;
+ pub fn tanf(n: c_float) -> c_float;
+ pub fn tanh(n: c_double) -> c_double;
+ pub fn tanhf(n: c_float) -> c_float;
+}
diff --git a/src/libstd/sys/redox/condvar.rs b/src/libstd/sys/redox/condvar.rs
new file mode 100644
index 0000000..a6365ca
--- /dev/null
+++ b/src/libstd/sys/redox/condvar.rs
@@ -0,0 +1,111 @@
+use crate::cell::UnsafeCell;
+use crate::intrinsics::{atomic_cxchg, atomic_load, atomic_xadd, atomic_xchg};
+use crate::ptr;
+use crate::time::Duration;
+
+use crate::sys::mutex::{mutex_unlock, Mutex};
+use crate::sys::syscall::{futex, TimeSpec, FUTEX_WAIT, FUTEX_WAKE, FUTEX_REQUEUE};
+
+pub struct Condvar {
+ lock: UnsafeCell<*mut i32>,
+ seq: UnsafeCell<i32>
+}
+
+impl Condvar {
+ pub const fn new() -> Condvar {
+ Condvar {
+ lock: UnsafeCell::new(ptr::null_mut()),
+ seq: UnsafeCell::new(0)
+ }
+ }
+
+ #[inline]
+ pub unsafe fn init(&self) {
+ *self.lock.get() = ptr::null_mut();
+ *self.seq.get() = 0;
+ }
+
+ #[inline]
+ pub fn notify_one(&self) {
+ unsafe {
+ let seq = self.seq.get();
+
+ atomic_xadd(seq, 1);
+
+ let _ = futex(seq, FUTEX_WAKE, 1, 0, ptr::null_mut());
+ }
+ }
+
+ #[inline]
+ pub fn notify_all(&self) {
+ unsafe {
+ let lock = self.lock.get();
+ let seq = self.seq.get();
+
+ if *lock == ptr::null_mut() {
+ return;
+ }
+
+ atomic_xadd(seq, 1);
+
+ let _ = futex(seq, FUTEX_REQUEUE, 1, crate::usize::MAX, *lock);
+ }
+ }
+
+ #[inline]
+ unsafe fn wait_inner(&self, mutex: &Mutex, timeout_ptr: *const TimeSpec) -> bool {
+ let lock = self.lock.get();
+ let seq = self.seq.get();
+
+ if *lock != mutex.lock.get() {
+ if *lock != ptr::null_mut() {
+ panic!("Condvar used with more than one Mutex");
+ }
+
+ atomic_cxchg(lock as *mut usize, 0, mutex.lock.get() as usize);
+ }
+
+ mutex_unlock(*lock);
+
+ let seq_before = atomic_load(seq);
+
+ let _ = futex(seq, FUTEX_WAIT, seq_before, timeout_ptr as usize, ptr::null_mut());
+
+ let seq_after = atomic_load(seq);
+
+ while atomic_xchg(*lock, 2) != 0 {
+ let _ = futex(*lock, FUTEX_WAIT, 2, 0, ptr::null_mut());
+ }
+
+ seq_before != seq_after
+ }
+
+ #[inline]
+ pub fn wait(&self, mutex: &Mutex) {
+ unsafe {
+ assert!(self.wait_inner(mutex, ptr::null()));
+ }
+ }
+
+ #[inline]
+ pub fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
+ unsafe {
+ let timeout = TimeSpec {
+ tv_sec: dur.as_secs() as i64,
+ tv_nsec: dur.subsec_nanos() as i32
+ };
+
+ self.wait_inner(mutex, &timeout as *const TimeSpec)
+ }
+ }
+
+ #[inline]
+ pub unsafe fn destroy(&self) {
+ *self.lock.get() = ptr::null_mut();
+ *self.seq.get() = 0;
+ }
+}
+
+unsafe impl Send for Condvar {}
+
+unsafe impl Sync for Condvar {}
diff --git a/src/libstd/sys/redox/env.rs b/src/libstd/sys/redox/env.rs
new file mode 100644
index 0000000..bcc0e12
--- /dev/null
+++ b/src/libstd/sys/redox/env.rs
@@ -0,0 +1,9 @@
+pub mod os {
+ pub const FAMILY: &str = "redox";
+ pub const OS: &str = "redox";
+ pub const DLL_PREFIX: &str = "lib";
+ pub const DLL_SUFFIX: &str = ".so";
+ pub const DLL_EXTENSION: &str = "so";
+ pub const EXE_SUFFIX: &str = "";
+ pub const EXE_EXTENSION: &str = "";
+}
diff --git a/src/libstd/sys/redox/ext/ffi.rs b/src/libstd/sys/redox/ext/ffi.rs
new file mode 100644
index 0000000..974d7b8
--- /dev/null
+++ b/src/libstd/sys/redox/ext/ffi.rs
@@ -0,0 +1,38 @@
+//! Redox-specific extension to the primitives in the `std::ffi` module.
+//!
+//! # Examples
+//!
+//! ```
+//! use std::ffi::OsString;
+//! use std::os::redox::ffi::OsStringExt;
+//!
+//! let bytes = b"foo".to_vec();
+//!
+//! // OsStringExt::from_vec
+//! let os_string = OsString::from_vec(bytes);
+//! assert_eq!(os_string.to_str(), Some("foo"));
+//!
+//! // OsStringExt::into_vec
+//! let bytes = os_string.into_vec();
+//! assert_eq!(bytes, b"foo");
+//! ```
+//!
+//! ```
+//! use std::ffi::OsStr;
+//! use std::os::redox::ffi::OsStrExt;
+//!
+//! let bytes = b"foo";
+//!
+//! // OsStrExt::from_bytes
+//! let os_str = OsStr::from_bytes(bytes);
+//! assert_eq!(os_str.to_str(), Some("foo"));
+//!
+//! // OsStrExt::as_bytes
+//! let bytes = os_str.as_bytes();
+//! assert_eq!(bytes, b"foo");
+//! ```
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use crate::sys_common::os_str_bytes::*;
diff --git a/src/libstd/sys/redox/ext/fs.rs b/src/libstd/sys/redox/ext/fs.rs
new file mode 100644
index 0000000..53b9dd6
--- /dev/null
+++ b/src/libstd/sys/redox/ext/fs.rs
@@ -0,0 +1,339 @@
+//! Redox-specific extensions to primitives in the `std::fs` module.
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+use crate::fs::{self, Permissions, OpenOptions};
+use crate::io;
+use crate::path::Path;
+use crate::sys;
+use crate::sys_common::{FromInner, AsInner, AsInnerMut};
+
+/// Redox-specific extensions to [`fs::Permissions`].
+///
+/// [`fs::Permissions`]: ../../../../std/fs/struct.Permissions.html
+#[stable(feature = "fs_ext", since = "1.1.0")]
+pub trait PermissionsExt {
+ /// Returns the underlying raw `mode_t` bits that are the standard Redox
+ /// permissions for this file.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs::File;
+ /// use std::os::redox::fs::PermissionsExt;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let f = File::create("foo.txt")?;
+ /// let metadata = f.metadata()?;
+ /// let permissions = metadata.permissions();
+ ///
+ /// println!("permissions: {}", permissions.mode());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "fs_ext", since = "1.1.0")]
+ fn mode(&self) -> u32;
+
+ /// Sets the underlying raw bits for this set of permissions.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs::File;
+ /// use std::os::redox::fs::PermissionsExt;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let f = File::create("foo.txt")?;
+ /// let metadata = f.metadata()?;
+ /// let mut permissions = metadata.permissions();
+ ///
+ /// permissions.set_mode(0o644); // Read/write for owner and read for others.
+ /// assert_eq!(permissions.mode(), 0o644);
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "fs_ext", since = "1.1.0")]
+ fn set_mode(&mut self, mode: u32);
+
+ /// Creates a new instance of `Permissions` from the given set of Redox
+ /// permission bits.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::fs::Permissions;
+ /// use std::os::redox::fs::PermissionsExt;
+ ///
+ /// // Read/write for owner and read for others.
+ /// let permissions = Permissions::from_mode(0o644);
+ /// assert_eq!(permissions.mode(), 0o644);
+ /// ```
+ #[stable(feature = "fs_ext", since = "1.1.0")]
+ fn from_mode(mode: u32) -> Self;
+}
+
+#[stable(feature = "fs_ext", since = "1.1.0")]
+impl PermissionsExt for Permissions {
+ fn mode(&self) -> u32 {
+ self.as_inner().mode()
+ }
+
+ fn set_mode(&mut self, mode: u32) {
+ *self = Permissions::from_inner(FromInner::from_inner(mode));
+ }
+
+ fn from_mode(mode: u32) -> Permissions {
+ Permissions::from_inner(FromInner::from_inner(mode))
+ }
+}
+
+/// Redox-specific extensions to [`fs::OpenOptions`].
+///
+/// [`fs::OpenOptions`]: ../../../../std/fs/struct.OpenOptions.html
+#[stable(feature = "fs_ext", since = "1.1.0")]
+pub trait OpenOptionsExt {
+ /// Sets the mode bits that a new file will be created with.
+ ///
+ /// If a new file is created as part of a `File::open_opts` call then this
+ /// specified `mode` will be used as the permission bits for the new file.
+ /// If no `mode` is set, the default of `0o666` will be used.
+ /// The operating system masks out bits with the systems `umask`, to produce
+ /// the final permissions.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # #![feature(libc)]
+ /// extern crate libc;
+ /// use std::fs::OpenOptions;
+ /// use std::os::redox::fs::OpenOptionsExt;
+ ///
+ /// # fn main() {
+ /// let mut options = OpenOptions::new();
+ /// options.mode(0o644); // Give read/write for owner and read for others.
+ /// let file = options.open("foo.txt");
+ /// # }
+ /// ```
+ #[stable(feature = "fs_ext", since = "1.1.0")]
+ fn mode(&mut self, mode: u32) -> &mut Self;
+
+ /// Passes custom flags to the `flags` argument of `open`.
+ ///
+ /// The bits that define the access mode are masked out with `O_ACCMODE`, to
+ /// ensure they do not interfere with the access mode set by Rusts options.
+ ///
+ /// Custom flags can only set flags, not remove flags set by Rusts options.
+ /// This options overwrites any previously set custom flags.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # #![feature(libc)]
+ /// extern crate libc;
+ /// use std::fs::OpenOptions;
+ /// use std::os::redox::fs::OpenOptionsExt;
+ ///
+ /// # fn main() {
+ /// let mut options = OpenOptions::new();
+ /// options.write(true);
+ /// if cfg!(target_os = "redox") {
+ /// options.custom_flags(libc::O_NOFOLLOW);
+ /// }
+ /// let file = options.open("foo.txt");
+ /// # }
+ /// ```
+ #[stable(feature = "open_options_ext", since = "1.10.0")]
+ fn custom_flags(&mut self, flags: i32) -> &mut Self;
+}
+
+#[stable(feature = "fs_ext", since = "1.1.0")]
+impl OpenOptionsExt for OpenOptions {
+ fn mode(&mut self, mode: u32) -> &mut OpenOptions {
+ self.as_inner_mut().mode(mode); self
+ }
+
+ fn custom_flags(&mut self, flags: i32) -> &mut OpenOptions {
+ self.as_inner_mut().custom_flags(flags); self
+ }
+}
+
+/// Redox-specific extensions to [`fs::Metadata`].
+///
+/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+pub trait MetadataExt {
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn dev(&self) -> u64;
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn ino(&self) -> u64;
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn mode(&self) -> u32;
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn nlink(&self) -> u64;
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn uid(&self) -> u32;
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn gid(&self) -> u32;
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn size(&self) -> u64;
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn atime(&self) -> i64;
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn atime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn mtime(&self) -> i64;
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn mtime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn ctime(&self) -> i64;
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn ctime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn blksize(&self) -> u64;
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn blocks(&self) -> u64;
+}
+
+// Hm, why are there casts here to the returned type, shouldn't the types always
+// be the same? Right you are! Turns out, however, on android at least the types
+// in the raw `stat` structure are not the same as the types being returned. Who
+// knew!
+//
+// As a result to make sure this compiles for all platforms we do the manual
+// casts and rely on manual lowering to `stat` if the raw type is desired.
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+impl MetadataExt for fs::Metadata {
+ fn dev(&self) -> u64 {
+ self.as_inner().as_inner().st_dev as u64
+ }
+ fn ino(&self) -> u64 {
+ self.as_inner().as_inner().st_ino as u64
+ }
+ fn mode(&self) -> u32 {
+ self.as_inner().as_inner().st_mode as u32
+ }
+ fn nlink(&self) -> u64 {
+ self.as_inner().as_inner().st_nlink as u64
+ }
+ fn uid(&self) -> u32 {
+ self.as_inner().as_inner().st_uid as u32
+ }
+ fn gid(&self) -> u32 {
+ self.as_inner().as_inner().st_gid as u32
+ }
+ fn size(&self) -> u64 {
+ self.as_inner().as_inner().st_size as u64
+ }
+ fn atime(&self) -> i64 {
+ self.as_inner().as_inner().st_atime as i64
+ }
+ fn atime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_atime_nsec as i64
+ }
+ fn mtime(&self) -> i64 {
+ self.as_inner().as_inner().st_mtime as i64
+ }
+ fn mtime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_mtime_nsec as i64
+ }
+ fn ctime(&self) -> i64 {
+ self.as_inner().as_inner().st_ctime as i64
+ }
+ fn ctime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_ctime_nsec as i64
+ }
+ fn blksize(&self) -> u64 {
+ self.as_inner().as_inner().st_blksize as u64
+ }
+ fn blocks(&self) -> u64 {
+ self.as_inner().as_inner().st_blocks as u64
+ }
+}
+
+/// Redox-specific extensions for [`FileType`].
+///
+/// Adds support for special Unix file types such as block/character devices,
+/// pipes, and sockets.
+///
+/// [`FileType`]: ../../../../std/fs/struct.FileType.html
+#[stable(feature = "file_type_ext", since = "1.5.0")]
+pub trait FileTypeExt {
+ /// Returns whether this file type is a block device.
+ #[stable(feature = "file_type_ext", since = "1.5.0")]
+ fn is_block_device(&self) -> bool;
+ /// Returns whether this file type is a char device.
+ #[stable(feature = "file_type_ext", since = "1.5.0")]
+ fn is_char_device(&self) -> bool;
+ /// Returns whether this file type is a fifo.
+ #[stable(feature = "file_type_ext", since = "1.5.0")]
+ fn is_fifo(&self) -> bool;
+ /// Returns whether this file type is a socket.
+ #[stable(feature = "file_type_ext", since = "1.5.0")]
+ fn is_socket(&self) -> bool;
+}
+
+#[stable(feature = "file_type_ext", since = "1.5.0")]
+impl FileTypeExt for fs::FileType {
+ fn is_block_device(&self) -> bool { false /*FIXME: Implement block device mode*/ }
+ fn is_char_device(&self) -> bool { false /*FIXME: Implement char device mode*/ }
+ fn is_fifo(&self) -> bool { false /*FIXME: Implement fifo mode*/ }
+ fn is_socket(&self) -> bool { false /*FIXME: Implement socket mode*/ }
+}
+
+/// Creates a new symbolic link on the filesystem.
+///
+/// The `dst` path will be a symbolic link pointing to the `src` path.
+///
+/// # Note
+///
+/// On Windows, you must specify whether a symbolic link points to a file
+/// or directory. Use `os::windows::fs::symlink_file` to create a
+/// symbolic link to a file, or `os::windows::fs::symlink_dir` to create a
+/// symbolic link to a directory. Additionally, the process must have
+/// `SeCreateSymbolicLinkPrivilege` in order to be able to create a
+/// symbolic link.
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::os::redox::fs;
+///
+/// fn main() -> std::io::Result<()> {
+/// fs::symlink("a.txt", "b.txt")?;
+/// Ok(())
+/// }
+/// ```
+#[stable(feature = "symlink", since = "1.1.0")]
+pub fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()>
+{
+ sys::fs::symlink(src.as_ref(), dst.as_ref())
+}
+
+/// Redox-specific extensions to [`fs::DirBuilder`].
+///
+/// [`fs::DirBuilder`]: ../../../../std/fs/struct.DirBuilder.html
+#[stable(feature = "dir_builder", since = "1.6.0")]
+pub trait DirBuilderExt {
+ /// Sets the mode to create new directories with. This option defaults to
+ /// 0o777.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs::DirBuilder;
+ /// use std::os::redox::fs::DirBuilderExt;
+ ///
+ /// let mut builder = DirBuilder::new();
+ /// builder.mode(0o755);
+ /// ```
+ #[stable(feature = "dir_builder", since = "1.6.0")]
+ fn mode(&mut self, mode: u32) -> &mut Self;
+}
+
+#[stable(feature = "dir_builder", since = "1.6.0")]
+impl DirBuilderExt for fs::DirBuilder {
+ fn mode(&mut self, mode: u32) -> &mut fs::DirBuilder {
+ self.as_inner_mut().set_mode(mode);
+ self
+ }
+}
diff --git a/src/libstd/sys/redox/ext/io.rs b/src/libstd/sys/redox/ext/io.rs
new file mode 100644
index 0000000..c21d216
--- /dev/null
+++ b/src/libstd/sys/redox/ext/io.rs
@@ -0,0 +1,172 @@
+//! Unix-specific extensions to general I/O primitives
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+use crate::fs;
+use crate::net;
+use crate::sys;
+use crate::io;
+use crate::sys_common::{self, AsInner, FromInner, IntoInner};
+
+/// Raw file descriptors.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub type RawFd = usize;
+
+/// A trait to extract the raw unix file descriptor from an underlying
+/// object.
+///
+/// This is only available on unix platforms and must be imported in order
+/// to call the method. Windows platforms have a corresponding `AsRawHandle`
+/// and `AsRawSocket` set of traits.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub trait AsRawFd {
+ /// Extracts the raw file descriptor.
+ ///
+ /// This method does **not** pass ownership of the raw file descriptor
+ /// to the caller. The descriptor is only guaranteed to be valid while
+ /// the original object has not yet been destroyed.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ fn as_raw_fd(&self) -> RawFd;
+}
+
+/// A trait to express the ability to construct an object from a raw file
+/// descriptor.
+#[stable(feature = "from_raw_os", since = "1.1.0")]
+pub trait FromRawFd {
+ /// Constructs a new instances of `Self` from the given raw file
+ /// descriptor.
+ ///
+ /// This function **consumes ownership** of the specified file
+ /// descriptor. The returned object will take responsibility for closing
+ /// it when the object goes out of scope.
+ ///
+ /// This function is also unsafe as the primitives currently returned
+ /// have the contract that they are the sole owner of the file
+ /// descriptor they are wrapping. Usage of this function could
+ /// accidentally allow violating this contract which can cause memory
+ /// unsafety in code that relies on it being true.
+ #[stable(feature = "from_raw_os", since = "1.1.0")]
+ unsafe fn from_raw_fd(fd: RawFd) -> Self;
+}
+
+/// A trait to express the ability to consume an object and acquire ownership of
+/// its raw file descriptor.
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+pub trait IntoRawFd {
+ /// Consumes this object, returning the raw underlying file descriptor.
+ ///
+ /// This function **transfers ownership** of the underlying file descriptor
+ /// to the caller. Callers are then the unique owners of the file descriptor
+ /// and must close the descriptor once it's no longer needed.
+ #[stable(feature = "into_raw_os", since = "1.4.0")]
+ fn into_raw_fd(self) -> RawFd;
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRawFd for fs::File {
+ fn as_raw_fd(&self) -> RawFd {
+ self.as_inner().fd().raw()
+ }
+}
+#[stable(feature = "from_raw_os", since = "1.1.0")]
+impl FromRawFd for fs::File {
+ unsafe fn from_raw_fd(fd: RawFd) -> fs::File {
+ fs::File::from_inner(sys::fs::File::from_inner(fd))
+ }
+}
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+impl IntoRawFd for fs::File {
+ fn into_raw_fd(self) -> RawFd {
+ self.into_inner().into_fd().into_raw()
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRawFd for net::TcpStream {
+ fn as_raw_fd(&self) -> RawFd {
+ self.as_inner().as_inner().fd().raw()
+ }
+}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRawFd for net::TcpListener {
+ fn as_raw_fd(&self) -> RawFd {
+ self.as_inner().as_inner().fd().raw()
+ }
+}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRawFd for net::UdpSocket {
+ fn as_raw_fd(&self) -> RawFd {
+ self.as_inner().as_inner().fd().raw()
+ }
+}
+
+#[stable(feature = "asraw_stdio", since = "1.21.0")]
+impl AsRawFd for io::Stdin {
+ fn as_raw_fd(&self) -> RawFd { 0 }
+}
+
+#[stable(feature = "asraw_stdio", since = "1.21.0")]
+impl AsRawFd for io::Stdout {
+ fn as_raw_fd(&self) -> RawFd { 1 }
+}
+
+#[stable(feature = "asraw_stdio", since = "1.21.0")]
+impl AsRawFd for io::Stderr {
+ fn as_raw_fd(&self) -> RawFd { 2 }
+}
+
+#[stable(feature = "asraw_stdio_locks", since = "1.35.0")]
+impl<'a> AsRawFd for io::StdinLock<'a> {
+ fn as_raw_fd(&self) -> RawFd { 0 }
+}
+
+#[stable(feature = "asraw_stdio_locks", since = "1.35.0")]
+impl<'a> AsRawFd for io::StdoutLock<'a> {
+ fn as_raw_fd(&self) -> RawFd { 1 }
+}
+
+#[stable(feature = "asraw_stdio_locks", since = "1.35.0")]
+impl<'a> AsRawFd for io::StderrLock<'a> {
+ fn as_raw_fd(&self) -> RawFd { 2 }
+}
+
+#[stable(feature = "from_raw_os", since = "1.1.0")]
+impl FromRawFd for net::TcpStream {
+ unsafe fn from_raw_fd(fd: RawFd) -> net::TcpStream {
+ let file = sys::fs::File::from_inner(fd);
+ net::TcpStream::from_inner(sys_common::net::TcpStream::from_inner(file))
+ }
+}
+#[stable(feature = "from_raw_os", since = "1.1.0")]
+impl FromRawFd for net::TcpListener {
+ unsafe fn from_raw_fd(fd: RawFd) -> net::TcpListener {
+ let file = sys::fs::File::from_inner(fd);
+ net::TcpListener::from_inner(sys_common::net::TcpListener::from_inner(file))
+ }
+}
+#[stable(feature = "from_raw_os", since = "1.1.0")]
+impl FromRawFd for net::UdpSocket {
+ unsafe fn from_raw_fd(fd: RawFd) -> net::UdpSocket {
+ let file = sys::fs::File::from_inner(fd);
+ net::UdpSocket::from_inner(sys_common::net::UdpSocket::from_inner(file))
+ }
+}
+
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+impl IntoRawFd for net::TcpStream {
+ fn into_raw_fd(self) -> RawFd {
+ self.into_inner().into_inner().into_fd().into_raw()
+ }
+}
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+impl IntoRawFd for net::TcpListener {
+ fn into_raw_fd(self) -> RawFd {
+ self.into_inner().into_inner().into_fd().into_raw()
+ }
+}
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+impl IntoRawFd for net::UdpSocket {
+ fn into_raw_fd(self) -> RawFd {
+ self.into_inner().into_inner().into_fd().into_raw()
+ }
+}
diff --git a/src/libstd/sys/redox/ext/mod.rs b/src/libstd/sys/redox/ext/mod.rs
new file mode 100644
index 0000000..8a2d243
--- /dev/null
+++ b/src/libstd/sys/redox/ext/mod.rs
@@ -0,0 +1,45 @@
+//! Experimental extensions to `std` for Unix platforms.
+//!
+//! For now, this module is limited to extracting file descriptors,
+//! but its functionality will grow over time.
+//!
+//! # Examples
+//!
+//! ```no_run
+//! use std::fs::File;
+//! use std::os::unix::prelude::*;
+//!
+//! fn main() {
+//! let f = File::create("foo.txt").unwrap();
+//! let fd = f.as_raw_fd();
+//!
+//! // use fd with native unix bindings
+//! }
+//! ```
+
+#![stable(feature = "rust1", since = "1.0.0")]
+#![doc(cfg(target_os = "redox"))]
+
+pub mod ffi;
+pub mod fs;
+pub mod io;
+pub mod net;
+pub mod process;
+pub mod thread;
+
+/// A prelude for conveniently writing platform-specific code.
+///
+/// Includes all extension traits, and some important type definitions.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub mod prelude {
+ #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
+ pub use super::io::{RawFd, AsRawFd, FromRawFd, IntoRawFd};
+ #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
+ pub use super::ffi::{OsStrExt, OsStringExt};
+ #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
+ pub use super::fs::{FileTypeExt, PermissionsExt, OpenOptionsExt, MetadataExt};
+ #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
+ pub use super::thread::JoinHandleExt;
+ #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
+ pub use super::process::{CommandExt, ExitStatusExt};
+}
diff --git a/src/libstd/sys/redox/ext/net.rs b/src/libstd/sys/redox/ext/net.rs
new file mode 100644
index 0000000..096d068
--- /dev/null
+++ b/src/libstd/sys/redox/ext/net.rs
@@ -0,0 +1,759 @@
+#![stable(feature = "unix_socket_redox", since = "1.29")]
+
+//! Unix-specific networking functionality
+
+use crate::fmt;
+use crate::io::{self, Error, ErrorKind, Initializer};
+use crate::net::Shutdown;
+use crate::os::unix::io::{RawFd, AsRawFd, FromRawFd, IntoRawFd};
+use crate::path::Path;
+use crate::time::Duration;
+use crate::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 the address is unnamed.
+ ///
+ /// # Examples
+ ///
+ /// A named address:
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixListener;
+ ///
+ /// let socket = UnixListener::bind("/tmp/sock").unwrap();
+ /// let addr = socket.local_addr().expect("Couldn't get local address");
+ /// assert_eq!(addr.is_unnamed(), false);
+ /// ```
+ ///
+ /// An unnamed address:
+ ///
+ /// ```
+ /// use std::os::unix::net::UnixDatagram;
+ ///
+ /// let socket = UnixDatagram::unbound().unwrap();
+ /// let addr = socket.local_addr().expect("Couldn't get local address");
+ /// assert_eq!(addr.is_unnamed(), true);
+ /// ```
+ #[stable(feature = "unix_socket_redox", since = "1.29")]
+ pub fn is_unnamed(&self) -> bool {
+ false
+ }
+}
+#[stable(feature = "unix_socket_redox", since = "1.29")]
+impl fmt::Debug for SocketAddr {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(fmt, "SocketAddr")
+ }
+}
+
+/// A Unix stream socket.
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::os::unix::net::UnixStream;
+/// use std::io::prelude::*;
+///
+/// let mut stream = UnixStream::connect("/path/to/my/socket").unwrap();
+/// stream.write_all(b"hello world").unwrap();
+/// let mut response = String::new();
+/// stream.read_to_string(&mut response).unwrap();
+/// println!("{}", response);
+/// ```
+#[stable(feature = "unix_socket_redox", since = "1.29")]
+pub struct UnixStream(FileDesc);
+
+#[stable(feature = "unix_socket_redox", since = "1.29")]
+impl fmt::Debug for UnixStream {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ let mut builder = fmt.debug_struct("UnixStream");
+ builder.field("fd", &self.0.raw());
+ if let Ok(addr) = self.local_addr() {
+ builder.field("local", &addr);
+ }
+ if let Ok(addr) = self.peer_addr() {
+ builder.field("peer", &addr);
+ }
+ builder.finish()
+ }
+}
+
+impl UnixStream {
+ /// Connects to the socket named by `path`.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixStream;
+ ///
+ /// let socket = match UnixStream::connect("/tmp/sock") {
+ /// Ok(sock) => sock,
+ /// Err(e) => {
+ /// println!("Couldn't connect: {:?}", e);
+ /// return
+ /// }
+ /// };
+ /// ```
+ #[stable(feature = "unix_socket_redox", since = "1.29")]
+ pub fn connect<P: AsRef<Path>>(path: P) -> io::Result<UnixStream> {
+ if let Some(s) = path.as_ref().to_str() {
+ cvt(syscall::open(format!("chan:{}", s), syscall::O_CLOEXEC))
+ .map(FileDesc::new)
+ .map(UnixStream)
+ } else {
+ Err(Error::new(
+ ErrorKind::Other,
+ "UnixStream::connect: non-utf8 paths not supported on redox"
+ ))
+ }
+ }
+
+ /// Creates an unnamed pair of connected sockets.
+ ///
+ /// Returns two `UnixStream`s which are connected to each other.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixStream;
+ ///
+ /// let (sock1, sock2) = match UnixStream::pair() {
+ /// Ok((sock1, sock2)) => (sock1, sock2),
+ /// Err(e) => {
+ /// println!("Couldn't create a pair of sockets: {:?}", e);
+ /// return
+ /// }
+ /// };
+ /// ```
+ #[stable(feature = "unix_socket_redox", since = "1.29")]
+ pub fn pair() -> io::Result<(UnixStream, UnixStream)> {
+ let server = cvt(syscall::open("chan:", syscall::O_CREAT | syscall::O_CLOEXEC))
+ .map(FileDesc::new)?;
+ let client = server.duplicate_path(b"connect")?;
+ let stream = server.duplicate_path(b"listen")?;
+ Ok((UnixStream(client), UnixStream(stream)))
+ }
+
+ /// Creates a new independently owned handle to the underlying socket.
+ ///
+ /// The returned `UnixStream` is a reference to the same stream that this
+ /// object references. Both handles will read and write the same stream of
+ /// data, and options set on one stream will be propagated to the other
+ /// stream.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixStream;
+ ///
+ /// let socket = UnixStream::connect("/tmp/sock").unwrap();
+ /// let sock_copy = socket.try_clone().expect("Couldn't clone socket");
+ /// ```
+ #[stable(feature = "unix_socket_redox", since = "1.29")]
+ pub fn try_clone(&self) -> io::Result<UnixStream> {
+ self.0.duplicate().map(UnixStream)
+ }
+
+ /// Returns the socket address of the local half of this connection.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixStream;
+ ///
+ /// let socket = UnixStream::connect("/tmp/sock").unwrap();
+ /// let addr = socket.local_addr().expect("Couldn't get local address");
+ /// ```
+ #[stable(feature = "unix_socket_redox", since = "1.29")]
+ pub fn local_addr(&self) -> io::Result<SocketAddr> {
+ Err(Error::new(ErrorKind::Other, "UnixStream::local_addr unimplemented on redox"))
+ }
+
+ /// Returns the socket address of the remote half of this connection.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixStream;
+ ///
+ /// let socket = UnixStream::connect("/tmp/sock").unwrap();
+ /// let addr = socket.peer_addr().expect("Couldn't get peer address");
+ /// ```
+ #[stable(feature = "unix_socket_redox", since = "1.29")]
+ pub fn peer_addr(&self) -> io::Result<SocketAddr> {
+ Err(Error::new(ErrorKind::Other, "UnixStream::peer_addr unimplemented on redox"))
+ }
+
+ /// Sets the read timeout for the socket.
+ ///
+ /// If the provided value is [`None`], then [`read`] calls will block
+ /// indefinitely. An [`Err`] is returned if the zero [`Duration`] is passed to this
+ /// method.
+ ///
+ /// [`None`]: ../../../../std/option/enum.Option.html#variant.None
+ /// [`Err`]: ../../../../std/result/enum.Result.html#variant.Err
+ /// [`read`]: ../../../../std/io/trait.Read.html#tymethod.read
+ /// [`Duration`]: ../../../../std/time/struct.Duration.html
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixStream;
+ /// use std::time::Duration;
+ ///
+ /// let socket = UnixStream::connect("/tmp/sock").unwrap();
+ /// socket.set_read_timeout(Some(Duration::new(1, 0))).expect("Couldn't set read timeout");
+ /// ```
+ ///
+ /// An [`Err`] is returned if the zero [`Duration`] is passed to this
+ /// method:
+ ///
+ /// ```no_run
+ /// use std::io;
+ /// use std::os::unix::net::UnixStream;
+ /// use std::time::Duration;
+ ///
+ /// let socket = UnixStream::connect("/tmp/sock").unwrap();
+ /// let result = socket.set_read_timeout(Some(Duration::new(0, 0)));
+ /// let err = result.unwrap_err();
+ /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput)
+ /// ```
+ #[stable(feature = "unix_socket_redox", since = "1.29")]
+ pub fn set_read_timeout(&self, _timeout: Option<Duration>) -> io::Result<()> {
+ Err(Error::new(ErrorKind::Other, "UnixStream::set_read_timeout unimplemented on redox"))
+ }
+
+ /// Sets the write timeout for the socket.
+ ///
+ /// If the provided value is [`None`], then [`write`] calls will block
+ /// indefinitely. An [`Err`] is returned if the zero [`Duration`] is
+ /// passed to this method.
+ ///
+ /// [`None`]: ../../../../std/option/enum.Option.html#variant.None
+ /// [`Err`]: ../../../../std/result/enum.Result.html#variant.Err
+ /// [`write`]: ../../../../std/io/trait.Write.html#tymethod.write
+ /// [`Duration`]: ../../../../std/time/struct.Duration.html
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixStream;
+ /// use std::time::Duration;
+ ///
+ /// let socket = UnixStream::connect("/tmp/sock").unwrap();
+ /// socket.set_write_timeout(Some(Duration::new(1, 0))).expect("Couldn't set write timeout");
+ /// ```
+ ///
+ /// An [`Err`] is returned if the zero [`Duration`] is passed to this
+ /// method:
+ ///
+ /// ```no_run
+ /// use std::io;
+ /// use std::net::UdpSocket;
+ /// use std::time::Duration;
+ ///
+ /// let socket = UdpSocket::bind("127.0.0.1:34254").unwrap();
+ /// let result = socket.set_write_timeout(Some(Duration::new(0, 0)));
+ /// let err = result.unwrap_err();
+ /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput)
+ /// ```
+ #[stable(feature = "unix_socket_redox", since = "1.29")]
+ pub fn set_write_timeout(&self, _timeout: Option<Duration>) -> io::Result<()> {
+ Err(Error::new(ErrorKind::Other, "UnixStream::set_write_timeout unimplemented on redox"))
+ }
+
+ /// Returns the read timeout of this socket.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixStream;
+ /// use std::time::Duration;
+ ///
+ /// let socket = UnixStream::connect("/tmp/sock").unwrap();
+ /// socket.set_read_timeout(Some(Duration::new(1, 0))).expect("Couldn't set read timeout");
+ /// assert_eq!(socket.read_timeout().unwrap(), Some(Duration::new(1, 0)));
+ /// ```
+ #[stable(feature = "unix_socket_redox", since = "1.29")]
+ pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
+ Err(Error::new(ErrorKind::Other, "UnixStream::read_timeout unimplemented on redox"))
+ }
+
+ /// Returns the write timeout of this socket.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixStream;
+ /// use std::time::Duration;
+ ///
+ /// let socket = UnixStream::connect("/tmp/sock").unwrap();
+ /// socket.set_write_timeout(Some(Duration::new(1, 0))).expect("Couldn't set write timeout");
+ /// assert_eq!(socket.write_timeout().unwrap(), Some(Duration::new(1, 0)));
+ /// ```
+ #[stable(feature = "unix_socket_redox", since = "1.29")]
+ pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
+ Err(Error::new(ErrorKind::Other, "UnixStream::write_timeout unimplemented on redox"))
+ }
+
+ /// Moves the socket into or out of nonblocking mode.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixStream;
+ ///
+ /// let socket = UnixStream::connect("/tmp/sock").unwrap();
+ /// socket.set_nonblocking(true).expect("Couldn't set nonblocking");
+ /// ```
+ #[stable(feature = "unix_socket_redox", since = "1.29")]
+ pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
+ self.0.set_nonblocking(nonblocking)
+ }
+
+ /// Returns the value of the `SO_ERROR` option.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixStream;
+ ///
+ /// let socket = UnixStream::connect("/tmp/sock").unwrap();
+ /// if let Ok(Some(err)) = socket.take_error() {
+ /// println!("Got error: {:?}", err);
+ /// }
+ /// ```
+ ///
+ /// # Platform specific
+ /// On Redox this always returns `None`.
+ #[stable(feature = "unix_socket_redox", since = "1.29")]
+ pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+ Ok(None)
+ }
+
+ /// Shuts down the read, write, or both halves of this connection.
+ ///
+ /// This function will cause all pending and future I/O calls on the
+ /// specified portions to immediately return with an appropriate value
+ /// (see the documentation of [`Shutdown`]).
+ ///
+ /// [`Shutdown`]: ../../../../std/net/enum.Shutdown.html
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixStream;
+ /// use std::net::Shutdown;
+ ///
+ /// let socket = UnixStream::connect("/tmp/sock").unwrap();
+ /// socket.shutdown(Shutdown::Both).expect("shutdown function failed");
+ /// ```
+ #[stable(feature = "unix_socket_redox", since = "1.29")]
+ pub fn shutdown(&self, _how: Shutdown) -> io::Result<()> {
+ Err(Error::new(ErrorKind::Other, "UnixStream::shutdown unimplemented on redox"))
+ }
+}
+
+#[stable(feature = "unix_socket_redox", since = "1.29")]
+impl io::Read for UnixStream {
+ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+ io::Read::read(&mut &*self, buf)
+ }
+
+ #[inline]
+ unsafe fn initializer(&self) -> Initializer {
+ Initializer::nop()
+ }
+}
+
+#[stable(feature = "unix_socket_redox", since = "1.29")]
+impl<'a> io::Read for &'a UnixStream {
+ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+ self.0.read(buf)
+ }
+
+ #[inline]
+ unsafe fn initializer(&self) -> Initializer {
+ Initializer::nop()
+ }
+}
+
+#[stable(feature = "unix_socket_redox", since = "1.29")]
+impl io::Write for UnixStream {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ io::Write::write(&mut &*self, buf)
+ }
+
+ fn flush(&mut self) -> io::Result<()> {
+ io::Write::flush(&mut &*self)
+ }
+}
+
+#[stable(feature = "unix_socket_redox", since = "1.29")]
+impl<'a> io::Write for &'a UnixStream {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ self.0.write(buf)
+ }
+
+ fn flush(&mut self) -> io::Result<()> {
+ Ok(())
+ }
+}
+
+#[stable(feature = "unix_socket_redox", since = "1.29")]
+impl AsRawFd for UnixStream {
+ fn as_raw_fd(&self) -> RawFd {
+ self.0.raw()
+ }
+}
+
+#[stable(feature = "unix_socket_redox", since = "1.29")]
+impl FromRawFd for UnixStream {
+ unsafe fn from_raw_fd(fd: RawFd) -> UnixStream {
+ UnixStream(FileDesc::new(fd))
+ }
+}
+
+#[stable(feature = "unix_socket_redox", since = "1.29")]
+impl IntoRawFd for UnixStream {
+ fn into_raw_fd(self) -> RawFd {
+ self.0.into_raw()
+ }
+}
+
+/// A structure representing a Unix domain socket server.
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::thread;
+/// use std::os::unix::net::{UnixStream, UnixListener};
+///
+/// fn handle_client(stream: UnixStream) {
+/// // ...
+/// }
+///
+/// let listener = UnixListener::bind("/path/to/the/socket").unwrap();
+///
+/// // accept connections and process them, spawning a new thread for each one
+/// for stream in listener.incoming() {
+/// match stream {
+/// Ok(stream) => {
+/// /* connection succeeded */
+/// thread::spawn(|| handle_client(stream));
+/// }
+/// Err(err) => {
+/// /* connection failed */
+/// break;
+/// }
+/// }
+/// }
+/// ```
+#[stable(feature = "unix_socket_redox", since = "1.29")]
+pub struct UnixListener(FileDesc);
+
+#[stable(feature = "unix_socket_redox", since = "1.29")]
+impl fmt::Debug for UnixListener {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ let mut builder = fmt.debug_struct("UnixListener");
+ builder.field("fd", &self.0.raw());
+ if let Ok(addr) = self.local_addr() {
+ builder.field("local", &addr);
+ }
+ builder.finish()
+ }
+}
+
+impl UnixListener {
+ /// Creates a new `UnixListener` bound to the specified socket.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixListener;
+ ///
+ /// let listener = match UnixListener::bind("/path/to/the/socket") {
+ /// Ok(sock) => sock,
+ /// Err(e) => {
+ /// println!("Couldn't connect: {:?}", e);
+ /// return
+ /// }
+ /// };
+ /// ```
+ #[stable(feature = "unix_socket_redox", since = "1.29")]
+ pub fn bind<P: AsRef<Path>>(path: P) -> io::Result<UnixListener> {
+ if let Some(s) = path.as_ref().to_str() {
+ cvt(syscall::open(format!("chan:{}", s), syscall::O_CREAT | syscall::O_CLOEXEC))
+ .map(FileDesc::new)
+ .map(UnixListener)
+ } else {
+ Err(Error::new(
+ ErrorKind::Other,
+ "UnixListener::bind: non-utf8 paths not supported on redox"
+ ))
+ }
+ }
+
+ /// Accepts a new incoming connection to this listener.
+ ///
+ /// This function will block the calling thread until a new Unix connection
+ /// is established. When established, the corresponding [`UnixStream`] and
+ /// the remote peer's address will be returned.
+ ///
+ /// [`UnixStream`]: ../../../../std/os/unix/net/struct.UnixStream.html
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixListener;
+ ///
+ /// let listener = UnixListener::bind("/path/to/the/socket").unwrap();
+ ///
+ /// match listener.accept() {
+ /// Ok((socket, addr)) => println!("Got a client: {:?}", addr),
+ /// Err(e) => println!("accept function failed: {:?}", e),
+ /// }
+ /// ```
+ #[stable(feature = "unix_socket_redox", since = "1.29")]
+ pub fn accept(&self) -> io::Result<(UnixStream, SocketAddr)> {
+ self.0.duplicate_path(b"listen").map(|fd| (UnixStream(fd), SocketAddr(())))
+ }
+
+ /// Creates a new independently owned handle to the underlying socket.
+ ///
+ /// The returned `UnixListener` is a reference to the same socket that this
+ /// object references. Both handles can be used to accept incoming
+ /// connections and options set on one listener will affect the other.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixListener;
+ ///
+ /// let listener = UnixListener::bind("/path/to/the/socket").unwrap();
+ ///
+ /// let listener_copy = listener.try_clone().expect("try_clone failed");
+ /// ```
+ #[stable(feature = "unix_socket_redox", since = "1.29")]
+ pub fn try_clone(&self) -> io::Result<UnixListener> {
+ self.0.duplicate().map(UnixListener)
+ }
+
+ /// Returns the local socket address of this listener.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixListener;
+ ///
+ /// let listener = UnixListener::bind("/path/to/the/socket").unwrap();
+ ///
+ /// let addr = listener.local_addr().expect("Couldn't get local address");
+ /// ```
+ #[stable(feature = "unix_socket_redox", since = "1.29")]
+ pub fn local_addr(&self) -> io::Result<SocketAddr> {
+ Err(Error::new(ErrorKind::Other, "UnixListener::local_addr unimplemented on redox"))
+ }
+
+ /// Moves the socket into or out of nonblocking mode.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixListener;
+ ///
+ /// let listener = UnixListener::bind("/path/to/the/socket").unwrap();
+ ///
+ /// listener.set_nonblocking(true).expect("Couldn't set non blocking");
+ /// ```
+ #[stable(feature = "unix_socket_redox", since = "1.29")]
+ pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
+ self.0.set_nonblocking(nonblocking)
+ }
+
+ /// Returns the value of the `SO_ERROR` option.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixListener;
+ ///
+ /// let listener = UnixListener::bind("/tmp/sock").unwrap();
+ ///
+ /// if let Ok(Some(err)) = listener.take_error() {
+ /// println!("Got error: {:?}", err);
+ /// }
+ /// ```
+ ///
+ /// # Platform specific
+ /// On Redox this always returns `None`.
+ #[stable(feature = "unix_socket_redox", since = "1.29")]
+ pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+ Ok(None)
+ }
+
+ /// Returns an iterator over incoming connections.
+ ///
+ /// The iterator will never return [`None`] and will also not yield the
+ /// peer's [`SocketAddr`] structure.
+ ///
+ /// [`None`]: ../../../../std/option/enum.Option.html#variant.None
+ /// [`SocketAddr`]: struct.SocketAddr.html
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::thread;
+ /// use std::os::unix::net::{UnixStream, UnixListener};
+ ///
+ /// fn handle_client(stream: UnixStream) {
+ /// // ...
+ /// }
+ ///
+ /// let listener = UnixListener::bind("/path/to/the/socket").unwrap();
+ ///
+ /// for stream in listener.incoming() {
+ /// match stream {
+ /// Ok(stream) => {
+ /// thread::spawn(|| handle_client(stream));
+ /// }
+ /// Err(err) => {
+ /// break;
+ /// }
+ /// }
+ /// }
+ /// ```
+ #[stable(feature = "unix_socket_redox", since = "1.29")]
+ pub fn incoming<'a>(&'a self) -> Incoming<'a> {
+ Incoming { listener: self }
+ }
+}
+
+#[stable(feature = "unix_socket_redox", since = "1.29")]
+impl AsRawFd for UnixListener {
+ fn as_raw_fd(&self) -> RawFd {
+ self.0.raw()
+ }
+}
+
+#[stable(feature = "unix_socket_redox", since = "1.29")]
+impl FromRawFd for UnixListener {
+ unsafe fn from_raw_fd(fd: RawFd) -> UnixListener {
+ UnixListener(FileDesc::new(fd))
+ }
+}
+
+#[stable(feature = "unix_socket_redox", since = "1.29")]
+impl IntoRawFd for UnixListener {
+ fn into_raw_fd(self) -> RawFd {
+ self.0.into_raw()
+ }
+}
+
+#[stable(feature = "unix_socket_redox", since = "1.29")]
+impl<'a> IntoIterator for &'a UnixListener {
+ type Item = io::Result<UnixStream>;
+ type IntoIter = Incoming<'a>;
+
+ fn into_iter(self) -> Incoming<'a> {
+ self.incoming()
+ }
+}
+
+/// An iterator over incoming connections to a [`UnixListener`].
+///
+/// It will never return [`None`].
+///
+/// [`None`]: ../../../../std/option/enum.Option.html#variant.None
+/// [`UnixListener`]: struct.UnixListener.html
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::thread;
+/// use std::os::unix::net::{UnixStream, UnixListener};
+///
+/// fn handle_client(stream: UnixStream) {
+/// // ...
+/// }
+///
+/// let listener = UnixListener::bind("/path/to/the/socket").unwrap();
+///
+/// for stream in listener.incoming() {
+/// match stream {
+/// Ok(stream) => {
+/// thread::spawn(|| handle_client(stream));
+/// }
+/// Err(err) => {
+/// break;
+/// }
+/// }
+/// }
+/// ```
+#[derive(Debug)]
+#[stable(feature = "unix_socket_redox", since = "1.29")]
+pub struct Incoming<'a> {
+ listener: &'a UnixListener,
+}
+
+#[stable(feature = "unix_socket_redox", since = "1.29")]
+impl<'a> Iterator for Incoming<'a> {
+ type Item = io::Result<UnixStream>;
+
+ fn next(&mut self) -> Option<io::Result<UnixStream>> {
+ Some(self.listener.accept().map(|s| s.0))
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ (usize::max_value(), None)
+ }
+}
diff --git a/src/libstd/sys/redox/ext/process.rs b/src/libstd/sys/redox/ext/process.rs
new file mode 100644
index 0000000..e981cb9
--- /dev/null
+++ b/src/libstd/sys/redox/ext/process.rs
@@ -0,0 +1,197 @@
+//! Redox-specific extensions to primitives in the `std::process` module.
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+use crate::io;
+use crate::os::unix::io::{FromRawFd, RawFd, AsRawFd, IntoRawFd};
+use crate::process;
+use crate::sys;
+use crate::sys_common::{AsInnerMut, AsInner, FromInner, IntoInner};
+
+/// Redox-specific extensions to the [`process::Command`] builder,
+///
+/// [`process::Command`]: ../../../../std/process/struct.Command.html
+#[stable(feature = "rust1", since = "1.0.0")]
+pub trait CommandExt {
+ /// Sets the child process's user ID. This translates to a
+ /// `setuid` call in the child process. Failure in the `setuid`
+ /// call will cause the spawn to fail.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ fn uid(&mut self, id: u32) -> &mut process::Command;
+
+ /// Similar to `uid`, but sets the group ID of the child process. This has
+ /// the same semantics as the `uid` field.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ fn gid(&mut self, id: u32) -> &mut process::Command;
+
+ /// Schedules a closure to be run just before the `exec` function is
+ /// invoked.
+ ///
+ /// The closure is allowed to return an I/O error whose OS error code will
+ /// be communicated back to the parent and returned as an error from when
+ /// the spawn was requested.
+ ///
+ /// Multiple closures can be registered and they will be called in order of
+ /// their registration. If a closure returns `Err` then no further closures
+ /// will be called and the spawn operation will immediately return with a
+ /// failure.
+ ///
+ /// # Notes and Safety
+ ///
+ /// This closure will be run in the context of the child process after a
+ /// `fork`. This primarily means that any modifications made to memory on
+ /// behalf of this closure will **not** be visible to the parent process.
+ /// This is often a very constrained environment where normal operations
+ /// like `malloc` or acquiring a mutex are not guaranteed to work (due to
+ /// other threads perhaps still running when the `fork` was run).
+ ///
+ /// This also means that all resources such as file descriptors and
+ /// memory-mapped regions got duplicated. It is your responsibility to make
+ /// sure that the closure does not violate library invariants by making
+ /// invalid use of these duplicates.
+ ///
+ /// When this closure is run, aspects such as the stdio file descriptors and
+ /// working directory have successfully been changed, so output to these
+ /// locations may not appear where intended.
+ #[stable(feature = "process_pre_exec", since = "1.34.0")]
+ unsafe fn pre_exec<F>(&mut self, f: F) -> &mut process::Command
+ where F: FnMut() -> io::Result<()> + Send + Sync + 'static;
+
+ /// Schedules a closure to be run just before the `exec` function is
+ /// invoked.
+ ///
+ /// This method is stable and usable, but it should be unsafe. To fix
+ /// that, it got deprecated in favor of the unsafe [`pre_exec`].
+ ///
+ /// [`pre_exec`]: #tymethod.pre_exec
+ #[stable(feature = "process_exec", since = "1.15.0")]
+ #[rustc_deprecated(since = "1.37.0", reason = "should be unsafe, use `pre_exec` instead")]
+ fn before_exec<F>(&mut self, f: F) -> &mut process::Command
+ where F: FnMut() -> io::Result<()> + Send + Sync + 'static
+ {
+ unsafe { self.pre_exec(f) }
+ }
+
+ /// Performs all the required setup by this `Command`, followed by calling
+ /// the `execvp` syscall.
+ ///
+ /// On success this function will not return, and otherwise it will return
+ /// an error indicating why the exec (or another part of the setup of the
+ /// `Command`) failed.
+ ///
+ /// This function, unlike `spawn`, will **not** `fork` the process to create
+ /// a new child. Like spawn, however, the default behavior for the stdio
+ /// descriptors will be to inherited from the current process.
+ ///
+ /// # Notes
+ ///
+ /// The process may be in a "broken state" if this function returns in
+ /// error. For example the working directory, environment variables, signal
+ /// handling settings, various user/group information, or aspects of stdio
+ /// file descriptors may have changed. If a "transactional spawn" is
+ /// required to gracefully handle errors it is recommended to use the
+ /// cross-platform `spawn` instead.
+ #[stable(feature = "process_exec2", since = "1.9.0")]
+ fn exec(&mut self) -> io::Error;
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl CommandExt for process::Command {
+ fn uid(&mut self, id: u32) -> &mut process::Command {
+ self.as_inner_mut().uid(id);
+ self
+ }
+
+ fn gid(&mut self, id: u32) -> &mut process::Command {
+ self.as_inner_mut().gid(id);
+ self
+ }
+
+ unsafe fn pre_exec<F>(&mut self, f: F) -> &mut process::Command
+ where F: FnMut() -> io::Result<()> + Send + Sync + 'static
+ {
+ self.as_inner_mut().pre_exec(Box::new(f));
+ self
+ }
+
+ fn exec(&mut self) -> io::Error {
+ self.as_inner_mut().exec(sys::process::Stdio::Inherit)
+ }
+}
+
+/// Redox-specific extensions to [`process::ExitStatus`].
+///
+/// [`process::ExitStatus`]: ../../../../std/process/struct.ExitStatus.html
+#[stable(feature = "rust1", since = "1.0.0")]
+pub trait ExitStatusExt {
+ /// Creates a new `ExitStatus` from the raw underlying `i32` return value of
+ /// a process.
+ #[stable(feature = "exit_status_from", since = "1.12.0")]
+ fn from_raw(raw: i32) -> Self;
+
+ /// If the process was terminated by a signal, returns that signal.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ fn signal(&self) -> Option<i32>;
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl ExitStatusExt for process::ExitStatus {
+ fn from_raw(raw: i32) -> Self {
+ process::ExitStatus::from_inner(From::from(raw))
+ }
+
+ fn signal(&self) -> Option<i32> {
+ self.as_inner().signal()
+ }
+}
+
+#[stable(feature = "process_extensions", since = "1.2.0")]
+impl FromRawFd for process::Stdio {
+ unsafe fn from_raw_fd(fd: RawFd) -> process::Stdio {
+ let fd = sys::fd::FileDesc::new(fd);
+ let io = sys::process::Stdio::Fd(fd);
+ process::Stdio::from_inner(io)
+ }
+}
+
+#[stable(feature = "process_extensions", since = "1.2.0")]
+impl AsRawFd for process::ChildStdin {
+ fn as_raw_fd(&self) -> RawFd {
+ self.as_inner().fd().raw()
+ }
+}
+
+#[stable(feature = "process_extensions", since = "1.2.0")]
+impl AsRawFd for process::ChildStdout {
+ fn as_raw_fd(&self) -> RawFd {
+ self.as_inner().fd().raw()
+ }
+}
+
+#[stable(feature = "process_extensions", since = "1.2.0")]
+impl AsRawFd for process::ChildStderr {
+ fn as_raw_fd(&self) -> RawFd {
+ self.as_inner().fd().raw()
+ }
+}
+
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+impl IntoRawFd for process::ChildStdin {
+ fn into_raw_fd(self) -> RawFd {
+ self.into_inner().into_fd().into_raw()
+ }
+}
+
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+impl IntoRawFd for process::ChildStdout {
+ fn into_raw_fd(self) -> RawFd {
+ self.into_inner().into_fd().into_raw()
+ }
+}
+
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+impl IntoRawFd for process::ChildStderr {
+ fn into_raw_fd(self) -> RawFd {
+ self.into_inner().into_fd().into_raw()
+ }
+}
diff --git a/src/libstd/sys/redox/ext/thread.rs b/src/libstd/sys/redox/ext/thread.rs
new file mode 100644
index 0000000..629eaef
--- /dev/null
+++ b/src/libstd/sys/redox/ext/thread.rs
@@ -0,0 +1,39 @@
+//! Redox-specific extensions to primitives in the `std::thread` module.
+
+#![stable(feature = "thread_extensions", since = "1.9.0")]
+
+use crate::sys_common::{AsInner, IntoInner};
+use crate::thread::JoinHandle;
+
+#[stable(feature = "thread_extensions", since = "1.9.0")]
+#[allow(deprecated)]
+pub type RawPthread = usize;
+
+/// Redox-specific extensions to [`thread::JoinHandle`].
+///
+/// [`thread::JoinHandle`]: ../../../../std/thread/struct.JoinHandle.html
+#[stable(feature = "thread_extensions", since = "1.9.0")]
+pub trait JoinHandleExt {
+ /// Extracts the raw pthread_t without taking ownership
+ #[stable(feature = "thread_extensions", since = "1.9.0")]
+ fn as_pthread_t(&self) -> RawPthread;
+
+ /// Consumes the thread, returning the raw pthread_t
+ ///
+ /// This function **transfers ownership** of the underlying pthread_t to
+ /// the caller. Callers are then the unique owners of the pthread_t and
+ /// must either detach or join the pthread_t once it's no longer needed.
+ #[stable(feature = "thread_extensions", since = "1.9.0")]
+ fn into_pthread_t(self) -> RawPthread;
+}
+
+#[stable(feature = "thread_extensions", since = "1.9.0")]
+impl<T> JoinHandleExt for JoinHandle<T> {
+ fn as_pthread_t(&self) -> RawPthread {
+ self.as_inner().id() as RawPthread
+ }
+
+ fn into_pthread_t(self) -> RawPthread {
+ self.into_inner().into_id() as RawPthread
+ }
+}
diff --git a/src/libstd/sys/redox/fast_thread_local.rs b/src/libstd/sys/redox/fast_thread_local.rs
new file mode 100644
index 0000000..1202708
--- /dev/null
+++ b/src/libstd/sys/redox/fast_thread_local.rs
@@ -0,0 +1,111 @@
+#![cfg(target_thread_local)]
+#![unstable(feature = "thread_local_internals", issue = "0")]
+
+use crate::cell::{Cell, UnsafeCell};
+use crate::mem;
+use crate::ptr;
+
+
+pub struct Key<T> {
+ inner: UnsafeCell<Option<T>>,
+
+ // Metadata to keep track of the state of the destructor. Remember that
+ // these variables are thread-local, not global.
+ dtor_registered: Cell<bool>,
+ dtor_running: Cell<bool>,
+}
+
+unsafe impl<T> Sync for Key<T> { }
+
+impl<T> Key<T> {
+ pub const fn new() -> Key<T> {
+ Key {
+ inner: UnsafeCell::new(None),
+ dtor_registered: Cell::new(false),
+ dtor_running: Cell::new(false)
+ }
+ }
+
+ pub fn get(&'static self) -> Option<&'static UnsafeCell<Option<T>>> {
+ unsafe {
+ if mem::needs_drop::<T>() && self.dtor_running.get() {
+ return None
+ }
+ self.register_dtor();
+ }
+ Some(&self.inner)
+ }
+
+ unsafe fn register_dtor(&self) {
+ if !mem::needs_drop::<T>() || self.dtor_registered.get() {
+ return
+ }
+
+ register_dtor(self as *const _ as *mut u8,
+ destroy_value::<T>);
+ self.dtor_registered.set(true);
+ }
+}
+
+pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) {
+ // The fallback implementation uses a vanilla OS-based TLS key to track
+ // the list of destructors that need to be run for this thread. The key
+ // then has its own destructor which runs all the other destructors.
+ //
+ // The destructor for DTORS is a little special in that it has a `while`
+ // loop to continuously drain the list of registered destructors. It
+ // *should* be the case that this loop always terminates because we
+ // provide the guarantee that a TLS key cannot be set after it is
+ // flagged for destruction.
+ use crate::sys_common::thread_local as os;
+
+ static DTORS: os::StaticKey = os::StaticKey::new(Some(run_dtors));
+ type List = Vec<(*mut u8, unsafe extern fn(*mut u8))>;
+ if DTORS.get().is_null() {
+ let v: Box<List> = box Vec::new();
+ DTORS.set(Box::into_raw(v) as *mut u8);
+ }
+ let list: &mut List = &mut *(DTORS.get() as *mut List);
+ list.push((t, dtor));
+
+ unsafe extern fn run_dtors(mut ptr: *mut u8) {
+ while !ptr.is_null() {
+ let list: Box<List> = Box::from_raw(ptr as *mut List);
+ for (ptr, dtor) in list.into_iter() {
+ dtor(ptr);
+ }
+ ptr = DTORS.get();
+ DTORS.set(ptr::null_mut());
+ }
+ }
+}
+
+pub unsafe extern fn destroy_value<T>(ptr: *mut u8) {
+ let ptr = ptr as *mut Key<T>;
+ // Right before we run the user destructor be sure to flag the
+ // destructor as running for this thread so calls to `get` will return
+ // `None`.
+ (*ptr).dtor_running.set(true);
+
+ // The macOS implementation of TLS apparently had an odd aspect to it
+ // where the pointer we have may be overwritten while this destructor
+ // is running. Specifically if a TLS destructor re-accesses TLS it may
+ // trigger a re-initialization of all TLS variables, paving over at
+ // least some destroyed ones with initial values.
+ //
+ // This means that if we drop a TLS value in place on macOS that we could
+ // revert the value to its original state halfway through the
+ // destructor, which would be bad!
+ //
+ // Hence, we use `ptr::read` on macOS (to move to a "safe" location)
+ // instead of drop_in_place.
+ if cfg!(target_os = "macos") {
+ ptr::read((*ptr).inner.get());
+ } else {
+ ptr::drop_in_place((*ptr).inner.get());
+ }
+}
+
+pub fn requires_move_before_drop() -> bool {
+ false
+}
diff --git a/src/libstd/sys/redox/fd.rs b/src/libstd/sys/redox/fd.rs
new file mode 100644
index 0000000..a42e486
--- /dev/null
+++ b/src/libstd/sys/redox/fd.rs
@@ -0,0 +1,88 @@
+#![unstable(reason = "not public", issue = "0", feature = "fd")]
+
+use crate::io::{self, Read};
+use crate::mem;
+use crate::sys::{cvt, syscall};
+use crate::sys_common::AsInner;
+
+pub struct FileDesc {
+ fd: usize,
+}
+
+impl FileDesc {
+ pub fn new(fd: usize) -> FileDesc {
+ FileDesc { fd }
+ }
+
+ pub fn raw(&self) -> usize { self.fd }
+
+ /// Extracts the actual file descriptor without closing it.
+ pub fn into_raw(self) -> usize {
+ let fd = self.fd;
+ mem::forget(self);
+ fd
+ }
+
+ pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
+ cvt(syscall::read(self.fd, buf))
+ }
+
+ pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
+ let mut me = self;
+ (&mut me).read_to_end(buf)
+ }
+
+ pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
+ cvt(syscall::write(self.fd, buf))
+ }
+
+ pub fn duplicate(&self) -> io::Result<FileDesc> {
+ 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))
+ }
+
+ pub fn nonblocking(&self) -> io::Result<bool> {
+ let flags = cvt(syscall::fcntl(self.fd, syscall::F_GETFL, 0))?;
+ Ok(flags & syscall::O_NONBLOCK == syscall::O_NONBLOCK)
+ }
+
+ pub fn set_cloexec(&self) -> io::Result<()> {
+ let mut flags = cvt(syscall::fcntl(self.fd, syscall::F_GETFD, 0))?;
+ flags |= syscall::O_CLOEXEC;
+ cvt(syscall::fcntl(self.fd, syscall::F_SETFD, flags)).and(Ok(()))
+ }
+
+ pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
+ let mut flags = cvt(syscall::fcntl(self.fd, syscall::F_GETFL, 0))?;
+ if nonblocking {
+ flags |= syscall::O_NONBLOCK;
+ } else {
+ flags &= !syscall::O_NONBLOCK;
+ }
+ cvt(syscall::fcntl(self.fd, syscall::F_SETFL, flags)).and(Ok(()))
+ }
+}
+
+impl<'a> Read for &'a FileDesc {
+ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+ (**self).read(buf)
+ }
+}
+
+impl AsInner<usize> for FileDesc {
+ fn as_inner(&self) -> &usize { &self.fd }
+}
+
+impl Drop for FileDesc {
+ fn drop(&mut self) {
+ // Note that errors are ignored when closing a file descriptor. The
+ // reason for this is that if an error occurs we don't actually know if
+ // the file descriptor was closed or not, and if we retried (for
+ // something like EINTR), we might close another valid file descriptor
+ // (opened after we closed ours.
+ let _ = syscall::close(self.fd);
+ }
+}
diff --git a/src/libstd/sys/redox/fs.rs b/src/libstd/sys/redox/fs.rs
new file mode 100644
index 0000000..ebefbc9
--- /dev/null
+++ b/src/libstd/sys/redox/fs.rs
@@ -0,0 +1,439 @@
+use crate::os::unix::prelude::*;
+
+use crate::ffi::{OsString, OsStr};
+use crate::fmt;
+use crate::io::{self, Error, SeekFrom};
+use crate::path::{Path, PathBuf};
+use crate::sync::Arc;
+use crate::sys::fd::FileDesc;
+use crate::sys::time::SystemTime;
+use crate::sys::{cvt, syscall};
+use crate::sys_common::{AsInner, FromInner};
+
+pub use crate::sys_common::fs::copy;
+pub use crate::sys_common::fs::remove_dir_all;
+
+pub struct File(FileDesc);
+
+#[derive(Clone)]
+pub struct FileAttr {
+ stat: syscall::Stat,
+}
+
+pub struct ReadDir {
+ data: Vec<u8>,
+ i: usize,
+ root: Arc<PathBuf>,
+}
+
+struct Dir(FileDesc);
+
+unsafe impl Send for Dir {}
+unsafe impl Sync for Dir {}
+
+pub struct DirEntry {
+ root: Arc<PathBuf>,
+ name: Box<[u8]>
+}
+
+#[derive(Clone, Debug)]
+pub struct OpenOptions {
+ // generic
+ read: bool,
+ write: bool,
+ append: bool,
+ truncate: bool,
+ create: bool,
+ create_new: bool,
+ // system-specific
+ custom_flags: i32,
+ mode: u16,
+}
+
+#[derive(Clone, PartialEq, Eq, Debug)]
+pub struct FilePermissions { mode: u16 }
+
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
+pub struct FileType { mode: u16 }
+
+#[derive(Debug)]
+pub struct DirBuilder { mode: u16 }
+
+impl FileAttr {
+ pub fn size(&self) -> u64 { self.stat.st_size as u64 }
+ pub fn perm(&self) -> FilePermissions {
+ FilePermissions { mode: (self.stat.st_mode as u16) & 0o777 }
+ }
+
+ pub fn file_type(&self) -> FileType {
+ FileType { mode: self.stat.st_mode as u16 }
+ }
+}
+
+impl FileAttr {
+ pub fn modified(&self) -> io::Result<SystemTime> {
+ Ok(SystemTime::from(syscall::TimeSpec {
+ tv_sec: self.stat.st_mtime as i64,
+ tv_nsec: self.stat.st_mtime_nsec as i32,
+ }))
+ }
+
+ pub fn accessed(&self) -> io::Result<SystemTime> {
+ Ok(SystemTime::from(syscall::TimeSpec {
+ tv_sec: self.stat.st_atime as i64,
+ tv_nsec: self.stat.st_atime_nsec as i32,
+ }))
+ }
+
+ pub fn created(&self) -> io::Result<SystemTime> {
+ Ok(SystemTime::from(syscall::TimeSpec {
+ tv_sec: self.stat.st_ctime as i64,
+ tv_nsec: self.stat.st_ctime_nsec as i32,
+ }))
+ }
+}
+
+impl AsInner<syscall::Stat> for FileAttr {
+ fn as_inner(&self) -> &syscall::Stat { &self.stat }
+}
+
+impl FilePermissions {
+ pub fn readonly(&self) -> bool { self.mode & 0o222 == 0 }
+ pub fn set_readonly(&mut self, readonly: bool) {
+ if readonly {
+ self.mode &= !0o222;
+ } else {
+ self.mode |= 0o222;
+ }
+ }
+ pub fn mode(&self) -> u32 { self.mode as u32 }
+}
+
+impl FileType {
+ pub fn is_dir(&self) -> bool { self.is(syscall::MODE_DIR) }
+ pub fn is_file(&self) -> bool { self.is(syscall::MODE_FILE) }
+ pub fn is_symlink(&self) -> bool { self.is(syscall::MODE_SYMLINK) }
+
+ pub fn is(&self, mode: u16) -> bool {
+ self.mode & syscall::MODE_TYPE == mode
+ }
+}
+
+impl FromInner<u32> for FilePermissions {
+ fn from_inner(mode: u32) -> FilePermissions {
+ FilePermissions { mode: mode as u16 }
+ }
+}
+
+impl fmt::Debug for ReadDir {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ // This will only be called from std::fs::ReadDir, which will add a "ReadDir()" frame.
+ // Thus the result will be e g 'ReadDir("/home")'
+ fmt::Debug::fmt(&*self.root, f)
+ }
+}
+
+impl Iterator for ReadDir {
+ type Item = io::Result<DirEntry>;
+
+ fn next(&mut self) -> Option<io::Result<DirEntry>> {
+ loop {
+ let start = self.i;
+ let mut i = self.i;
+ while i < self.data.len() {
+ self.i += 1;
+ if self.data[i] == b'\n' {
+ break;
+ }
+ i += 1;
+ }
+ if start < self.i {
+ let ret = DirEntry {
+ name: self.data[start .. i].to_owned().into_boxed_slice(),
+ root: self.root.clone()
+ };
+ if ret.name_bytes() != b"." && ret.name_bytes() != b".." {
+ return Some(Ok(ret))
+ }
+ } else {
+ return None;
+ }
+ }
+ }
+}
+
+impl DirEntry {
+ pub fn path(&self) -> PathBuf {
+ self.root.join(OsStr::from_bytes(self.name_bytes()))
+ }
+
+ pub fn file_name(&self) -> OsString {
+ OsStr::from_bytes(self.name_bytes()).to_os_string()
+ }
+
+ pub fn metadata(&self) -> io::Result<FileAttr> {
+ lstat(&self.path())
+ }
+
+ pub fn file_type(&self) -> io::Result<FileType> {
+ lstat(&self.path()).map(|m| m.file_type())
+ }
+
+ fn name_bytes(&self) -> &[u8] {
+ &*self.name
+ }
+}
+
+impl OpenOptions {
+ pub fn new() -> OpenOptions {
+ OpenOptions {
+ // generic
+ read: false,
+ write: false,
+ append: false,
+ truncate: false,
+ create: false,
+ create_new: false,
+ // system-specific
+ custom_flags: 0,
+ mode: 0o666,
+ }
+ }
+
+ pub fn read(&mut self, read: bool) { self.read = read; }
+ pub fn write(&mut self, write: bool) { self.write = write; }
+ pub fn append(&mut self, append: bool) { self.append = append; }
+ pub fn truncate(&mut self, truncate: bool) { self.truncate = truncate; }
+ pub fn create(&mut self, create: bool) { self.create = create; }
+ pub fn create_new(&mut self, create_new: bool) { self.create_new = create_new; }
+
+ pub fn custom_flags(&mut self, flags: i32) { self.custom_flags = flags; }
+ pub fn mode(&mut self, mode: u32) { self.mode = mode as u16; }
+
+ fn get_access_mode(&self) -> io::Result<usize> {
+ match (self.read, self.write, self.append) {
+ (true, false, false) => Ok(syscall::O_RDONLY),
+ (false, true, false) => Ok(syscall::O_WRONLY),
+ (true, true, false) => Ok(syscall::O_RDWR),
+ (false, _, true) => Ok(syscall::O_WRONLY | syscall::O_APPEND),
+ (true, _, true) => Ok(syscall::O_RDWR | syscall::O_APPEND),
+ (false, false, false) => Err(Error::from_raw_os_error(syscall::EINVAL)),
+ }
+ }
+
+ fn get_creation_mode(&self) -> io::Result<usize> {
+ match (self.write, self.append) {
+ (true, false) => {}
+ (false, false) =>
+ if self.truncate || self.create || self.create_new {
+ return Err(Error::from_raw_os_error(syscall::EINVAL));
+ },
+ (_, true) =>
+ if self.truncate && !self.create_new {
+ return Err(Error::from_raw_os_error(syscall::EINVAL));
+ },
+ }
+
+ Ok(match (self.create, self.truncate, self.create_new) {
+ (false, false, false) => 0,
+ (true, false, false) => syscall::O_CREAT,
+ (false, true, false) => syscall::O_TRUNC,
+ (true, true, false) => syscall::O_CREAT | syscall::O_TRUNC,
+ (_, _, true) => syscall::O_CREAT | syscall::O_EXCL,
+ })
+ }
+}
+
+impl File {
+ pub fn open(path: &Path, opts: &OpenOptions) -> io::Result<File> {
+ let flags = syscall::O_CLOEXEC |
+ opts.get_access_mode()? as usize |
+ opts.get_creation_mode()? as usize |
+ (opts.custom_flags as usize & !syscall::O_ACCMODE);
+ let fd = cvt(syscall::open(path.to_str().unwrap(), flags | opts.mode as usize))?;
+ Ok(File(FileDesc::new(fd)))
+ }
+
+ pub fn file_attr(&self) -> io::Result<FileAttr> {
+ let mut stat = syscall::Stat::default();
+ cvt(syscall::fstat(self.0.raw(), &mut stat))?;
+ Ok(FileAttr { stat })
+ }
+
+ pub fn fsync(&self) -> io::Result<()> {
+ cvt(syscall::fsync(self.0.raw()))?;
+ Ok(())
+ }
+
+ pub fn datasync(&self) -> io::Result<()> {
+ self.fsync()
+ }
+
+ pub fn truncate(&self, size: u64) -> io::Result<()> {
+ cvt(syscall::ftruncate(self.0.raw(), size as usize))?;
+ Ok(())
+ }
+
+ pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
+ self.0.read(buf)
+ }
+
+ pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
+ self.0.write(buf)
+ }
+
+ pub fn flush(&self) -> io::Result<()> { Ok(()) }
+
+ pub fn seek(&self, pos: SeekFrom) -> io::Result<u64> {
+ let (whence, pos) = match pos {
+ // Casting to `i64` is fine, too large values will end up as
+ // negative which will cause an error in `lseek64`.
+ SeekFrom::Start(off) => (syscall::SEEK_SET, off as i64),
+ SeekFrom::End(off) => (syscall::SEEK_END, off),
+ SeekFrom::Current(off) => (syscall::SEEK_CUR, off),
+ };
+ let n = cvt(syscall::lseek(self.0.raw(), pos as isize, whence))?;
+ Ok(n as u64)
+ }
+
+ pub fn duplicate(&self) -> io::Result<File> {
+ self.0.duplicate().map(File)
+ }
+
+ pub fn dup(&self, buf: &[u8]) -> io::Result<File> {
+ let fd = cvt(syscall::dup(*self.fd().as_inner() as usize, buf))?;
+ Ok(File(FileDesc::new(fd)))
+ }
+
+ pub fn set_permissions(&self, perm: FilePermissions) -> io::Result<()> {
+ set_perm(&self.path()?, perm)
+ }
+
+ pub fn path(&self) -> io::Result<PathBuf> {
+ let mut buf: [u8; 4096] = [0; 4096];
+ let count = cvt(syscall::fpath(*self.fd().as_inner() as usize, &mut buf))?;
+ Ok(PathBuf::from(unsafe { String::from_utf8_unchecked(Vec::from(&buf[..count])) }))
+ }
+
+ pub fn fd(&self) -> &FileDesc { &self.0 }
+
+ pub fn into_fd(self) -> FileDesc { self.0 }
+}
+
+impl DirBuilder {
+ pub fn new() -> DirBuilder {
+ DirBuilder { mode: 0o777 }
+ }
+
+ pub fn mkdir(&self, p: &Path) -> io::Result<()> {
+ let flags = syscall::O_CREAT | syscall::O_CLOEXEC | syscall::O_DIRECTORY | syscall::O_EXCL;
+ let fd = cvt(syscall::open(p.to_str().unwrap(), flags | (self.mode as usize & 0o777)))?;
+ let _ = syscall::close(fd);
+ Ok(())
+ }
+
+ pub fn set_mode(&mut self, mode: u32) {
+ self.mode = mode as u16;
+ }
+}
+
+impl FromInner<usize> for File {
+ fn from_inner(fd: usize) -> File {
+ File(FileDesc::new(fd))
+ }
+}
+
+impl fmt::Debug for File {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ let mut b = f.debug_struct("File");
+ b.field("fd", &self.0.raw());
+ if let Ok(path) = self.path() {
+ b.field("path", &path);
+ }
+ /*
+ if let Some((read, write)) = get_mode(fd) {
+ b.field("read", &read).field("write", &write);
+ }
+ */
+ b.finish()
+ }
+}
+
+pub fn readdir(p: &Path) -> io::Result<ReadDir> {
+ let root = Arc::new(p.to_path_buf());
+
+ let flags = syscall::O_CLOEXEC | syscall::O_RDONLY | syscall::O_DIRECTORY;
+ let fd = cvt(syscall::open(p.to_str().unwrap(), flags))?;
+ let file = FileDesc::new(fd);
+ let mut data = Vec::new();
+ file.read_to_end(&mut data)?;
+
+ Ok(ReadDir { data: data, i: 0, root: root })
+}
+
+pub fn unlink(p: &Path) -> io::Result<()> {
+ cvt(syscall::unlink(p.to_str().unwrap()))?;
+ Ok(())
+}
+
+pub fn rename(old: &Path, new: &Path) -> io::Result<()> {
+ let fd = cvt(syscall::open(old.to_str().unwrap(),
+ syscall::O_CLOEXEC | syscall::O_STAT | syscall::O_NOFOLLOW))?;
+ let res = cvt(syscall::frename(fd, new.to_str().unwrap()));
+ cvt(syscall::close(fd))?;
+ res?;
+ Ok(())
+}
+
+pub fn set_perm(p: &Path, perm: FilePermissions) -> io::Result<()> {
+ cvt(syscall::chmod(p.to_str().unwrap(), perm.mode as usize))?;
+ Ok(())
+}
+
+pub fn rmdir(p: &Path) -> io::Result<()> {
+ cvt(syscall::rmdir(p.to_str().unwrap()))?;
+ Ok(())
+}
+
+pub fn readlink(p: &Path) -> io::Result<PathBuf> {
+ let fd = cvt(syscall::open(p.to_str().unwrap(),
+ syscall::O_CLOEXEC | syscall::O_SYMLINK | syscall::O_RDONLY))?;
+ let mut buf: [u8; 4096] = [0; 4096];
+ let res = cvt(syscall::read(fd, &mut buf));
+ cvt(syscall::close(fd))?;
+ let count = res?;
+ Ok(PathBuf::from(unsafe { String::from_utf8_unchecked(Vec::from(&buf[..count])) }))
+}
+
+pub fn symlink(src: &Path, dst: &Path) -> io::Result<()> {
+ let fd = cvt(syscall::open(dst.to_str().unwrap(),
+ syscall::O_CLOEXEC | syscall::O_SYMLINK |
+ syscall::O_CREAT | syscall::O_WRONLY | 0o777))?;
+ let res = cvt(syscall::write(fd, src.to_str().unwrap().as_bytes()));
+ cvt(syscall::close(fd))?;
+ res?;
+ Ok(())
+}
+
+pub fn link(_src: &Path, _dst: &Path) -> io::Result<()> {
+ Err(Error::from_raw_os_error(syscall::ENOSYS))
+}
+
+pub fn stat(p: &Path) -> io::Result<FileAttr> {
+ let fd = cvt(syscall::open(p.to_str().unwrap(), syscall::O_CLOEXEC | syscall::O_STAT))?;
+ let file = File(FileDesc::new(fd));
+ file.file_attr()
+}
+
+pub fn lstat(p: &Path) -> io::Result<FileAttr> {
+ let fd = cvt(syscall::open(p.to_str().unwrap(),
+ syscall::O_CLOEXEC | syscall::O_STAT | syscall::O_NOFOLLOW))?;
+ let file = File(FileDesc::new(fd));
+ file.file_attr()
+}
+
+pub fn canonicalize(p: &Path) -> io::Result<PathBuf> {
+ let fd = cvt(syscall::open(p.to_str().unwrap(), syscall::O_CLOEXEC | syscall::O_STAT))?;
+ let file = File(FileDesc::new(fd));
+ file.path()
+}
diff --git a/src/libstd/sys/redox/io.rs b/src/libstd/sys/redox/io.rs
new file mode 100644
index 0000000..8b02d3f
--- /dev/null
+++ b/src/libstd/sys/redox/io.rs
@@ -0,0 +1,32 @@
+pub struct IoVec<'a>(&'a [u8]);
+
+impl<'a> IoVec<'a> {
+ #[inline]
+ pub fn new(buf: &'a [u8]) -> IoVec<'a> {
+ IoVec(buf)
+ }
+
+ #[inline]
+ pub fn as_slice(&self) -> &[u8] {
+ self.0
+ }
+}
+
+pub struct IoVecMut<'a>(&'a mut [u8]);
+
+impl<'a> IoVecMut<'a> {
+ #[inline]
+ pub fn new(buf: &'a mut [u8]) -> IoVecMut<'a> {
+ IoVecMut(buf)
+ }
+
+ #[inline]
+ pub fn as_slice(&self) -> &[u8] {
+ self.0
+ }
+
+ #[inline]
+ pub fn as_mut_slice(&mut self) -> &mut [u8] {
+ self.0
+ }
+}
diff --git a/src/libstd/sys/redox/memchr.rs b/src/libstd/sys/redox/memchr.rs
new file mode 100644
index 0000000..d2bfcce
--- /dev/null
+++ b/src/libstd/sys/redox/memchr.rs
@@ -0,0 +1,4 @@
+// Original implementation taken from rust-memchr.
+// Copyright 2015 Andrew Gallant, bluss and Nicolas Koch
+
+pub use core::slice::memchr::{memchr, memrchr};
diff --git a/src/libstd/sys/redox/mod.rs b/src/libstd/sys/redox/mod.rs
new file mode 100644
index 0000000..0e8ed8e
--- /dev/null
+++ b/src/libstd/sys/redox/mod.rs
@@ -0,0 +1,98 @@
+#![allow(dead_code, missing_docs, nonstandard_style)]
+
+use crate::io::ErrorKind;
+
+pub use libc::strlen;
+pub use self::rand::hashmap_random_keys;
+
+#[path = "../unix/alloc.rs"]
+pub mod alloc;
+pub mod args;
+#[cfg(feature = "backtrace")]
+pub mod backtrace;
+pub mod cmath;
+pub mod condvar;
+pub mod env;
+pub mod ext;
+pub mod fast_thread_local;
+pub mod fd;
+pub mod fs;
+pub mod io;
+pub mod memchr;
+pub mod mutex;
+pub mod net;
+pub mod os;
+pub mod path;
+pub mod pipe;
+pub mod process;
+pub mod rand;
+pub mod rwlock;
+pub mod stack_overflow;
+pub mod stdio;
+pub mod syscall;
+pub mod thread;
+pub mod thread_local;
+pub mod time;
+
+pub use crate::sys_common::os_str_bytes as os_str;
+
+#[cfg(not(test))]
+pub fn init() {}
+
+pub fn decode_error_kind(errno: i32) -> ErrorKind {
+ match errno {
+ syscall::ECONNREFUSED => ErrorKind::ConnectionRefused,
+ syscall::ECONNRESET => ErrorKind::ConnectionReset,
+ syscall::EPERM | syscall::EACCES => ErrorKind::PermissionDenied,
+ syscall::EPIPE => ErrorKind::BrokenPipe,
+ syscall::ENOTCONN => ErrorKind::NotConnected,
+ syscall::ECONNABORTED => ErrorKind::ConnectionAborted,
+ syscall::EADDRNOTAVAIL => ErrorKind::AddrNotAvailable,
+ syscall::EADDRINUSE => ErrorKind::AddrInUse,
+ syscall::ENOENT => ErrorKind::NotFound,
+ syscall::EINTR => ErrorKind::Interrupted,
+ syscall::EINVAL => ErrorKind::InvalidInput,
+ syscall::ETIMEDOUT => ErrorKind::TimedOut,
+ syscall::EEXIST => ErrorKind::AlreadyExists,
+
+ // These two constants can have the same value on some systems,
+ // but different values on others, so we can't use a match
+ // clause
+ x if x == syscall::EAGAIN || x == syscall::EWOULDBLOCK =>
+ ErrorKind::WouldBlock,
+
+ _ => ErrorKind::Other,
+ }
+}
+
+pub fn cvt(result: Result<usize, syscall::Error>) -> crate::io::Result<usize> {
+ result.map_err(|err| crate::io::Error::from_raw_os_error(err.errno))
+}
+
+#[doc(hidden)]
+pub trait IsMinusOne {
+ fn is_minus_one(&self) -> bool;
+}
+
+macro_rules! impl_is_minus_one {
+ ($($t:ident)*) => ($(impl IsMinusOne for $t {
+ fn is_minus_one(&self) -> bool {
+ *self == -1
+ }
+ })*)
+}
+
+impl_is_minus_one! { i8 i16 i32 i64 isize }
+
+pub fn cvt_libc<T: IsMinusOne>(t: T) -> crate::io::Result<T> {
+ if t.is_minus_one() {
+ Err(crate::io::Error::last_os_error())
+ } else {
+ Ok(t)
+ }
+}
+
+/// On Redox, use an illegal instruction to abort
+pub unsafe fn abort_internal() -> ! {
+ core::intrinsics::abort();
+}
diff --git a/src/libstd/sys/redox/mutex.rs b/src/libstd/sys/redox/mutex.rs
new file mode 100644
index 0000000..59399df
--- /dev/null
+++ b/src/libstd/sys/redox/mutex.rs
@@ -0,0 +1,169 @@
+use crate::cell::UnsafeCell;
+use crate::intrinsics::{atomic_cxchg, atomic_xchg};
+use crate::ptr;
+
+use crate::sys::syscall::{futex, getpid, FUTEX_WAIT, FUTEX_WAKE};
+
+pub unsafe fn mutex_try_lock(m: *mut i32) -> bool {
+ atomic_cxchg(m, 0, 1).0 == 0
+}
+
+pub unsafe fn mutex_lock(m: *mut i32) {
+ let mut c = 0;
+ //Set to larger value for longer spin test
+ for _i in 0..100 {
+ c = atomic_cxchg(m, 0, 1).0;
+ if c == 0 {
+ break;
+ }
+ //cpu_relax()
+ }
+ if c == 1 {
+ c = atomic_xchg(m, 2);
+ }
+ while c != 0 {
+ let _ = futex(m, FUTEX_WAIT, 2, 0, ptr::null_mut());
+ c = atomic_xchg(m, 2);
+ }
+}
+
+pub unsafe fn mutex_unlock(m: *mut i32) {
+ if *m == 2 {
+ *m = 0;
+ } else if atomic_xchg(m, 0) == 1 {
+ return;
+ }
+ //Set to larger value for longer spin test
+ for _i in 0..100 {
+ if *m != 0 {
+ if atomic_cxchg(m, 1, 2).0 != 0 {
+ return;
+ }
+ }
+ //cpu_relax()
+ }
+ let _ = futex(m, FUTEX_WAKE, 1, 0, ptr::null_mut());
+}
+
+pub struct Mutex {
+ pub lock: UnsafeCell<i32>,
+}
+
+impl Mutex {
+ /// Creates a new mutex.
+ pub const fn new() -> Self {
+ Mutex {
+ lock: UnsafeCell::new(0),
+ }
+ }
+
+ #[inline]
+ pub unsafe fn init(&self) {
+ *self.lock.get() = 0;
+ }
+
+ /// Try to lock the mutex
+ #[inline]
+ pub unsafe fn try_lock(&self) -> bool {
+ mutex_try_lock(self.lock.get())
+ }
+
+ /// Lock the mutex
+ #[inline]
+ pub unsafe fn lock(&self) {
+ mutex_lock(self.lock.get());
+ }
+
+ /// Unlock the mutex
+ #[inline]
+ pub unsafe fn unlock(&self) {
+ mutex_unlock(self.lock.get());
+ }
+
+ #[inline]
+ pub unsafe fn destroy(&self) {
+ *self.lock.get() = 0;
+ }
+}
+
+unsafe impl Send for Mutex {}
+
+unsafe impl Sync for Mutex {}
+
+pub struct ReentrantMutex {
+ pub lock: UnsafeCell<i32>,
+ pub owner: UnsafeCell<usize>,
+ pub own_count: UnsafeCell<usize>,
+}
+
+impl ReentrantMutex {
+ pub const fn uninitialized() -> Self {
+ ReentrantMutex {
+ lock: UnsafeCell::new(0),
+ owner: UnsafeCell::new(0),
+ own_count: UnsafeCell::new(0),
+ }
+ }
+
+ #[inline]
+ pub unsafe fn init(&mut self) {
+ *self.lock.get() = 0;
+ *self.owner.get() = 0;
+ *self.own_count.get() = 0;
+ }
+
+ /// Try to lock the mutex
+ #[inline]
+ pub unsafe fn try_lock(&self) -> bool {
+ let pid = getpid().unwrap();
+ if *self.own_count.get() > 0 && *self.owner.get() == pid {
+ *self.own_count.get() += 1;
+ true
+ } else {
+ if mutex_try_lock(self.lock.get()) {
+ *self.owner.get() = pid;
+ *self.own_count.get() = 1;
+ true
+ } else {
+ false
+ }
+ }
+ }
+
+ /// Lock the mutex
+ #[inline]
+ pub unsafe fn lock(&self) {
+ let pid = getpid().unwrap();
+ if *self.own_count.get() > 0 && *self.owner.get() == pid {
+ *self.own_count.get() += 1;
+ } else {
+ mutex_lock(self.lock.get());
+ *self.owner.get() = pid;
+ *self.own_count.get() = 1;
+ }
+ }
+
+ /// Unlock the mutex
+ #[inline]
+ pub unsafe fn unlock(&self) {
+ let pid = getpid().unwrap();
+ if *self.own_count.get() > 0 && *self.owner.get() == pid {
+ *self.own_count.get() -= 1;
+ if *self.own_count.get() == 0 {
+ *self.owner.get() = 0;
+ mutex_unlock(self.lock.get());
+ }
+ }
+ }
+
+ #[inline]
+ pub unsafe fn destroy(&self) {
+ *self.lock.get() = 0;
+ *self.owner.get() = 0;
+ *self.own_count.get() = 0;
+ }
+}
+
+unsafe impl Send for ReentrantMutex {}
+
+unsafe impl Sync for ReentrantMutex {}
diff --git a/src/libstd/sys/redox/net/dns/answer.rs b/src/libstd/sys/redox/net/dns/answer.rs
new file mode 100644
index 0000000..e9b406b
--- /dev/null
+++ b/src/libstd/sys/redox/net/dns/answer.rs
@@ -0,0 +1,12 @@
+use crate::string::String;
+use crate::vec::Vec;
+
+#[derive(Clone, Debug)]
+pub struct DnsAnswer {
+ pub name: String,
+ pub a_type: u16,
+ pub a_class: u16,
+ pub ttl_a: u16,
+ pub ttl_b: u16,
+ pub data: Vec<u8>
+}
diff --git a/src/libstd/sys/redox/net/dns/mod.rs b/src/libstd/sys/redox/net/dns/mod.rs
new file mode 100644
index 0000000..6533e0d
--- /dev/null
+++ b/src/libstd/sys/redox/net/dns/mod.rs
@@ -0,0 +1,205 @@
+pub use self::answer::DnsAnswer;
+pub use self::query::DnsQuery;
+
+use crate::slice;
+use crate::u16;
+use crate::string::String;
+use crate::vec::Vec;
+
+mod answer;
+mod query;
+
+#[unstable(feature = "n16", issue="0")]
+#[allow(non_camel_case_types)]
+#[derive(Copy, Clone, Debug, Default)]
+#[repr(packed)]
+pub struct n16 {
+ inner: u16
+}
+
+impl n16 {
+ #[unstable(feature = "n16", issue="0")]
+ pub fn as_bytes(&self) -> &[u8] {
+ unsafe { slice::from_raw_parts((&self.inner as *const u16) as *const u8, 2) }
+ }
+
+ #[unstable(feature = "n16", issue="0")]
+ pub fn from_bytes(bytes: &[u8]) -> Self {
+ n16 {
+ inner: unsafe { slice::from_raw_parts(bytes.as_ptr() as *const u16, bytes.len()/2)[0] }
+ }
+ }
+}
+
+#[unstable(feature = "n16", issue="0")]
+impl From<u16> for n16 {
+ fn from(value: u16) -> Self {
+ n16 {
+ inner: value.to_be()
+ }
+ }
+}
+
+#[unstable(feature = "n16", issue="0")]
+impl From<n16> for u16 {
+ fn from(value: n16) -> Self {
+ u16::from_be(value.inner)
+ }
+}
+
+#[derive(Clone, Debug)]
+pub struct Dns {
+ pub transaction_id: u16,
+ pub flags: u16,
+ pub queries: Vec<DnsQuery>,
+ pub answers: Vec<DnsAnswer>
+}
+
+impl Dns {
+ pub fn compile(&self) -> Vec<u8> {
+ let mut data = Vec::new();
+
+ macro_rules! push_u8 {
+ ($value:expr) => {
+ data.push($value);
+ };
+ };
+
+ macro_rules! push_n16 {
+ ($value:expr) => {
+ data.extend_from_slice(n16::from($value).as_bytes());
+ };
+ };
+
+ push_n16!(self.transaction_id);
+ push_n16!(self.flags);
+ push_n16!(self.queries.len() as u16);
+ push_n16!(self.answers.len() as u16);
+ push_n16!(0);
+ push_n16!(0);
+
+ for query in self.queries.iter() {
+ for part in query.name.split('.') {
+ push_u8!(part.len() as u8);
+ data.extend_from_slice(part.as_bytes());
+ }
+ push_u8!(0);
+ push_n16!(query.q_type);
+ push_n16!(query.q_class);
+ }
+
+ data
+ }
+
+ pub fn parse(data: &[u8]) -> Result<Self, String> {
+ let name_ind = 0b11000000;
+ let mut i = 0;
+
+ macro_rules! pop_u8 {
+ () => {
+ {
+ i += 1;
+ if i > data.len() {
+ return Err(format!("{}: {}: pop_u8", file!(), line!()));
+ }
+ data[i - 1]
+ }
+ };
+ };
+
+ macro_rules! pop_n16 {
+ () => {
+ {
+ i += 2;
+ if i > data.len() {
+ return Err(format!("{}: {}: pop_n16", file!(), line!()));
+ }
+ u16::from(n16::from_bytes(&data[i - 2 .. i]))
+ }
+ };
+ };
+
+ macro_rules! pop_data {
+ () => {
+ {
+ let mut data = Vec::new();
+
+ let data_len = pop_n16!();
+ for _data_i in 0..data_len {
+ data.push(pop_u8!());
+ }
+
+ data
+ }
+ };
+ };
+
+ macro_rules! pop_name {
+ () => {
+ {
+ let mut name = String::new();
+ let old_i = i;
+
+ loop {
+ let name_len = pop_u8!();
+ if name_len & name_ind == name_ind {
+ i -= 1;
+ i = (pop_n16!() - ((name_ind as u16) << 8)) as usize;
+ continue;
+ }
+ if name_len == 0 {
+ break;
+ }
+ if ! name.is_empty() {
+ name.push('.');
+ }
+ for _name_i in 0..name_len {
+ name.push(pop_u8!() as char);
+ }
+ }
+
+ if i <= old_i {
+ i = old_i + 2;
+ }
+
+ name
+ }
+ };
+ };
+
+ let transaction_id = pop_n16!();
+ let flags = pop_n16!();
+ let queries_len = pop_n16!();
+ let answers_len = pop_n16!();
+ pop_n16!();
+ pop_n16!();
+
+ let mut queries = Vec::new();
+ for _query_i in 0..queries_len {
+ queries.push(DnsQuery {
+ name: pop_name!(),
+ q_type: pop_n16!(),
+ q_class: pop_n16!()
+ });
+ }
+
+ let mut answers = Vec::new();
+ for _answer_i in 0..answers_len {
+ answers.push(DnsAnswer {
+ name: pop_name!(),
+ a_type: pop_n16!(),
+ a_class: pop_n16!(),
+ ttl_a: pop_n16!(),
+ ttl_b: pop_n16!(),
+ data: pop_data!()
+ });
+ }
+
+ Ok(Dns {
+ transaction_id,
+ flags,
+ queries,
+ answers,
+ })
+ }
+}
diff --git a/src/libstd/sys/redox/net/dns/query.rs b/src/libstd/sys/redox/net/dns/query.rs
new file mode 100644
index 0000000..65fb241
--- /dev/null
+++ b/src/libstd/sys/redox/net/dns/query.rs
@@ -0,0 +1,8 @@
+use crate::string::String;
+
+#[derive(Clone, Debug)]
+pub struct DnsQuery {
+ pub name: String,
+ pub q_type: u16,
+ pub q_class: u16
+}
diff --git a/src/libstd/sys/redox/net/mod.rs b/src/libstd/sys/redox/net/mod.rs
new file mode 100644
index 0000000..dbaa140
--- /dev/null
+++ b/src/libstd/sys/redox/net/mod.rs
@@ -0,0 +1,140 @@
+use crate::fs::File;
+use crate::io::{Error, Read, self};
+use crate::iter::Iterator;
+use crate::net::{Ipv4Addr, SocketAddr, SocketAddrV4};
+use crate::str::FromStr;
+use crate::string::{String, ToString};
+use crate::sys::syscall::EINVAL;
+use crate::time::{self, Duration};
+use crate::vec::{IntoIter, Vec};
+use crate::convert::{TryFrom, TryInto};
+
+use self::dns::{Dns, DnsQuery};
+
+pub use self::tcp::{TcpStream, TcpListener};
+pub use self::udp::UdpSocket;
+
+pub mod netc;
+
+mod dns;
+mod tcp;
+mod udp;
+
+pub struct LookupHost(IntoIter<SocketAddr>, u16);
+
+impl LookupHost {
+ pub fn port(&self) -> u16 {
+ self.1
+ }
+}
+
+impl Iterator for LookupHost {
+ type Item = SocketAddr;
+ fn next(&mut self) -> Option<Self::Item> {
+ self.0.next()
+ }
+}
+
+impl TryFrom<&str> for LookupHost {
+ type Error = io::Error;
+
+ fn try_from(s: &str) -> io::Result<LookupHost> {
+ macro_rules! try_opt {
+ ($e:expr, $msg:expr) => (
+ match $e {
+ Some(r) => r,
+ None => return Err(io::Error::new(io::ErrorKind::InvalidInput,
+ $msg)),
+ }
+ )
+ }
+
+ // split the string by ':' and convert the second part to u16
+ let mut parts_iter = s.rsplitn(2, ':');
+ let port_str = try_opt!(parts_iter.next(), "invalid socket address");
+ let host = try_opt!(parts_iter.next(), "invalid socket address");
+ let port: u16 = try_opt!(port_str.parse().ok(), "invalid port value");
+
+ (host, port).try_into()
+ }
+}
+
+impl<'a> TryFrom<(&'a str, u16)> for LookupHost {
+ type Error = io::Error;
+
+ fn try_from((host, port): (&'a str, u16)) -> io::Result<LookupHost> {
+ let mut ip_string = String::new();
+ File::open("/etc/net/ip")?.read_to_string(&mut ip_string)?;
+ let ip: Vec<u8> = ip_string.trim().split('.').map(|part| part.parse::<u8>()
+ .unwrap_or(0)).collect();
+
+ let mut dns_string = String::new();
+ File::open("/etc/net/dns")?.read_to_string(&mut dns_string)?;
+ let dns: Vec<u8> = dns_string.trim().split('.').map(|part| part.parse::<u8>()
+ .unwrap_or(0)).collect();
+
+ if ip.len() == 4 && dns.len() == 4 {
+ let time = time::SystemTime::now().duration_since(time::UNIX_EPOCH).unwrap();
+ let tid = (time.subsec_nanos() >> 16) as u16;
+
+ let packet = Dns {
+ transaction_id: tid,
+ flags: 0x0100,
+ queries: vec![DnsQuery {
+ name: host.to_string(),
+ q_type: 0x0001,
+ q_class: 0x0001,
+ }],
+ answers: vec![]
+ };
+
+ let packet_data = packet.compile();
+
+ let my_ip = Ipv4Addr::new(ip[0], ip[1], ip[2], ip[3]);
+ let dns_ip = Ipv4Addr::new(dns[0], dns[1], dns[2], dns[3]);
+ let socket = UdpSocket::bind(Ok(&SocketAddr::V4(SocketAddrV4::new(my_ip, 0))))?;
+ socket.set_read_timeout(Some(Duration::new(5, 0)))?;
+ socket.set_write_timeout(Some(Duration::new(5, 0)))?;
+ socket.connect(Ok(&SocketAddr::V4(SocketAddrV4::new(dns_ip, 53))))?;
+ socket.send(&packet_data)?;
+
+ let mut buf = [0; 65536];
+ let count = socket.recv(&mut buf)?;
+
+ match Dns::parse(&buf[.. count]) {
+ Ok(response) => {
+ let mut addrs = vec![];
+ for answer in response.answers.iter() {
+ if answer.a_type == 0x0001 && answer.a_class == 0x0001
+ && answer.data.len() == 4
+ {
+ let answer_ip = Ipv4Addr::new(answer.data[0],
+ answer.data[1],
+ answer.data[2],
+ answer.data[3]);
+ addrs.push(SocketAddr::V4(SocketAddrV4::new(answer_ip, 0)));
+ }
+ }
+ Ok(LookupHost(addrs.into_iter(), port))
+ },
+ Err(_err) => Err(Error::from_raw_os_error(EINVAL))
+ }
+ } else {
+ Err(Error::from_raw_os_error(EINVAL))
+ }
+ }
+}
+
+fn path_to_peer_addr(path_str: &str) -> SocketAddr {
+ let mut parts = path_str.split('/').next().unwrap_or("").split(':').skip(1);
+ let host = Ipv4Addr::from_str(parts.next().unwrap_or("")).unwrap_or(Ipv4Addr::new(0, 0, 0, 0));
+ let port = parts.next().unwrap_or("").parse::<u16>().unwrap_or(0);
+ SocketAddr::V4(SocketAddrV4::new(host, port))
+}
+
+fn path_to_local_addr(path_str: &str) -> SocketAddr {
+ let mut parts = path_str.split('/').nth(1).unwrap_or("").split(':');
+ let host = Ipv4Addr::from_str(parts.next().unwrap_or("")).unwrap_or(Ipv4Addr::new(0, 0, 0, 0));
+ let port = parts.next().unwrap_or("").parse::<u16>().unwrap_or(0);
+ SocketAddr::V4(SocketAddrV4::new(host, port))
+}
diff --git a/src/libstd/sys/redox/net/netc.rs b/src/libstd/sys/redox/net/netc.rs
new file mode 100644
index 0000000..420a15a
--- /dev/null
+++ b/src/libstd/sys/redox/net/netc.rs
@@ -0,0 +1,47 @@
+pub type in_addr_t = u32;
+pub type in_port_t = u16;
+
+pub type socklen_t = u32;
+pub type sa_family_t = u16;
+
+pub const AF_INET: sa_family_t = 2;
+pub const AF_INET6: sa_family_t = 23;
+
+#[derive(Copy, Clone)]
+#[repr(C)]
+pub struct in_addr {
+ pub s_addr: in_addr_t,
+}
+
+#[derive(Copy, Clone)]
+#[repr(align(4))]
+#[repr(C)]
+pub struct in6_addr {
+ pub s6_addr: [u8; 16],
+}
+
+#[derive(Copy, Clone)]
+#[repr(C)]
+pub struct sockaddr {
+ pub sa_family: sa_family_t,
+ pub sa_data: [u8; 14],
+}
+
+#[derive(Copy, Clone)]
+#[repr(C)]
+pub struct sockaddr_in {
+ pub sin_family: sa_family_t,
+ pub sin_port: in_port_t,
+ pub sin_addr: in_addr,
+ pub sin_zero: [u8; 8],
+}
+
+#[derive(Copy, Clone)]
+#[repr(C)]
+pub struct sockaddr_in6 {
+ pub sin6_family: sa_family_t,
+ pub sin6_port: in_port_t,
+ pub sin6_flowinfo: u32,
+ pub sin6_addr: in6_addr,
+ pub sin6_scope_id: u32,
+}
diff --git a/src/libstd/sys/redox/net/tcp.rs b/src/libstd/sys/redox/net/tcp.rs
new file mode 100644
index 0000000..3f2f616
--- /dev/null
+++ b/src/libstd/sys/redox/net/tcp.rs
@@ -0,0 +1,251 @@
+use crate::cmp;
+use crate::io::{self, Error, ErrorKind, Result, IoVec, IoVecMut};
+use crate::mem;
+use crate::net::{SocketAddr, Shutdown};
+use crate::path::Path;
+use crate::sys::fs::{File, OpenOptions};
+use crate::sys::syscall::TimeSpec;
+use crate::sys_common::{AsInner, FromInner, IntoInner};
+use crate::time::Duration;
+
+use super::{path_to_peer_addr, path_to_local_addr};
+
+#[derive(Debug)]
+pub struct TcpStream(File);
+
+impl TcpStream {
+ pub fn connect(addr: Result<&SocketAddr>) -> Result<TcpStream> {
+ let path = format!("tcp:{}", addr?);
+ let mut options = OpenOptions::new();
+ options.read(true);
+ options.write(true);
+ Ok(TcpStream(File::open(Path::new(path.as_str()), &options)?))
+ }
+
+ pub fn connect_timeout(_addr: &SocketAddr, _timeout: Duration) -> Result<TcpStream> {
+ Err(Error::new(ErrorKind::Other, "TcpStream::connect_timeout not implemented"))
+ }
+
+ pub fn duplicate(&self) -> Result<TcpStream> {
+ Ok(TcpStream(self.0.dup(&[])?))
+ }
+
+ pub fn read(&self, buf: &mut [u8]) -> Result<usize> {
+ self.0.read(buf)
+ }
+
+ pub fn read_vectored(&self, bufs: &mut [IoVecMut<'_>]) -> io::Result<usize> {
+ io::default_read_vectored(|b| self.read(b), bufs)
+ }
+
+ pub fn write(&self, buf: &[u8]) -> Result<usize> {
+ self.0.write(buf)
+ }
+
+ pub fn write_vectored(&self, bufs: &[IoVec<'_>]) -> io::Result<usize> {
+ io::default_write_vectored(|b| self.write(b), bufs)
+ }
+
+ pub fn take_error(&self) -> Result<Option<Error>> {
+ Ok(None)
+ }
+
+ pub fn peer_addr(&self) -> Result<SocketAddr> {
+ let path = self.0.path()?;
+ Ok(path_to_peer_addr(path.to_str().unwrap_or("")))
+ }
+
+ pub fn socket_addr(&self) -> Result<SocketAddr> {
+ let path = self.0.path()?;
+ Ok(path_to_local_addr(path.to_str().unwrap_or("")))
+ }
+
+ pub fn peek(&self, _buf: &mut [u8]) -> Result<usize> {
+ Err(Error::new(ErrorKind::Other, "TcpStream::peek not implemented"))
+ }
+
+ pub fn shutdown(&self, _how: Shutdown) -> Result<()> {
+ Err(Error::new(ErrorKind::Other, "TcpStream::shutdown not implemented"))
+ }
+
+ pub fn nodelay(&self) -> Result<bool> {
+ Err(Error::new(ErrorKind::Other, "TcpStream::nodelay not implemented"))
+ }
+
+ pub fn nonblocking(&self) -> Result<bool> {
+ self.0.fd().nonblocking()
+ }
+
+ pub fn only_v6(&self) -> Result<bool> {
+ Err(Error::new(ErrorKind::Other, "TcpStream::only_v6 not implemented"))
+ }
+
+ pub fn ttl(&self) -> Result<u32> {
+ let mut ttl = [0];
+ let file = self.0.dup(b"ttl")?;
+ file.read(&mut ttl)?;
+ Ok(ttl[0] as u32)
+ }
+
+ pub fn read_timeout(&self) -> Result<Option<Duration>> {
+ let mut time = TimeSpec::default();
+ let file = self.0.dup(b"read_timeout")?;
+ if file.read(&mut time)? >= mem::size_of::<TimeSpec>() {
+ Ok(Some(Duration::new(time.tv_sec as u64, time.tv_nsec as u32)))
+ } else {
+ Ok(None)
+ }
+ }
+
+ pub fn write_timeout(&self) -> Result<Option<Duration>> {
+ let mut time = TimeSpec::default();
+ let file = self.0.dup(b"write_timeout")?;
+ if file.read(&mut time)? >= mem::size_of::<TimeSpec>() {
+ Ok(Some(Duration::new(time.tv_sec as u64, time.tv_nsec as u32)))
+ } else {
+ Ok(None)
+ }
+ }
+
+ pub fn set_nodelay(&self, _nodelay: bool) -> Result<()> {
+ Err(Error::new(ErrorKind::Other, "TcpStream::set_nodelay not implemented"))
+ }
+
+ pub fn set_nonblocking(&self, nonblocking: bool) -> Result<()> {
+ self.0.fd().set_nonblocking(nonblocking)
+ }
+
+ pub fn set_only_v6(&self, _only_v6: bool) -> Result<()> {
+ Err(Error::new(ErrorKind::Other, "TcpStream::set_only_v6 not implemented"))
+ }
+
+ pub fn set_ttl(&self, ttl: u32) -> Result<()> {
+ let file = self.0.dup(b"ttl")?;
+ file.write(&[cmp::min(ttl, 255) as u8])?;
+ Ok(())
+ }
+
+ pub fn set_read_timeout(&self, duration_option: Option<Duration>) -> Result<()> {
+ let file = self.0.dup(b"read_timeout")?;
+ if let Some(duration) = duration_option {
+ if duration.as_secs() == 0 && duration.subsec_nanos() == 0 {
+ return Err(io::Error::new(io::ErrorKind::InvalidInput,
+ "cannot set a 0 duration timeout"));
+ }
+ file.write(&TimeSpec {
+ tv_sec: duration.as_secs() as i64,
+ tv_nsec: duration.subsec_nanos() as i32
+ })?;
+ } else {
+ file.write(&[])?;
+ }
+ Ok(())
+ }
+
+ pub fn set_write_timeout(&self, duration_option: Option<Duration>) -> Result<()> {
+ let file = self.0.dup(b"write_timeout")?;
+ if let Some(duration) = duration_option {
+ if duration.as_secs() == 0 && duration.subsec_nanos() == 0 {
+ return Err(io::Error::new(io::ErrorKind::InvalidInput,
+ "cannot set a 0 duration timeout"));
+ }
+ file.write(&TimeSpec {
+ tv_sec: duration.as_secs() as i64,
+ tv_nsec: duration.subsec_nanos() as i32
+ })?;
+ } else {
+ file.write(&[])?;
+ }
+ Ok(())
+ }
+}
+
+impl AsInner<File> for TcpStream {
+ fn as_inner(&self) -> &File { &self.0 }
+}
+
+impl FromInner<File> for TcpStream {
+ fn from_inner(file: File) -> TcpStream {
+ TcpStream(file)
+ }
+}
+
+impl IntoInner<File> for TcpStream {
+ fn into_inner(self) -> File { self.0 }
+}
+
+#[derive(Debug)]
+pub struct TcpListener(File);
+
+impl TcpListener {
+ pub fn bind(addr: Result<&SocketAddr>) -> Result<TcpListener> {
+ let path = format!("tcp:/{}", addr?);
+ let mut options = OpenOptions::new();
+ options.read(true);
+ options.write(true);
+ Ok(TcpListener(File::open(Path::new(path.as_str()), &options)?))
+ }
+
+ pub fn accept(&self) -> Result<(TcpStream, SocketAddr)> {
+ let file = self.0.dup(b"listen")?;
+ let path = file.path()?;
+ let peer_addr = path_to_peer_addr(path.to_str().unwrap_or(""));
+ Ok((TcpStream(file), peer_addr))
+ }
+
+ pub fn duplicate(&self) -> Result<TcpListener> {
+ Ok(TcpListener(self.0.dup(&[])?))
+ }
+
+ pub fn take_error(&self) -> Result<Option<Error>> {
+ Ok(None)
+ }
+
+ pub fn socket_addr(&self) -> Result<SocketAddr> {
+ let path = self.0.path()?;
+ Ok(path_to_local_addr(path.to_str().unwrap_or("")))
+ }
+
+ pub fn nonblocking(&self) -> Result<bool> {
+ Err(Error::new(ErrorKind::Other, "TcpListener::nonblocking not implemented"))
+ }
+
+ pub fn only_v6(&self) -> Result<bool> {
+ Err(Error::new(ErrorKind::Other, "TcpListener::only_v6 not implemented"))
+ }
+
+ pub fn ttl(&self) -> Result<u32> {
+ let mut ttl = [0];
+ let file = self.0.dup(b"ttl")?;
+ file.read(&mut ttl)?;
+ Ok(ttl[0] as u32)
+ }
+
+ pub fn set_nonblocking(&self, _nonblocking: bool) -> Result<()> {
+ Err(Error::new(ErrorKind::Other, "TcpListener::set_nonblocking not implemented"))
+ }
+
+ pub fn set_only_v6(&self, _only_v6: bool) -> Result<()> {
+ Err(Error::new(ErrorKind::Other, "TcpListener::set_only_v6 not implemented"))
+ }
+
+ pub fn set_ttl(&self, ttl: u32) -> Result<()> {
+ let file = self.0.dup(b"ttl")?;
+ file.write(&[cmp::min(ttl, 255) as u8])?;
+ Ok(())
+ }
+}
+
+impl AsInner<File> for TcpListener {
+ fn as_inner(&self) -> &File { &self.0 }
+}
+
+impl FromInner<File> for TcpListener {
+ fn from_inner(file: File) -> TcpListener {
+ TcpListener(file)
+ }
+}
+
+impl IntoInner<File> for TcpListener {
+ fn into_inner(self) -> File { self.0 }
+}
diff --git a/src/libstd/sys/redox/net/udp.rs b/src/libstd/sys/redox/net/udp.rs
new file mode 100644
index 0000000..274123d
--- /dev/null
+++ b/src/libstd/sys/redox/net/udp.rs
@@ -0,0 +1,237 @@
+use crate::cell::UnsafeCell;
+use crate::cmp;
+use crate::io::{self, Error, ErrorKind, Result};
+use crate::mem;
+use crate::net::{SocketAddr, Ipv4Addr, Ipv6Addr};
+use crate::path::Path;
+use crate::sys::fs::{File, OpenOptions};
+use crate::sys::syscall::TimeSpec;
+use crate::sys_common::{AsInner, FromInner, IntoInner};
+use crate::time::Duration;
+
+use super::{path_to_peer_addr, path_to_local_addr};
+
+#[derive(Debug)]
+pub struct UdpSocket(File, UnsafeCell<Option<SocketAddr>>);
+
+impl UdpSocket {
+ pub fn bind(addr: Result<&SocketAddr>) -> Result<UdpSocket> {
+ let path = format!("udp:/{}", addr?);
+ let mut options = OpenOptions::new();
+ options.read(true);
+ options.write(true);
+ Ok(UdpSocket(File::open(Path::new(path.as_str()), &options)?, UnsafeCell::new(None)))
+ }
+
+ fn get_conn(&self) -> &mut Option<SocketAddr> {
+ unsafe { &mut *(self.1.get()) }
+ }
+
+ pub fn connect(&self, addr: Result<&SocketAddr>) -> Result<()> {
+ unsafe { *self.1.get() = Some(*addr?) };
+ Ok(())
+ }
+
+ pub fn duplicate(&self) -> Result<UdpSocket> {
+ let new_bind = self.0.dup(&[])?;
+ let new_conn = *self.get_conn();
+ Ok(UdpSocket(new_bind, UnsafeCell::new(new_conn)))
+ }
+
+ pub fn recv_from(&self, buf: &mut [u8]) -> Result<(usize, SocketAddr)> {
+ let from = self.0.dup(b"listen")?;
+ let path = from.path()?;
+ let peer_addr = path_to_peer_addr(path.to_str().unwrap_or(""));
+ let count = from.read(buf)?;
+ Ok((count, peer_addr))
+ }
+
+ pub fn recv(&self, buf: &mut [u8]) -> Result<usize> {
+ if let Some(addr) = *self.get_conn() {
+ let from = self.0.dup(addr.to_string().as_bytes())?;
+ from.read(buf)
+ } else {
+ Err(Error::new(ErrorKind::Other, "UdpSocket::recv not connected"))
+ }
+ }
+
+ pub fn send_to(&self, buf: &[u8], addr: &SocketAddr) -> Result<usize> {
+ let to = self.0.dup(format!("{}", addr).as_bytes())?;
+ to.write(buf)
+ }
+
+ pub fn send(&self, buf: &[u8]) -> Result<usize> {
+ if let Some(addr) = *self.get_conn() {
+ self.send_to(buf, &addr)
+ } else {
+ Err(Error::new(ErrorKind::Other, "UdpSocket::send not connected"))
+ }
+ }
+
+ pub fn take_error(&self) -> Result<Option<Error>> {
+ Ok(None)
+ }
+
+ pub fn peer_addr(&self) -> Result<SocketAddr> {
+ let path = self.0.path()?;
+ Ok(path_to_peer_addr(path.to_str().unwrap_or("")))
+ }
+
+ pub fn socket_addr(&self) -> Result<SocketAddr> {
+ let path = self.0.path()?;
+ Ok(path_to_local_addr(path.to_str().unwrap_or("")))
+ }
+
+ pub fn peek(&self, _buf: &mut [u8]) -> Result<usize> {
+ Err(Error::new(ErrorKind::Other, "UdpSocket::peek not implemented"))
+ }
+
+ pub fn peek_from(&self, _buf: &mut [u8]) -> Result<(usize, SocketAddr)> {
+ Err(Error::new(ErrorKind::Other, "UdpSocket::peek_from not implemented"))
+ }
+
+ pub fn broadcast(&self) -> Result<bool> {
+ Err(Error::new(ErrorKind::Other, "UdpSocket::broadcast not implemented"))
+ }
+
+ pub fn multicast_loop_v4(&self) -> Result<bool> {
+ Err(Error::new(ErrorKind::Other, "UdpSocket::multicast_loop_v4 not implemented"))
+ }
+
+ pub fn multicast_loop_v6(&self) -> Result<bool> {
+ Err(Error::new(ErrorKind::Other, "UdpSocket::multicast_loop_v6 not implemented"))
+ }
+
+ pub fn multicast_ttl_v4(&self) -> Result<u32> {
+ Err(Error::new(ErrorKind::Other, "UdpSocket::multicast_ttl_v4 not implemented"))
+ }
+
+ pub fn nonblocking(&self) -> Result<bool> {
+ self.0.fd().nonblocking()
+ }
+
+ pub fn only_v6(&self) -> Result<bool> {
+ Err(Error::new(ErrorKind::Other, "UdpSocket::only_v6 not implemented"))
+ }
+
+ pub fn ttl(&self) -> Result<u32> {
+ let mut ttl = [0];
+ let file = self.0.dup(b"ttl")?;
+ file.read(&mut ttl)?;
+ Ok(ttl[0] as u32)
+ }
+
+ pub fn read_timeout(&self) -> Result<Option<Duration>> {
+ let mut time = TimeSpec::default();
+ let file = self.0.dup(b"read_timeout")?;
+ if file.read(&mut time)? >= mem::size_of::<TimeSpec>() {
+ Ok(Some(Duration::new(time.tv_sec as u64, time.tv_nsec as u32)))
+ } else {
+ Ok(None)
+ }
+ }
+
+ pub fn write_timeout(&self) -> Result<Option<Duration>> {
+ let mut time = TimeSpec::default();
+ let file = self.0.dup(b"write_timeout")?;
+ if file.read(&mut time)? >= mem::size_of::<TimeSpec>() {
+ Ok(Some(Duration::new(time.tv_sec as u64, time.tv_nsec as u32)))
+ } else {
+ Ok(None)
+ }
+ }
+
+ pub fn set_broadcast(&self, _broadcast: bool) -> Result<()> {
+ Err(Error::new(ErrorKind::Other, "UdpSocket::set_broadcast not implemented"))
+ }
+
+ pub fn set_multicast_loop_v4(&self, _multicast_loop_v4: bool) -> Result<()> {
+ Err(Error::new(ErrorKind::Other, "UdpSocket::set_multicast_loop_v4 not implemented"))
+ }
+
+ pub fn set_multicast_loop_v6(&self, _multicast_loop_v6: bool) -> Result<()> {
+ Err(Error::new(ErrorKind::Other, "UdpSocket::set_multicast_loop_v6 not implemented"))
+ }
+
+ pub fn set_multicast_ttl_v4(&self, _multicast_ttl_v4: u32) -> Result<()> {
+ Err(Error::new(ErrorKind::Other, "UdpSocket::set_multicast_ttl_v4 not implemented"))
+ }
+
+ pub fn set_nonblocking(&self, nonblocking: bool) -> Result<()> {
+ self.0.fd().set_nonblocking(nonblocking)
+ }
+
+ pub fn set_only_v6(&self, _only_v6: bool) -> Result<()> {
+ Err(Error::new(ErrorKind::Other, "UdpSocket::set_only_v6 not implemented"))
+ }
+
+ pub fn set_ttl(&self, ttl: u32) -> Result<()> {
+ let file = self.0.dup(b"ttl")?;
+ file.write(&[cmp::min(ttl, 255) as u8])?;
+ Ok(())
+ }
+
+ pub fn set_read_timeout(&self, duration_option: Option<Duration>) -> Result<()> {
+ let file = self.0.dup(b"read_timeout")?;
+ if let Some(duration) = duration_option {
+ if duration.as_secs() == 0 && duration.subsec_nanos() == 0 {
+ return Err(io::Error::new(io::ErrorKind::InvalidInput,
+ "cannot set a 0 duration timeout"));
+ }
+ file.write(&TimeSpec {
+ tv_sec: duration.as_secs() as i64,
+ tv_nsec: duration.subsec_nanos() as i32
+ })?;
+ } else {
+ file.write(&[])?;
+ }
+ Ok(())
+ }
+
+ pub fn set_write_timeout(&self, duration_option: Option<Duration>) -> Result<()> {
+ let file = self.0.dup(b"write_timeout")?;
+ if let Some(duration) = duration_option {
+ if duration.as_secs() == 0 && duration.subsec_nanos() == 0 {
+ return Err(io::Error::new(io::ErrorKind::InvalidInput,
+ "cannot set a 0 duration timeout"));
+ }
+ file.write(&TimeSpec {
+ tv_sec: duration.as_secs() as i64,
+ tv_nsec: duration.subsec_nanos() as i32
+ })?;
+ } else {
+ file.write(&[])?;
+ }
+ Ok(())
+ }
+
+ pub fn join_multicast_v4(&self, _multiaddr: &Ipv4Addr, _interface: &Ipv4Addr) -> Result<()> {
+ Err(Error::new(ErrorKind::Other, "UdpSocket::join_multicast_v4 not implemented"))
+ }
+
+ pub fn join_multicast_v6(&self, _multiaddr: &Ipv6Addr, _interface: u32) -> Result<()> {
+ Err(Error::new(ErrorKind::Other, "UdpSocket::join_multicast_v6 not implemented"))
+ }
+
+ pub fn leave_multicast_v4(&self, _multiaddr: &Ipv4Addr, _interface: &Ipv4Addr) -> Result<()> {
+ Err(Error::new(ErrorKind::Other, "UdpSocket::leave_multicast_v4 not implemented"))
+ }
+
+ pub fn leave_multicast_v6(&self, _multiaddr: &Ipv6Addr, _interface: u32) -> Result<()> {
+ Err(Error::new(ErrorKind::Other, "UdpSocket::leave_multicast_v6 not implemented"))
+ }
+}
+
+impl AsInner<File> for UdpSocket {
+ fn as_inner(&self) -> &File { &self.0 }
+}
+
+impl FromInner<File> for UdpSocket {
+ fn from_inner(file: File) -> UdpSocket {
+ UdpSocket(file, UnsafeCell::new(None))
+ }
+}
+
+impl IntoInner<File> for UdpSocket {
+ fn into_inner(self) -> File { self.0 }
+}
diff --git a/src/libstd/sys/redox/os.rs b/src/libstd/sys/redox/os.rs
new file mode 100644
index 0000000..3ae201f
--- /dev/null
+++ b/src/libstd/sys/redox/os.rs
@@ -0,0 +1,241 @@
+//! Implementation of `std::os` functionality for unix systems
+
+#![allow(unused_imports)] // lots of cfg code here
+
+use libc::c_char;
+
+use crate::os::unix::prelude::*;
+
+use crate::error::Error as StdError;
+use crate::ffi::{CStr, CString, OsStr, OsString};
+use crate::fmt;
+use crate::io::{self, Read, Write};
+use crate::iter;
+use crate::marker::PhantomData;
+use crate::mem;
+use crate::memchr;
+use crate::path::{self, PathBuf};
+use crate::ptr;
+use crate::slice;
+use crate::str;
+use crate::sys_common::mutex::Mutex;
+use crate::sys::{cvt, cvt_libc, fd, syscall};
+use crate::vec;
+
+extern {
+ #[link_name = "__errno_location"]
+ fn errno_location() -> *mut i32;
+}
+
+/// Returns the platform-specific value of errno
+pub fn errno() -> i32 {
+ unsafe {
+ (*errno_location())
+ }
+}
+
+/// Gets a detailed string description for the given error number.
+pub fn error_string(errno: i32) -> String {
+ if let Some(string) = syscall::STR_ERROR.get(errno as usize) {
+ string.to_string()
+ } else {
+ "unknown error".to_string()
+ }
+}
+
+pub fn getcwd() -> io::Result<PathBuf> {
+ let mut buf = [0; 4096];
+ let count = cvt(syscall::getcwd(&mut buf))?;
+ Ok(PathBuf::from(OsString::from_vec(buf[.. count].to_vec())))
+}
+
+pub fn chdir(p: &path::Path) -> io::Result<()> {
+ cvt(syscall::chdir(p.to_str().unwrap())).and(Ok(()))
+}
+
+pub struct SplitPaths<'a> {
+ iter: iter::Map<slice::Split<'a, u8, fn(&u8) -> bool>,
+ fn(&'a [u8]) -> PathBuf>,
+}
+
+pub fn split_paths(unparsed: &OsStr) -> SplitPaths<'_> {
+ fn bytes_to_path(b: &[u8]) -> PathBuf {
+ PathBuf::from(<OsStr as OsStrExt>::from_bytes(b))
+ }
+ fn is_semicolon(b: &u8) -> bool { *b == b';' }
+ let unparsed = unparsed.as_bytes();
+ SplitPaths {
+ iter: unparsed.split(is_semicolon as fn(&u8) -> bool)
+ .map(bytes_to_path as fn(&[u8]) -> PathBuf)
+ }
+}
+
+impl<'a> Iterator for SplitPaths<'a> {
+ type Item = PathBuf;
+ fn next(&mut self) -> Option<PathBuf> { self.iter.next() }
+ fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
+}
+
+#[derive(Debug)]
+pub struct JoinPathsError;
+
+pub fn join_paths<I, T>(paths: I) -> Result<OsString, JoinPathsError>
+ where I: Iterator<Item=T>, T: AsRef<OsStr>
+{
+ let mut joined = Vec::new();
+ let sep = b';';
+
+ for (i, path) in paths.enumerate() {
+ let path = path.as_ref().as_bytes();
+ if i > 0 { joined.push(sep) }
+ if path.contains(&sep) {
+ return Err(JoinPathsError)
+ }
+ joined.extend_from_slice(path);
+ }
+ Ok(OsStringExt::from_vec(joined))
+}
+
+impl fmt::Display for JoinPathsError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ "path segment contains separator `:`".fmt(f)
+ }
+}
+
+impl StdError for JoinPathsError {
+ fn description(&self) -> &str { "failed to join paths" }
+}
+
+pub fn current_exe() -> io::Result<PathBuf> {
+ use crate::fs::File;
+
+ let mut file = File::open("sys:exe")?;
+
+ let mut path = String::new();
+ file.read_to_string(&mut path)?;
+
+ if path.ends_with('\n') {
+ path.pop();
+ }
+
+ Ok(PathBuf::from(path))
+}
+
+pub static ENV_LOCK: Mutex = Mutex::new();
+
+pub struct Env {
+ iter: vec::IntoIter<(OsString, OsString)>,
+ _dont_send_or_sync_me: PhantomData<*mut ()>,
+}
+
+impl Iterator for Env {
+ type Item = (OsString, OsString);
+ fn next(&mut self) -> Option<(OsString, OsString)> { self.iter.next() }
+ fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
+}
+
+pub unsafe fn environ() -> *mut *const *const c_char {
+ extern { static mut environ: *const *const c_char; }
+ &mut environ
+}
+
+/// Returns a vector of (variable, value) byte-vector pairs for all the
+/// environment variables of the current process.
+pub fn env() -> Env {
+ unsafe {
+ let _guard = ENV_LOCK.lock();
+ let mut environ = *environ();
+ if environ == ptr::null() {
+ panic!("os::env() failure getting env string from OS: {}",
+ io::Error::last_os_error());
+ }
+ let mut result = Vec::new();
+ while *environ != ptr::null() {
+ if let Some(key_value) = parse(CStr::from_ptr(*environ).to_bytes()) {
+ result.push(key_value);
+ }
+ environ = environ.offset(1);
+ }
+ return Env {
+ iter: result.into_iter(),
+ _dont_send_or_sync_me: PhantomData,
+ }
+ }
+
+ fn parse(input: &[u8]) -> Option<(OsString, OsString)> {
+ // Strategy (copied from glibc): Variable name and value are separated
+ // by an ASCII equals sign '='. Since a variable name must not be
+ // empty, allow variable names starting with an equals sign. Skip all
+ // malformed lines.
+ if input.is_empty() {
+ return None;
+ }
+ let pos = memchr::memchr(b'=', &input[1..]).map(|p| p + 1);
+ pos.map(|p| (
+ OsStringExt::from_vec(input[..p].to_vec()),
+ OsStringExt::from_vec(input[p+1..].to_vec()),
+ ))
+ }
+}
+
+pub fn getenv(k: &OsStr) -> io::Result<Option<OsString>> {
+ // environment variables with a nul byte can't be set, so their value is
+ // always None as well
+ let k = CString::new(k.as_bytes())?;
+ unsafe {
+ let _guard = ENV_LOCK.lock();
+ let s = libc::getenv(k.as_ptr()) as *const libc::c_char;
+ let ret = if s.is_null() {
+ None
+ } else {
+ Some(OsStringExt::from_vec(CStr::from_ptr(s).to_bytes().to_vec()))
+ };
+ Ok(ret)
+ }
+}
+
+pub fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> {
+ let k = CString::new(k.as_bytes())?;
+ let v = CString::new(v.as_bytes())?;
+
+ unsafe {
+ let _guard = ENV_LOCK.lock();
+ cvt_libc(libc::setenv(k.as_ptr(), v.as_ptr(), 1)).map(|_| ())
+ }
+}
+
+pub fn unsetenv(n: &OsStr) -> io::Result<()> {
+ let nbuf = CString::new(n.as_bytes())?;
+
+ unsafe {
+ let _guard = ENV_LOCK.lock();
+ cvt_libc(libc::unsetenv(nbuf.as_ptr())).map(|_| ())
+ }
+}
+
+pub fn page_size() -> usize {
+ 4096
+}
+
+pub fn temp_dir() -> PathBuf {
+ crate::env::var_os("TMPDIR").map(PathBuf::from).unwrap_or_else(|| {
+ PathBuf::from("/tmp")
+ })
+}
+
+pub fn home_dir() -> Option<PathBuf> {
+ return crate::env::var_os("HOME").map(PathBuf::from);
+}
+
+pub fn exit(code: i32) -> ! {
+ let _ = syscall::exit(code as usize);
+ unreachable!();
+}
+
+pub fn getpid() -> u32 {
+ syscall::getpid().unwrap() as u32
+}
+
+pub fn getppid() -> u32 {
+ syscall::getppid().unwrap() as u32
+}
diff --git a/src/libstd/sys/redox/path.rs b/src/libstd/sys/redox/path.rs
new file mode 100644
index 0000000..b62d6c9
--- /dev/null
+++ b/src/libstd/sys/redox/path.rs
@@ -0,0 +1,29 @@
+use crate::ffi::OsStr;
+use crate::path::Prefix;
+
+#[inline]
+pub fn is_sep_byte(b: u8) -> bool {
+ b == b'/'
+}
+
+#[inline]
+pub fn is_verbatim_sep(b: u8) -> bool {
+ b == b'/'
+}
+
+pub fn parse_prefix(path: &OsStr) -> Option<Prefix<'_>> {
+ if let Some(path_str) = path.to_str() {
+ if let Some(_i) = path_str.find(':') {
+ // FIXME: Redox specific prefix
+ // Some(Prefix::Verbatim(OsStr::new(&path_str[..i])))
+ None
+ } else {
+ None
+ }
+ } else {
+ None
+ }
+}
+
+pub const MAIN_SEP_STR: &str = "/";
+pub const MAIN_SEP: char = '/';
diff --git a/src/libstd/sys/redox/pipe.rs b/src/libstd/sys/redox/pipe.rs
new file mode 100644
index 0000000..911ba9c
--- /dev/null
+++ b/src/libstd/sys/redox/pipe.rs
@@ -0,0 +1,93 @@
+use crate::io;
+use crate::sys::{cvt, syscall};
+use crate::sys::fd::FileDesc;
+
+////////////////////////////////////////////////////////////////////////////////
+// Anonymous pipes
+////////////////////////////////////////////////////////////////////////////////
+
+pub struct AnonPipe(FileDesc);
+
+pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> {
+ let mut fds = [0; 2];
+ cvt(syscall::pipe2(&mut fds, syscall::O_CLOEXEC))?;
+ Ok((AnonPipe(FileDesc::new(fds[0])), AnonPipe(FileDesc::new(fds[1]))))
+}
+
+impl AnonPipe {
+ pub fn from_fd(fd: FileDesc) -> io::Result<AnonPipe> {
+ fd.set_cloexec()?;
+ Ok(AnonPipe(fd))
+ }
+
+ pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
+ self.0.read(buf)
+ }
+
+ pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
+ self.0.write(buf)
+ }
+
+ pub fn fd(&self) -> &FileDesc { &self.0 }
+ pub fn into_fd(self) -> FileDesc { self.0 }
+}
+
+pub fn read2(p1: AnonPipe,
+ v1: &mut Vec<u8>,
+ p2: AnonPipe,
+ v2: &mut Vec<u8>) -> io::Result<()> {
+ //FIXME: Use event based I/O multiplexing
+ //unimplemented!()
+
+ p1.0.read_to_end(v1)?;
+ p2.0.read_to_end(v2)?;
+
+ Ok(())
+
+ /*
+ // Set both pipes into nonblocking mode as we're gonna be reading from both
+ // in the `select` loop below, and we wouldn't want one to block the other!
+ let p1 = p1.into_fd();
+ let p2 = p2.into_fd();
+ p1.set_nonblocking(true)?;
+ p2.set_nonblocking(true)?;
+
+ loop {
+ // wait for either pipe to become readable using `select`
+ cvt_r(|| unsafe {
+ let mut read: libc::fd_set = mem::zeroed();
+ libc::FD_SET(p1.raw(), &mut read);
+ libc::FD_SET(p2.raw(), &mut read);
+ libc::select(max + 1, &mut read, ptr::null_mut(), ptr::null_mut(),
+ ptr::null_mut())
+ })?;
+
+ // Read as much as we can from each pipe, ignoring EWOULDBLOCK or
+ // EAGAIN. If we hit EOF, then this will happen because the underlying
+ // reader will return Ok(0), in which case we'll see `Ok` ourselves. In
+ // this case we flip the other fd back into blocking mode and read
+ // whatever's leftover on that file descriptor.
+ let read = |fd: &FileDesc, dst: &mut Vec<u8>| {
+ match fd.read_to_end(dst) {
+ Ok(_) => Ok(true),
+ Err(e) => {
+ if e.raw_os_error() == Some(libc::EWOULDBLOCK) ||
+ e.raw_os_error() == Some(libc::EAGAIN) {
+ Ok(false)
+ } else {
+ Err(e)
+ }
+ }
+ }
+ };
+ if read(&p1, v1)? {
+ p2.set_nonblocking(false)?;
+ return p2.read_to_end(v2).map(|_| ());
+ }
+ if read(&p2, v2)? {
+ p1.set_nonblocking(false)?;
+ return p1.read_to_end(v1).map(|_| ());
+ }
+ }
+ */
+}
diff --git a/src/libstd/sys/redox/process.rs b/src/libstd/sys/redox/process.rs
new file mode 100644
index 0000000..8e6f507
--- /dev/null
+++ b/src/libstd/sys/redox/process.rs
@@ -0,0 +1,614 @@
+use crate::env::{self, split_paths};
+use crate::ffi::{CStr, OsStr};
+use crate::fmt;
+use crate::fs::File;
+use crate::io::{self, prelude::*, BufReader, Error, ErrorKind, SeekFrom};
+use crate::os::unix::ffi::OsStrExt;
+use crate::path::{Path, PathBuf};
+use crate::ptr;
+use crate::sys::ext::fs::MetadataExt;
+use crate::sys::ext::io::AsRawFd;
+use crate::sys::fd::FileDesc;
+use crate::sys::fs::{File as SysFile, OpenOptions};
+use crate::sys::os::{ENV_LOCK, environ};
+use crate::sys::pipe::{self, AnonPipe};
+use crate::sys::{cvt, syscall};
+use crate::sys_common::process::{CommandEnv, DefaultEnvKey};
+
+use libc::{EXIT_SUCCESS, EXIT_FAILURE};
+
+////////////////////////////////////////////////////////////////////////////////
+// Command
+////////////////////////////////////////////////////////////////////////////////
+
+pub struct Command {
+ // Currently we try hard to ensure that the call to `.exec()` doesn't
+ // actually allocate any memory. While many platforms try to ensure that
+ // memory allocation works after a fork in a multithreaded process, it's
+ // been observed to be buggy and somewhat unreliable, so we do our best to
+ // just not do it at all!
+ //
+ // Along those lines, the `argv` and `envp` raw pointers here are exactly
+ // what's gonna get passed to `execvp`. The `argv` array starts with the
+ // `program` and ends with a NULL, and the `envp` pointer, if present, is
+ // also null-terminated.
+ //
+ // Right now we don't support removing arguments, so there's no much fancy
+ // support there, but we support adding and removing environment variables,
+ // so a side table is used to track where in the `envp` array each key is
+ // located. Whenever we add a key we update it in place if it's already
+ // present, and whenever we remove a key we update the locations of all
+ // other keys.
+ program: String,
+ args: Vec<String>,
+ env: CommandEnv<DefaultEnvKey>,
+
+ cwd: Option<String>,
+ uid: Option<u32>,
+ gid: Option<u32>,
+ saw_nul: bool,
+ closures: Vec<Box<dyn FnMut() -> io::Result<()> + Send + Sync>>,
+ stdin: Option<Stdio>,
+ stdout: Option<Stdio>,
+ stderr: Option<Stdio>,
+}
+
+// passed back to std::process with the pipes connected to the child, if any
+// were requested
+pub struct StdioPipes {
+ pub stdin: Option<AnonPipe>,
+ pub stdout: Option<AnonPipe>,
+ pub stderr: Option<AnonPipe>,
+}
+
+// passed to do_exec() with configuration of what the child stdio should look
+// like
+struct ChildPipes {
+ stdin: ChildStdio,
+ stdout: ChildStdio,
+ stderr: ChildStdio,
+}
+
+enum ChildStdio {
+ Inherit,
+ Explicit(usize),
+ Owned(FileDesc),
+}
+
+pub enum Stdio {
+ Inherit,
+ Null,
+ MakePipe,
+ Fd(FileDesc),
+}
+
+impl Command {
+ pub fn new(program: &OsStr) -> Command {
+ Command {
+ program: program.to_str().unwrap().to_owned(),
+ args: Vec::new(),
+ env: Default::default(),
+ cwd: None,
+ uid: None,
+ gid: None,
+ saw_nul: false,
+ closures: Vec::new(),
+ stdin: None,
+ stdout: None,
+ stderr: None,
+ }
+ }
+
+ pub fn arg(&mut self, arg: &OsStr) {
+ self.args.push(arg.to_str().unwrap().to_owned());
+ }
+
+ pub fn env_mut(&mut self) -> &mut CommandEnv<DefaultEnvKey> {
+ &mut self.env
+ }
+
+ pub fn cwd(&mut self, dir: &OsStr) {
+ self.cwd = Some(dir.to_str().unwrap().to_owned());
+ }
+ pub fn uid(&mut self, id: u32) {
+ self.uid = Some(id);
+ }
+ pub fn gid(&mut self, id: u32) {
+ self.gid = Some(id);
+ }
+
+ pub unsafe fn pre_exec(
+ &mut self,
+ f: Box<dyn FnMut() -> io::Result<()> + Send + Sync>,
+ ) {
+ self.closures.push(f);
+ }
+
+ pub fn stdin(&mut self, stdin: Stdio) {
+ self.stdin = Some(stdin);
+ }
+ pub fn stdout(&mut self, stdout: Stdio) {
+ self.stdout = Some(stdout);
+ }
+ pub fn stderr(&mut self, stderr: Stdio) {
+ self.stderr = Some(stderr);
+ }
+
+ pub fn spawn(&mut self, default: Stdio, needs_stdin: bool)
+ -> io::Result<(Process, StdioPipes)> {
+ const CLOEXEC_MSG_FOOTER: &[u8] = b"NOEX";
+
+ if self.saw_nul {
+ return Err(io::Error::new(ErrorKind::InvalidInput,
+ "nul byte found in provided data"));
+ }
+
+ let (ours, theirs) = self.setup_io(default, needs_stdin)?;
+ let (input, output) = pipe::anon_pipe()?;
+
+ let pid = unsafe {
+ match cvt(syscall::clone(0))? {
+ 0 => {
+ drop(input);
+ let err = self.do_exec(theirs);
+ let errno = err.raw_os_error().unwrap_or(syscall::EINVAL) as u32;
+ let bytes = [
+ (errno >> 24) as u8,
+ (errno >> 16) as u8,
+ (errno >> 8) as u8,
+ (errno >> 0) as u8,
+ CLOEXEC_MSG_FOOTER[0], CLOEXEC_MSG_FOOTER[1],
+ CLOEXEC_MSG_FOOTER[2], CLOEXEC_MSG_FOOTER[3]
+ ];
+ // pipe I/O up to PIPE_BUF bytes should be atomic, and then
+ // we want to be sure we *don't* run at_exit destructors as
+ // we're being torn down regardless
+ assert!(output.write(&bytes).is_ok());
+ let _ = syscall::exit(1);
+ panic!("failed to exit");
+ }
+ n => n,
+ }
+ };
+
+ let mut p = Process { pid: pid, status: None };
+ drop(output);
+ let mut bytes = [0; 8];
+
+ // loop to handle EINTR
+ loop {
+ match input.read(&mut bytes) {
+ Ok(0) => return Ok((p, ours)),
+ Ok(8) => {
+ assert!(combine(CLOEXEC_MSG_FOOTER) == combine(&bytes[4.. 8]),
+ "Validation on the CLOEXEC pipe failed: {:?}", bytes);
+ let errno = combine(&bytes[0.. 4]);
+ assert!(p.wait().is_ok(),
+ "wait() should either return Ok or panic");
+ return Err(Error::from_raw_os_error(errno))
+ }
+ Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
+ Err(e) => {
+ assert!(p.wait().is_ok(),
+ "wait() should either return Ok or panic");
+ panic!("the CLOEXEC pipe failed: {:?}", e)
+ },
+ Ok(..) => { // pipe I/O up to PIPE_BUF bytes should be atomic
+ assert!(p.wait().is_ok(),
+ "wait() should either return Ok or panic");
+ panic!("short read on the CLOEXEC pipe")
+ }
+ }
+ }
+
+ fn combine(arr: &[u8]) -> i32 {
+ let a = arr[0] as u32;
+ let b = arr[1] as u32;
+ let c = arr[2] as u32;
+ let d = arr[3] as u32;
+
+ ((a << 24) | (b << 16) | (c << 8) | (d << 0)) as i32
+ }
+ }
+
+ pub fn exec(&mut self, default: Stdio) -> io::Error {
+ if self.saw_nul {
+ return io::Error::new(ErrorKind::InvalidInput,
+ "nul byte found in provided data")
+ }
+
+ match self.setup_io(default, true) {
+ Ok((_, theirs)) => unsafe { self.do_exec(theirs) },
+ Err(e) => e,
+ }
+ }
+
+ // And at this point we've reached a special time in the life of the
+ // child. The child must now be considered hamstrung and unable to
+ // do anything other than syscalls really. Consider the following
+ // scenario:
+ //
+ // 1. Thread A of process 1 grabs the malloc() mutex
+ // 2. Thread B of process 1 forks(), creating thread C
+ // 3. Thread C of process 2 then attempts to malloc()
+ // 4. The memory of process 2 is the same as the memory of
+ // process 1, so the mutex is locked.
+ //
+ // This situation looks a lot like deadlock, right? It turns out
+ // that this is what pthread_atfork() takes care of, which is
+ // presumably implemented across platforms. The first thing that
+ // threads to *before* forking is to do things like grab the malloc
+ // mutex, and then after the fork they unlock it.
+ //
+ // Despite this information, libnative's spawn has been witnessed to
+ // deadlock on both macOS and FreeBSD. I'm not entirely sure why, but
+ // all collected backtraces point at malloc/free traffic in the
+ // child spawned process.
+ //
+ // For this reason, the block of code below should contain 0
+ // invocations of either malloc of free (or their related friends).
+ //
+ // As an example of not having malloc/free traffic, we don't close
+ // this file descriptor by dropping the FileDesc (which contains an
+ // allocation). Instead we just close it manually. This will never
+ // have the drop glue anyway because this code never returns (the
+ // child will either exec() or invoke syscall::exit)
+ unsafe fn do_exec(&mut self, stdio: ChildPipes) -> io::Error {
+ macro_rules! t {
+ ($e:expr) => (match $e {
+ Ok(e) => e,
+ Err(e) => return e,
+ })
+ }
+
+ if let Some(fd) = stdio.stderr.fd() {
+ t!(cvt(syscall::dup2(fd, 2, &[])));
+ let mut flags = t!(cvt(syscall::fcntl(2, syscall::F_GETFD, 0)));
+ flags &= ! syscall::O_CLOEXEC;
+ t!(cvt(syscall::fcntl(2, syscall::F_SETFD, flags)));
+ }
+ if let Some(fd) = stdio.stdout.fd() {
+ t!(cvt(syscall::dup2(fd, 1, &[])));
+ let mut flags = t!(cvt(syscall::fcntl(1, syscall::F_GETFD, 0)));
+ flags &= ! syscall::O_CLOEXEC;
+ t!(cvt(syscall::fcntl(1, syscall::F_SETFD, flags)));
+ }
+ if let Some(fd) = stdio.stdin.fd() {
+ t!(cvt(syscall::dup2(fd, 0, &[])));
+ let mut flags = t!(cvt(syscall::fcntl(0, syscall::F_GETFD, 0)));
+ flags &= ! syscall::O_CLOEXEC;
+ t!(cvt(syscall::fcntl(0, syscall::F_SETFD, flags)));
+ }
+
+ if let Some(g) = self.gid {
+ t!(cvt(syscall::setregid(g as usize, g as usize)));
+ }
+ if let Some(u) = self.uid {
+ t!(cvt(syscall::setreuid(u as usize, u as usize)));
+ }
+ if let Some(ref cwd) = self.cwd {
+ t!(cvt(syscall::chdir(cwd)));
+ }
+
+ for callback in self.closures.iter_mut() {
+ t!(callback());
+ }
+
+ self.env.apply();
+
+ let program = if self.program.contains(':') || self.program.contains('/') {
+ Some(PathBuf::from(&self.program))
+ } else if let Ok(path_env) = env::var("PATH") {
+ let mut program = None;
+ for mut path in split_paths(&path_env) {
+ path.push(&self.program);
+ if path.exists() {
+ program = Some(path);
+ break;
+ }
+ }
+ program
+ } else {
+ None
+ };
+
+ let mut file = if let Some(program) = program {
+ t!(File::open(program.as_os_str()))
+ } else {
+ return io::Error::from_raw_os_error(syscall::ENOENT);
+ };
+
+ // Push all the arguments
+ let mut args: Vec<[usize; 2]> = Vec::with_capacity(1 + self.args.len());
+
+ let interpreter = {
+ let mut reader = BufReader::new(&file);
+
+ let mut shebang = [0; 2];
+ let mut read = 0;
+ loop {
+ match t!(reader.read(&mut shebang[read..])) {
+ 0 => break,
+ n => read += n,
+ }
+ }
+
+ if &shebang == b"#!" {
+ // This is an interpreted script.
+ // First of all, since we'll be passing another file to
+ // fexec(), we need to manually check that we have permission
+ // to execute this file:
+ let uid = t!(cvt(syscall::getuid()));
+ let gid = t!(cvt(syscall::getgid()));
+ let meta = t!(file.metadata());
+
+ let mode = if uid == meta.uid() as usize {
+ meta.mode() >> 3*2 & 0o7
+ } else if gid == meta.gid() as usize {
+ meta.mode() >> 3*1 & 0o7
+ } else {
+ meta.mode() & 0o7
+ };
+ if mode & 1 == 0 {
+ return io::Error::from_raw_os_error(syscall::EPERM);
+ }
+
+ // Second of all, we need to actually read which interpreter it wants
+ let mut interpreter = Vec::new();
+ t!(reader.read_until(b'\n', &mut interpreter));
+ // Pop one trailing newline, if any
+ if interpreter.ends_with(&[b'\n']) {
+ interpreter.pop().unwrap();
+ }
+
+ // FIXME: Here we could just reassign `file` directly, if it
+ // wasn't for lexical lifetimes. Remove the whole `let
+ // interpreter = { ... };` hack once NLL lands.
+ // NOTE: Although DO REMEMBER to make sure the interpreter path
+ // still lives long enough to reach fexec.
+ Some(interpreter)
+ } else {
+ None
+ }
+ };
+ if let Some(ref interpreter) = interpreter {
+ let path: &OsStr = OsStr::from_bytes(&interpreter);
+ file = t!(File::open(path));
+
+ args.push([interpreter.as_ptr() as usize, interpreter.len()]);
+ } else {
+ t!(file.seek(SeekFrom::Start(0)));
+ }
+
+ args.push([self.program.as_ptr() as usize, self.program.len()]);
+ args.extend(self.args.iter().map(|arg| [arg.as_ptr() as usize, arg.len()]));
+
+ // Push all the variables
+ let mut vars: Vec<[usize; 2]> = Vec::new();
+ {
+ let _guard = ENV_LOCK.lock();
+ let mut environ = *environ();
+ while *environ != ptr::null() {
+ let var = CStr::from_ptr(*environ).to_bytes();
+ vars.push([var.as_ptr() as usize, var.len()]);
+ environ = environ.offset(1);
+ }
+ }
+
+ if let Err(err) = syscall::fexec(file.as_raw_fd(), &args, &vars) {
+ io::Error::from_raw_os_error(err.errno as i32)
+ } else {
+ panic!("return from exec without err");
+ }
+ }
+
+
+ fn setup_io(&self, default: Stdio, needs_stdin: bool)
+ -> io::Result<(StdioPipes, ChildPipes)> {
+ let null = Stdio::Null;
+ let default_stdin = if needs_stdin {&default} else {&null};
+ let stdin = self.stdin.as_ref().unwrap_or(default_stdin);
+ let stdout = self.stdout.as_ref().unwrap_or(&default);
+ let stderr = self.stderr.as_ref().unwrap_or(&default);
+ let (their_stdin, our_stdin) = stdin.to_child_stdio(true)?;
+ let (their_stdout, our_stdout) = stdout.to_child_stdio(false)?;
+ let (their_stderr, our_stderr) = stderr.to_child_stdio(false)?;
+ let ours = StdioPipes {
+ stdin: our_stdin,
+ stdout: our_stdout,
+ stderr: our_stderr,
+ };
+ let theirs = ChildPipes {
+ stdin: their_stdin,
+ stdout: their_stdout,
+ stderr: their_stderr,
+ };
+ Ok((ours, theirs))
+ }
+}
+
+impl Stdio {
+ fn to_child_stdio(&self, readable: bool)
+ -> io::Result<(ChildStdio, Option<AnonPipe>)> {
+ match *self {
+ Stdio::Inherit => Ok((ChildStdio::Inherit, None)),
+
+ // Make sure that the source descriptors are not an stdio
+ // descriptor, otherwise the order which we set the child's
+ // descriptors may blow away a descriptor which we are hoping to
+ // save. For example, suppose we want the child's stderr to be the
+ // parent's stdout, and the child's stdout to be the parent's
+ // stderr. No matter which we dup first, the second will get
+ // overwritten prematurely.
+ Stdio::Fd(ref fd) => {
+ if fd.raw() <= 2 {
+ Ok((ChildStdio::Owned(fd.duplicate()?), None))
+ } else {
+ Ok((ChildStdio::Explicit(fd.raw()), None))
+ }
+ }
+
+ Stdio::MakePipe => {
+ let (reader, writer) = pipe::anon_pipe()?;
+ let (ours, theirs) = if readable {
+ (writer, reader)
+ } else {
+ (reader, writer)
+ };
+ Ok((ChildStdio::Owned(theirs.into_fd()), Some(ours)))
+ }
+
+ Stdio::Null => {
+ let mut opts = OpenOptions::new();
+ opts.read(readable);
+ opts.write(!readable);
+ let fd = SysFile::open(Path::new("null:"), &opts)?;
+ Ok((ChildStdio::Owned(fd.into_fd()), None))
+ }
+ }
+ }
+}
+
+impl From<AnonPipe> for Stdio {
+ fn from(pipe: AnonPipe) -> Stdio {
+ Stdio::Fd(pipe.into_fd())
+ }
+}
+
+impl From<SysFile> for Stdio {
+ fn from(file: SysFile) -> Stdio {
+ Stdio::Fd(file.into_fd())
+ }
+}
+
+impl ChildStdio {
+ fn fd(&self) -> Option<usize> {
+ match *self {
+ ChildStdio::Inherit => None,
+ ChildStdio::Explicit(fd) => Some(fd),
+ ChildStdio::Owned(ref fd) => Some(fd.raw()),
+ }
+ }
+}
+
+impl fmt::Debug for Command {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "{:?}", self.program)?;
+ for arg in &self.args {
+ write!(f, " {:?}", arg)?;
+ }
+ Ok(())
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Processes
+////////////////////////////////////////////////////////////////////////////////
+
+/// Unix exit statuses
+#[derive(PartialEq, Eq, Clone, Copy, Debug)]
+pub struct ExitStatus(i32);
+
+impl ExitStatus {
+ fn exited(&self) -> bool {
+ self.0 & 0x7F == 0
+ }
+
+ pub fn success(&self) -> bool {
+ self.code() == Some(0)
+ }
+
+ pub fn code(&self) -> Option<i32> {
+ if self.exited() {
+ Some((self.0 >> 8) & 0xFF)
+ } else {
+ None
+ }
+ }
+
+ pub fn signal(&self) -> Option<i32> {
+ if !self.exited() {
+ Some(self.0 & 0x7F)
+ } else {
+ None
+ }
+ }
+}
+
+impl From<i32> for ExitStatus {
+ fn from(a: i32) -> ExitStatus {
+ ExitStatus(a)
+ }
+}
+
+impl fmt::Display for ExitStatus {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ if let Some(code) = self.code() {
+ write!(f, "exit code: {}", code)
+ } else {
+ let signal = self.signal().unwrap();
+ write!(f, "signal: {}", signal)
+ }
+ }
+}
+
+#[derive(PartialEq, Eq, Clone, Copy, Debug)]
+pub struct ExitCode(u8);
+
+impl ExitCode {
+ pub const SUCCESS: ExitCode = ExitCode(EXIT_SUCCESS as _);
+ pub const FAILURE: ExitCode = ExitCode(EXIT_FAILURE as _);
+
+ pub fn as_i32(&self) -> i32 {
+ self.0 as i32
+ }
+}
+
+/// The unique ID of the process (this should never be negative).
+pub struct Process {
+ pid: usize,
+ status: Option<ExitStatus>,
+}
+
+impl Process {
+ pub fn id(&self) -> u32 {
+ self.pid as u32
+ }
+
+ pub fn kill(&mut self) -> io::Result<()> {
+ // If we've already waited on this process then the pid can be recycled
+ // and used for another process, and we probably shouldn't be killing
+ // random processes, so just return an error.
+ if self.status.is_some() {
+ Err(Error::new(ErrorKind::InvalidInput,
+ "invalid argument: can't kill an exited process"))
+ } else {
+ cvt(syscall::kill(self.pid, syscall::SIGKILL))?;
+ Ok(())
+ }
+ }
+
+ pub fn wait(&mut self) -> io::Result<ExitStatus> {
+ if let Some(status) = self.status {
+ return Ok(status)
+ }
+ let mut status = 0;
+ cvt(syscall::waitpid(self.pid, &mut status, 0))?;
+ self.status = Some(ExitStatus(status as i32));
+ Ok(ExitStatus(status as i32))
+ }
+
+ pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
+ if let Some(status) = self.status {
+ return Ok(Some(status))
+ }
+ let mut status = 0;
+ let pid = cvt(syscall::waitpid(self.pid, &mut status, syscall::WNOHANG))?;
+ if pid == 0 {
+ Ok(None)
+ } else {
+ self.status = Some(ExitStatus(status as i32));
+ Ok(Some(ExitStatus(status as i32)))
+ }
+ }
+}
diff --git a/src/libstd/sys/redox/rand.rs b/src/libstd/sys/redox/rand.rs
new file mode 100644
index 0000000..5b58d17
--- /dev/null
+++ b/src/libstd/sys/redox/rand.rs
@@ -0,0 +1,3 @@
+pub fn hashmap_random_keys() -> (u64, u64) {
+ (0, 0)
+}
diff --git a/src/libstd/sys/redox/rwlock.rs b/src/libstd/sys/redox/rwlock.rs
new file mode 100644
index 0000000..990e755
--- /dev/null
+++ b/src/libstd/sys/redox/rwlock.rs
@@ -0,0 +1,51 @@
+use super::mutex::Mutex;
+
+pub struct RWLock {
+ mutex: Mutex
+}
+
+unsafe impl Send for RWLock {}
+unsafe impl Sync for RWLock {}
+
+impl RWLock {
+ pub const fn new() -> RWLock {
+ RWLock {
+ mutex: Mutex::new()
+ }
+ }
+
+ #[inline]
+ pub unsafe fn read(&self) {
+ self.mutex.lock();
+ }
+
+ #[inline]
+ pub unsafe fn try_read(&self) -> bool {
+ self.mutex.try_lock()
+ }
+
+ #[inline]
+ pub unsafe fn write(&self) {
+ self.mutex.lock();
+ }
+
+ #[inline]
+ pub unsafe fn try_write(&self) -> bool {
+ self.mutex.try_lock()
+ }
+
+ #[inline]
+ pub unsafe fn read_unlock(&self) {
+ self.mutex.unlock();
+ }
+
+ #[inline]
+ pub unsafe fn write_unlock(&self) {
+ self.mutex.unlock();
+ }
+
+ #[inline]
+ pub unsafe fn destroy(&self) {
+ self.mutex.destroy();
+ }
+}
diff --git a/src/libstd/sys/redox/stack_overflow.rs b/src/libstd/sys/redox/stack_overflow.rs
new file mode 100644
index 0000000..cf01d32
--- /dev/null
+++ b/src/libstd/sys/redox/stack_overflow.rs
@@ -0,0 +1,17 @@
+#![cfg_attr(test, allow(dead_code))]
+
+pub struct Handler;
+
+impl Handler {
+ pub unsafe fn new() -> Handler {
+ Handler
+ }
+}
+
+pub unsafe fn init() {
+
+}
+
+pub unsafe fn cleanup() {
+
+}
diff --git a/src/libstd/sys/redox/stdio.rs b/src/libstd/sys/redox/stdio.rs
new file mode 100644
index 0000000..33f5bdb
--- /dev/null
+++ b/src/libstd/sys/redox/stdio.rs
@@ -0,0 +1,64 @@
+use crate::io;
+use crate::sys::{cvt, syscall};
+use crate::sys::fd::FileDesc;
+
+pub struct Stdin(());
+pub struct Stdout(());
+pub struct Stderr(());
+
+impl Stdin {
+ pub fn new() -> io::Result<Stdin> { Ok(Stdin(())) }
+}
+
+impl io::Read for Stdin {
+ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+ let fd = FileDesc::new(0);
+ let ret = fd.read(buf);
+ fd.into_raw();
+ ret
+ }
+}
+
+impl Stdout {
+ pub fn new() -> io::Result<Stdout> { Ok(Stdout(())) }
+}
+
+impl io::Write for Stdout {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ let fd = FileDesc::new(1);
+ let ret = fd.write(buf);
+ fd.into_raw();
+ ret
+ }
+
+ fn flush(&mut self) -> io::Result<()> {
+ cvt(syscall::fsync(1)).and(Ok(()))
+ }
+}
+
+impl Stderr {
+ pub fn new() -> io::Result<Stderr> { Ok(Stderr(())) }
+}
+
+impl io::Write for Stderr {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ let fd = FileDesc::new(2);
+ let ret = fd.write(buf);
+ fd.into_raw();
+ ret
+ }
+
+ fn flush(&mut self) -> io::Result<()> {
+ cvt(syscall::fsync(2)).and(Ok(()))
+ }
+}
+
+pub fn is_ebadf(err: &io::Error) -> bool {
+ err.raw_os_error() == Some(crate::sys::syscall::EBADF as i32)
+}
+
+pub const STDIN_BUF_SIZE: usize = crate::sys_common::io::DEFAULT_BUF_SIZE;
+
+pub fn panic_output() -> Option<impl io::Write> {
+ Stderr::new().ok()
+}
diff --git a/src/libstd/sys/redox/syscall/arch/arm.rs b/src/libstd/sys/redox/syscall/arch/arm.rs
new file mode 100644
index 0000000..e640f7e
--- /dev/null
+++ b/src/libstd/sys/redox/syscall/arch/arm.rs
@@ -0,0 +1,73 @@
+use super::error::{Error, Result};
+
+pub unsafe fn syscall0(mut a: usize) -> Result<usize> {
+ asm!("swi $$0"
+ : "={r0}"(a)
+ : "{r7}"(a)
+ : "memory"
+ : "volatile");
+
+ Error::demux(a)
+}
+
+pub unsafe fn syscall1(mut a: usize, b: usize) -> Result<usize> {
+ asm!("swi $$0"
+ : "={r0}"(a)
+ : "{r7}"(a), "{r0}"(b)
+ : "memory"
+ : "volatile");
+
+ Error::demux(a)
+}
+
+// Clobbers all registers - special for clone
+pub unsafe fn syscall1_clobber(mut a: usize, b: usize) -> Result<usize> {
+ asm!("swi $$0"
+ : "={r0}"(a)
+ : "{r7}"(a), "{r0}"(b)
+ : "memory", "r0", "r1", "r2", "r3", "r4"
+ : "volatile");
+
+ Error::demux(a)
+}
+
+pub unsafe fn syscall2(mut a: usize, b: usize, c: usize) -> Result<usize> {
+ asm!("swi $$0"
+ : "={r0}"(a)
+ : "{r7}"(a), "{r0}"(b), "{r1}"(c)
+ : "memory"
+ : "volatile");
+
+ Error::demux(a)
+}
+
+pub unsafe fn syscall3(mut a: usize, b: usize, c: usize, d: usize) -> Result<usize> {
+ asm!("swi $$0"
+ : "={r0}"(a)
+ : "{r7}"(a), "{r0}"(b), "{r1}"(c), "{r2}"(d)
+ : "memory"
+ : "volatile");
+
+ Error::demux(a)
+}
+
+pub unsafe fn syscall4(mut a: usize, b: usize, c: usize, d: usize, e: usize) -> Result<usize> {
+ asm!("swi $$0"
+ : "={r0}"(a)
+ : "{r7}"(a), "{r0}"(b), "{r1}"(c), "{r2}"(d), "{r3}"(e)
+ : "memory"
+ : "volatile");
+
+ Error::demux(a)
+}
+
+pub unsafe fn syscall5(mut a: usize, b: usize, c: usize, d: usize, e: usize, f: usize)
+ -> Result<usize> {
+ asm!("swi $$0"
+ : "={r0}"(a)
+ : "{r7}"(a), "{r0}"(b), "{r1}"(c), "{r2}"(d), "{r3}"(e), "{r4}"(f)
+ : "memory"
+ : "volatile");
+
+ Error::demux(a)
+}
diff --git a/src/libstd/sys/redox/syscall/arch/x86.rs b/src/libstd/sys/redox/syscall/arch/x86.rs
new file mode 100644
index 0000000..0cd6409
--- /dev/null
+++ b/src/libstd/sys/redox/syscall/arch/x86.rs
@@ -0,0 +1,73 @@
+use super::error::{Error, Result};
+
+pub unsafe fn syscall0(mut a: usize) -> Result<usize> {
+ asm!("int 0x80"
+ : "={eax}"(a)
+ : "{eax}"(a)
+ : "memory"
+ : "intel", "volatile");
+
+ Error::demux(a)
+}
+
+pub unsafe fn syscall1(mut a: usize, b: usize) -> Result<usize> {
+ asm!("int 0x80"
+ : "={eax}"(a)
+ : "{eax}"(a), "{ebx}"(b)
+ : "memory"
+ : "intel", "volatile");
+
+ Error::demux(a)
+}
+
+// Clobbers all registers - special for clone
+pub unsafe fn syscall1_clobber(mut a: usize, b: usize) -> Result<usize> {
+ asm!("int 0x80"
+ : "={eax}"(a)
+ : "{eax}"(a), "{ebx}"(b)
+ : "memory", "ebx", "ecx", "edx", "esi", "edi"
+ : "intel", "volatile");
+
+ Error::demux(a)
+}
+
+pub unsafe fn syscall2(mut a: usize, b: usize, c: usize) -> Result<usize> {
+ asm!("int 0x80"
+ : "={eax}"(a)
+ : "{eax}"(a), "{ebx}"(b), "{ecx}"(c)
+ : "memory"
+ : "intel", "volatile");
+
+ Error::demux(a)
+}
+
+pub unsafe fn syscall3(mut a: usize, b: usize, c: usize, d: usize) -> Result<usize> {
+ asm!("int 0x80"
+ : "={eax}"(a)
+ : "{eax}"(a), "{ebx}"(b), "{ecx}"(c), "{edx}"(d)
+ : "memory"
+ : "intel", "volatile");
+
+ Error::demux(a)
+}
+
+pub unsafe fn syscall4(mut a: usize, b: usize, c: usize, d: usize, e: usize) -> Result<usize> {
+ asm!("int 0x80"
+ : "={eax}"(a)
+ : "{eax}"(a), "{ebx}"(b), "{ecx}"(c), "{edx}"(d), "{esi}"(e)
+ : "memory"
+ : "intel", "volatile");
+
+ Error::demux(a)
+}
+
+pub unsafe fn syscall5(mut a: usize, b: usize, c: usize, d: usize, e: usize, f: usize)
+ -> Result<usize> {
+ asm!("int 0x80"
+ : "={eax}"(a)
+ : "{eax}"(a), "{ebx}"(b), "{ecx}"(c), "{edx}"(d), "{esi}"(e), "{edi}"(f)
+ : "memory"
+ : "intel", "volatile");
+
+ Error::demux(a)
+}
diff --git a/src/libstd/sys/redox/syscall/arch/x86_64.rs b/src/libstd/sys/redox/syscall/arch/x86_64.rs
new file mode 100644
index 0000000..52ad01b
--- /dev/null
+++ b/src/libstd/sys/redox/syscall/arch/x86_64.rs
@@ -0,0 +1,74 @@
+use super::error::{Error, Result};
+
+pub unsafe fn syscall0(mut a: usize) -> Result<usize> {
+ asm!("int 0x80"
+ : "={rax}"(a)
+ : "{rax}"(a)
+ : "memory"
+ : "intel", "volatile");
+
+ Error::demux(a)
+}
+
+pub unsafe fn syscall1(mut a: usize, b: usize) -> Result<usize> {
+ asm!("int 0x80"
+ : "={rax}"(a)
+ : "{rax}"(a), "{rbx}"(b)
+ : "memory"
+ : "intel", "volatile");
+
+ Error::demux(a)
+}
+
+// Clobbers all registers - special for clone
+pub unsafe fn syscall1_clobber(mut a: usize, b: usize) -> Result<usize> {
+ asm!("int 0x80"
+ : "={rax}"(a)
+ : "{rax}"(a), "{rbx}"(b)
+ : "memory", "rbx", "rcx", "rdx", "rsi", "rdi", "r8",
+ "r9", "r10", "r11", "r12", "r13", "r14", "r15"
+ : "intel", "volatile");
+
+ Error::demux(a)
+}
+
+pub unsafe fn syscall2(mut a: usize, b: usize, c: usize) -> Result<usize> {
+ asm!("int 0x80"
+ : "={rax}"(a)
+ : "{rax}"(a), "{rbx}"(b), "{rcx}"(c)
+ : "memory"
+ : "intel", "volatile");
+
+ Error::demux(a)
+}
+
+pub unsafe fn syscall3(mut a: usize, b: usize, c: usize, d: usize) -> Result<usize> {
+ asm!("int 0x80"
+ : "={rax}"(a)
+ : "{rax}"(a), "{rbx}"(b), "{rcx}"(c), "{rdx}"(d)
+ : "memory"
+ : "intel", "volatile");
+
+ Error::demux(a)
+}
+
+pub unsafe fn syscall4(mut a: usize, b: usize, c: usize, d: usize, e: usize) -> Result<usize> {
+ asm!("int 0x80"
+ : "={rax}"(a)
+ : "{rax}"(a), "{rbx}"(b), "{rcx}"(c), "{rdx}"(d), "{rsi}"(e)
+ : "memory"
+ : "intel", "volatile");
+
+ Error::demux(a)
+}
+
+pub unsafe fn syscall5(mut a: usize, b: usize, c: usize, d: usize, e: usize, f: usize)
+ -> Result<usize> {
+ asm!("int 0x80"
+ : "={rax}"(a)
+ : "{rax}"(a), "{rbx}"(b), "{rcx}"(c), "{rdx}"(d), "{rsi}"(e), "{rdi}"(f)
+ : "memory"
+ : "intel", "volatile");
+
+ Error::demux(a)
+}
diff --git a/src/libstd/sys/redox/syscall/call.rs b/src/libstd/sys/redox/syscall/call.rs
new file mode 100644
index 0000000..b9abb48
--- /dev/null
+++ b/src/libstd/sys/redox/syscall/call.rs
@@ -0,0 +1,348 @@
+use super::arch::*;
+use super::data::{SigAction, Stat, StatVfs, TimeSpec};
+use super::error::Result;
+use super::number::*;
+
+use core::{mem, ptr};
+
+// Signal restorer
+extern "C" fn restorer() -> ! {
+ sigreturn().unwrap();
+ unreachable!();
+}
+
+/// Set the end of the process's heap
+///
+/// When `addr` is `0`, this function will return the current break.
+///
+/// When `addr` is nonzero, this function will attempt to set the end of the process's
+/// heap to `addr` and return the new program break. The new program break should be
+/// checked by the allocator, it may not be exactly `addr`, as it may be aligned to a page
+/// boundary.
+///
+/// On error, `Err(ENOMEM)` will be returned indicating that no memory is available
+pub unsafe fn brk(addr: usize) -> Result<usize> {
+ syscall1(SYS_BRK, addr)
+}
+
+/// Changes the process's working directory.
+///
+/// This function will attempt to set the process's working directory to `path`, which can be
+/// either a relative, scheme relative, or absolute path.
+///
+/// On success, `Ok(0)` will be returned. On error, one of the following errors will be returned.
+///
+/// # Errors
+///
+/// * `EACCES` - permission is denied for one of the components of `path`, or `path`
+/// * `EFAULT` - `path` does not point to the process's addressable memory
+/// * `EIO` - an I/O error occurred
+/// * `ENOENT` - `path` does not exit
+/// * `ENOTDIR` - `path` is not a directory
+pub fn chdir<T: AsRef<[u8]>>(path: T) -> Result<usize> {
+ unsafe { syscall2(SYS_CHDIR, path.as_ref().as_ptr() as usize, path.as_ref().len()) }
+}
+
+pub fn chmod<T: AsRef<[u8]>>(path: T, mode: usize) -> Result<usize> {
+ unsafe { syscall3(SYS_CHMOD, path.as_ref().as_ptr() as usize, path.as_ref().len(), mode) }
+}
+
+/// Produces a fork of the current process, or a new process thread.
+pub unsafe fn clone(flags: usize) -> Result<usize> {
+ syscall1_clobber(SYS_CLONE, flags)
+}
+
+/// Closes a file.
+pub fn close(fd: usize) -> Result<usize> {
+ unsafe { syscall1(SYS_CLOSE, fd) }
+}
+
+/// Gets the current system time.
+pub fn clock_gettime(clock: usize, tp: &mut TimeSpec) -> Result<usize> {
+ unsafe { syscall2(SYS_CLOCK_GETTIME, clock, tp as *mut TimeSpec as usize) }
+}
+
+/// Copies and transforms a file descriptor.
+pub fn dup(fd: usize, buf: &[u8]) -> Result<usize> {
+ unsafe { syscall3(SYS_DUP, fd, buf.as_ptr() as usize, buf.len()) }
+}
+
+/// Copies and transforms a file descriptor.
+pub fn dup2(fd: usize, newfd: usize, buf: &[u8]) -> Result<usize> {
+ unsafe { syscall4(SYS_DUP2, fd, newfd, buf.as_ptr() as usize, buf.len()) }
+}
+
+/// Exits the current process.
+pub fn exit(status: usize) -> Result<usize> {
+ unsafe { syscall1(SYS_EXIT, status) }
+}
+
+/// Changes file permissions.
+pub fn fchmod(fd: usize, mode: u16) -> Result<usize> {
+ unsafe { syscall2(SYS_FCHMOD, fd, mode as usize) }
+
+}
+
+/// Changes file ownership.
+pub fn fchown(fd: usize, uid: u32, gid: u32) -> Result<usize> {
+ unsafe { syscall3(SYS_FCHOWN, fd, uid as usize, gid as usize) }
+
+}
+
+/// Changes file descriptor flags.
+pub fn fcntl(fd: usize, cmd: usize, arg: usize) -> Result<usize> {
+ unsafe { syscall3(SYS_FCNTL, fd, cmd, arg) }
+}
+
+/// Replaces the current process with a new executable.
+pub fn fexec(fd: usize, args: &[[usize; 2]], vars: &[[usize; 2]]) -> Result<usize> {
+ unsafe { syscall5(SYS_FEXEC, fd, args.as_ptr() as usize, args.len(),
+ vars.as_ptr() as usize, vars.len()) }
+}
+
+/// Maps a file into memory.
+pub unsafe fn fmap(fd: usize, offset: usize, size: usize) -> Result<usize> {
+ syscall3(SYS_FMAP, fd, offset, size)
+}
+
+/// Unmaps a memory-mapped file.
+pub unsafe fn funmap(addr: usize) -> Result<usize> {
+ syscall1(SYS_FUNMAP, addr)
+}
+
+/// Retrieves the canonical path of a file.
+pub fn fpath(fd: usize, buf: &mut [u8]) -> Result<usize> {
+ unsafe { syscall3(SYS_FPATH, fd, buf.as_mut_ptr() as usize, buf.len()) }
+}
+
+/// Renames a file.
+pub fn frename<T: AsRef<[u8]>>(fd: usize, path: T) -> Result<usize> {
+ unsafe { syscall3(SYS_FRENAME, fd, path.as_ref().as_ptr() as usize, path.as_ref().len()) }
+}
+
+/// Gets metadata about a file.
+pub fn fstat(fd: usize, stat: &mut Stat) -> Result<usize> {
+ unsafe { syscall3(SYS_FSTAT, fd, stat as *mut Stat as usize, mem::size_of::<Stat>()) }
+}
+
+/// Gets metadata about a filesystem.
+pub fn fstatvfs(fd: usize, stat: &mut StatVfs) -> Result<usize> {
+ unsafe { syscall3(SYS_FSTATVFS, fd, stat as *mut StatVfs as usize, mem::size_of::<StatVfs>()) }
+}
+
+/// Syncs a file descriptor to its underlying medium.
+pub fn fsync(fd: usize) -> Result<usize> {
+ unsafe { syscall1(SYS_FSYNC, fd) }
+}
+
+/// Truncate or extend a file to a specified length
+pub fn ftruncate(fd: usize, len: usize) -> Result<usize> {
+ unsafe { syscall2(SYS_FTRUNCATE, fd, len) }
+}
+
+// Change modify and/or access times
+pub fn futimens(fd: usize, times: &[TimeSpec]) -> Result<usize> {
+ unsafe { syscall3(SYS_FUTIMENS, fd, times.as_ptr() as usize,
+ times.len() * mem::size_of::<TimeSpec>()) }
+}
+
+/// Fast userspace mutex
+pub unsafe fn futex(addr: *mut i32, op: usize, val: i32, val2: usize, addr2: *mut i32)
+ -> Result<usize> {
+ syscall5(SYS_FUTEX, addr as usize, op, (val as isize) as usize, val2, addr2 as usize)
+}
+
+/// Gets the current working directory.
+pub fn getcwd(buf: &mut [u8]) -> Result<usize> {
+ unsafe { syscall2(SYS_GETCWD, buf.as_mut_ptr() as usize, buf.len()) }
+}
+
+/// Gets the effective group ID.
+pub fn getegid() -> Result<usize> {
+ unsafe { syscall0(SYS_GETEGID) }
+}
+
+/// Gets the effective namespace.
+pub fn getens() -> Result<usize> {
+ unsafe { syscall0(SYS_GETENS) }
+}
+
+/// Gets the effective user ID.
+pub fn geteuid() -> Result<usize> {
+ unsafe { syscall0(SYS_GETEUID) }
+}
+
+/// Gets the current group ID.
+pub fn getgid() -> Result<usize> {
+ unsafe { syscall0(SYS_GETGID) }
+}
+
+/// Gets the current namespace.
+pub fn getns() -> Result<usize> {
+ unsafe { syscall0(SYS_GETNS) }
+}
+
+/// Gets the current process ID.
+pub fn getpid() -> Result<usize> {
+ unsafe { syscall0(SYS_GETPID) }
+}
+
+/// Gets the process group ID.
+pub fn getpgid(pid: usize) -> Result<usize> {
+ unsafe { syscall1(SYS_GETPGID, pid) }
+}
+
+/// Gets the parent process ID.
+pub fn getppid() -> Result<usize> {
+ unsafe { syscall0(SYS_GETPPID) }
+}
+
+/// Gets the current user ID.
+pub fn getuid() -> Result<usize> {
+ unsafe { syscall0(SYS_GETUID) }
+}
+
+/// Sets the I/O privilege level
+pub unsafe fn iopl(level: usize) -> Result<usize> {
+ syscall1(SYS_IOPL, level)
+}
+
+/// Sends a signal `sig` to the process identified by `pid`.
+pub fn kill(pid: usize, sig: usize) -> Result<usize> {
+ unsafe { syscall2(SYS_KILL, pid, sig) }
+}
+
+/// Creates a link to a file.
+pub unsafe fn link(old: *const u8, new: *const u8) -> Result<usize> {
+ syscall2(SYS_LINK, old as usize, new as usize)
+}
+
+/// Seeks to `offset` bytes in a file descriptor.
+pub fn lseek(fd: usize, offset: isize, whence: usize) -> Result<usize> {
+ unsafe { syscall3(SYS_LSEEK, fd, offset as usize, whence) }
+}
+
+/// Makes a new scheme namespace.
+pub fn mkns(schemes: &[[usize; 2]]) -> Result<usize> {
+ unsafe { syscall2(SYS_MKNS, schemes.as_ptr() as usize, schemes.len()) }
+}
+
+/// Sleeps for the time specified in `req`.
+pub fn nanosleep(req: &TimeSpec, rem: &mut TimeSpec) -> Result<usize> {
+ unsafe { syscall2(SYS_NANOSLEEP, req as *const TimeSpec as usize,
+ rem as *mut TimeSpec as usize) }
+}
+
+/// Opens a file.
+pub fn open<T: AsRef<[u8]>>(path: T, flags: usize) -> Result<usize> {
+ unsafe { syscall3(SYS_OPEN, path.as_ref().as_ptr() as usize, path.as_ref().len(), flags) }
+}
+
+/// Allocates pages, linearly in physical memory.
+pub unsafe fn physalloc(size: usize) -> Result<usize> {
+ syscall1(SYS_PHYSALLOC, size)
+}
+
+/// Frees physically allocated pages.
+pub unsafe fn physfree(physical_address: usize, size: usize) -> Result<usize> {
+ syscall2(SYS_PHYSFREE, physical_address, size)
+}
+
+/// Maps physical memory to virtual memory.
+pub unsafe fn physmap(physical_address: usize, size: usize, flags: usize) -> Result<usize> {
+ syscall3(SYS_PHYSMAP, physical_address, size, flags)
+}
+
+/// Unmaps previously mapped physical memory.
+pub unsafe fn physunmap(virtual_address: usize) -> Result<usize> {
+ syscall1(SYS_PHYSUNMAP, virtual_address)
+}
+
+/// Creates a pair of file descriptors referencing the read and write ends of a pipe.
+pub fn pipe2(fds: &mut [usize; 2], flags: usize) -> Result<usize> {
+ unsafe { syscall2(SYS_PIPE2, fds.as_ptr() as usize, flags) }
+}
+
+/// Read from a file descriptor into a buffer
+pub fn read(fd: usize, buf: &mut [u8]) -> Result<usize> {
+ unsafe { syscall3(SYS_READ, fd, buf.as_mut_ptr() as usize, buf.len()) }
+}
+
+/// Removes a directory.
+pub fn rmdir<T: AsRef<[u8]>>(path: T) -> Result<usize> {
+ unsafe { syscall2(SYS_RMDIR, path.as_ref().as_ptr() as usize, path.as_ref().len()) }
+}
+
+/// Sets the process group ID.
+pub fn setpgid(pid: usize, pgid: usize) -> Result<usize> {
+ unsafe { syscall2(SYS_SETPGID, pid, pgid) }
+}
+
+/// Sets the current process group IDs.
+pub fn setregid(rgid: usize, egid: usize) -> Result<usize> {
+ unsafe { syscall2(SYS_SETREGID, rgid, egid) }
+}
+
+/// Makes a new scheme namespace.
+pub fn setrens(rns: usize, ens: usize) -> Result<usize> {
+ unsafe { syscall2(SYS_SETRENS, rns, ens) }
+}
+
+/// Sets the current process user IDs.
+pub fn setreuid(ruid: usize, euid: usize) -> Result<usize> {
+ unsafe { syscall2(SYS_SETREUID, ruid, euid) }
+}
+
+/// Sets up a signal handler.
+pub fn sigaction(sig: usize, act: Option<&SigAction>, oldact: Option<&mut SigAction>)
+-> Result<usize> {
+ unsafe { syscall4(SYS_SIGACTION, sig,
+ act.map(|x| x as *const _).unwrap_or_else(ptr::null) as usize,
+ oldact.map(|x| x as *mut _).unwrap_or_else(ptr::null_mut) as usize,
+ restorer as usize) }
+}
+
+/// Returns from signal handler.
+pub fn sigreturn() -> Result<usize> {
+ unsafe { syscall0(SYS_SIGRETURN) }
+}
+
+/// Removes a file.
+pub fn unlink<T: AsRef<[u8]>>(path: T) -> Result<usize> {
+ unsafe { syscall2(SYS_UNLINK, path.as_ref().as_ptr() as usize, path.as_ref().len()) }
+}
+
+/// Converts a virtual address to a physical one.
+pub unsafe fn virttophys(virtual_address: usize) -> Result<usize> {
+ syscall1(SYS_VIRTTOPHYS, virtual_address)
+}
+
+/// Checks if a child process has exited or received a signal.
+pub fn waitpid(pid: usize, status: &mut usize, options: usize) -> Result<usize> {
+ unsafe { syscall3(SYS_WAITPID, pid, status as *mut usize as usize, options) }
+}
+
+/// Writes a buffer to a file descriptor.
+///
+/// The kernel will attempt to write the bytes in `buf` to the file descriptor `fd`, returning
+/// either an `Err`, explained below, or `Ok(count)` where `count` is the number of bytes which
+/// were written.
+///
+/// # Errors
+///
+/// * `EAGAIN` - the file descriptor was opened with `O_NONBLOCK` and writing would block
+/// * `EBADF` - the file descriptor is not valid or is not open for writing
+/// * `EFAULT` - `buf` does not point to the process's addressable memory
+/// * `EIO` - an I/O error occurred
+/// * `ENOSPC` - the device containing the file descriptor has no room for data
+/// * `EPIPE` - the file descriptor refers to a pipe or socket whose reading end is closed
+pub fn write(fd: usize, buf: &[u8]) -> Result<usize> {
+ unsafe { syscall3(SYS_WRITE, fd, buf.as_ptr() as usize, buf.len()) }
+}
+
+/// Yields the process's time slice to the kernel.
+///
+/// This function will return Ok(0) on success
+pub fn sched_yield() -> Result<usize> {
+ unsafe { syscall0(SYS_YIELD) }
+}
diff --git a/src/libstd/sys/redox/syscall/data.rs b/src/libstd/sys/redox/syscall/data.rs
new file mode 100644
index 0000000..0b458ea
--- /dev/null
+++ b/src/libstd/sys/redox/syscall/data.rs
@@ -0,0 +1,191 @@
+use core::ops::{Deref, DerefMut};
+use core::{mem, slice};
+
+#[derive(Copy, Clone, Debug, Default)]
+pub struct Event {
+ pub id: usize,
+ pub flags: usize,
+ pub data: usize
+}
+
+impl Deref for Event {
+ type Target = [u8];
+ fn deref(&self) -> &[u8] {
+ unsafe {
+ slice::from_raw_parts(
+ self as *const Event as *const u8,
+ mem::size_of::<Event>()
+ ) as &[u8]
+ }
+ }
+}
+
+impl DerefMut for Event {
+ fn deref_mut(&mut self) -> &mut [u8] {
+ unsafe {
+ slice::from_raw_parts_mut(
+ self as *mut Event as *mut u8,
+ mem::size_of::<Event>()
+ ) as &mut [u8]
+ }
+ }
+}
+
+#[derive(Copy, Clone, Debug, Default)]
+#[repr(C)]
+pub struct Packet {
+ pub id: u64,
+ pub pid: usize,
+ pub uid: u32,
+ pub gid: u32,
+ pub a: usize,
+ pub b: usize,
+ pub c: usize,
+ pub d: usize
+}
+
+impl Deref for Packet {
+ type Target = [u8];
+ fn deref(&self) -> &[u8] {
+ unsafe {
+ slice::from_raw_parts(
+ self as *const Packet as *const u8,
+ mem::size_of::<Packet>()
+ ) as &[u8]
+ }
+ }
+}
+
+impl DerefMut for Packet {
+ fn deref_mut(&mut self) -> &mut [u8] {
+ unsafe {
+ slice::from_raw_parts_mut(
+ self as *mut Packet as *mut u8,
+ mem::size_of::<Packet>()
+ ) as &mut [u8]
+ }
+ }
+}
+
+#[derive(Copy, Clone, Debug)]
+#[repr(C)]
+pub struct SigAction {
+ pub sa_handler: extern "C" fn(usize),
+ pub sa_mask: [u64; 2],
+ pub sa_flags: usize,
+}
+
+impl Default for SigAction {
+ fn default() -> Self {
+ Self {
+ sa_handler: unsafe { mem::transmute(0usize) },
+ sa_mask: [0; 2],
+ sa_flags: 0,
+ }
+ }
+}
+
+#[derive(Copy, Clone, Debug, Default)]
+#[repr(C)]
+pub struct Stat {
+ pub st_dev: u64,
+ pub st_ino: u64,
+ pub st_mode: u16,
+ pub st_nlink: u32,
+ pub st_uid: u32,
+ pub st_gid: u32,
+ pub st_size: u64,
+ pub st_blksize: u32,
+ pub st_blocks: u64,
+ pub st_mtime: u64,
+ pub st_mtime_nsec: u32,
+ pub st_atime: u64,
+ pub st_atime_nsec: u32,
+ pub st_ctime: u64,
+ pub st_ctime_nsec: u32,
+}
+
+impl Deref for Stat {
+ type Target = [u8];
+ fn deref(&self) -> &[u8] {
+ unsafe {
+ slice::from_raw_parts(
+ self as *const Stat as *const u8,
+ mem::size_of::<Stat>()
+ ) as &[u8]
+ }
+ }
+}
+
+impl DerefMut for Stat {
+ fn deref_mut(&mut self) -> &mut [u8] {
+ unsafe {
+ slice::from_raw_parts_mut(
+ self as *mut Stat as *mut u8,
+ mem::size_of::<Stat>()
+ ) as &mut [u8]
+ }
+ }
+}
+
+#[derive(Copy, Clone, Debug, Default)]
+#[repr(C)]
+pub struct StatVfs {
+ pub f_bsize: u32,
+ pub f_blocks: u64,
+ pub f_bfree: u64,
+ pub f_bavail: u64,
+}
+
+impl Deref for StatVfs {
+ type Target = [u8];
+ fn deref(&self) -> &[u8] {
+ unsafe {
+ slice::from_raw_parts(
+ self as *const StatVfs as *const u8,
+ mem::size_of::<StatVfs>()
+ ) as &[u8]
+ }
+ }
+}
+
+impl DerefMut for StatVfs {
+ fn deref_mut(&mut self) -> &mut [u8] {
+ unsafe {
+ slice::from_raw_parts_mut(
+ self as *mut StatVfs as *mut u8,
+ mem::size_of::<StatVfs>()
+ ) as &mut [u8]
+ }
+ }
+}
+
+#[derive(Copy, Clone, Debug, Default)]
+#[repr(C)]
+pub struct TimeSpec {
+ pub tv_sec: i64,
+ pub tv_nsec: i32,
+}
+
+impl Deref for TimeSpec {
+ type Target = [u8];
+ fn deref(&self) -> &[u8] {
+ unsafe {
+ slice::from_raw_parts(
+ self as *const TimeSpec as *const u8,
+ mem::size_of::<TimeSpec>()
+ ) as &[u8]
+ }
+ }
+}
+
+impl DerefMut for TimeSpec {
+ fn deref_mut(&mut self) -> &mut [u8] {
+ unsafe {
+ slice::from_raw_parts_mut(
+ self as *mut TimeSpec as *mut u8,
+ mem::size_of::<TimeSpec>()
+ ) as &mut [u8]
+ }
+ }
+}
diff --git a/src/libstd/sys/redox/syscall/error.rs b/src/libstd/sys/redox/syscall/error.rs
new file mode 100644
index 0000000..da84ffb
--- /dev/null
+++ b/src/libstd/sys/redox/syscall/error.rs
@@ -0,0 +1,315 @@
+use core::{fmt, result};
+
+#[derive(Eq, PartialEq)]
+pub struct Error {
+ pub errno: i32,
+}
+
+pub type Result<T> = result::Result<T, Error>;
+
+impl Error {
+ pub fn new(errno: i32) -> Error {
+ Error { errno }
+ }
+
+ pub fn mux(result: Result<usize>) -> usize {
+ match result {
+ Ok(value) => value,
+ Err(error) => -error.errno as usize,
+ }
+ }
+
+ pub fn demux(value: usize) -> Result<usize> {
+ let errno = -(value as i32);
+ if errno >= 1 && errno < STR_ERROR.len() as i32 {
+ Err(Error::new(errno))
+ } else {
+ Ok(value)
+ }
+ }
+
+ pub fn text(&self) -> &str {
+ if let Some(description) = STR_ERROR.get(self.errno as usize) {
+ description
+ } else {
+ "Unknown Error"
+ }
+ }
+}
+
+impl fmt::Debug for Error {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.write_str(self.text())
+ }
+}
+
+impl fmt::Display for Error {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.write_str(self.text())
+ }
+}
+
+pub const EPERM: i32 = 1; /* Operation not permitted */
+pub const ENOENT: i32 = 2; /* No such file or directory */
+pub const ESRCH: i32 = 3; /* No such process */
+pub const EINTR: i32 = 4; /* Interrupted system call */
+pub const EIO: i32 = 5; /* I/O error */
+pub const ENXIO: i32 = 6; /* No such device or address */
+pub const E2BIG: i32 = 7; /* Argument list too long */
+pub const ENOEXEC: i32 = 8; /* Exec format error */
+pub const EBADF: i32 = 9; /* Bad file number */
+pub const ECHILD: i32 = 10; /* No child processes */
+pub const EAGAIN: i32 = 11; /* Try again */
+pub const ENOMEM: i32 = 12; /* Out of memory */
+pub const EACCES: i32 = 13; /* Permission denied */
+pub const EFAULT: i32 = 14; /* Bad address */
+pub const ENOTBLK: i32 = 15; /* Block device required */
+pub const EBUSY: i32 = 16; /* Device or resource busy */
+pub const EEXIST: i32 = 17; /* File exists */
+pub const EXDEV: i32 = 18; /* Cross-device link */
+pub const ENODEV: i32 = 19; /* No such device */
+pub const ENOTDIR: i32 = 20; /* Not a directory */
+pub const EISDIR: i32 = 21; /* Is a directory */
+pub const EINVAL: i32 = 22; /* Invalid argument */
+pub const ENFILE: i32 = 23; /* File table overflow */
+pub const EMFILE: i32 = 24; /* Too many open files */
+pub const ENOTTY: i32 = 25; /* Not a typewriter */
+pub const ETXTBSY: i32 = 26; /* Text file busy */
+pub const EFBIG: i32 = 27; /* File too large */
+pub const ENOSPC: i32 = 28; /* No space left on device */
+pub const ESPIPE: i32 = 29; /* Illegal seek */
+pub const EROFS: i32 = 30; /* Read-only file system */
+pub const EMLINK: i32 = 31; /* Too many links */
+pub const EPIPE: i32 = 32; /* Broken pipe */
+pub const EDOM: i32 = 33; /* Math argument out of domain of func */
+pub const ERANGE: i32 = 34; /* Math result not representable */
+pub const EDEADLK: i32 = 35; /* Resource deadlock would occur */
+pub const ENAMETOOLONG: i32 = 36; /* File name too long */
+pub const ENOLCK: i32 = 37; /* No record locks available */
+pub const ENOSYS: i32 = 38; /* Function not implemented */
+pub const ENOTEMPTY: i32 = 39; /* Directory not empty */
+pub const ELOOP: i32 = 40; /* Too many symbolic links encountered */
+pub const EWOULDBLOCK: i32 = 41; /* Operation would block */
+pub const ENOMSG: i32 = 42; /* No message of desired type */
+pub const EIDRM: i32 = 43; /* Identifier removed */
+pub const ECHRNG: i32 = 44; /* Channel number out of range */
+pub const EL2NSYNC: i32 = 45; /* Level 2 not synchronized */
+pub const EL3HLT: i32 = 46; /* Level 3 halted */
+pub const EL3RST: i32 = 47; /* Level 3 reset */
+pub const ELNRNG: i32 = 48; /* Link number out of range */
+pub const EUNATCH: i32 = 49; /* Protocol driver not attached */
+pub const ENOCSI: i32 = 50; /* No CSI structure available */
+pub const EL2HLT: i32 = 51; /* Level 2 halted */
+pub const EBADE: i32 = 52; /* Invalid exchange */
+pub const EBADR: i32 = 53; /* Invalid request descriptor */
+pub const EXFULL: i32 = 54; /* Exchange full */
+pub const ENOANO: i32 = 55; /* No anode */
+pub const EBADRQC: i32 = 56; /* Invalid request code */
+pub const EBADSLT: i32 = 57; /* Invalid slot */
+pub const EDEADLOCK: i32 = 58; /* Resource deadlock would occur */
+pub const EBFONT: i32 = 59; /* Bad font file format */
+pub const ENOSTR: i32 = 60; /* Device not a stream */
+pub const ENODATA: i32 = 61; /* No data available */
+pub const ETIME: i32 = 62; /* Timer expired */
+pub const ENOSR: i32 = 63; /* Out of streams resources */
+pub const ENONET: i32 = 64; /* Machine is not on the network */
+pub const ENOPKG: i32 = 65; /* Package not installed */
+pub const EREMOTE: i32 = 66; /* Object is remote */
+pub const ENOLINK: i32 = 67; /* Link has been severed */
+pub const EADV: i32 = 68; /* Advertise error */
+pub const ESRMNT: i32 = 69; /* Srmount error */
+pub const ECOMM: i32 = 70; /* Communication error on send */
+pub const EPROTO: i32 = 71; /* Protocol error */
+pub const EMULTIHOP: i32 = 72; /* Multihop attempted */
+pub const EDOTDOT: i32 = 73; /* RFS specific error */
+pub const EBADMSG: i32 = 74; /* Not a data message */
+pub const EOVERFLOW: i32 = 75; /* Value too large for defined data type */
+pub const ENOTUNIQ: i32 = 76; /* Name not unique on network */
+pub const EBADFD: i32 = 77; /* File descriptor in bad state */
+pub const EREMCHG: i32 = 78; /* Remote address changed */
+pub const ELIBACC: i32 = 79; /* Can not access a needed shared library */
+pub const ELIBBAD: i32 = 80; /* Accessing a corrupted shared library */
+pub const ELIBSCN: i32 = 81; /* .lib section in a.out corrupted */
+pub const ELIBMAX: i32 = 82; /* Attempting to link in too many shared libraries */
+pub const ELIBEXEC: i32 = 83; /* Cannot exec a shared library directly */
+pub const EILSEQ: i32 = 84; /* Illegal byte sequence */
+pub const ERESTART: i32 = 85; /* Interrupted system call should be restarted */
+pub const ESTRPIPE: i32 = 86; /* Streams pipe error */
+pub const EUSERS: i32 = 87; /* Too many users */
+pub const ENOTSOCK: i32 = 88; /* Socket operation on non-socket */
+pub const EDESTADDRREQ: i32 = 89; /* Destination address required */
+pub const EMSGSIZE: i32 = 90; /* Message too long */
+pub const EPROTOTYPE: i32 = 91; /* Protocol wrong type for socket */
+pub const ENOPROTOOPT: i32 = 92; /* Protocol not available */
+pub const EPROTONOSUPPORT: i32 = 93; /* Protocol not supported */
+pub const ESOCKTNOSUPPORT: i32 = 94; /* Socket type not supported */
+pub const EOPNOTSUPP: i32 = 95; /* Operation not supported on transport endpoint */
+pub const EPFNOSUPPORT: i32 = 96; /* Protocol family not supported */
+pub const EAFNOSUPPORT: i32 = 97; /* Address family not supported by protocol */
+pub const EADDRINUSE: i32 = 98; /* Address already in use */
+pub const EADDRNOTAVAIL: i32 = 99; /* Cannot assign requested address */
+pub const ENETDOWN: i32 = 100; /* Network is down */
+pub const ENETUNREACH: i32 = 101; /* Network is unreachable */
+pub const ENETRESET: i32 = 102; /* Network dropped connection because of reset */
+pub const ECONNABORTED: i32 = 103; /* Software caused connection abort */
+pub const ECONNRESET: i32 = 104; /* Connection reset by peer */
+pub const ENOBUFS: i32 = 105; /* No buffer space available */
+pub const EISCONN: i32 = 106; /* Transport endpoint is already connected */
+pub const ENOTCONN: i32 = 107; /* Transport endpoint is not connected */
+pub const ESHUTDOWN: i32 = 108; /* Cannot send after transport endpoint shutdown */
+pub const ETOOMANYREFS: i32 = 109; /* Too many references: cannot splice */
+pub const ETIMEDOUT: i32 = 110; /* Connection timed out */
+pub const ECONNREFUSED: i32 = 111; /* Connection refused */
+pub const EHOSTDOWN: i32 = 112; /* Host is down */
+pub const EHOSTUNREACH: i32 = 113; /* No route to host */
+pub const EALREADY: i32 = 114; /* Operation already in progress */
+pub const EINPROGRESS: i32 = 115; /* Operation now in progress */
+pub const ESTALE: i32 = 116; /* Stale NFS file handle */
+pub const EUCLEAN: i32 = 117; /* Structure needs cleaning */
+pub const ENOTNAM: i32 = 118; /* Not a XENIX named type file */
+pub const ENAVAIL: i32 = 119; /* No XENIX semaphores available */
+pub const EISNAM: i32 = 120; /* Is a named type file */
+pub const EREMOTEIO: i32 = 121; /* Remote I/O error */
+pub const EDQUOT: i32 = 122; /* Quota exceeded */
+pub const ENOMEDIUM: i32 = 123; /* No medium found */
+pub const EMEDIUMTYPE: i32 = 124; /* Wrong medium type */
+pub const ECANCELED: i32 = 125; /* Operation Canceled */
+pub const ENOKEY: i32 = 126; /* Required key not available */
+pub const EKEYEXPIRED: i32 = 127; /* Key has expired */
+pub const EKEYREVOKED: i32 = 128; /* Key has been revoked */
+pub const EKEYREJECTED: i32 = 129; /* Key was rejected by service */
+pub const EOWNERDEAD: i32 = 130; /* Owner died */
+pub const ENOTRECOVERABLE: i32 = 131; /* State not recoverable */
+
+pub static STR_ERROR: [&'static str; 132] = ["Success",
+ "Operation not permitted",
+ "No such file or directory",
+ "No such process",
+ "Interrupted system call",
+ "I/O error",
+ "No such device or address",
+ "Argument list too long",
+ "Exec format error",
+ "Bad file number",
+ "No child processes",
+ "Try again",
+ "Out of memory",
+ "Permission denied",
+ "Bad address",
+ "Block device required",
+ "Device or resource busy",
+ "File exists",
+ "Cross-device link",
+ "No such device",
+ "Not a directory",
+ "Is a directory",
+ "Invalid argument",
+ "File table overflow",
+ "Too many open files",
+ "Not a typewriter",
+ "Text file busy",
+ "File too large",
+ "No space left on device",
+ "Illegal seek",
+ "Read-only file system",
+ "Too many links",
+ "Broken pipe",
+ "Math argument out of domain of func",
+ "Math result not representable",
+ "Resource deadlock would occur",
+ "File name too long",
+ "No record locks available",
+ "Function not implemented",
+ "Directory not empty",
+ "Too many symbolic links encountered",
+ "Operation would block",
+ "No message of desired type",
+ "Identifier removed",
+ "Channel number out of range",
+ "Level 2 not synchronized",
+ "Level 3 halted",
+ "Level 3 reset",
+ "Link number out of range",
+ "Protocol driver not attached",
+ "No CSI structure available",
+ "Level 2 halted",
+ "Invalid exchange",
+ "Invalid request descriptor",
+ "Exchange full",
+ "No anode",
+ "Invalid request code",
+ "Invalid slot",
+ "Resource deadlock would occur",
+ "Bad font file format",
+ "Device not a stream",
+ "No data available",
+ "Timer expired",
+ "Out of streams resources",
+ "Machine is not on the network",
+ "Package not installed",
+ "Object is remote",
+ "Link has been severed",
+ "Advertise error",
+ "Srmount error",
+ "Communication error on send",
+ "Protocol error",
+ "Multihop attempted",
+ "RFS specific error",
+ "Not a data message",
+ "Value too large for defined data type",
+ "Name not unique on network",
+ "File descriptor in bad state",
+ "Remote address changed",
+ "Can not access a needed shared library",
+ "Accessing a corrupted shared library",
+ ".lib section in a.out corrupted",
+ "Attempting to link in too many shared libraries",
+ "Cannot exec a shared library directly",
+ "Illegal byte sequence",
+ "Interrupted system call should be restarted",
+ "Streams pipe error",
+ "Too many users",
+ "Socket operation on non-socket",
+ "Destination address required",
+ "Message too long",
+ "Protocol wrong type for socket",
+ "Protocol not available",
+ "Protocol not supported",
+ "Socket type not supported",
+ "Operation not supported on transport endpoint",
+ "Protocol family not supported",
+ "Address family not supported by protocol",
+ "Address already in use",
+ "Cannot assign requested address",
+ "Network is down",
+ "Network is unreachable",
+ "Network dropped connection because of reset",
+ "Software caused connection abort",
+ "Connection reset by peer",
+ "No buffer space available",
+ "Transport endpoint is already connected",
+ "Transport endpoint is not connected",
+ "Cannot send after transport endpoint shutdown",
+ "Too many references: cannot splice",
+ "Connection timed out",
+ "Connection refused",
+ "Host is down",
+ "No route to host",
+ "Operation already in progress",
+ "Operation now in progress",
+ "Stale NFS file handle",
+ "Structure needs cleaning",
+ "Not a XENIX named type file",
+ "No XENIX semaphores available",
+ "Is a named type file",
+ "Remote I/O error",
+ "Quota exceeded",
+ "No medium found",
+ "Wrong medium type",
+ "Operation Canceled",
+ "Required key not available",
+ "Key has expired",
+ "Key has been revoked",
+ "Key was rejected by service",
+ "Owner died",
+ "State not recoverable"];
diff --git a/src/libstd/sys/redox/syscall/flag.rs b/src/libstd/sys/redox/syscall/flag.rs
new file mode 100644
index 0000000..5820f1a
--- /dev/null
+++ b/src/libstd/sys/redox/syscall/flag.rs
@@ -0,0 +1,148 @@
+pub const CLONE_VM: usize = 0x100;
+pub const CLONE_FS: usize = 0x200;
+pub const CLONE_FILES: usize = 0x400;
+pub const CLONE_SIGHAND: usize = 0x800;
+pub const CLONE_VFORK: usize = 0x4000;
+pub const CLONE_THREAD: usize = 0x10000;
+
+pub const CLOCK_REALTIME: usize = 1;
+pub const CLOCK_MONOTONIC: usize = 4;
+
+pub const EVENT_NONE: usize = 0;
+pub const EVENT_READ: usize = 1;
+pub const EVENT_WRITE: usize = 2;
+
+pub const F_DUPFD: usize = 0;
+pub const F_GETFD: usize = 1;
+pub const F_SETFD: usize = 2;
+pub const F_GETFL: usize = 3;
+pub const F_SETFL: usize = 4;
+
+pub const FUTEX_WAIT: usize = 0;
+pub const FUTEX_WAKE: usize = 1;
+pub const FUTEX_REQUEUE: usize = 2;
+
+pub const MAP_WRITE: usize = 1;
+pub const MAP_WRITE_COMBINE: usize = 2;
+
+pub const MODE_TYPE: u16 = 0xF000;
+pub const MODE_DIR: u16 = 0x4000;
+pub const MODE_FILE: u16 = 0x8000;
+pub const MODE_SYMLINK: u16 = 0xA000;
+pub const MODE_FIFO: u16 = 0x1000;
+pub const MODE_CHR: u16 = 0x2000;
+
+pub const MODE_PERM: u16 = 0x0FFF;
+pub const MODE_SETUID: u16 = 0o4000;
+pub const MODE_SETGID: u16 = 0o2000;
+
+pub const O_RDONLY: usize = 0x0001_0000;
+pub const O_WRONLY: usize = 0x0002_0000;
+pub const O_RDWR: usize = 0x0003_0000;
+pub const O_NONBLOCK: usize = 0x0004_0000;
+pub const O_APPEND: usize = 0x0008_0000;
+pub const O_SHLOCK: usize = 0x0010_0000;
+pub const O_EXLOCK: usize = 0x0020_0000;
+pub const O_ASYNC: usize = 0x0040_0000;
+pub const O_FSYNC: usize = 0x0080_0000;
+pub const O_CLOEXEC: usize = 0x0100_0000;
+pub const O_CREAT: usize = 0x0200_0000;
+pub const O_TRUNC: usize = 0x0400_0000;
+pub const O_EXCL: usize = 0x0800_0000;
+pub const O_DIRECTORY: usize = 0x1000_0000;
+pub const O_STAT: usize = 0x2000_0000;
+pub const O_SYMLINK: usize = 0x4000_0000;
+pub const O_NOFOLLOW: usize = 0x8000_0000;
+pub const O_ACCMODE: usize = O_RDONLY | O_WRONLY | O_RDWR;
+
+pub const SEEK_SET: usize = 0;
+pub const SEEK_CUR: usize = 1;
+pub const SEEK_END: usize = 2;
+
+pub const SIGHUP: usize = 1;
+pub const SIGINT: usize = 2;
+pub const SIGQUIT: usize = 3;
+pub const SIGILL: usize = 4;
+pub const SIGTRAP: usize = 5;
+pub const SIGABRT: usize = 6;
+pub const SIGBUS: usize = 7;
+pub const SIGFPE: usize = 8;
+pub const SIGKILL: usize = 9;
+pub const SIGUSR1: usize = 10;
+pub const SIGSEGV: usize = 11;
+pub const SIGUSR2: usize = 12;
+pub const SIGPIPE: usize = 13;
+pub const SIGALRM: usize = 14;
+pub const SIGTERM: usize = 15;
+pub const SIGSTKFLT: usize= 16;
+pub const SIGCHLD: usize = 17;
+pub const SIGCONT: usize = 18;
+pub const SIGSTOP: usize = 19;
+pub const SIGTSTP: usize = 20;
+pub const SIGTTIN: usize = 21;
+pub const SIGTTOU: usize = 22;
+pub const SIGURG: usize = 23;
+pub const SIGXCPU: usize = 24;
+pub const SIGXFSZ: usize = 25;
+pub const SIGVTALRM: usize= 26;
+pub const SIGPROF: usize = 27;
+pub const SIGWINCH: usize = 28;
+pub const SIGIO: usize = 29;
+pub const SIGPWR: usize = 30;
+pub const SIGSYS: usize = 31;
+
+pub const SIG_DFL: usize = 0;
+pub const SIG_IGN: usize = 1;
+
+pub const SA_NOCLDSTOP: usize = 0x00000001;
+pub const SA_NOCLDWAIT: usize = 0x00000002;
+pub const SA_SIGINFO: usize = 0x00000004;
+pub const SA_RESTORER: usize = 0x04000000;
+pub const SA_ONSTACK: usize = 0x08000000;
+pub const SA_RESTART: usize = 0x10000000;
+pub const SA_NODEFER: usize = 0x40000000;
+pub const SA_RESETHAND: usize = 0x80000000;
+
+pub const WNOHANG: usize = 0x01;
+pub const WUNTRACED: usize = 0x02;
+pub const WCONTINUED: usize = 0x08;
+
+/// Returns `true` if status indicates the child is stopped.
+pub fn wifstopped(status: usize) -> bool {
+ (status & 0xff) == 0x7f
+}
+
+/// If wifstopped(status), returns the signal that stopped the child.
+pub fn wstopsig(status: usize) -> usize {
+ (status >> 8) & 0xff
+}
+
+/// Returns `true` if status indicates the child continued after a stop.
+pub fn wifcontinued(status: usize) -> bool {
+ status == 0xffff
+}
+
+/// Returns `true` if status indicates termination by a signal.
+pub fn wifsignaled(status: usize) -> bool {
+ ((status & 0x7f) + 1) as i8 >= 2
+}
+
+/// If wifsignaled(status), returns the terminating signal.
+pub fn wtermsig(status: usize) -> usize {
+ status & 0x7f
+}
+
+/// Returns `true` if status indicates normal termination.
+pub fn wifexited(status: usize) -> bool {
+ wtermsig(status) == 0
+}
+
+/// If wifexited(status), returns the exit status.
+pub fn wexitstatus(status: usize) -> usize {
+ (status >> 8) & 0xff
+}
+
+/// Returns `true` if status indicates a core dump was created.
+pub fn wcoredump(status: usize) -> bool {
+ (status & 0x80) != 0
+}
diff --git a/src/libstd/sys/redox/syscall/mod.rs b/src/libstd/sys/redox/syscall/mod.rs
new file mode 100644
index 0000000..b16f5db
--- /dev/null
+++ b/src/libstd/sys/redox/syscall/mod.rs
@@ -0,0 +1,33 @@
+pub use self::arch::*;
+pub use self::call::*;
+pub use self::data::*;
+pub use self::error::*;
+pub use self::flag::*;
+pub use self::number::*;
+
+#[cfg(target_arch = "arm")]
+#[path="arch/arm.rs"]
+mod arch;
+
+#[cfg(target_arch = "x86")]
+#[path="arch/x86.rs"]
+mod arch;
+
+#[cfg(target_arch = "x86_64")]
+#[path="arch/x86_64.rs"]
+mod arch;
+
+/// Function definitions
+pub mod call;
+
+/// Complex structures that are used for some system calls
+pub mod data;
+
+/// All errors that can be generated by a system call
+pub mod error;
+
+/// Flags used as an argument to many system calls
+pub mod flag;
+
+/// Call numbers used by each system call
+pub mod number;
diff --git a/src/libstd/sys/redox/syscall/number.rs b/src/libstd/sys/redox/syscall/number.rs
new file mode 100644
index 0000000..f8884aa
--- /dev/null
+++ b/src/libstd/sys/redox/syscall/number.rs
@@ -0,0 +1,73 @@
+pub const SYS_CLASS: usize = 0xF000_0000;
+pub const SYS_CLASS_PATH: usize=0x1000_0000;
+pub const SYS_CLASS_FILE: usize=0x2000_0000;
+
+pub const SYS_ARG: usize = 0x0F00_0000;
+pub const SYS_ARG_SLICE: usize =0x0100_0000;
+pub const SYS_ARG_MSLICE: usize=0x0200_0000;
+pub const SYS_ARG_PATH: usize = 0x0300_0000;
+
+pub const SYS_RET: usize = 0x00F0_0000;
+pub const SYS_RET_FILE: usize = 0x0010_0000;
+
+pub const SYS_LINK: usize = SYS_CLASS_PATH | SYS_ARG_PATH | 9;
+pub const SYS_OPEN: usize = SYS_CLASS_PATH | SYS_RET_FILE | 5;
+pub const SYS_CHMOD: usize = SYS_CLASS_PATH | 15;
+pub const SYS_RMDIR: usize = SYS_CLASS_PATH | 84;
+pub const SYS_UNLINK: usize = SYS_CLASS_PATH | 10;
+
+pub const SYS_CLOSE: usize = SYS_CLASS_FILE | 6;
+pub const SYS_DUP: usize = SYS_CLASS_FILE | SYS_RET_FILE | 41;
+pub const SYS_DUP2: usize = SYS_CLASS_FILE | SYS_RET_FILE | 63;
+pub const SYS_READ: usize = SYS_CLASS_FILE | SYS_ARG_MSLICE | 3;
+pub const SYS_WRITE: usize = SYS_CLASS_FILE | SYS_ARG_SLICE | 4;
+pub const SYS_LSEEK: usize = SYS_CLASS_FILE | 19;
+pub const SYS_FCHMOD: usize = SYS_CLASS_FILE | 94;
+pub const SYS_FCHOWN: usize = SYS_CLASS_FILE | 207;
+pub const SYS_FCNTL: usize = SYS_CLASS_FILE | 55;
+pub const SYS_FEVENT: usize = SYS_CLASS_FILE | 927;
+pub const SYS_FEXEC: usize = SYS_CLASS_FILE | 11;
+pub const SYS_FMAP: usize = SYS_CLASS_FILE | 90;
+pub const SYS_FUNMAP: usize = SYS_CLASS_FILE | 91;
+pub const SYS_FPATH: usize = SYS_CLASS_FILE | SYS_ARG_MSLICE | 928;
+pub const SYS_FRENAME: usize = SYS_CLASS_FILE | SYS_ARG_PATH | 38;
+pub const SYS_FSTAT: usize = SYS_CLASS_FILE | SYS_ARG_MSLICE | 28;
+pub const SYS_FSTATVFS: usize = SYS_CLASS_FILE | SYS_ARG_MSLICE | 100;
+pub const SYS_FSYNC: usize = SYS_CLASS_FILE | 118;
+pub const SYS_FTRUNCATE: usize =SYS_CLASS_FILE | 93;
+pub const SYS_FUTIMENS: usize = SYS_CLASS_FILE | SYS_ARG_SLICE | 320;
+
+pub const SYS_BRK: usize = 45;
+pub const SYS_CHDIR: usize = 12;
+pub const SYS_CLOCK_GETTIME: usize = 265;
+pub const SYS_CLONE: usize = 120;
+pub const SYS_EXIT: usize = 1;
+pub const SYS_FUTEX: usize = 240;
+pub const SYS_GETCWD: usize = 183;
+pub const SYS_GETEGID: usize = 202;
+pub const SYS_GETENS: usize = 951;
+pub const SYS_GETEUID: usize = 201;
+pub const SYS_GETGID: usize = 200;
+pub const SYS_GETNS: usize = 950;
+pub const SYS_GETPID: usize = 20;
+pub const SYS_GETPGID: usize = 132;
+pub const SYS_GETPPID: usize = 64;
+pub const SYS_GETUID: usize = 199;
+pub const SYS_IOPL: usize = 110;
+pub const SYS_KILL: usize = 37;
+pub const SYS_MKNS: usize = 984;
+pub const SYS_NANOSLEEP: usize =162;
+pub const SYS_PHYSALLOC: usize =945;
+pub const SYS_PHYSFREE: usize = 946;
+pub const SYS_PHYSMAP: usize = 947;
+pub const SYS_PHYSUNMAP: usize =948;
+pub const SYS_VIRTTOPHYS: usize=949;
+pub const SYS_PIPE2: usize = 331;
+pub const SYS_SETPGID: usize = 57;
+pub const SYS_SETREGID: usize = 204;
+pub const SYS_SETRENS: usize = 952;
+pub const SYS_SETREUID: usize = 203;
+pub const SYS_SIGACTION: usize =67;
+pub const SYS_SIGRETURN: usize =119;
+pub const SYS_WAITPID: usize = 7;
+pub const SYS_YIELD: usize = 158;
diff --git a/src/libstd/sys/redox/thread.rs b/src/libstd/sys/redox/thread.rs
new file mode 100644
index 0000000..ae0b91b
--- /dev/null
+++ b/src/libstd/sys/redox/thread.rs
@@ -0,0 +1,85 @@
+use crate::boxed::FnBox;
+use crate::ffi::CStr;
+use crate::io;
+use crate::mem;
+use crate::sys_common::thread::start_thread;
+use crate::sys::{cvt, syscall};
+use crate::time::Duration;
+
+pub const DEFAULT_MIN_STACK_SIZE: usize = 2 * 1024 * 1024;
+
+pub struct Thread {
+ id: usize,
+}
+
+// Some platforms may have pthread_t as a pointer in which case we still want
+// a thread to be Send/Sync
+unsafe impl Send for Thread {}
+unsafe impl Sync for Thread {}
+
+impl Thread {
+ // unsafe: see thread::Builder::spawn_unchecked for safety requirements
+ pub unsafe fn new(_stack: usize, p: Box<dyn FnBox()>) -> io::Result<Thread> {
+ let p = box p;
+
+ let id = cvt(syscall::clone(syscall::CLONE_VM | syscall::CLONE_FS | syscall::CLONE_FILES))?;
+ if id == 0 {
+ start_thread(&*p as *const _ as *mut _);
+ let _ = syscall::exit(0);
+ panic!("thread failed to exit");
+ } else {
+ mem::forget(p);
+ Ok(Thread { id })
+ }
+ }
+
+ pub fn yield_now() {
+ let ret = syscall::sched_yield().expect("failed to sched_yield");
+ debug_assert_eq!(ret, 0);
+ }
+
+ pub fn set_name(_name: &CStr) {
+
+ }
+
+ pub fn sleep(dur: Duration) {
+ let mut secs = dur.as_secs();
+ let mut nsecs = dur.subsec_nanos() as i32;
+
+ // If we're awoken with a signal then the return value will be -1 and
+ // nanosleep will fill in `ts` with the remaining time.
+ while secs > 0 || nsecs > 0 {
+ let req = syscall::TimeSpec {
+ tv_sec: secs as i64,
+ tv_nsec: nsecs,
+ };
+ secs -= req.tv_sec as u64;
+ let mut rem = syscall::TimeSpec::default();
+ if syscall::nanosleep(&req, &mut rem).is_err() {
+ secs += rem.tv_sec as u64;
+ nsecs = rem.tv_nsec;
+ } else {
+ nsecs = 0;
+ }
+ }
+ }
+
+ pub fn join(self) {
+ let mut status = 0;
+ syscall::waitpid(self.id, &mut status, 0).unwrap();
+ }
+
+ pub fn id(&self) -> usize { self.id }
+
+ pub fn into_id(self) -> usize {
+ let id = self.id;
+ mem::forget(self);
+ id
+ }
+}
+
+pub mod guard {
+ pub type Guard = !;
+ pub unsafe fn current() -> Option<Guard> { None }
+ pub unsafe fn init() -> Option<Guard> { None }
+}
diff --git a/src/libstd/sys/redox/thread_local.rs b/src/libstd/sys/redox/thread_local.rs
new file mode 100644
index 0000000..4bc8c4d
--- /dev/null
+++ b/src/libstd/sys/redox/thread_local.rs
@@ -0,0 +1,61 @@
+#![allow(dead_code)] // not used on all platforms
+
+use crate::collections::BTreeMap;
+use crate::ptr;
+use crate::sync::atomic::{AtomicUsize, Ordering};
+
+pub type Key = usize;
+
+type Dtor = unsafe extern fn(*mut u8);
+
+static NEXT_KEY: AtomicUsize = AtomicUsize::new(0);
+
+static mut KEYS: *mut BTreeMap<Key, Option<Dtor>> = ptr::null_mut();
+
+#[thread_local]
+static mut LOCALS: *mut BTreeMap<Key, *mut u8> = ptr::null_mut();
+
+unsafe fn keys() -> &'static mut BTreeMap<Key, Option<Dtor>> {
+ if KEYS == ptr::null_mut() {
+ KEYS = Box::into_raw(Box::new(BTreeMap::new()));
+ }
+ &mut *KEYS
+}
+
+unsafe fn locals() -> &'static mut BTreeMap<Key, *mut u8> {
+ if LOCALS == ptr::null_mut() {
+ LOCALS = Box::into_raw(Box::new(BTreeMap::new()));
+ }
+ &mut *LOCALS
+}
+
+#[inline]
+pub unsafe fn create(dtor: Option<Dtor>) -> Key {
+ let key = NEXT_KEY.fetch_add(1, Ordering::SeqCst);
+ keys().insert(key, dtor);
+ key
+}
+
+#[inline]
+pub unsafe fn get(key: Key) -> *mut u8 {
+ if let Some(&entry) = locals().get(&key) {
+ entry
+ } else {
+ ptr::null_mut()
+ }
+}
+
+#[inline]
+pub unsafe fn set(key: Key, value: *mut u8) {
+ locals().insert(key, value);
+}
+
+#[inline]
+pub unsafe fn destroy(key: Key) {
+ keys().remove(&key);
+}
+
+#[inline]
+pub fn requires_synchronized_create() -> bool {
+ false
+}
diff --git a/src/libstd/sys/redox/time.rs b/src/libstd/sys/redox/time.rs
new file mode 100644
index 0000000..0814374
--- /dev/null
+++ b/src/libstd/sys/redox/time.rs
@@ -0,0 +1,207 @@
+use crate::cmp::Ordering;
+use crate::fmt;
+use crate::sys::{cvt, syscall};
+use crate::time::Duration;
+use crate::convert::TryInto;
+
+use core::hash::{Hash, Hasher};
+
+const NSEC_PER_SEC: u64 = 1_000_000_000;
+
+#[derive(Copy, Clone)]
+struct Timespec {
+ t: syscall::TimeSpec,
+}
+
+impl Timespec {
+ fn sub_timespec(&self, other: &Timespec) -> Result<Duration, Duration> {
+ if self >= other {
+ Ok(if self.t.tv_nsec >= other.t.tv_nsec {
+ Duration::new((self.t.tv_sec - other.t.tv_sec) as u64,
+ (self.t.tv_nsec - other.t.tv_nsec) as u32)
+ } else {
+ Duration::new((self.t.tv_sec - 1 - other.t.tv_sec) as u64,
+ self.t.tv_nsec as u32 + (NSEC_PER_SEC as u32) -
+ other.t.tv_nsec as u32)
+ })
+ } else {
+ match other.sub_timespec(self) {
+ Ok(d) => Err(d),
+ Err(d) => Ok(d),
+ }
+ }
+ }
+
+ fn checked_add_duration(&self, other: &Duration) -> Option<Timespec> {
+ let mut secs = other
+ .as_secs()
+ .try_into() // <- target type would be `i64`
+ .ok()
+ .and_then(|secs| self.t.tv_sec.checked_add(secs))?;
+
+ // Nano calculations can't overflow because nanos are <1B which fit
+ // in a u32.
+ let mut nsec = other.subsec_nanos() + self.t.tv_nsec as u32;
+ if nsec >= NSEC_PER_SEC as u32 {
+ nsec -= NSEC_PER_SEC as u32;
+ secs = secs.checked_add(1)?;
+ }
+ Some(Timespec {
+ t: syscall::TimeSpec {
+ tv_sec: secs,
+ tv_nsec: nsec as i32,
+ },
+ })
+ }
+
+ fn checked_sub_duration(&self, other: &Duration) -> Option<Timespec> {
+ let mut secs = other
+ .as_secs()
+ .try_into() // <- target type would be `i64`
+ .ok()
+ .and_then(|secs| self.t.tv_sec.checked_sub(secs))?;
+
+ // Similar to above, nanos can't overflow.
+ let mut nsec = self.t.tv_nsec as i32 - other.subsec_nanos() as i32;
+ if nsec < 0 {
+ nsec += NSEC_PER_SEC as i32;
+ secs = secs.checked_sub(1)?;
+ }
+ Some(Timespec {
+ t: syscall::TimeSpec {
+ tv_sec: secs,
+ tv_nsec: nsec as i32,
+ },
+ })
+ }
+}
+
+impl PartialEq for Timespec {
+ fn eq(&self, other: &Timespec) -> bool {
+ self.t.tv_sec == other.t.tv_sec && self.t.tv_nsec == other.t.tv_nsec
+ }
+}
+
+impl Eq for Timespec {}
+
+impl PartialOrd for Timespec {
+ fn partial_cmp(&self, other: &Timespec) -> Option<Ordering> {
+ Some(self.cmp(other))
+ }
+}
+
+impl Ord for Timespec {
+ fn cmp(&self, other: &Timespec) -> Ordering {
+ let me = (self.t.tv_sec, self.t.tv_nsec);
+ let other = (other.t.tv_sec, other.t.tv_nsec);
+ me.cmp(&other)
+ }
+}
+
+impl Hash for Timespec {
+ fn hash<H : Hasher>(&self, state: &mut H) {
+ self.t.tv_sec.hash(state);
+ self.t.tv_nsec.hash(state);
+ }
+}
+
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub struct Instant {
+ t: Timespec,
+}
+
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub struct SystemTime {
+ t: Timespec,
+}
+
+pub const UNIX_EPOCH: SystemTime = SystemTime {
+ t: Timespec {
+ t: syscall::TimeSpec {
+ tv_sec: 0,
+ tv_nsec: 0,
+ },
+ },
+};
+
+impl Instant {
+ pub fn now() -> Instant {
+ Instant { t: now(syscall::CLOCK_MONOTONIC) }
+ }
+
+ pub const fn zero() -> Instant {
+ Instant { t: Timespec { t: syscall::TimeSpec { tv_sec: 0, tv_nsec: 0 } } }
+ }
+
+ pub fn actually_monotonic() -> bool {
+ false
+ }
+
+ pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
+ self.t.sub_timespec(&other.t).ok()
+ }
+
+ pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
+ Some(Instant { t: self.t.checked_add_duration(other)? })
+ }
+
+ pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
+ Some(Instant { t: self.t.checked_sub_duration(other)? })
+ }
+}
+
+impl fmt::Debug for Instant {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("Instant")
+ .field("tv_sec", &self.t.t.tv_sec)
+ .field("tv_nsec", &self.t.t.tv_nsec)
+ .finish()
+ }
+}
+
+impl SystemTime {
+ pub fn now() -> SystemTime {
+ SystemTime { t: now(syscall::CLOCK_REALTIME) }
+ }
+
+ pub fn sub_time(&self, other: &SystemTime)
+ -> Result<Duration, Duration> {
+ self.t.sub_timespec(&other.t)
+ }
+
+ pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
+ Some(SystemTime { t: self.t.checked_add_duration(other)? })
+ }
+
+ pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
+ Some(SystemTime { t: self.t.checked_sub_duration(other)? })
+ }
+}
+
+impl From<syscall::TimeSpec> for SystemTime {
+ fn from(t: syscall::TimeSpec) -> SystemTime {
+ SystemTime { t: Timespec { t } }
+ }
+}
+
+impl fmt::Debug for SystemTime {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("SystemTime")
+ .field("tv_sec", &self.t.t.tv_sec)
+ .field("tv_nsec", &self.t.t.tv_nsec)
+ .finish()
+ }
+}
+
+pub type clock_t = usize;
+
+fn now(clock: clock_t) -> Timespec {
+ let mut t = Timespec {
+ t: syscall::TimeSpec {
+ tv_sec: 0,
+ tv_nsec: 0,
+ }
+ };
+ cvt(syscall::clock_gettime(clock, &mut t.t)).unwrap();
+ t
+}
diff --git a/src/libstd/sys/sgx/abi/entry.S b/src/libstd/sys/sgx/abi/entry.S
new file mode 100644
index 0000000..c03e386
--- /dev/null
+++ b/src/libstd/sys/sgx/abi/entry.S
@@ -0,0 +1,314 @@
+/* This symbol is used at runtime to figure out the virtual address that the */
+/* enclave is loaded at. */
+.section absolute
+.global IMAGE_BASE
+IMAGE_BASE:
+
+.section ".note.x86_64-fortanix-unknown-sgx", "", @note
+ .align 4
+ .long 1f - 0f /* name length (not including padding) */
+ .long 3f - 2f /* desc length (not including padding) */
+ .long 1 /* type = NT_VERSION */
+0: .asciz "toolchain-version" /* name */
+1: .align 4
+2: .long 0 /* desc - toolchain version number, 32-bit LE */
+3: .align 4
+
+.section .rodata
+/* The XSAVE area needs to be a large chunk of readable memory, but since we are */
+/* going to restore everything to its initial state (XSTATE_BV=0), only certain */
+/* parts need to have a defined value. In particular: */
+/* */
+/* * MXCSR in the legacy area. This register is always restored if RFBM[1] or */
+/* RFBM[2] is set, regardless of the value of XSTATE_BV */
+/* * XSAVE header */
+.align 64
+.Lxsave_clear:
+.org .+24
+.Lxsave_mxcsr:
+ .int 0
+
+/* We can store a bunch of data in the gap between MXCSR and the XSAVE header */
+
+/* The following symbols point at read-only data that will be filled in by the */
+/* post-linker. */
+
+/* When using this macro, don't forget to adjust the linker version script! */
+.macro globvar name:req size:req
+ .global \name
+ .protected \name
+ .align \size
+ .size \name , \size
+ \name :
+ .org .+\size
+.endm
+ /* The base address (relative to enclave start) of the heap area */
+ globvar HEAP_BASE 8
+ /* The heap size in bytes */
+ globvar HEAP_SIZE 8
+ /* Value of the RELA entry in the dynamic table */
+ globvar RELA 8
+ /* Value of the RELACOUNT entry in the dynamic table */
+ globvar RELACOUNT 8
+ /* The enclave size in bytes */
+ globvar ENCLAVE_SIZE 8
+ /* The base address (relative to enclave start) of the enclave configuration area */
+ globvar CFGDATA_BASE 8
+ /* Non-zero if debugging is enabled, zero otherwise */
+ globvar DEBUG 1
+ /* The base address (relative to enclave start) of the enclave text section */
+ globvar TEXT_BASE 8
+ /* The size in bytes of enclacve text section */
+ globvar TEXT_SIZE 8
+ /* The base address (relative to enclave start) of the enclave EH_FRM_HDR section */
+ globvar EH_FRM_HDR_BASE 8
+ /* The size in bytes of enclacve EH_FRM_HDR section */
+ globvar EH_FRM_HDR_SIZE 8
+
+.Lreentry_panic_msg:
+ .asciz "Re-entered aborted enclave!"
+.Lreentry_panic_msg_end:
+
+.org .Lxsave_clear+512
+.Lxsave_header:
+ .int 0, 0 /* XSTATE_BV */
+ .int 0, 0 /* XCOMP_BV */
+ .org .+48 /* reserved bits */
+
+.data
+.Laborted:
+ .byte 0
+
+/* TCS local storage section */
+.equ tcsls_tos, 0x00 /* initialized by loader to *offset* from image base to TOS */
+.equ tcsls_flags, 0x08 /* initialized by loader */
+.equ tcsls_flag_secondary, 0 /* initialized by loader; 0 = standard TCS, 1 = secondary TCS */
+.equ tcsls_flag_init_once, 1 /* initialized by loader to 0 */
+/* 14 unused bits */
+.equ tcsls_user_fcw, 0x0a
+.equ tcsls_user_mxcsr, 0x0c
+.equ tcsls_last_rsp, 0x10 /* initialized by loader to 0 */
+.equ tcsls_panic_last_rsp, 0x18 /* initialized by loader to 0 */
+.equ tcsls_debug_panic_buf_ptr, 0x20 /* initialized by loader to 0 */
+.equ tcsls_user_rsp, 0x28
+.equ tcsls_user_retip, 0x30
+.equ tcsls_user_rbp, 0x38
+.equ tcsls_user_r12, 0x40
+.equ tcsls_user_r13, 0x48
+.equ tcsls_user_r14, 0x50
+.equ tcsls_user_r15, 0x58
+.equ tcsls_tls_ptr, 0x60
+.equ tcsls_tcs_addr, 0x68
+
+.macro load_tcsls_flag_secondary_bool reg:req comments:vararg
+ .ifne tcsls_flag_secondary /* to convert to a bool, must be the first bit */
+ .abort
+ .endif
+ mov $(1<<tcsls_flag_secondary),%e\reg
+ and %gs:tcsls_flags,%\reg
+.endm
+
+.text
+.global sgx_entry
+.type sgx_entry,function
+sgx_entry:
+/* save user registers */
+ mov %rcx,%gs:tcsls_user_retip
+ mov %rsp,%gs:tcsls_user_rsp
+ mov %rbp,%gs:tcsls_user_rbp
+ mov %r12,%gs:tcsls_user_r12
+ mov %r13,%gs:tcsls_user_r13
+ mov %r14,%gs:tcsls_user_r14
+ mov %r15,%gs:tcsls_user_r15
+ mov %rbx,%gs:tcsls_tcs_addr
+ stmxcsr %gs:tcsls_user_mxcsr
+ fnstcw %gs:tcsls_user_fcw
+/* reset user state */
+ cld /* x86-64 ABI requires DF to be unset at function entry/exit */
+/* check for debug buffer pointer */
+ testb $0xff,DEBUG(%rip)
+ jz .Lskip_debug_init
+ mov %r10,%gs:tcsls_debug_panic_buf_ptr
+.Lskip_debug_init:
+/* check for abort */
+ bt $0,.Laborted(%rip)
+ jc .Lreentry_panic
+/* check if returning from usercall */
+ mov %gs:tcsls_last_rsp,%r11
+ test %r11,%r11
+ jnz .Lusercall_ret
+/* setup stack */
+ mov %gs:tcsls_tos,%rsp /* initially, RSP is not set to the correct value */
+ /* here. This is fixed below under "adjust stack". */
+/* check for thread init */
+ bts $tcsls_flag_init_once,%gs:tcsls_flags
+ jc .Lskip_init
+/* adjust stack */
+ lea IMAGE_BASE(%rip),%rax
+ add %rax,%rsp
+ mov %rsp,%gs:tcsls_tos
+/* call tcs_init */
+/* store caller-saved registers in callee-saved registers */
+ mov %rdi,%rbx
+ mov %rsi,%r12
+ mov %rdx,%r13
+ mov %r8,%r14
+ mov %r9,%r15
+ load_tcsls_flag_secondary_bool di /* RDI = tcs_init() argument: secondary: bool */
+ call tcs_init
+/* reload caller-saved registers */
+ mov %rbx,%rdi
+ mov %r12,%rsi
+ mov %r13,%rdx
+ mov %r14,%r8
+ mov %r15,%r9
+.Lskip_init:
+/* call into main entry point */
+ load_tcsls_flag_secondary_bool cx /* RCX = entry() argument: secondary: bool */
+ call entry /* RDI, RSI, RDX, R8, R9 passed in from userspace */
+ mov %rax,%rsi /* RSI = return value */
+ /* NOP: mov %rdx,%rdx */ /* RDX = return value */
+ xor %rdi,%rdi /* RDI = normal exit */
+.Lexit:
+/* clear general purpose register state */
+ /* RAX overwritten by ENCLU */
+ /* RBX set later */
+ /* RCX overwritten by ENCLU */
+ /* RDX contains return value */
+ /* RSP set later */
+ /* RBP set later */
+ /* RDI contains exit mode */
+ /* RSI contains return value */
+ xor %r8,%r8
+ xor %r9,%r9
+ xor %r10,%r10
+ xor %r11,%r11
+ /* R12 ~ R15 set by sgx_exit */
+.Lsgx_exit:
+/* clear extended register state */
+ mov %rdx, %rcx /* save RDX */
+ mov $-1, %rax
+ mov %rax, %rdx
+ xrstor .Lxsave_clear(%rip)
+ mov %rcx, %rdx /* restore RDX */
+/* clear flags */
+ pushq $0
+ popfq
+/* restore user registers */
+ mov %gs:tcsls_user_r12,%r12
+ mov %gs:tcsls_user_r13,%r13
+ mov %gs:tcsls_user_r14,%r14
+ mov %gs:tcsls_user_r15,%r15
+ mov %gs:tcsls_user_retip,%rbx
+ mov %gs:tcsls_user_rsp,%rsp
+ mov %gs:tcsls_user_rbp,%rbp
+ fldcw %gs:tcsls_user_fcw
+ ldmxcsr %gs:tcsls_user_mxcsr
+/* exit enclave */
+ mov $0x4,%eax /* EEXIT */
+ enclu
+/* end sgx_entry */
+
+.Lreentry_panic:
+ lea .Lreentry_panic_msg(%rip),%rdi
+ mov $.Lreentry_panic_msg_end-.Lreentry_panic_msg,%esi
+ orq $8,%rsp
+ jmp panic_msg
+
+/* This *MUST* be called with 6 parameters, otherwise register information */
+/* might leak! */
+.global usercall
+usercall:
+ test %rcx,%rcx /* check `abort` function argument */
+ jnz .Lusercall_abort /* abort is set, jump to abort code (unlikely forward conditional) */
+ jmp .Lusercall_save_state /* non-aborting usercall */
+.Lusercall_abort:
+/* set aborted bit */
+ movb $1,.Laborted(%rip)
+/* save registers in DEBUG mode, so that debugger can reconstruct the stack */
+ testb $0xff,DEBUG(%rip)
+ jz .Lusercall_noreturn
+.Lusercall_save_state:
+/* save callee-saved state */
+ push %r15
+ push %r14
+ push %r13
+ push %r12
+ push %rbp
+ push %rbx
+ sub $8, %rsp
+ fstcw 4(%rsp)
+ stmxcsr (%rsp)
+ movq %rsp,%gs:tcsls_last_rsp
+.Lusercall_noreturn:
+/* clear general purpose register state */
+ /* RAX overwritten by ENCLU */
+ /* RBX set by sgx_exit */
+ /* RCX overwritten by ENCLU */
+ /* RDX contains parameter */
+ /* RSP set by sgx_exit */
+ /* RBP set by sgx_exit */
+ /* RDI contains parameter */
+ /* RSI contains parameter */
+ /* R8 contains parameter */
+ /* R9 contains parameter */
+ xor %r10,%r10
+ xor %r11,%r11
+ /* R12 ~ R15 set by sgx_exit */
+/* extended registers/flags cleared by sgx_exit */
+/* exit */
+ jmp .Lsgx_exit
+.Lusercall_ret:
+ movq $0,%gs:tcsls_last_rsp
+/* restore callee-saved state, cf. "save" above */
+ mov %r11,%rsp
+ ldmxcsr (%rsp)
+ fldcw 4(%rsp)
+ add $8, %rsp
+ pop %rbx
+ pop %rbp
+ pop %r12
+ pop %r13
+ pop %r14
+ pop %r15
+/* return */
+ mov %rsi,%rax /* RAX = return value */
+ /* NOP: mov %rdx,%rdx */ /* RDX = return value */
+ ret
+
+/*
+The following functions need to be defined externally:
+```
+// Called by entry code when it needs to panic
+extern "C" fn panic_msg(msg: &'static str) -> ! {
+ panic!(msg)
+}
+
+// Called once when a TCS is first entered
+extern "C" fn tcs_init(secondary: bool);
+
+// Standard TCS entrypoint
+extern "C" fn entry(p1: u64, p2: u64, p3: u64, secondary: bool, p4: u64, p5: u64) -> (u64, u64);
+```
+*/
+
+.global get_tcs_addr
+get_tcs_addr:
+ mov %gs:tcsls_tcs_addr,%rax
+ ret
+
+.global get_tls_ptr
+get_tls_ptr:
+ mov %gs:tcsls_tls_ptr,%rax
+ ret
+
+.global set_tls_ptr
+set_tls_ptr:
+ mov %rdi,%gs:tcsls_tls_ptr
+ ret
+
+.global take_debug_panic_buf_ptr
+take_debug_panic_buf_ptr:
+ xor %rax,%rax
+ xchg %gs:tcsls_debug_panic_buf_ptr,%rax
+ ret
diff --git a/src/libstd/sys/sgx/abi/mem.rs b/src/libstd/sys/sgx/abi/mem.rs
new file mode 100644
index 0000000..808f1ce
--- /dev/null
+++ b/src/libstd/sys/sgx/abi/mem.rs
@@ -0,0 +1,45 @@
+// Do not remove inline: will result in relocation failure
+#[inline(always)]
+pub(crate) unsafe fn rel_ptr<T>(offset: u64) -> *const T {
+ (image_base() + offset) as *const T
+}
+
+// Do not remove inline: will result in relocation failure
+#[inline(always)]
+pub(crate) unsafe fn rel_ptr_mut<T>(offset: u64) -> *mut T {
+ (image_base() + offset) as *mut T
+}
+
+extern {
+ static ENCLAVE_SIZE: usize;
+}
+
+// Do not remove inline: will result in relocation failure
+// For the same reason we use inline ASM here instead of an extern static to
+// locate the base
+/// Returns address at which current enclave is loaded.
+#[inline(always)]
+#[unstable(feature = "sgx_platform", issue = "56975")]
+pub fn image_base() -> u64 {
+ let base;
+ unsafe { asm!("lea IMAGE_BASE(%rip),$0":"=r"(base)) };
+ base
+}
+
+/// Returns `true` if the specified memory range is in the enclave.
+#[unstable(feature = "sgx_platform", issue = "56975")]
+pub fn is_enclave_range(p: *const u8, len: usize) -> bool {
+ let start=p as u64;
+ let end=start + (len as u64);
+ start >= image_base() &&
+ end <= image_base() + (unsafe { ENCLAVE_SIZE } as u64) // unsafe ok: link-time constant
+}
+
+/// Returns `true` if the specified memory range is in userspace.
+#[unstable(feature = "sgx_platform", issue = "56975")]
+pub fn is_user_range(p: *const u8, len: usize) -> bool {
+ let start=p as u64;
+ let end=start + (len as u64);
+ end <= image_base() ||
+ start >= image_base() + (unsafe { ENCLAVE_SIZE } as u64) // unsafe ok: link-time constant
+}
diff --git a/src/libstd/sys/sgx/abi/mod.rs b/src/libstd/sys/sgx/abi/mod.rs
new file mode 100644
index 0000000..1f433e2
--- /dev/null
+++ b/src/libstd/sys/sgx/abi/mod.rs
@@ -0,0 +1,94 @@
+#![cfg_attr(test, allow(unused))] // RT initialization logic is not compiled for test
+
+use core::sync::atomic::{AtomicUsize, Ordering};
+use crate::io::Write;
+
+// runtime features
+mod reloc;
+pub(super) mod panic;
+
+// library features
+pub mod mem;
+pub mod thread;
+pub mod tls;
+#[macro_use]
+pub mod usercalls;
+
+#[cfg(not(test))]
+global_asm!(include_str!("entry.S"));
+
+#[cfg(not(test))]
+#[no_mangle]
+unsafe extern "C" fn tcs_init(secondary: bool) {
+ // Be very careful when changing this code: it runs before the binary has been
+ // relocated. Any indirect accesses to symbols will likely fail.
+ const UNINIT: usize = 0;
+ const BUSY: usize = 1;
+ const DONE: usize = 2;
+ // Three-state spin-lock
+ static RELOC_STATE: AtomicUsize = AtomicUsize::new(UNINIT);
+
+ if secondary && RELOC_STATE.load(Ordering::Relaxed) != DONE {
+ panic::panic_msg("Entered secondary TCS before main TCS!")
+ }
+
+ // Try to atomically swap UNINIT with BUSY. The returned state can be:
+ match RELOC_STATE.compare_and_swap(UNINIT, BUSY, Ordering::Acquire) {
+ // This thread just obtained the lock and other threads will observe BUSY
+ UNINIT => {
+ reloc::relocate_elf_rela();
+ RELOC_STATE.store(DONE, Ordering::Release);
+ },
+ // We need to wait until the initialization is done.
+ BUSY => while RELOC_STATE.load(Ordering::Acquire) == BUSY {
+ core::arch::x86_64::_mm_pause()
+ },
+ // Initialization is done.
+ DONE => {},
+ _ => unreachable!()
+ }
+}
+
+// FIXME: this item should only exist if this is linked into an executable
+// (main function exists). If this is a library, the crate author should be
+// able to specify this
+#[cfg(not(test))]
+#[no_mangle]
+extern "C" fn entry(p1: u64, p2: u64, p3: u64, secondary: bool, p4: u64, p5: u64) -> (u64, u64) {
+ // FIXME: how to support TLS in library mode?
+ let tls = Box::new(tls::Tls::new());
+ let _tls_guard = unsafe { tls.activate() };
+
+ if secondary {
+ super::thread::Thread::entry();
+
+ (0, 0)
+ } else {
+ extern "C" {
+ fn main(argc: isize, argv: *const *const u8) -> isize;
+ }
+
+ // check entry is being called according to ABI
+ rtassert!(p3 == 0);
+ rtassert!(p4 == 0);
+ rtassert!(p5 == 0);
+
+ unsafe {
+ // The actual types of these arguments are `p1: *const Arg, p2:
+ // usize`. We can't currently customize the argument list of Rust's
+ // main function, so we pass these in as the standard pointer-sized
+ // values in `argc` and `argv`.
+ let ret = main(p2 as _, p1 as _);
+ exit_with_code(ret)
+ }
+ }
+}
+
+pub(super) fn exit_with_code(code: isize) -> ! {
+ if code != 0 {
+ if let Some(mut out) = panic::SgxPanicOutput::new() {
+ let _ = write!(out, "Exited with status code {}", code);
+ }
+ }
+ usercalls::exit(code != 0);
+}
diff --git a/src/libstd/sys/sgx/abi/panic.rs b/src/libstd/sys/sgx/abi/panic.rs
new file mode 100644
index 0000000..de86394
--- /dev/null
+++ b/src/libstd/sys/sgx/abi/panic.rs
@@ -0,0 +1,56 @@
+use super::usercalls::{alloc::UserRef, self};
+use crate::cmp;
+use crate::io::{self, Write};
+use crate::mem;
+
+extern "C" {
+ fn take_debug_panic_buf_ptr() -> *mut u8;
+ static DEBUG: u8;
+}
+
+pub(crate) struct SgxPanicOutput(Option<&'static mut UserRef<[u8]>>);
+
+fn empty_user_slice() -> &'static mut UserRef<[u8]> {
+ unsafe { UserRef::from_raw_parts_mut(1 as *mut u8, 0) }
+}
+
+impl SgxPanicOutput {
+ pub(crate) fn new() -> Option<Self> {
+ if unsafe { DEBUG == 0 } {
+ None
+ } else {
+ Some(SgxPanicOutput(None))
+ }
+ }
+
+ fn init(&mut self) -> &mut &'static mut UserRef<[u8]> {
+ self.0.get_or_insert_with(|| unsafe {
+ let ptr = take_debug_panic_buf_ptr();
+ if ptr.is_null() {
+ empty_user_slice()
+ } else {
+ UserRef::from_raw_parts_mut(ptr, 1024)
+ }
+ })
+ }
+}
+
+impl Write for SgxPanicOutput {
+ fn write(&mut self, src: &[u8]) -> io::Result<usize> {
+ let dst = mem::replace(self.init(), empty_user_slice());
+ let written = cmp::min(src.len(), dst.len());
+ dst[..written].copy_from_enclave(&src[..written]);
+ self.0 = Some(&mut dst[written..]);
+ Ok(written)
+ }
+
+ fn flush(&mut self) -> io::Result<()> {
+ Ok(())
+ }
+}
+
+#[cfg_attr(not(test), no_mangle)]
+pub extern "C" fn panic_msg(msg: &str) -> ! {
+ let _ = SgxPanicOutput::new().map(|mut out| out.write(msg.as_bytes()));
+ usercalls::exit(true)
+}
diff --git a/src/libstd/sys/sgx/abi/reloc.rs b/src/libstd/sys/sgx/abi/reloc.rs
new file mode 100644
index 0000000..6dd24c5
--- /dev/null
+++ b/src/libstd/sys/sgx/abi/reloc.rs
@@ -0,0 +1,30 @@
+use crate::slice::from_raw_parts;
+use super::mem;
+
+const R_X86_64_RELATIVE: u32 = 8;
+
+#[repr(packed)]
+struct Rela<T> {
+ offset: T,
+ info: T,
+ addend: T,
+}
+
+pub fn relocate_elf_rela() {
+ extern {
+ static RELA: u64;
+ static RELACOUNT: usize;
+ }
+
+ if unsafe { RELACOUNT } == 0 { return } // unsafe ok: link-time constant
+
+ let relas = unsafe {
+ from_raw_parts::<Rela<u64>>(mem::rel_ptr(RELA), RELACOUNT) // unsafe ok: link-time constant
+ };
+ for rela in relas {
+ if rela.info != (/*0 << 32 |*/ R_X86_64_RELATIVE as u64) {
+ rtabort!("Invalid relocation");
+ }
+ unsafe { *mem::rel_ptr_mut::<*const ()>(rela.offset) = mem::rel_ptr(rela.addend) };
+ }
+}
diff --git a/src/libstd/sys/sgx/abi/thread.rs b/src/libstd/sys/sgx/abi/thread.rs
new file mode 100644
index 0000000..c17fa2d
--- /dev/null
+++ b/src/libstd/sys/sgx/abi/thread.rs
@@ -0,0 +1,11 @@
+use fortanix_sgx_abi::Tcs;
+
+/// Gets the ID for the current thread. The ID is guaranteed to be unique among
+/// all currently running threads in the enclave, and it is guaranteed to be
+/// constant for the lifetime of the thread. More specifically for SGX, there
+/// is a one-to-one correspondence of the ID to the address of the TCS.
+#[unstable(feature = "sgx_platform", issue = "56975")]
+pub fn current() -> Tcs {
+ extern "C" { fn get_tcs_addr() -> Tcs; }
+ unsafe { get_tcs_addr() }
+}
diff --git a/src/libstd/sys/sgx/abi/tls.rs b/src/libstd/sys/sgx/abi/tls.rs
new file mode 100644
index 0000000..03e08ad
--- /dev/null
+++ b/src/libstd/sys/sgx/abi/tls.rs
@@ -0,0 +1,244 @@
+use crate::sync::atomic::{AtomicUsize, Ordering};
+use crate::ptr;
+use crate::mem;
+use crate::cell::Cell;
+use crate::num::NonZeroUsize;
+use self::sync_bitset::*;
+
+#[cfg(target_pointer_width="64")]
+const USIZE_BITS: usize = 64;
+const TLS_KEYS: usize = 128; // Same as POSIX minimum
+const TLS_KEYS_BITSET_SIZE: usize = (TLS_KEYS + (USIZE_BITS - 1)) / USIZE_BITS;
+
+#[cfg_attr(test, linkage = "available_externally")]
+#[export_name = "_ZN16__rust_internals3std3sys3sgx3abi3tls14TLS_KEY_IN_USEE"]
+static TLS_KEY_IN_USE: SyncBitset = SYNC_BITSET_INIT;
+macro_rules! dup {
+ ((* $($exp:tt)*) $($val:tt)*) => (dup!( ($($exp)*) $($val)* $($val)* ));
+ (() $($val:tt)*) => ([$($val),*])
+}
+#[cfg_attr(test, linkage = "available_externally")]
+#[export_name = "_ZN16__rust_internals3std3sys3sgx3abi3tls14TLS_DESTRUCTORE"]
+static TLS_DESTRUCTOR: [AtomicUsize; TLS_KEYS] = dup!((* * * * * * *) (AtomicUsize::new(0)));
+
+extern "C" {
+ fn get_tls_ptr() -> *const u8;
+ fn set_tls_ptr(tls: *const u8);
+}
+
+#[derive(Copy, Clone)]
+#[repr(C)]
+pub struct Key(NonZeroUsize);
+
+impl Key {
+ fn to_index(self) -> usize {
+ self.0.get() - 1
+ }
+
+ fn from_index(index: usize) -> Self {
+ Key(NonZeroUsize::new(index + 1).unwrap())
+ }
+
+ pub fn as_usize(self) -> usize {
+ self.0.get()
+ }
+
+ pub fn from_usize(index: usize) -> Self {
+ Key(NonZeroUsize::new(index).unwrap())
+ }
+}
+
+#[repr(C)]
+pub struct Tls {
+ data: [Cell<*mut u8>; TLS_KEYS]
+}
+
+pub struct ActiveTls<'a> {
+ tls: &'a Tls
+}
+
+impl<'a> Drop for ActiveTls<'a> {
+ fn drop(&mut self) {
+ let value_with_destructor = |key: usize| {
+ let ptr = TLS_DESTRUCTOR[key].load(Ordering::Relaxed);
+ unsafe { mem::transmute::<_,Option<unsafe extern fn(*mut u8)>>(ptr) }
+ .map(|dtor| (&self.tls.data[key], dtor))
+ };
+
+ let mut any_non_null_dtor = true;
+ while any_non_null_dtor {
+ any_non_null_dtor = false;
+ for (value, dtor) in TLS_KEY_IN_USE.iter().filter_map(&value_with_destructor) {
+ let value = value.replace(ptr::null_mut());
+ if value != ptr::null_mut() {
+ any_non_null_dtor = true;
+ unsafe { dtor(value) }
+ }
+ }
+ }
+ }
+}
+
+impl Tls {
+ pub fn new() -> Tls {
+ Tls { data: dup!((* * * * * * *) (Cell::new(ptr::null_mut()))) }
+ }
+
+ pub unsafe fn activate(&self) -> ActiveTls<'_> {
+ set_tls_ptr(self as *const Tls as _);
+ ActiveTls { tls: self }
+ }
+
+ #[allow(unused)]
+ pub unsafe fn activate_persistent(self: Box<Self>) {
+ set_tls_ptr((&*self) as *const Tls as _);
+ mem::forget(self);
+ }
+
+ unsafe fn current<'a>() -> &'a Tls {
+ &*(get_tls_ptr() as *const Tls)
+ }
+
+ pub fn create(dtor: Option<unsafe extern fn(*mut u8)>) -> Key {
+ let index = if let Some(index) = TLS_KEY_IN_USE.set() {
+ index
+ } else {
+ rtabort!("TLS limit exceeded")
+ };
+ TLS_DESTRUCTOR[index].store(dtor.map_or(0, |f| f as usize), Ordering::Relaxed);
+ Key::from_index(index)
+ }
+
+ pub fn set(key: Key, value: *mut u8) {
+ let index = key.to_index();
+ rtassert!(TLS_KEY_IN_USE.get(index));
+ unsafe { Self::current() }.data[index].set(value);
+ }
+
+ pub fn get(key: Key) -> *mut u8 {
+ let index = key.to_index();
+ rtassert!(TLS_KEY_IN_USE.get(index));
+ unsafe { Self::current() }.data[index].get()
+ }
+
+ pub fn destroy(key: Key) {
+ TLS_KEY_IN_USE.clear(key.to_index());
+ }
+}
+
+mod sync_bitset {
+ use crate::sync::atomic::{AtomicUsize, Ordering};
+ use crate::iter::{Enumerate, Peekable};
+ use crate::slice::Iter;
+ use super::{TLS_KEYS_BITSET_SIZE, USIZE_BITS};
+
+ /// A bitset that can be used synchronously.
+ pub(super) struct SyncBitset([AtomicUsize; TLS_KEYS_BITSET_SIZE]);
+
+ pub(super) const SYNC_BITSET_INIT: SyncBitset =
+ SyncBitset([AtomicUsize::new(0), AtomicUsize::new(0)]);
+
+ impl SyncBitset {
+ pub fn get(&self, index: usize) -> bool {
+ let (hi, lo) = Self::split(index);
+ (self.0[hi].load(Ordering::Relaxed) & lo) != 0
+ }
+
+ /// Not atomic.
+ pub fn iter(&self) -> SyncBitsetIter<'_> {
+ SyncBitsetIter {
+ iter: self.0.iter().enumerate().peekable(),
+ elem_idx: 0,
+ }
+ }
+
+ pub fn clear(&self, index: usize) {
+ let (hi, lo) = Self::split(index);
+ self.0[hi].fetch_and(!lo, Ordering::Relaxed);
+ }
+
+ /// Sets any unset bit. Not atomic. Returns `None` if all bits were
+ /// observed to be set.
+ pub fn set(&self) -> Option<usize> {
+ 'elems: for (idx, elem) in self.0.iter().enumerate() {
+ let mut current = elem.load(Ordering::Relaxed);
+ loop {
+ if 0 == !current {
+ continue 'elems;
+ }
+ let trailing_ones = (!current).trailing_zeros() as usize;
+ match elem.compare_exchange(
+ current,
+ current | (1 << trailing_ones),
+ Ordering::AcqRel,
+ Ordering::Relaxed
+ ) {
+ Ok(_) => return Some(idx * USIZE_BITS + trailing_ones),
+ Err(previous) => current = previous,
+ }
+ }
+ }
+ None
+ }
+
+ fn split(index: usize) -> (usize, usize) {
+ (index / USIZE_BITS, 1 << (index % USIZE_BITS))
+ }
+ }
+
+ pub(super) struct SyncBitsetIter<'a> {
+ iter: Peekable<Enumerate<Iter<'a, AtomicUsize>>>,
+ elem_idx: usize,
+ }
+
+ impl<'a> Iterator for SyncBitsetIter<'a> {
+ type Item = usize;
+
+ fn next(&mut self) -> Option<usize> {
+ self.iter.peek().cloned().and_then(|(idx, elem)| {
+ let elem = elem.load(Ordering::Relaxed);
+ let low_mask = (1 << self.elem_idx) - 1;
+ let next = elem & !low_mask;
+ let next_idx = next.trailing_zeros() as usize;
+ self.elem_idx = next_idx + 1;
+ if self.elem_idx >= 64 {
+ self.elem_idx = 0;
+ self.iter.next();
+ }
+ match next_idx {
+ 64 => self.next(),
+ _ => Some(idx * USIZE_BITS + next_idx),
+ }
+ })
+ }
+ }
+
+ #[cfg(test)]
+ mod tests {
+ use super::*;
+
+ fn test_data(bitset: [usize; 2], bit_indices: &[usize]) {
+ let set = SyncBitset([AtomicUsize::new(bitset[0]), AtomicUsize::new(bitset[1])]);
+ assert_eq!(set.iter().collect::<Vec<_>>(), bit_indices);
+ for &i in bit_indices {
+ assert!(set.get(i));
+ }
+ }
+
+ #[test]
+ fn iter() {
+ test_data([0b0110_1001, 0], &[0, 3, 5, 6]);
+ test_data([0x8000_0000_0000_0000, 0x8000_0000_0000_0001], &[63, 64, 127]);
+ test_data([0, 0], &[]);
+ }
+
+ #[test]
+ fn set_get_clear() {
+ let set = SYNC_BITSET_INIT;
+ let key = set.set().unwrap();
+ assert!(set.get(key));
+ set.clear(key);
+ assert!(!set.get(key));
+ }
+ }
+}
diff --git a/src/libstd/sys/sgx/abi/usercalls/alloc.rs b/src/libstd/sys/sgx/abi/usercalls/alloc.rs
new file mode 100644
index 0000000..22ae2a8
--- /dev/null
+++ b/src/libstd/sys/sgx/abi/usercalls/alloc.rs
@@ -0,0 +1,562 @@
+#![allow(unused)]
+
+use crate::ptr::{self, NonNull};
+use crate::mem;
+use crate::cell::UnsafeCell;
+use crate::slice;
+use crate::ops::{Deref, DerefMut, Index, IndexMut, CoerceUnsized};
+use crate::slice::SliceIndex;
+
+use fortanix_sgx_abi::*;
+use super::super::mem::is_user_range;
+
+/// A type that can be safely read from or written to userspace.
+///
+/// Non-exhaustive list of specific requirements for reading and writing:
+/// * **Type is `Copy`** (and therefore also not `Drop`). Copies will be
+/// created when copying from/to userspace. Destructors will not be called.
+/// * **No references or Rust-style owned pointers** (`Vec`, `Arc`, etc.). When
+/// reading from userspace, references into enclave memory must not be
+/// created. Also, only enclave memory is considered managed by the Rust
+/// compiler's static analysis. When reading from userspace, there can be no
+/// guarantee that the value correctly adheres to the expectations of the
+/// type. When writing to userspace, memory addresses of data in enclave
+/// memory must not be leaked for confidentiality reasons. `User` and
+/// `UserRef` are also not allowed for the same reasons.
+/// * **No fat pointers.** When reading from userspace, the size or vtable
+/// pointer could be automatically interpreted and used by the code. When
+/// writing to userspace, memory addresses of data in enclave memory (such
+/// as vtable pointers) must not be leaked for confidentiality reasons.
+///
+/// Non-exhaustive list of specific requirements for reading from userspace:
+/// * **Any bit pattern is valid** for this type (no `enum`s). There can be no
+/// guarantee that the value correctly adheres to the expectations of the
+/// type, so any value must be valid for this type.
+///
+/// Non-exhaustive list of specific requirements for writing to userspace:
+/// * **No pointers to enclave memory.** Memory addresses of data in enclave
+/// memory must not be leaked for confidentiality reasons.
+/// * **No internal padding.** Padding might contain previously-initialized
+/// secret data stored at that memory location and must not be leaked for
+/// confidentiality reasons.
+#[unstable(feature = "sgx_platform", issue = "56975")]
+pub unsafe trait UserSafeSized: Copy + Sized {}
+
+#[unstable(feature = "sgx_platform", issue = "56975")]
+unsafe impl UserSafeSized for u8 {}
+#[unstable(feature = "sgx_platform", issue = "56975")]
+unsafe impl<T> UserSafeSized for FifoDescriptor<T> {}
+#[unstable(feature = "sgx_platform", issue = "56975")]
+unsafe impl UserSafeSized for ByteBuffer {}
+#[unstable(feature = "sgx_platform", issue = "56975")]
+unsafe impl UserSafeSized for Usercall {}
+#[unstable(feature = "sgx_platform", issue = "56975")]
+unsafe impl UserSafeSized for Return {}
+#[unstable(feature = "sgx_platform", issue = "56975")]
+unsafe impl<T: UserSafeSized> UserSafeSized for [T; 2] {}
+
+/// A type that can be represented in memory as one or more `UserSafeSized`s.
+#[unstable(feature = "sgx_platform", issue = "56975")]
+pub unsafe trait UserSafe {
+ /// Equivalent to `mem::align_of::<Self>`.
+ fn align_of() -> usize;
+
+ /// Construct a pointer to `Self` given a memory range in user space.
+ ///
+ /// N.B., this takes a size, not a length!
+ ///
+ /// # Safety
+ ///
+ /// The caller must ensure the memory range is in user memory, is the
+ /// correct size and is correctly aligned and points to the right type.
+ unsafe fn from_raw_sized_unchecked(ptr: *mut u8, size: usize) -> *mut Self;
+
+ /// Construct a pointer to `Self` given a memory range.
+ ///
+ /// N.B., this takes a size, not a length!
+ ///
+ /// # Safety
+ ///
+ /// The caller must ensure the memory range points to the correct type.
+ ///
+ /// # Panics
+ ///
+ /// This function panics if:
+ ///
+ /// * the pointer is not aligned.
+ /// * the pointer is null.
+ /// * the pointed-to range is not in user memory.
+ unsafe fn from_raw_sized(ptr: *mut u8, size: usize) -> NonNull<Self> {
+ let ret = Self::from_raw_sized_unchecked(ptr, size);
+ Self::check_ptr(ret);
+ NonNull::new_unchecked(ret as _)
+ }
+
+ /// Checks if a pointer may point to `Self` in user memory.
+ ///
+ /// # Safety
+ ///
+ /// The caller must ensure the memory range points to the correct type and
+ /// length (if this is a slice).
+ ///
+ /// # Panics
+ ///
+ /// This function panics if:
+ ///
+ /// * the pointer is not aligned.
+ /// * the pointer is null.
+ /// * the pointed-to range is not in user memory.
+ unsafe fn check_ptr(ptr: *const Self) {
+ let is_aligned = |p| -> bool {
+ 0 == (p as usize) & (Self::align_of() - 1)
+ };
+
+ assert!(is_aligned(ptr as *const u8));
+ assert!(is_user_range(ptr as _, mem::size_of_val(&*ptr)));
+ assert!(!ptr.is_null());
+ }
+}
+
+#[unstable(feature = "sgx_platform", issue = "56975")]
+unsafe impl<T: UserSafeSized> UserSafe for T {
+ fn align_of() -> usize {
+ mem::align_of::<T>()
+ }
+
+ unsafe fn from_raw_sized_unchecked(ptr: *mut u8, size: usize) -> *mut Self {
+ assert_eq!(size, mem::size_of::<T>());
+ ptr as _
+ }
+}
+
+#[unstable(feature = "sgx_platform", issue = "56975")]
+unsafe impl<T: UserSafeSized> UserSafe for [T] {
+ fn align_of() -> usize {
+ mem::align_of::<T>()
+ }
+
+ unsafe fn from_raw_sized_unchecked(ptr: *mut u8, size: usize) -> *mut Self {
+ let elem_size = mem::size_of::<T>();
+ assert_eq!(size % elem_size, 0);
+ let len = size / elem_size;
+ slice::from_raw_parts_mut(ptr as _, len)
+ }
+}
+
+/// A reference to some type in userspace memory. `&UserRef<T>` is equivalent
+/// to `&T` in enclave memory. Access to the memory is only allowed by copying
+/// to avoid TOCTTOU issues. After copying, code should make sure to completely
+/// check the value before use.
+///
+/// It is also possible to obtain a mutable reference `&mut UserRef<T>`. Unlike
+/// regular mutable references, these are not exclusive. Userspace may always
+/// write to the backing memory at any time, so it can't be assumed that there
+/// the pointed-to memory is uniquely borrowed. The two different refence types
+/// are used solely to indicate intent: a mutable reference is for writing to
+/// user memory, an immutable reference for reading from user memory.
+#[unstable(feature = "sgx_platform", issue = "56975")]
+pub struct UserRef<T: ?Sized>(UnsafeCell<T>);
+/// An owned type in userspace memory. `User<T>` is equivalent to `Box<T>` in
+/// enclave memory. Access to the memory is only allowed by copying to avoid
+/// TOCTTOU issues. The user memory will be freed when the value is dropped.
+/// After copying, code should make sure to completely check the value before
+/// use.
+#[unstable(feature = "sgx_platform", issue = "56975")]
+pub struct User<T: UserSafe + ?Sized>(NonNull<UserRef<T>>);
+
+trait NewUserRef<T: ?Sized> {
+ unsafe fn new_userref(v: T) -> Self;
+}
+
+impl<T: ?Sized> NewUserRef<*mut T> for NonNull<UserRef<T>> {
+ unsafe fn new_userref(v: *mut T) -> Self {
+ NonNull::new_unchecked(v as _)
+ }
+}
+
+impl<T: ?Sized> NewUserRef<NonNull<T>> for NonNull<UserRef<T>> {
+ unsafe fn new_userref(v: NonNull<T>) -> Self {
+ NonNull::new_userref(v.as_ptr())
+ }
+}
+
+#[unstable(feature = "sgx_platform", issue = "56975")]
+impl<T: ?Sized> User<T> where T: UserSafe {
+ // This function returns memory that is practically uninitialized, but is
+ // not considered "unspecified" or "undefined" for purposes of an
+ // optimizing compiler. This is achieved by returning a pointer from
+ // from outside as obtained by `super::alloc`.
+ fn new_uninit_bytes(size: usize) -> Self {
+ unsafe {
+ // Mustn't call alloc with size 0.
+ let ptr = if size > 0 {
+ rtunwrap!(Ok, super::alloc(size, T::align_of())) as _
+ } else {
+ T::align_of() as _ // dangling pointer ok for size 0
+ };
+ if let Ok(v) = crate::panic::catch_unwind(|| T::from_raw_sized(ptr, size)) {
+ User(NonNull::new_userref(v))
+ } else {
+ rtabort!("Got invalid pointer from alloc() usercall")
+ }
+ }
+ }
+
+ /// Copies `val` into freshly allocated space in user memory.
+ pub fn new_from_enclave(val: &T) -> Self {
+ unsafe {
+ let ret = Self::new_uninit_bytes(mem::size_of_val(val));
+ ptr::copy(
+ val as *const T as *const u8,
+ ret.0.as_ptr() as *mut u8,
+ mem::size_of_val(val)
+ );
+ ret
+ }
+ }
+
+ /// Creates an owned `User<T>` from a raw pointer.
+ ///
+ /// # Safety
+ /// The caller must ensure `ptr` points to `T`, is freeable with the `free`
+ /// usercall and the alignment of `T`, and is uniquely owned.
+ ///
+ /// # Panics
+ /// This function panics if:
+ ///
+ /// * The pointer is not aligned
+ /// * The pointer is null
+ /// * The pointed-to range is not in user memory
+ pub unsafe fn from_raw(ptr: *mut T) -> Self {
+ T::check_ptr(ptr);
+ User(NonNull::new_userref(ptr))
+ }
+
+ /// Converts this value into a raw pointer. The value will no longer be
+ /// automatically freed.
+ pub fn into_raw(self) -> *mut T {
+ let ret = self.0;
+ mem::forget(self);
+ ret.as_ptr() as _
+ }
+}
+
+#[unstable(feature = "sgx_platform", issue = "56975")]
+impl<T> User<T> where T: UserSafe {
+ /// Allocate space for `T` in user memory.
+ pub fn uninitialized() -> Self {
+ Self::new_uninit_bytes(mem::size_of::<T>())
+ }
+}
+
+#[unstable(feature = "sgx_platform", issue = "56975")]
+impl<T> User<[T]> where [T]: UserSafe {
+ /// Allocate space for a `[T]` of `n` elements in user memory.
+ pub fn uninitialized(n: usize) -> Self {
+ Self::new_uninit_bytes(n * mem::size_of::<T>())
+ }
+
+ /// Creates an owned `User<[T]>` from a raw thin pointer and a slice length.
+ ///
+ /// # Safety
+ /// The caller must ensure `ptr` points to `len` elements of `T`, is
+ /// freeable with the `free` usercall and the alignment of `T`, and is
+ /// uniquely owned.
+ ///
+ /// # Panics
+ /// This function panics if:
+ ///
+ /// * The pointer is not aligned
+ /// * The pointer is null
+ /// * The pointed-to range is not in user memory
+ pub unsafe fn from_raw_parts(ptr: *mut T, len: usize) -> Self {
+ User(NonNull::new_userref(<[T]>::from_raw_sized(ptr as _, len * mem::size_of::<T>())))
+ }
+}
+
+#[unstable(feature = "sgx_platform", issue = "56975")]
+impl<T: ?Sized> UserRef<T> where T: UserSafe {
+ /// Creates a `&UserRef<[T]>` from a raw pointer.
+ ///
+ /// # Safety
+ /// The caller must ensure `ptr` points to `T`.
+ ///
+ /// # Panics
+ /// This function panics if:
+ ///
+ /// * The pointer is not aligned
+ /// * The pointer is null
+ /// * The pointed-to range is not in user memory
+ pub unsafe fn from_ptr<'a>(ptr: *const T) -> &'a Self {
+ T::check_ptr(ptr);
+ &*(ptr as *const Self)
+ }
+
+ /// Creates a `&mut UserRef<[T]>` from a raw pointer. See the struct
+ /// documentation for the nuances regarding a `&mut UserRef<T>`.
+ ///
+ /// # Safety
+ /// The caller must ensure `ptr` points to `T`.
+ ///
+ /// # Panics
+ /// This function panics if:
+ ///
+ /// * The pointer is not aligned
+ /// * The pointer is null
+ /// * The pointed-to range is not in user memory
+ pub unsafe fn from_mut_ptr<'a>(ptr: *mut T) -> &'a mut Self {
+ T::check_ptr(ptr);
+ &mut*(ptr as *mut Self)
+ }
+
+ /// Copies `val` into user memory.
+ ///
+ /// # Panics
+ /// This function panics if the destination doesn't have the same size as
+ /// the source. This can happen for dynamically-sized types such as slices.
+ pub fn copy_from_enclave(&mut self, val: &T) {
+ unsafe {
+ assert_eq!(mem::size_of_val(val), mem::size_of_val( &*self.0.get() ));
+ ptr::copy(
+ val as *const T as *const u8,
+ self.0.get() as *mut T as *mut u8,
+ mem::size_of_val(val)
+ );
+ }
+ }
+
+ /// Copies the value from user memory and place it into `dest`.
+ ///
+ /// # Panics
+ /// This function panics if the destination doesn't have the same size as
+ /// the source. This can happen for dynamically-sized types such as slices.
+ pub fn copy_to_enclave(&self, dest: &mut T) {
+ unsafe {
+ assert_eq!(mem::size_of_val(dest), mem::size_of_val( &*self.0.get() ));
+ ptr::copy(
+ self.0.get() as *const T as *const u8,
+ dest as *mut T as *mut u8,
+ mem::size_of_val(dest)
+ );
+ }
+ }
+
+ /// Obtain a raw pointer from this reference.
+ pub fn as_raw_ptr(&self) -> *const T {
+ self as *const _ as _
+ }
+
+ /// Obtain a raw pointer from this reference.
+ pub fn as_raw_mut_ptr(&mut self) -> *mut T {
+ self as *mut _ as _
+ }
+}
+
+#[unstable(feature = "sgx_platform", issue = "56975")]
+impl<T> UserRef<T> where T: UserSafe {
+ /// Copies the value from user memory into enclave memory.
+ pub fn to_enclave(&self) -> T {
+ unsafe { ptr::read(self.0.get()) }
+ }
+}
+
+#[unstable(feature = "sgx_platform", issue = "56975")]
+impl<T> UserRef<[T]> where [T]: UserSafe {
+ /// Creates a `&UserRef<[T]>` from a raw thin pointer and a slice length.
+ ///
+ /// # Safety
+ /// The caller must ensure `ptr` points to `n` elements of `T`.
+ ///
+ /// # Panics
+ /// This function panics if:
+ ///
+ /// * The pointer is not aligned
+ /// * The pointer is null
+ /// * The pointed-to range is not in user memory
+ pub unsafe fn from_raw_parts<'a>(ptr: *const T, len: usize) -> &'a Self {
+ &*(<[T]>::from_raw_sized(ptr as _, len * mem::size_of::<T>()).as_ptr() as *const Self)
+ }
+
+ /// Creates a `&mut UserRef<[T]>` from a raw thin pointer and a slice length.
+ /// See the struct documentation for the nuances regarding a
+ /// `&mut UserRef<T>`.
+ ///
+ /// # Safety
+ /// The caller must ensure `ptr` points to `n` elements of `T`.
+ ///
+ /// # Panics
+ /// This function panics if:
+ ///
+ /// * The pointer is not aligned
+ /// * The pointer is null
+ /// * The pointed-to range is not in user memory
+ pub unsafe fn from_raw_parts_mut<'a>(ptr: *mut T, len: usize) -> &'a mut Self {
+ &mut*(<[T]>::from_raw_sized(ptr as _, len * mem::size_of::<T>()).as_ptr() as *mut Self)
+ }
+
+ /// Obtain a raw pointer to the first element of this user slice.
+ pub fn as_ptr(&self) -> *const T {
+ self.0.get() as _
+ }
+
+ /// Obtain a raw pointer to the first element of this user slice.
+ pub fn as_mut_ptr(&mut self) -> *mut T {
+ self.0.get() as _
+ }
+
+ /// Obtain the number of elements in this user slice.
+ pub fn len(&self) -> usize {
+ unsafe { (*self.0.get()).len() }
+ }
+
+ /// Copies the value from user memory and place it into `dest`. Afterwards,
+ /// `dest` will contain exactly `self.len()` elements.
+ ///
+ /// # Panics
+ /// This function panics if the destination doesn't have the same size as
+ /// the source. This can happen for dynamically-sized types such as slices.
+ pub fn copy_to_enclave_vec(&self, dest: &mut Vec<T>) {
+ unsafe {
+ if let Some(missing) = self.len().checked_sub(dest.capacity()) {
+ dest.reserve(missing)
+ }
+ dest.set_len(self.len());
+ self.copy_to_enclave(&mut dest[..]);
+ }
+ }
+
+ /// Copies the value from user memory into a vector in enclave memory.
+ pub fn to_enclave(&self) -> Vec<T> {
+ let mut ret = Vec::with_capacity(self.len());
+ self.copy_to_enclave_vec(&mut ret);
+ ret
+ }
+
+ /// Returns an iterator over the slice.
+ pub fn iter(&self) -> Iter<'_, T>
+ where T: UserSafe // FIXME: should be implied by [T]: UserSafe?
+ {
+ unsafe {
+ Iter((&*self.as_raw_ptr()).iter())
+ }
+ }
+
+ /// Returns an iterator that allows modifying each value.
+ pub fn iter_mut(&mut self) -> IterMut<'_, T>
+ where T: UserSafe // FIXME: should be implied by [T]: UserSafe?
+ {
+ unsafe {
+ IterMut((&mut*self.as_raw_mut_ptr()).iter_mut())
+ }
+ }
+}
+
+/// Immutable user slice iterator
+///
+/// This struct is created by the `iter` method on `UserRef<[T]>`.
+#[unstable(feature = "sgx_platform", issue = "56975")]
+pub struct Iter<'a, T: 'a + UserSafe>(slice::Iter<'a, T>);
+
+#[unstable(feature = "sgx_platform", issue = "56975")]
+impl<'a, T: UserSafe> Iterator for Iter<'a, T> {
+ type Item = &'a UserRef<T>;
+
+ #[inline]
+ fn next(&mut self) -> Option<Self::Item> {
+ unsafe {
+ self.0.next().map(|e| UserRef::from_ptr(e))
+ }
+ }
+}
+
+/// Mutable user slice iterator
+///
+/// This struct is created by the `iter_mut` method on `UserRef<[T]>`.
+#[unstable(feature = "sgx_platform", issue = "56975")]
+pub struct IterMut<'a, T: 'a + UserSafe>(slice::IterMut<'a, T>);
+
+#[unstable(feature = "sgx_platform", issue = "56975")]
+impl<'a, T: UserSafe> Iterator for IterMut<'a, T> {
+ type Item = &'a mut UserRef<T>;
+
+ #[inline]
+ fn next(&mut self) -> Option<Self::Item> {
+ unsafe {
+ self.0.next().map(|e| UserRef::from_mut_ptr(e))
+ }
+ }
+}
+
+#[unstable(feature = "sgx_platform", issue = "56975")]
+impl<T: ?Sized> Deref for User<T> where T: UserSafe {
+ type Target = UserRef<T>;
+
+ fn deref(&self) -> &Self::Target {
+ unsafe { &*self.0.as_ptr() }
+ }
+}
+
+#[unstable(feature = "sgx_platform", issue = "56975")]
+impl<T: ?Sized> DerefMut for User<T> where T: UserSafe {
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ unsafe { &mut*self.0.as_ptr() }
+ }
+}
+
+#[unstable(feature = "sgx_platform", issue = "56975")]
+impl<T: ?Sized> Drop for User<T> where T: UserSafe {
+ fn drop(&mut self) {
+ unsafe {
+ let ptr = (*self.0.as_ptr()).0.get();
+ super::free(ptr as _, mem::size_of_val(&mut*ptr), T::align_of());
+ }
+ }
+}
+
+#[unstable(feature = "sgx_platform", issue = "56975")]
+impl<T: CoerceUnsized<U>, U> CoerceUnsized<UserRef<U>> for UserRef<T> {}
+
+#[unstable(feature = "sgx_platform", issue = "56975")]
+impl<T, I: SliceIndex<[T]>> Index<I> for UserRef<[T]> where [T]: UserSafe, I::Output: UserSafe {
+ type Output = UserRef<I::Output>;
+
+ #[inline]
+ fn index(&self, index: I) -> &UserRef<I::Output> {
+ unsafe {
+ UserRef::from_ptr(index.index(&*self.as_raw_ptr()))
+ }
+ }
+}
+
+#[unstable(feature = "sgx_platform", issue = "56975")]
+impl<T, I: SliceIndex<[T]>> IndexMut<I> for UserRef<[T]> where [T]: UserSafe, I::Output: UserSafe {
+ #[inline]
+ fn index_mut(&mut self, index: I) -> &mut UserRef<I::Output> {
+ unsafe {
+ UserRef::from_mut_ptr(index.index_mut(&mut*self.as_raw_mut_ptr()))
+ }
+ }
+}
+
+#[unstable(feature = "sgx_platform", issue = "56975")]
+impl UserRef<super::raw::ByteBuffer> {
+ /// Copies the user memory range pointed to by the user `ByteBuffer` to
+ /// enclave memory.
+ ///
+ /// # Panics
+ /// This function panics if:
+ ///
+ /// * The pointer in the user `ByteBuffer` is null
+ /// * The pointed-to range in the user `ByteBuffer` is not in user memory
+ pub fn copy_user_buffer(&self) -> Vec<u8> {
+ unsafe {
+ let buf = self.to_enclave();
+ if buf.len > 0 {
+ User::from_raw_parts(buf.data as _, buf.len).to_enclave()
+ } else {
+ // Mustn't look at `data` or call `free` if `len` is `0`.
+ Vec::with_capacity(0)
+ }
+ }
+ }
+}
diff --git a/src/libstd/sys/sgx/abi/usercalls/mod.rs b/src/libstd/sys/sgx/abi/usercalls/mod.rs
new file mode 100644
index 0000000..0abfc26
--- /dev/null
+++ b/src/libstd/sys/sgx/abi/usercalls/mod.rs
@@ -0,0 +1,211 @@
+use crate::io::{Error as IoError, Result as IoResult};
+use crate::time::Duration;
+
+pub(crate) mod alloc;
+#[macro_use]
+pub(crate) mod raw;
+
+use self::raw::*;
+
+/// Usercall `read`. See the ABI documentation for more information.
+#[unstable(feature = "sgx_platform", issue = "56975")]
+pub fn read(fd: Fd, buf: &mut [u8]) -> IoResult<usize> {
+ unsafe {
+ let mut userbuf = alloc::User::<[u8]>::uninitialized(buf.len());
+ let len = raw::read(fd, userbuf.as_mut_ptr(), userbuf.len()).from_sgx_result()?;
+ userbuf[..len].copy_to_enclave(&mut buf[..len]);
+ Ok(len)
+ }
+}
+
+/// Usercall `read_alloc`. See the ABI documentation for more information.
+#[unstable(feature = "sgx_platform", issue = "56975")]
+pub fn read_alloc(fd: Fd) -> IoResult<Vec<u8>> {
+ unsafe {
+ let userbuf = ByteBuffer { data: crate::ptr::null_mut(), len: 0 };
+ let mut userbuf = alloc::User::new_from_enclave(&userbuf);
+ raw::read_alloc(fd, userbuf.as_raw_mut_ptr()).from_sgx_result()?;
+ Ok(userbuf.copy_user_buffer())
+ }
+}
+
+/// Usercall `write`. See the ABI documentation for more information.
+#[unstable(feature = "sgx_platform", issue = "56975")]
+pub fn write(fd: Fd, buf: &[u8]) -> IoResult<usize> {
+ unsafe {
+ let userbuf = alloc::User::new_from_enclave(buf);
+ raw::write(fd, userbuf.as_ptr(), userbuf.len()).from_sgx_result()
+ }
+}
+
+/// Usercall `flush`. See the ABI documentation for more information.
+#[unstable(feature = "sgx_platform", issue = "56975")]
+pub fn flush(fd: Fd) -> IoResult<()> {
+ unsafe { raw::flush(fd).from_sgx_result() }
+}
+
+/// Usercall `close`. See the ABI documentation for more information.
+#[unstable(feature = "sgx_platform", issue = "56975")]
+pub fn close(fd: Fd) {
+ unsafe { raw::close(fd) }
+}
+
+fn string_from_bytebuffer(buf: &alloc::UserRef<ByteBuffer>, usercall: &str, arg: &str) -> String {
+ String::from_utf8(buf.copy_user_buffer())
+ .unwrap_or_else(|_| rtabort!("Usercall {}: expected {} to be valid UTF-8", usercall, arg))
+}
+
+/// Usercall `bind_stream`. See the ABI documentation for more information.
+#[unstable(feature = "sgx_platform", issue = "56975")]
+pub fn bind_stream(addr: &str) -> IoResult<(Fd, String)> {
+ unsafe {
+ let addr_user = alloc::User::new_from_enclave(addr.as_bytes());
+ let mut local = alloc::User::<ByteBuffer>::uninitialized();
+ let fd = raw::bind_stream(
+ addr_user.as_ptr(),
+ addr_user.len(),
+ local.as_raw_mut_ptr()
+ ).from_sgx_result()?;
+ let local = string_from_bytebuffer(&local, "bind_stream", "local_addr");
+ Ok((fd, local))
+ }
+}
+
+/// Usercall `accept_stream`. See the ABI documentation for more information.
+#[unstable(feature = "sgx_platform", issue = "56975")]
+pub fn accept_stream(fd: Fd) -> IoResult<(Fd, String, String)> {
+ unsafe {
+ let mut bufs = alloc::User::<[ByteBuffer; 2]>::uninitialized();
+ let mut buf_it = alloc::UserRef::iter_mut(&mut *bufs); // FIXME: can this be done
+ // without forcing coercion?
+ let (local, peer) = (buf_it.next().unwrap(), buf_it.next().unwrap());
+ let fd = raw::accept_stream(
+ fd,
+ local.as_raw_mut_ptr(),
+ peer.as_raw_mut_ptr()
+ ).from_sgx_result()?;
+ let local = string_from_bytebuffer(&local, "accept_stream", "local_addr");
+ let peer = string_from_bytebuffer(&peer, "accept_stream", "peer_addr");
+ Ok((fd, local, peer))
+ }
+}
+
+/// Usercall `connect_stream`. See the ABI documentation for more information.
+#[unstable(feature = "sgx_platform", issue = "56975")]
+pub fn connect_stream(addr: &str) -> IoResult<(Fd, String, String)> {
+ unsafe {
+ let addr_user = alloc::User::new_from_enclave(addr.as_bytes());
+ let mut bufs = alloc::User::<[ByteBuffer; 2]>::uninitialized();
+ let mut buf_it = alloc::UserRef::iter_mut(&mut *bufs); // FIXME: can this be done
+ // without forcing coercion?
+ let (local, peer) = (buf_it.next().unwrap(), buf_it.next().unwrap());
+ let fd = raw::connect_stream(
+ addr_user.as_ptr(),
+ addr_user.len(),
+ local.as_raw_mut_ptr(),
+ peer.as_raw_mut_ptr()
+ ).from_sgx_result()?;
+ let local = string_from_bytebuffer(&local, "connect_stream", "local_addr");
+ let peer = string_from_bytebuffer(&peer, "connect_stream", "peer_addr");
+ Ok((fd, local, peer))
+ }
+}
+
+/// Usercall `launch_thread`. See the ABI documentation for more information.
+#[unstable(feature = "sgx_platform", issue = "56975")]
+pub unsafe fn launch_thread() -> IoResult<()> {
+ raw::launch_thread().from_sgx_result()
+}
+
+/// Usercall `exit`. See the ABI documentation for more information.
+#[unstable(feature = "sgx_platform", issue = "56975")]
+pub fn exit(panic: bool) -> ! {
+ unsafe { raw::exit(panic) }
+}
+
+/// Usercall `wait`. See the ABI documentation for more information.
+#[unstable(feature = "sgx_platform", issue = "56975")]
+pub fn wait(event_mask: u64, timeout: u64) -> IoResult<u64> {
+ unsafe { raw::wait(event_mask, timeout).from_sgx_result() }
+}
+
+/// Usercall `send`. See the ABI documentation for more information.
+#[unstable(feature = "sgx_platform", issue = "56975")]
+pub fn send(event_set: u64, tcs: Option<Tcs>) -> IoResult<()> {
+ unsafe { raw::send(event_set, tcs).from_sgx_result() }
+}
+
+/// Usercall `insecure_time`. See the ABI documentation for more information.
+#[unstable(feature = "sgx_platform", issue = "56975")]
+pub fn insecure_time() -> Duration {
+ let t = unsafe { raw::insecure_time() };
+ Duration::new(t / 1_000_000_000, (t % 1_000_000_000) as _)
+}
+
+/// Usercall `alloc`. See the ABI documentation for more information.
+#[unstable(feature = "sgx_platform", issue = "56975")]
+pub fn alloc(size: usize, alignment: usize) -> IoResult<*mut u8> {
+ unsafe { raw::alloc(size, alignment).from_sgx_result() }
+}
+
+#[unstable(feature = "sgx_platform", issue = "56975")]
+#[doc(inline)]
+pub use self::raw::free;
+
+fn check_os_error(err: Result) -> i32 {
+ // FIXME: not sure how to make sure all variants of Error are covered
+ if err == Error::NotFound as _ ||
+ err == Error::PermissionDenied as _ ||
+ err == Error::ConnectionRefused as _ ||
+ err == Error::ConnectionReset as _ ||
+ err == Error::ConnectionAborted as _ ||
+ err == Error::NotConnected as _ ||
+ err == Error::AddrInUse as _ ||
+ err == Error::AddrNotAvailable as _ ||
+ err == Error::BrokenPipe as _ ||
+ err == Error::AlreadyExists as _ ||
+ err == Error::WouldBlock as _ ||
+ err == Error::InvalidInput as _ ||
+ err == Error::InvalidData as _ ||
+ err == Error::TimedOut as _ ||
+ err == Error::WriteZero as _ ||
+ err == Error::Interrupted as _ ||
+ err == Error::Other as _ ||
+ err == Error::UnexpectedEof as _ ||
+ ((Error::UserRangeStart as _)..=(Error::UserRangeEnd as _)).contains(&err)
+ {
+ err
+ } else {
+ rtabort!("Usercall: returned invalid error value {}", err)
+ }
+}
+
+trait FromSgxResult {
+ type Return;
+
+ fn from_sgx_result(self) -> IoResult<Self::Return>;
+}
+
+impl<T> FromSgxResult for (Result, T) {
+ type Return = T;
+
+ fn from_sgx_result(self) -> IoResult<Self::Return> {
+ if self.0 == RESULT_SUCCESS {
+ Ok(self.1)
+ } else {
+ Err(IoError::from_raw_os_error(check_os_error(self.0)))
+ }
+ }
+}
+
+impl FromSgxResult for Result {
+ type Return = ();
+
+ fn from_sgx_result(self) -> IoResult<Self::Return> {
+ if self == RESULT_SUCCESS {
+ Ok(())
+ } else {
+ Err(IoError::from_raw_os_error(check_os_error(self)))
+ }
+ }
+}
diff --git a/src/libstd/sys/sgx/abi/usercalls/raw.rs b/src/libstd/sys/sgx/abi/usercalls/raw.rs
new file mode 100644
index 0000000..e4694a8
--- /dev/null
+++ b/src/libstd/sys/sgx/abi/usercalls/raw.rs
@@ -0,0 +1,249 @@
+#![allow(unused)]
+
+#[unstable(feature = "sgx_platform", issue = "56975")]
+pub use fortanix_sgx_abi::*;
+
+use crate::ptr::NonNull;
+use crate::num::NonZeroU64;
+
+#[repr(C)]
+struct UsercallReturn(u64, u64);
+
+extern "C" {
+ fn usercall(nr: NonZeroU64, p1: u64, p2: u64, abort: u64, p3: u64, p4: u64) -> UsercallReturn;
+}
+
+/// Performs the raw usercall operation as defined in the ABI calling convention.
+///
+/// # Safety
+///
+/// The caller must ensure to pass parameters appropriate for the usercall `nr`
+/// and to observe all requirements specified in the ABI.
+///
+/// # Panics
+///
+/// Panics if `nr` is `0`.
+#[unstable(feature = "sgx_platform", issue = "56975")]
+#[inline]
+pub unsafe fn do_usercall(nr: NonZeroU64, p1: u64, p2: u64, p3: u64, p4: u64, abort: bool)
+ -> (u64, u64)
+{
+ let UsercallReturn(a, b) = usercall(nr, p1, p2, abort as _, p3, p4);
+ (a, b)
+}
+
+type Register = u64;
+
+trait RegisterArgument {
+ fn from_register(_: Register) -> Self;
+ fn into_register(self) -> Register;
+}
+
+trait ReturnValue {
+ fn from_registers(call: &'static str, regs: (Register, Register)) -> Self;
+}
+
+macro_rules! define_usercalls {
+ ($(fn $f:ident($($n:ident: $t:ty),*) $(-> $r:tt)*; )*) => {
+ /// Usercall numbers as per the ABI.
+ #[repr(u64)]
+ #[unstable(feature = "sgx_platform", issue = "56975")]
+ #[derive(Copy, Clone, Hash, PartialEq, Eq, Debug)]
+ #[allow(missing_docs, non_camel_case_types)]
+ #[non_exhaustive]
+ pub enum Usercalls {
+ #[doc(hidden)]
+ __enclave_usercalls_invalid = 0,
+ $($f,)*
+ }
+
+ $(enclave_usercalls_internal_define_usercalls!(def fn $f($($n: $t),*) $(-> $r)*);)*
+ };
+}
+
+macro_rules! define_ra {
+ (< $i:ident > $t:ty) => {
+ impl<$i> RegisterArgument for $t {
+ fn from_register(a: Register) -> Self {
+ a as _
+ }
+ fn into_register(self) -> Register {
+ self as _
+ }
+ }
+ };
+ ($i:ty as $t:ty) => {
+ impl RegisterArgument for $t {
+ fn from_register(a: Register) -> Self {
+ a as $i as _
+ }
+ fn into_register(self) -> Register {
+ self as $i as _
+ }
+ }
+ };
+ ($t:ty) => {
+ impl RegisterArgument for $t {
+ fn from_register(a: Register) -> Self {
+ a as _
+ }
+ fn into_register(self) -> Register {
+ self as _
+ }
+ }
+ };
+}
+
+define_ra!(Register);
+define_ra!(i64);
+define_ra!(u32);
+define_ra!(u32 as i32);
+define_ra!(u16);
+define_ra!(u16 as i16);
+define_ra!(u8);
+define_ra!(u8 as i8);
+define_ra!(usize);
+define_ra!(usize as isize);
+define_ra!(<T> *const T);
+define_ra!(<T> *mut T);
+
+impl RegisterArgument for bool {
+ fn from_register(a: Register) -> bool {
+ if a != 0 {
+ true
+ } else {
+ false
+ }
+ }
+ fn into_register(self) -> Register {
+ self as _
+ }
+}
+
+impl<T: RegisterArgument> RegisterArgument for Option<NonNull<T>> {
+ fn from_register(a: Register) -> Option<NonNull<T>> {
+ NonNull::new(a as _)
+ }
+ fn into_register(self) -> Register {
+ self.map_or(0 as _, NonNull::as_ptr) as _
+ }
+}
+
+impl ReturnValue for ! {
+ fn from_registers(call: &'static str, _regs: (Register, Register)) -> Self {
+ rtabort!("Usercall {}: did not expect to be re-entered", call);
+ }
+}
+
+impl ReturnValue for () {
+ fn from_registers(call: &'static str, usercall_retval: (Register, Register)) -> Self {
+ rtassert!(usercall_retval.0 == 0);
+ rtassert!(usercall_retval.1 == 0);
+ ()
+ }
+}
+
+impl<T: RegisterArgument> ReturnValue for T {
+ fn from_registers(call: &'static str, usercall_retval: (Register, Register)) -> Self {
+ rtassert!(usercall_retval.1 == 0);
+ T::from_register(usercall_retval.0)
+ }
+}
+
+impl<T: RegisterArgument, U: RegisterArgument> ReturnValue for (T, U) {
+ fn from_registers(_call: &'static str, regs: (Register, Register)) -> Self {
+ (
+ T::from_register(regs.0),
+ U::from_register(regs.1)
+ )
+ }
+}
+
+macro_rules! return_type_is_abort {
+ (!) => { true };
+ ($r:ty) => { false };
+}
+
+// In this macro: using `$r:tt` because `$r:ty` doesn't match ! in `return_type_is_abort`
+macro_rules! enclave_usercalls_internal_define_usercalls {
+ (def fn $f:ident($n1:ident: $t1:ty, $n2:ident: $t2:ty,
+ $n3:ident: $t3:ty, $n4:ident: $t4:ty) -> $r:tt) => (
+ /// This is the raw function definition, see the ABI documentation for
+ /// more information.
+ #[unstable(feature = "sgx_platform", issue = "56975")]
+ #[inline(always)]
+ pub unsafe fn $f($n1: $t1, $n2: $t2, $n3: $t3, $n4: $t4) -> $r {
+ ReturnValue::from_registers(stringify!($f), do_usercall(
+ rtunwrap!(Some, NonZeroU64::new(Usercalls::$f as Register)),
+ RegisterArgument::into_register($n1),
+ RegisterArgument::into_register($n2),
+ RegisterArgument::into_register($n3),
+ RegisterArgument::into_register($n4),
+ return_type_is_abort!($r)
+ ))
+ }
+ );
+ (def fn $f:ident($n1:ident: $t1:ty, $n2:ident: $t2:ty, $n3:ident: $t3:ty) -> $r:tt) => (
+ /// This is the raw function definition, see the ABI documentation for
+ /// more information.
+ #[unstable(feature = "sgx_platform", issue = "56975")]
+ #[inline(always)]
+ pub unsafe fn $f($n1: $t1, $n2: $t2, $n3: $t3) -> $r {
+ ReturnValue::from_registers(stringify!($f), do_usercall(
+ rtunwrap!(Some, NonZeroU64::new(Usercalls::$f as Register)),
+ RegisterArgument::into_register($n1),
+ RegisterArgument::into_register($n2),
+ RegisterArgument::into_register($n3),
+ 0,
+ return_type_is_abort!($r)
+ ))
+ }
+ );
+ (def fn $f:ident($n1:ident: $t1:ty, $n2:ident: $t2:ty) -> $r:tt) => (
+ /// This is the raw function definition, see the ABI documentation for
+ /// more information.
+ #[unstable(feature = "sgx_platform", issue = "56975")]
+ #[inline(always)]
+ pub unsafe fn $f($n1: $t1, $n2: $t2) -> $r {
+ ReturnValue::from_registers(stringify!($f), do_usercall(
+ rtunwrap!(Some, NonZeroU64::new(Usercalls::$f as Register)),
+ RegisterArgument::into_register($n1),
+ RegisterArgument::into_register($n2),
+ 0,0,
+ return_type_is_abort!($r)
+ ))
+ }
+ );
+ (def fn $f:ident($n1:ident: $t1:ty) -> $r:tt) => (
+ /// This is the raw function definition, see the ABI documentation for
+ /// more information.
+ #[unstable(feature = "sgx_platform", issue = "56975")]
+ #[inline(always)]
+ pub unsafe fn $f($n1: $t1) -> $r {
+ ReturnValue::from_registers(stringify!($f), do_usercall(
+ rtunwrap!(Some, NonZeroU64::new(Usercalls::$f as Register)),
+ RegisterArgument::into_register($n1),
+ 0,0,0,
+ return_type_is_abort!($r)
+ ))
+ }
+ );
+ (def fn $f:ident() -> $r:tt) => (
+ /// This is the raw function definition, see the ABI documentation for
+ /// more information.
+ #[unstable(feature = "sgx_platform", issue = "56975")]
+ #[inline(always)]
+ pub unsafe fn $f() -> $r {
+ ReturnValue::from_registers(stringify!($f), do_usercall(
+ rtunwrap!(Some, NonZeroU64::new(Usercalls::$f as Register)),
+ 0,0,0,0,
+ return_type_is_abort!($r)
+ ))
+ }
+ );
+ (def fn $f:ident($($n:ident: $t:ty),*)) => (
+ enclave_usercalls_internal_define_usercalls!(def fn $f($($n: $t),*) -> ());
+ );
+}
+
+invoke_with_usercalls!(define_usercalls);
diff --git a/src/libstd/sys/sgx/alloc.rs b/src/libstd/sys/sgx/alloc.rs
new file mode 100644
index 0000000..b385d56
--- /dev/null
+++ b/src/libstd/sys/sgx/alloc.rs
@@ -0,0 +1,46 @@
+use crate::alloc::{self, GlobalAlloc, Layout, System};
+
+use super::waitqueue::SpinMutex;
+
+// Using a SpinMutex because we never want to exit the enclave waiting for the
+// allocator.
+#[cfg_attr(test, linkage = "available_externally")]
+#[export_name = "_ZN16__rust_internals3std3sys3sgx5alloc8DLMALLOCE"]
+static DLMALLOC: SpinMutex<dlmalloc::Dlmalloc> = SpinMutex::new(dlmalloc::DLMALLOC_INIT);
+
+#[stable(feature = "alloc_system_type", since = "1.28.0")]
+unsafe impl GlobalAlloc for System {
+ #[inline]
+ unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
+ DLMALLOC.lock().malloc(layout.size(), layout.align())
+ }
+
+ #[inline]
+ unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
+ DLMALLOC.lock().calloc(layout.size(), layout.align())
+ }
+
+ #[inline]
+ unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
+ DLMALLOC.lock().free(ptr, layout.size(), layout.align())
+ }
+
+ #[inline]
+ unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
+ DLMALLOC.lock().realloc(ptr, layout.size(), layout.align(), new_size)
+ }
+}
+
+// The following functions are needed by libunwind. These symbols are named
+// in pre-link args for the target specification, so keep that in sync.
+#[cfg(not(test))]
+#[no_mangle]
+pub unsafe extern "C" fn __rust_c_alloc(size: usize, align: usize) -> *mut u8 {
+ alloc::alloc(Layout::from_size_align_unchecked(size, align))
+}
+
+#[cfg(not(test))]
+#[no_mangle]
+pub unsafe extern "C" fn __rust_c_dealloc(ptr: *mut u8, size: usize, align: usize) {
+ alloc::dealloc(ptr, Layout::from_size_align_unchecked(size, align))
+}
diff --git a/src/libstd/sys/sgx/args.rs b/src/libstd/sys/sgx/args.rs
new file mode 100644
index 0000000..a84ab41
--- /dev/null
+++ b/src/libstd/sys/sgx/args.rs
@@ -0,0 +1,68 @@
+use super::abi::usercalls::{alloc, raw::ByteBuffer};
+use crate::ffi::OsString;
+use crate::sync::atomic::{AtomicUsize, Ordering};
+use crate::sys::os_str::Buf;
+use crate::sys_common::FromInner;
+use crate::slice;
+
+#[cfg_attr(test, linkage = "available_externally")]
+#[export_name = "_ZN16__rust_internals3std3sys3sgx4args4ARGSE"]
+static ARGS: AtomicUsize = AtomicUsize::new(0);
+type ArgsStore = Vec<OsString>;
+
+#[cfg_attr(test, allow(dead_code))]
+pub unsafe fn init(argc: isize, argv: *const *const u8) {
+ if argc != 0 {
+ let args = alloc::User::<[ByteBuffer]>::from_raw_parts(argv as _, argc as _);
+ let args = args.iter()
+ .map( |a| OsString::from_inner(Buf { inner: a.copy_user_buffer() }) )
+ .collect::<ArgsStore>();
+ ARGS.store(Box::into_raw(Box::new(args)) as _, Ordering::Relaxed);
+ }
+}
+
+pub unsafe fn cleanup() {
+ let args = ARGS.swap(0, Ordering::Relaxed);
+ if args != 0 {
+ drop(Box::<ArgsStore>::from_raw(args as _))
+ }
+}
+
+pub fn args() -> Args {
+ let args = unsafe { (ARGS.load(Ordering::Relaxed) as *const ArgsStore).as_ref() };
+ if let Some(args) = args {
+ Args(args.iter())
+ } else {
+ Args([].iter())
+ }
+}
+
+pub struct Args(slice::Iter<'static, OsString>);
+
+impl Args {
+ pub fn inner_debug(&self) -> &[OsString] {
+ self.0.as_slice()
+ }
+}
+
+impl Iterator for Args {
+ type Item = OsString;
+ fn next(&mut self) -> Option<OsString> {
+ self.0.next().cloned()
+ }
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ self.0.size_hint()
+ }
+}
+
+impl ExactSizeIterator for Args {
+ fn len(&self) -> usize {
+ self.0.len()
+ }
+}
+
+impl DoubleEndedIterator for Args {
+ fn next_back(&mut self) -> Option<OsString> {
+ self.0.next_back().cloned()
+ }
+}
diff --git a/src/libstd/sys/sgx/backtrace.rs b/src/libstd/sys/sgx/backtrace.rs
new file mode 100644
index 0000000..326737a
--- /dev/null
+++ b/src/libstd/sys/sgx/backtrace.rs
@@ -0,0 +1,98 @@
+use crate::io;
+use crate::error::Error;
+use crate::fmt;
+use crate::sys_common::backtrace::Frame;
+use crate::sys::sgx::abi::mem::image_base;
+
+use unwind as uw;
+
+pub struct BacktraceContext;
+
+struct Context<'a> {
+ idx: usize,
+ frames: &'a mut [Frame],
+}
+
+#[derive(Debug)]
+struct UnwindError(uw::_Unwind_Reason_Code);
+
+impl Error for UnwindError {
+ fn description(&self) -> &'static str {
+ "unexpected return value while unwinding"
+ }
+}
+
+impl fmt::Display for UnwindError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "{}: {:?}", self.description(), self.0)
+ }
+}
+
+#[inline(never)] // this function call can be skipped it when tracing.
+pub fn unwind_backtrace(frames: &mut [Frame]) -> io::Result<(usize, BacktraceContext)> {
+ let mut cx = Context { idx: 0, frames };
+ let result_unwind = unsafe {
+ uw::_Unwind_Backtrace(trace_fn, &mut cx as *mut Context<'_> as *mut libc::c_void)
+ };
+ // See libunwind:src/unwind/Backtrace.c for the return values.
+ // No, there is no doc.
+ let res = match result_unwind {
+ // These return codes seem to be benign and need to be ignored for backtraces
+ // to show up properly on all tested platforms.
+ uw::_URC_END_OF_STACK | uw::_URC_FATAL_PHASE1_ERROR | uw::_URC_FAILURE => {
+ Ok((cx.idx, BacktraceContext))
+ }
+ _ => Err(io::Error::new(
+ io::ErrorKind::Other,
+ UnwindError(result_unwind),
+ )),
+ };
+ res
+}
+
+extern "C" fn trace_fn(
+ ctx: *mut uw::_Unwind_Context,
+ arg: *mut libc::c_void,
+) -> uw::_Unwind_Reason_Code {
+ let cx = unsafe { &mut *(arg as *mut Context<'_>) };
+ if cx.idx >= cx.frames.len() {
+ return uw::_URC_NORMAL_STOP;
+ }
+
+ let mut ip_before_insn = 0;
+ let mut ip = unsafe { uw::_Unwind_GetIPInfo(ctx, &mut ip_before_insn) as *mut libc::c_void };
+ if !ip.is_null() && ip_before_insn == 0 {
+ // this is a non-signaling frame, so `ip` refers to the address
+ // after the calling instruction. account for that.
+ ip = (ip as usize - 1) as *mut _;
+ }
+
+ let symaddr = unsafe { uw::_Unwind_FindEnclosingFunction(ip) };
+ cx.frames[cx.idx] = Frame {
+ symbol_addr: symaddr as *mut u8,
+ exact_position: ip as *mut u8,
+ inline_context: 0,
+ };
+ cx.idx += 1;
+
+ uw::_URC_NO_REASON
+}
+
+// To reduce TCB size in Sgx enclave, we do not want to implement resolve_symname functionality.
+// Rather, we print the offset of the address here, which could be later mapped to correct function.
+pub fn resolve_symname<F>(frame: Frame,
+ callback: F,
+ _: &BacktraceContext) -> io::Result<()>
+ where F: FnOnce(Option<&str>) -> io::Result<()>
+{
+ callback(Some(&format!("0x{:x}",
+ (frame.symbol_addr.wrapping_offset_from(image_base() as _)))))
+}
+
+pub fn foreach_symbol_fileline<F>(_: Frame,
+ _: F,
+ _: &BacktraceContext) -> io::Result<bool>
+ where F: FnMut(&[u8], u32) -> io::Result<()>
+{
+ Ok(false)
+}
diff --git a/src/libstd/sys/sgx/cmath.rs b/src/libstd/sys/sgx/cmath.rs
new file mode 100644
index 0000000..5aabdc1
--- /dev/null
+++ b/src/libstd/sys/sgx/cmath.rs
@@ -0,0 +1,31 @@
+#![cfg(not(test))]
+
+// These symbols are all defined in `compiler-builtins`
+extern {
+ pub fn acos(n: f64) -> f64;
+ pub fn acosf(n: f32) -> f32;
+ pub fn asin(n: f64) -> f64;
+ pub fn asinf(n: f32) -> f32;
+ pub fn atan(n: f64) -> f64;
+ pub fn atan2(a: f64, b: f64) -> f64;
+ pub fn atan2f(a: f32, b: f32) -> f32;
+ pub fn atanf(n: f32) -> f32;
+ pub fn cbrt(n: f64) -> f64;
+ pub fn cbrtf(n: f32) -> f32;
+ pub fn cosh(n: f64) -> f64;
+ pub fn coshf(n: f32) -> f32;
+ pub fn expm1(n: f64) -> f64;
+ pub fn expm1f(n: f32) -> f32;
+ pub fn fdim(a: f64, b: f64) -> f64;
+ pub fn fdimf(a: f32, b: f32) -> f32;
+ pub fn hypot(x: f64, y: f64) -> f64;
+ pub fn hypotf(x: f32, y: f32) -> f32;
+ pub fn log1p(n: f64) -> f64;
+ pub fn log1pf(n: f32) -> f32;
+ pub fn sinh(n: f64) -> f64;
+ pub fn sinhf(n: f32) -> f32;
+ pub fn tan(n: f64) -> f64;
+ pub fn tanf(n: f32) -> f32;
+ pub fn tanh(n: f64) -> f64;
+ pub fn tanhf(n: f32) -> f32;
+}
diff --git a/src/libstd/sys/sgx/condvar.rs b/src/libstd/sys/sgx/condvar.rs
new file mode 100644
index 0000000..000bb19
--- /dev/null
+++ b/src/libstd/sys/sgx/condvar.rs
@@ -0,0 +1,41 @@
+use crate::sys::mutex::Mutex;
+use crate::time::Duration;
+
+use super::waitqueue::{WaitVariable, WaitQueue, SpinMutex};
+
+pub struct Condvar {
+ inner: SpinMutex<WaitVariable<()>>,
+}
+
+impl Condvar {
+ pub const fn new() -> Condvar {
+ Condvar { inner: SpinMutex::new(WaitVariable::new(())) }
+ }
+
+ #[inline]
+ pub unsafe fn init(&mut self) {}
+
+ #[inline]
+ pub unsafe fn notify_one(&self) {
+ let _ = WaitQueue::notify_one(self.inner.lock());
+ }
+
+ #[inline]
+ pub unsafe fn notify_all(&self) {
+ let _ = WaitQueue::notify_all(self.inner.lock());
+ }
+
+ pub unsafe fn wait(&self, mutex: &Mutex) {
+ let guard = self.inner.lock();
+ mutex.unlock();
+ WaitQueue::wait(guard);
+ mutex.lock()
+ }
+
+ pub unsafe fn wait_timeout(&self, _mutex: &Mutex, _dur: Duration) -> bool {
+ rtabort!("timeout not supported in SGX");
+ }
+
+ #[inline]
+ pub unsafe fn destroy(&self) {}
+}
diff --git a/src/libstd/sys/sgx/env.rs b/src/libstd/sys/sgx/env.rs
new file mode 100644
index 0000000..6fa0ed7
--- /dev/null
+++ b/src/libstd/sys/sgx/env.rs
@@ -0,0 +1,9 @@
+pub mod os {
+ pub const FAMILY: &'static str = "";
+ pub const OS: &'static str = "";
+ pub const DLL_PREFIX: &'static str = "";
+ pub const DLL_SUFFIX: &'static str = ".sgxs";
+ pub const DLL_EXTENSION: &'static str = "sgxs";
+ pub const EXE_SUFFIX: &'static str = ".sgxs";
+ pub const EXE_EXTENSION: &'static str = "sgxs";
+}
diff --git a/src/libstd/sys/sgx/ext/arch.rs b/src/libstd/sys/sgx/ext/arch.rs
new file mode 100644
index 0000000..5056e38
--- /dev/null
+++ b/src/libstd/sys/sgx/ext/arch.rs
@@ -0,0 +1,74 @@
+//! SGX-specific access to architectural features.
+//!
+//! The functionality in this module is further documented in the Intel
+//! Software Developer's Manual, Volume 3, Chapter 40.
+#![unstable(feature = "sgx_platform", issue = "56975")]
+
+use crate::mem::MaybeUninit;
+
+/// Wrapper struct to force 16-byte alignment.
+#[repr(align(16))]
+#[unstable(feature = "sgx_platform", issue = "56975")]
+pub struct Align16<T>(pub T);
+
+/// Wrapper struct to force 128-byte alignment.
+#[repr(align(128))]
+#[unstable(feature = "sgx_platform", issue = "56975")]
+pub struct Align128<T>(pub T);
+
+/// Wrapper struct to force 512-byte alignment.
+#[repr(align(512))]
+#[unstable(feature = "sgx_platform", issue = "56975")]
+pub struct Align512<T>(pub T);
+
+const ENCLU_EREPORT: u32 = 0;
+const ENCLU_EGETKEY: u32 = 1;
+
+/// Call the `EGETKEY` instruction to obtain a 128-bit secret key.
+#[unstable(feature = "sgx_platform", issue = "56975")]
+pub fn egetkey(request: &Align512<[u8; 512]>) -> Result<Align16<[u8; 16]>, u32> {
+ unsafe {
+ let mut out = MaybeUninit::uninit();
+ let error;
+
+ asm!(
+ "enclu"
+ : "={eax}"(error)
+ : "{eax}"(ENCLU_EGETKEY),
+ "{rbx}"(request),
+ "{rcx}"(out.as_mut_ptr())
+ : "flags"
+ );
+
+ match error {
+ 0 => Ok(out.assume_init()),
+ err => Err(err),
+ }
+ }
+}
+
+/// Call the `EREPORT` instruction.
+///
+/// This creates a cryptographic report describing the contents of the current
+/// enclave. The report may be verified by the enclave described in
+/// `targetinfo`.
+#[unstable(feature = "sgx_platform", issue = "56975")]
+pub fn ereport(
+ targetinfo: &Align512<[u8; 512]>,
+ reportdata: &Align128<[u8; 64]>,
+) -> Align512<[u8; 432]> {
+ unsafe {
+ let mut report = MaybeUninit::uninit();
+
+ asm!(
+ "enclu"
+ : /* no output registers */
+ : "{eax}"(ENCLU_EREPORT),
+ "{rbx}"(targetinfo),
+ "{rcx}"(reportdata),
+ "{rdx}"(report.as_mut_ptr())
+ );
+
+ report.assume_init()
+ }
+}
diff --git a/src/libstd/sys/sgx/ext/ffi.rs b/src/libstd/sys/sgx/ext/ffi.rs
new file mode 100644
index 0000000..63fc5ff
--- /dev/null
+++ b/src/libstd/sys/sgx/ext/ffi.rs
@@ -0,0 +1,38 @@
+//! SGX-specific extension to the primitives in the `std::ffi` module
+//!
+//! # Examples
+//!
+//! ```
+//! use std::ffi::OsString;
+//! use std::os::fortanix_sgx::ffi::OsStringExt;
+//!
+//! let bytes = b"foo".to_vec();
+//!
+//! // OsStringExt::from_vec
+//! let os_string = OsString::from_vec(bytes);
+//! assert_eq!(os_string.to_str(), Some("foo"));
+//!
+//! // OsStringExt::into_vec
+//! let bytes = os_string.into_vec();
+//! assert_eq!(bytes, b"foo");
+//! ```
+//!
+//! ```
+//! use std::ffi::OsStr;
+//! use std::os::fortanix_sgx::ffi::OsStrExt;
+//!
+//! let bytes = b"foo";
+//!
+//! // OsStrExt::from_bytes
+//! let os_str = OsStr::from_bytes(bytes);
+//! assert_eq!(os_str.to_str(), Some("foo"));
+//!
+//! // OsStrExt::as_bytes
+//! let bytes = os_str.as_bytes();
+//! assert_eq!(bytes, b"foo");
+//! ```
+
+#![unstable(feature = "sgx_platform", issue = "56975")]
+
+#[unstable(feature = "sgx_platform", issue = "56975")]
+pub use crate::sys_common::os_str_bytes::*;
diff --git a/src/libstd/sys/sgx/ext/io.rs b/src/libstd/sys/sgx/ext/io.rs
new file mode 100644
index 0000000..fc88d10
--- /dev/null
+++ b/src/libstd/sys/sgx/ext/io.rs
@@ -0,0 +1,109 @@
+//! SGX-specific extensions to general I/O primitives
+//!
+//! SGX file descriptors behave differently from Unix file descriptors. See the
+//! description of [`TryIntoRawFd`](trait.TryIntoRawFd.html) for more details.
+#![unstable(feature = "sgx_platform", issue = "56975")]
+
+pub use crate::sys::abi::usercalls::raw::Fd as RawFd;
+use crate::net;
+use crate::sys::{self, AsInner, FromInner, IntoInner, TryIntoInner};
+
+/// A trait to extract the raw SGX file descriptor from an underlying
+/// object.
+#[unstable(feature = "sgx_platform", issue = "56975")]
+pub trait AsRawFd {
+ /// Extracts the raw file descriptor.
+ ///
+ /// This method does **not** pass ownership of the raw file descriptor
+ /// to the caller. The descriptor is only guaranteed to be valid while
+ /// the original object has not yet been destroyed.
+ #[unstable(feature = "sgx_platform", issue = "56975")]
+ fn as_raw_fd(&self) -> RawFd;
+}
+
+/// A trait to express the ability to construct an object from a raw file
+/// descriptor.
+#[unstable(feature = "sgx_platform", issue = "56975")]
+pub trait FromRawFd {
+ /// Constructs a new instance of `Self` from the given raw file
+ /// descriptor.
+ ///
+ /// This function **consumes ownership** of the specified file
+ /// descriptor. The returned object will take responsibility for closing
+ /// it when the object goes out of scope.
+ ///
+ /// This function is also unsafe as the primitives currently returned
+ /// have the contract that they are the sole owner of the file
+ /// descriptor they are wrapping. Usage of this function could
+ /// accidentally allow violating this contract which can cause memory
+ /// unsafety in code that relies on it being true.
+ #[unstable(feature = "sgx_platform", issue = "56975")]
+ unsafe fn from_raw_fd(fd: RawFd) -> Self;
+}
+
+/// A trait to express the ability to consume an object and acquire ownership of
+/// its raw file descriptor.
+#[unstable(feature = "sgx_platform", issue = "56975")]
+pub trait TryIntoRawFd: Sized {
+ /// Consumes this object, returning the raw underlying file descriptor, if
+ /// this object is not cloned.
+ ///
+ /// This function **transfers ownership** of the underlying file descriptor
+ /// to the caller. Callers are then the unique owners of the file descriptor
+ /// and must close the descriptor once it's no longer needed.
+ ///
+ /// Unlike other platforms, on SGX, the file descriptor is shared between
+ /// all clones of an object. To avoid race conditions, this function will
+ /// only return `Ok` when called on the final clone.
+ #[unstable(feature = "sgx_platform", issue = "56975")]
+ fn try_into_raw_fd(self) -> Result<RawFd, Self>;
+}
+
+impl AsRawFd for net::TcpStream {
+ fn as_raw_fd(&self) -> RawFd { *self.as_inner().as_inner().as_inner().as_inner() }
+}
+
+impl AsRawFd for net::TcpListener {
+ fn as_raw_fd(&self) -> RawFd { *self.as_inner().as_inner().as_inner().as_inner() }
+}
+
+impl FromRawFd for net::TcpStream {
+ unsafe fn from_raw_fd(fd: RawFd) -> net::TcpStream {
+ let fd = sys::fd::FileDesc::from_inner(fd);
+ let socket = sys::net::Socket::from_inner(fd);
+ net::TcpStream::from_inner(sys::net::TcpStream::from_inner((socket, None)))
+ }
+}
+
+impl FromRawFd for net::TcpListener {
+ unsafe fn from_raw_fd(fd: RawFd) -> net::TcpListener {
+ let fd = sys::fd::FileDesc::from_inner(fd);
+ let socket = sys::net::Socket::from_inner(fd);
+ net::TcpListener::from_inner(sys::net::TcpListener::from_inner(socket))
+ }
+}
+
+impl TryIntoRawFd for net::TcpStream {
+ fn try_into_raw_fd(self) -> Result<RawFd, Self> {
+ let (socket, peer_addr) = self.into_inner().into_inner();
+ match socket.try_into_inner() {
+ Ok(fd) => Ok(fd.into_inner()),
+ Err(socket) => {
+ let sys = sys::net::TcpStream::from_inner((socket, peer_addr));
+ Err(net::TcpStream::from_inner(sys))
+ }
+ }
+ }
+}
+
+impl TryIntoRawFd for net::TcpListener {
+ fn try_into_raw_fd(self) -> Result<RawFd, Self> {
+ match self.into_inner().into_inner().try_into_inner() {
+ Ok(fd) => Ok(fd.into_inner()),
+ Err(socket) => {
+ let sys = sys::net::TcpListener::from_inner(socket);
+ Err(net::TcpListener::from_inner(sys))
+ }
+ }
+ }
+}
diff --git a/src/libstd/sys/sgx/ext/mod.rs b/src/libstd/sys/sgx/ext/mod.rs
new file mode 100644
index 0000000..51b2659
--- /dev/null
+++ b/src/libstd/sys/sgx/ext/mod.rs
@@ -0,0 +1,5 @@
+#![unstable(feature = "sgx_platform", issue = "56975")]
+
+pub mod arch;
+pub mod io;
+pub mod ffi;
diff --git a/src/libstd/sys/sgx/fd.rs b/src/libstd/sys/sgx/fd.rs
new file mode 100644
index 0000000..a9924f5
--- /dev/null
+++ b/src/libstd/sys/sgx/fd.rs
@@ -0,0 +1,62 @@
+use fortanix_sgx_abi::Fd;
+
+use crate::io;
+use crate::mem;
+use crate::sys::{AsInner, FromInner, IntoInner};
+use super::abi::usercalls;
+
+#[derive(Debug)]
+pub struct FileDesc {
+ fd: Fd,
+}
+
+impl FileDesc {
+ pub fn new(fd: Fd) -> FileDesc {
+ FileDesc { fd: fd }
+ }
+
+ pub fn raw(&self) -> Fd { self.fd }
+
+ /// Extracts the actual filedescriptor without closing it.
+ pub fn into_raw(self) -> Fd {
+ let fd = self.fd;
+ mem::forget(self);
+ fd
+ }
+
+ pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
+ usercalls::read(self.fd, buf)
+ }
+
+ pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
+ usercalls::write(self.fd, buf)
+ }
+
+ pub fn flush(&self) -> io::Result<()> {
+ usercalls::flush(self.fd)
+ }
+}
+
+impl AsInner<Fd> for FileDesc {
+ fn as_inner(&self) -> &Fd { &self.fd }
+}
+
+impl IntoInner<Fd> for FileDesc {
+ fn into_inner(self) -> Fd {
+ let fd = self.fd;
+ mem::forget(self);
+ fd
+ }
+}
+
+impl FromInner<Fd> for FileDesc {
+ fn from_inner(fd: Fd) -> FileDesc {
+ FileDesc { fd }
+ }
+}
+
+impl Drop for FileDesc {
+ fn drop(&mut self) {
+ usercalls::close(self.fd)
+ }
+}
diff --git a/src/libstd/sys/sgx/fs.rs b/src/libstd/sys/sgx/fs.rs
new file mode 100644
index 0000000..68c8e93
--- /dev/null
+++ b/src/libstd/sys/sgx/fs.rs
@@ -0,0 +1,294 @@
+use crate::ffi::OsString;
+use crate::fmt;
+use crate::hash::{Hash, Hasher};
+use crate::io::{self, SeekFrom};
+use crate::path::{Path, PathBuf};
+use crate::sys::time::SystemTime;
+use crate::sys::{unsupported, Void};
+
+pub struct File(Void);
+
+pub struct FileAttr(Void);
+
+pub struct ReadDir(Void);
+
+pub struct DirEntry(Void);
+
+#[derive(Clone, Debug)]
+pub struct OpenOptions { }
+
+pub struct FilePermissions(Void);
+
+pub struct FileType(Void);
+
+#[derive(Debug)]
+pub struct DirBuilder { }
+
+impl FileAttr {
+ pub fn size(&self) -> u64 {
+ match self.0 {}
+ }
+
+ pub fn perm(&self) -> FilePermissions {
+ match self.0 {}
+ }
+
+ pub fn file_type(&self) -> FileType {
+ match self.0 {}
+ }
+
+ pub fn modified(&self) -> io::Result<SystemTime> {
+ match self.0 {}
+ }
+
+ pub fn accessed(&self) -> io::Result<SystemTime> {
+ match self.0 {}
+ }
+
+ pub fn created(&self) -> io::Result<SystemTime> {
+ match self.0 {}
+ }
+}
+
+impl Clone for FileAttr {
+ fn clone(&self) -> FileAttr {
+ match self.0 {}
+ }
+}
+
+impl FilePermissions {
+ pub fn readonly(&self) -> bool {
+ match self.0 {}
+ }
+
+ pub fn set_readonly(&mut self, _readonly: bool) {
+ match self.0 {}
+ }
+}
+
+impl Clone for FilePermissions {
+ fn clone(&self) -> FilePermissions {
+ match self.0 {}
+ }
+}
+
+impl PartialEq for FilePermissions {
+ fn eq(&self, _other: &FilePermissions) -> bool {
+ match self.0 {}
+ }
+}
+
+impl Eq for FilePermissions {
+}
+
+impl fmt::Debug for FilePermissions {
+ fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self.0 {}
+ }
+}
+
+impl FileType {
+ pub fn is_dir(&self) -> bool {
+ match self.0 {}
+ }
+
+ pub fn is_file(&self) -> bool {
+ match self.0 {}
+ }
+
+ pub fn is_symlink(&self) -> bool {
+ match self.0 {}
+ }
+}
+
+impl Clone for FileType {
+ fn clone(&self) -> FileType {
+ match self.0 {}
+ }
+}
+
+impl Copy for FileType {}
+
+impl PartialEq for FileType {
+ fn eq(&self, _other: &FileType) -> bool {
+ match self.0 {}
+ }
+}
+
+impl Eq for FileType {
+}
+
+impl Hash for FileType {
+ fn hash<H: Hasher>(&self, _h: &mut H) {
+ match self.0 {}
+ }
+}
+
+impl fmt::Debug for FileType {
+ fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self.0 {}
+ }
+}
+
+impl fmt::Debug for ReadDir {
+ fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self.0 {}
+ }
+}
+
+impl Iterator for ReadDir {
+ type Item = io::Result<DirEntry>;
+
+ fn next(&mut self) -> Option<io::Result<DirEntry>> {
+ match self.0 {}
+ }
+}
+
+impl DirEntry {
+ pub fn path(&self) -> PathBuf {
+ match self.0 {}
+ }
+
+ pub fn file_name(&self) -> OsString {
+ match self.0 {}
+ }
+
+ pub fn metadata(&self) -> io::Result<FileAttr> {
+ match self.0 {}
+ }
+
+ pub fn file_type(&self) -> io::Result<FileType> {
+ match self.0 {}
+ }
+}
+
+impl OpenOptions {
+ pub fn new() -> OpenOptions {
+ OpenOptions { }
+ }
+
+ pub fn read(&mut self, _read: bool) { }
+ pub fn write(&mut self, _write: bool) { }
+ pub fn append(&mut self, _append: bool) { }
+ pub fn truncate(&mut self, _truncate: bool) { }
+ pub fn create(&mut self, _create: bool) { }
+ pub fn create_new(&mut self, _create_new: bool) { }
+}
+
+impl File {
+ pub fn open(_path: &Path, _opts: &OpenOptions) -> io::Result<File> {
+ unsupported()
+ }
+
+ pub fn file_attr(&self) -> io::Result<FileAttr> {
+ match self.0 {}
+ }
+
+ pub fn fsync(&self) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn datasync(&self) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn truncate(&self, _size: u64) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn read(&self, _buf: &mut [u8]) -> io::Result<usize> {
+ match self.0 {}
+ }
+
+ pub fn write(&self, _buf: &[u8]) -> io::Result<usize> {
+ match self.0 {}
+ }
+
+ pub fn flush(&self) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn seek(&self, _pos: SeekFrom) -> io::Result<u64> {
+ match self.0 {}
+ }
+
+ pub fn duplicate(&self) -> io::Result<File> {
+ match self.0 {}
+ }
+
+ pub fn set_permissions(&self, _perm: FilePermissions) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn diverge(&self) -> ! {
+ match self.0 {}
+ }
+}
+
+impl DirBuilder {
+ pub fn new() -> DirBuilder {
+ DirBuilder { }
+ }
+
+ pub fn mkdir(&self, _p: &Path) -> io::Result<()> {
+ unsupported()
+ }
+}
+
+impl fmt::Debug for File {
+ fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self.0 {}
+ }
+}
+
+pub fn readdir(_p: &Path) -> io::Result<ReadDir> {
+ unsupported()
+}
+
+pub fn unlink(_p: &Path) -> io::Result<()> {
+ unsupported()
+}
+
+pub fn rename(_old: &Path, _new: &Path) -> io::Result<()> {
+ unsupported()
+}
+
+pub fn set_perm(_p: &Path, perm: FilePermissions) -> io::Result<()> {
+ match perm.0 {}
+}
+
+pub fn rmdir(_p: &Path) -> io::Result<()> {
+ unsupported()
+}
+
+pub fn remove_dir_all(_path: &Path) -> io::Result<()> {
+ unsupported()
+}
+
+pub fn readlink(_p: &Path) -> io::Result<PathBuf> {
+ unsupported()
+}
+
+pub fn symlink(_src: &Path, _dst: &Path) -> io::Result<()> {
+ unsupported()
+}
+
+pub fn link(_src: &Path, _dst: &Path) -> io::Result<()> {
+ unsupported()
+}
+
+pub fn stat(_p: &Path) -> io::Result<FileAttr> {
+ unsupported()
+}
+
+pub fn lstat(_p: &Path) -> io::Result<FileAttr> {
+ unsupported()
+}
+
+pub fn canonicalize(_p: &Path) -> io::Result<PathBuf> {
+ unsupported()
+}
+
+pub fn copy(_from: &Path, _to: &Path) -> io::Result<u64> {
+ unsupported()
+}
diff --git a/src/libstd/sys/sgx/io.rs b/src/libstd/sys/sgx/io.rs
new file mode 100644
index 0000000..8b02d3f
--- /dev/null
+++ b/src/libstd/sys/sgx/io.rs
@@ -0,0 +1,32 @@
+pub struct IoVec<'a>(&'a [u8]);
+
+impl<'a> IoVec<'a> {
+ #[inline]
+ pub fn new(buf: &'a [u8]) -> IoVec<'a> {
+ IoVec(buf)
+ }
+
+ #[inline]
+ pub fn as_slice(&self) -> &[u8] {
+ self.0
+ }
+}
+
+pub struct IoVecMut<'a>(&'a mut [u8]);
+
+impl<'a> IoVecMut<'a> {
+ #[inline]
+ pub fn new(buf: &'a mut [u8]) -> IoVecMut<'a> {
+ IoVecMut(buf)
+ }
+
+ #[inline]
+ pub fn as_slice(&self) -> &[u8] {
+ self.0
+ }
+
+ #[inline]
+ pub fn as_mut_slice(&mut self) -> &mut [u8] {
+ self.0
+ }
+}
diff --git a/src/libstd/sys/sgx/memchr.rs b/src/libstd/sys/sgx/memchr.rs
new file mode 100644
index 0000000..9967482
--- /dev/null
+++ b/src/libstd/sys/sgx/memchr.rs
@@ -0,0 +1 @@
+pub use core::slice::memchr::{memchr, memrchr};
diff --git a/src/libstd/sys/sgx/mod.rs b/src/libstd/sys/sgx/mod.rs
new file mode 100644
index 0000000..a99a534
--- /dev/null
+++ b/src/libstd/sys/sgx/mod.rs
@@ -0,0 +1,161 @@
+//! System bindings for the Fortanix SGX platform
+//!
+//! This module contains the facade (aka platform-specific) implementations of
+//! OS level functionality for Fortanix SGX.
+
+use crate::io::ErrorKind;
+use crate::os::raw::c_char;
+use crate::sync::atomic::{AtomicBool, Ordering};
+
+pub mod abi;
+mod waitqueue;
+
+pub mod alloc;
+pub mod args;
+#[cfg(feature = "backtrace")]
+pub mod backtrace;
+pub mod cmath;
+pub mod condvar;
+pub mod env;
+pub mod ext;
+pub mod fd;
+pub mod fs;
+pub mod io;
+pub mod memchr;
+pub mod mutex;
+pub mod net;
+pub mod os;
+pub mod path;
+pub mod pipe;
+pub mod process;
+pub mod rwlock;
+pub mod stack_overflow;
+pub mod thread;
+pub mod thread_local;
+pub mod time;
+pub mod stdio;
+
+pub use crate::sys_common::os_str_bytes as os_str;
+
+#[cfg(not(test))]
+pub fn init() {
+}
+
+/// This function is used to implement functionality that simply doesn't exist.
+/// Programs relying on this functionality will need to deal with the error.
+pub fn unsupported<T>() -> crate::io::Result<T> {
+ Err(unsupported_err())
+}
+
+pub fn unsupported_err() -> crate::io::Error {
+ crate::io::Error::new(ErrorKind::Other,
+ "operation not supported on SGX yet")
+}
+
+/// This function is used to implement various functions that doesn't exist,
+/// but the lack of which might not be reason for error. If no error is
+/// returned, the program might very well be able to function normally. This is
+/// what happens when `SGX_INEFFECTIVE_ERROR` is set to `true`. If it is
+/// `false`, the behavior is the same as `unsupported`.
+pub fn sgx_ineffective<T>(v: T) -> crate::io::Result<T> {
+ static SGX_INEFFECTIVE_ERROR: AtomicBool = AtomicBool::new(false);
+ if SGX_INEFFECTIVE_ERROR.load(Ordering::Relaxed) {
+ Err(crate::io::Error::new(ErrorKind::Other,
+ "operation can't be trusted to have any effect on SGX"))
+ } else {
+ Ok(v)
+ }
+}
+
+pub fn decode_error_kind(code: i32) -> ErrorKind {
+ use fortanix_sgx_abi::Error;
+
+ // FIXME: not sure how to make sure all variants of Error are covered
+ if code == Error::NotFound as _ {
+ ErrorKind::NotFound
+ } else if code == Error::PermissionDenied as _ {
+ ErrorKind::PermissionDenied
+ } else if code == Error::ConnectionRefused as _ {
+ ErrorKind::ConnectionRefused
+ } else if code == Error::ConnectionReset as _ {
+ ErrorKind::ConnectionReset
+ } else if code == Error::ConnectionAborted as _ {
+ ErrorKind::ConnectionAborted
+ } else if code == Error::NotConnected as _ {
+ ErrorKind::NotConnected
+ } else if code == Error::AddrInUse as _ {
+ ErrorKind::AddrInUse
+ } else if code == Error::AddrNotAvailable as _ {
+ ErrorKind::AddrNotAvailable
+ } else if code == Error::BrokenPipe as _ {
+ ErrorKind::BrokenPipe
+ } else if code == Error::AlreadyExists as _ {
+ ErrorKind::AlreadyExists
+ } else if code == Error::WouldBlock as _ {
+ ErrorKind::WouldBlock
+ } else if code == Error::InvalidInput as _ {
+ ErrorKind::InvalidInput
+ } else if code == Error::InvalidData as _ {
+ ErrorKind::InvalidData
+ } else if code == Error::TimedOut as _ {
+ ErrorKind::TimedOut
+ } else if code == Error::WriteZero as _ {
+ ErrorKind::WriteZero
+ } else if code == Error::Interrupted as _ {
+ ErrorKind::Interrupted
+ } else if code == Error::Other as _ {
+ ErrorKind::Other
+ } else if code == Error::UnexpectedEof as _ {
+ ErrorKind::UnexpectedEof
+ } else {
+ ErrorKind::Other
+ }
+}
+
+// This enum is used as the storage for a bunch of types which can't actually
+// exist.
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
+pub enum Void {}
+
+pub unsafe fn strlen(mut s: *const c_char) -> usize {
+ let mut n = 0;
+ while *s != 0 {
+ n += 1;
+ s = s.offset(1);
+ }
+ return n
+}
+
+pub unsafe fn abort_internal() -> ! {
+ abi::usercalls::exit(true)
+}
+
+// This function is needed by the panic runtime. The symbol is named in
+// pre-link args for the target specification, so keep that in sync.
+#[cfg(not(test))]
+#[no_mangle]
+// NB. used by both libunwind and libpanic_abort
+pub unsafe extern "C" fn __rust_abort() {
+ abort_internal();
+}
+
+pub fn hashmap_random_keys() -> (u64, u64) {
+ fn rdrand64() -> u64 {
+ unsafe {
+ let mut ret: u64 = crate::mem::uninitialized();
+ for _ in 0..10 {
+ if crate::arch::x86_64::_rdrand64_step(&mut ret) == 1 {
+ return ret;
+ }
+ }
+ rtabort!("Failed to obtain random data");
+ }
+ }
+ (rdrand64(), rdrand64())
+}
+
+pub use crate::sys_common::{AsInner, FromInner, IntoInner};
+
+pub trait TryIntoInner<Inner>: Sized {
+ fn try_into_inner(self) -> Result<Inner, Self>;
+}
diff --git a/src/libstd/sys/sgx/mutex.rs b/src/libstd/sys/sgx/mutex.rs
new file mode 100644
index 0000000..f325fb1
--- /dev/null
+++ b/src/libstd/sys/sgx/mutex.rs
@@ -0,0 +1,140 @@
+use fortanix_sgx_abi::Tcs;
+
+use super::abi::thread;
+
+use super::waitqueue::{WaitVariable, WaitQueue, SpinMutex, NotifiedTcs, try_lock_or_false};
+
+pub struct Mutex {
+ inner: SpinMutex<WaitVariable<bool>>,
+}
+
+// Implementation according to “Operating Systems: Three Easy Pieces”, chapter 28
+impl Mutex {
+ pub const fn new() -> Mutex {
+ Mutex { inner: SpinMutex::new(WaitVariable::new(false)) }
+ }
+
+ #[inline]
+ pub unsafe fn init(&mut self) {}
+
+ #[inline]
+ pub unsafe fn lock(&self) {
+ let mut guard = self.inner.lock();
+ if *guard.lock_var() {
+ // Another thread has the lock, wait
+ WaitQueue::wait(guard)
+ // Another thread has passed the lock to us
+ } else {
+ // We are just now obtaining the lock
+ *guard.lock_var_mut() = true;
+ }
+ }
+
+ #[inline]
+ pub unsafe fn unlock(&self) {
+ let guard = self.inner.lock();
+ if let Err(mut guard) = WaitQueue::notify_one(guard) {
+ // No other waiters, unlock
+ *guard.lock_var_mut() = false;
+ } else {
+ // There was a thread waiting, just pass the lock
+ }
+ }
+
+ #[inline]
+ pub unsafe fn try_lock(&self) -> bool {
+ let mut guard = try_lock_or_false!(self.inner);
+ if *guard.lock_var() {
+ // Another thread has the lock
+ false
+ } else {
+ // We are just now obtaining the lock
+ *guard.lock_var_mut() = true;
+ true
+ }
+ }
+
+ #[inline]
+ pub unsafe fn destroy(&self) {}
+}
+
+struct ReentrantLock {
+ owner: Option<Tcs>,
+ count: usize
+}
+
+pub struct ReentrantMutex {
+ inner: SpinMutex<WaitVariable<ReentrantLock>>,
+}
+
+impl ReentrantMutex {
+ pub const fn uninitialized() -> ReentrantMutex {
+ ReentrantMutex {
+ inner: SpinMutex::new(WaitVariable::new(ReentrantLock { owner: None, count: 0 }))
+ }
+ }
+
+ #[inline]
+ pub unsafe fn init(&mut self) {}
+
+ #[inline]
+ pub unsafe fn lock(&self) {
+ let mut guard = self.inner.lock();
+ match guard.lock_var().owner {
+ Some(tcs) if tcs != thread::current() => {
+ // Another thread has the lock, wait
+ WaitQueue::wait(guard);
+ // Another thread has passed the lock to us
+ },
+ _ => {
+ // We are just now obtaining the lock
+ guard.lock_var_mut().owner = Some(thread::current());
+ guard.lock_var_mut().count += 1;
+ },
+ }
+ }
+
+ #[inline]
+ pub unsafe fn unlock(&self) {
+ let mut guard = self.inner.lock();
+ if guard.lock_var().count > 1 {
+ guard.lock_var_mut().count -= 1;
+ } else {
+ match WaitQueue::notify_one(guard) {
+ Err(mut guard) => {
+ // No other waiters, unlock
+ guard.lock_var_mut().count = 0;
+ guard.lock_var_mut().owner = None;
+ },
+ Ok(mut guard) => {
+ // There was a thread waiting, just pass the lock
+ if let NotifiedTcs::Single(tcs) = guard.notified_tcs() {
+ guard.lock_var_mut().owner = Some(tcs)
+ } else {
+ unreachable!() // called notify_one
+ }
+ }
+ }
+ }
+ }
+
+ #[inline]
+ pub unsafe fn try_lock(&self) -> bool {
+ let mut guard = try_lock_or_false!(self.inner);
+ match guard.lock_var().owner {
+ Some(tcs) if tcs != thread::current() => {
+ // Another thread has the lock
+ false
+ },
+ _ => {
+ // We are just now obtaining the lock
+ guard.lock_var_mut().owner = Some(thread::current());
+ guard.lock_var_mut().count += 1;
+ true
+ },
+ }
+ }
+
+ #[inline]
+ pub unsafe fn destroy(&self) {}
+}
diff --git a/src/libstd/sys/sgx/net.rs b/src/libstd/sys/sgx/net.rs
new file mode 100644
index 0000000..10cc644
--- /dev/null
+++ b/src/libstd/sys/sgx/net.rs
@@ -0,0 +1,518 @@
+use crate::fmt;
+use crate::io::{self, IoVec, IoVecMut};
+use crate::net::{SocketAddr, Shutdown, Ipv4Addr, Ipv6Addr, ToSocketAddrs};
+use crate::time::Duration;
+use crate::sys::{unsupported, Void, sgx_ineffective, AsInner, FromInner, IntoInner, TryIntoInner};
+use crate::sys::fd::FileDesc;
+use crate::convert::TryFrom;
+use crate::error;
+use crate::sync::Arc;
+
+use super::abi::usercalls;
+
+const DEFAULT_FAKE_TTL: u32 = 64;
+
+#[derive(Debug, Clone)]
+pub struct Socket {
+ inner: Arc<FileDesc>,
+ local_addr: Option<String>,
+}
+
+impl Socket {
+ fn new(fd: usercalls::raw::Fd, local_addr: String) -> Socket {
+ Socket { inner: Arc::new(FileDesc::new(fd)), local_addr: Some(local_addr) }
+ }
+}
+
+impl AsInner<FileDesc> for Socket {
+ fn as_inner(&self) -> &FileDesc { &self.inner }
+}
+
+impl TryIntoInner<FileDesc> for Socket {
+ fn try_into_inner(self) -> Result<FileDesc, Socket> {
+ let Socket { inner, local_addr } = self;
+ Arc::try_unwrap(inner).map_err(|inner| Socket { inner, local_addr } )
+ }
+}
+
+impl FromInner<FileDesc> for Socket {
+ fn from_inner(inner: FileDesc) -> Socket {
+ Socket { inner: Arc::new(inner), local_addr: None }
+ }
+}
+
+#[derive(Clone)]
+pub struct TcpStream {
+ inner: Socket,
+ peer_addr: Option<String>,
+}
+
+impl fmt::Debug for TcpStream {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ let mut res = f.debug_struct("TcpStream");
+
+ if let Some(ref addr) = self.inner.local_addr {
+ res.field("addr", addr);
+ }
+
+ if let Some(ref peer) = self.peer_addr {
+ res.field("peer", peer);
+ }
+
+ res.field("fd", &self.inner.inner.as_inner())
+ .finish()
+ }
+}
+
+fn io_err_to_addr(result: io::Result<&SocketAddr>) -> io::Result<String> {
+ match result {
+ Ok(saddr) => Ok(saddr.to_string()),
+ // need to downcast twice because io::Error::into_inner doesn't return the original
+ // value if the conversion fails
+ Err(e) => if e.get_ref().and_then(|e| e.downcast_ref::<NonIpSockAddr>()).is_some() {
+ Ok(e.into_inner().unwrap().downcast::<NonIpSockAddr>().unwrap().host)
+ } else {
+ Err(e)
+ }
+ }
+}
+
+fn addr_to_sockaddr(addr: &Option<String>) -> io::Result<SocketAddr> {
+ addr.as_ref()
+ .ok_or(io::ErrorKind::AddrNotAvailable)?
+ .to_socket_addrs()
+ // unwrap OK: if an iterator is returned, we're guaranteed to get exactly one entry
+ .map(|mut it| it.next().unwrap())
+}
+
+impl TcpStream {
+ pub fn connect(addr: io::Result<&SocketAddr>) -> io::Result<TcpStream> {
+ let addr = io_err_to_addr(addr)?;
+ let (fd, local_addr, peer_addr) = usercalls::connect_stream(&addr)?;
+ Ok(TcpStream { inner: Socket::new(fd, local_addr), peer_addr: Some(peer_addr) })
+ }
+
+ pub fn connect_timeout(addr: &SocketAddr, dur: Duration) -> io::Result<TcpStream> {
+ if dur == Duration::default() {
+ return Err(io::Error::new(io::ErrorKind::InvalidInput,
+ "cannot set a 0 duration timeout"));
+ }
+ Self::connect(Ok(addr)) // FIXME: ignoring timeout
+ }
+
+ pub fn set_read_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
+ match dur {
+ Some(dur) if dur == Duration::default() => {
+ return Err(io::Error::new(io::ErrorKind::InvalidInput,
+ "cannot set a 0 duration timeout"));
+ }
+ _ => sgx_ineffective(())
+ }
+ }
+
+ pub fn set_write_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
+ match dur {
+ Some(dur) if dur == Duration::default() => {
+ return Err(io::Error::new(io::ErrorKind::InvalidInput,
+ "cannot set a 0 duration timeout"));
+ }
+ _ => sgx_ineffective(())
+ }
+ }
+
+ pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
+ sgx_ineffective(None)
+ }
+
+ pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
+ sgx_ineffective(None)
+ }
+
+ pub fn peek(&self, _: &mut [u8]) -> io::Result<usize> {
+ Ok(0)
+ }
+
+ pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
+ self.inner.inner.read(buf)
+ }
+
+ pub fn read_vectored(&self, bufs: &mut [IoVecMut<'_>]) -> io::Result<usize> {
+ io::default_read_vectored(|b| self.read(b), bufs)
+ }
+
+ pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
+ self.inner.inner.write(buf)
+ }
+
+ pub fn write_vectored(&self, bufs: &[IoVec<'_>]) -> io::Result<usize> {
+ io::default_write_vectored(|b| self.write(b), bufs)
+ }
+
+ pub fn peer_addr(&self) -> io::Result<SocketAddr> {
+ addr_to_sockaddr(&self.peer_addr)
+ }
+
+ pub fn socket_addr(&self) -> io::Result<SocketAddr> {
+ addr_to_sockaddr(&self.inner.local_addr)
+ }
+
+ pub fn shutdown(&self, _: Shutdown) -> io::Result<()> {
+ sgx_ineffective(())
+ }
+
+ pub fn duplicate(&self) -> io::Result<TcpStream> {
+ Ok(self.clone())
+ }
+
+ pub fn set_nodelay(&self, _: bool) -> io::Result<()> {
+ sgx_ineffective(())
+ }
+
+ pub fn nodelay(&self) -> io::Result<bool> {
+ sgx_ineffective(false)
+ }
+
+ pub fn set_ttl(&self, _: u32) -> io::Result<()> {
+ sgx_ineffective(())
+ }
+
+ pub fn ttl(&self) -> io::Result<u32> {
+ sgx_ineffective(DEFAULT_FAKE_TTL)
+ }
+
+ pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+ Ok(None)
+ }
+
+ pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
+ sgx_ineffective(())
+ }
+}
+
+impl AsInner<Socket> for TcpStream {
+ fn as_inner(&self) -> &Socket { &self.inner }
+}
+
+// `Inner` includes `peer_addr` so that a `TcpStream` maybe correctly
+// reconstructed if `Socket::try_into_inner` fails.
+impl IntoInner<(Socket, Option<String>)> for TcpStream {
+ fn into_inner(self) -> (Socket, Option<String>) {
+ (self.inner, self.peer_addr)
+ }
+}
+
+impl FromInner<(Socket, Option<String>)> for TcpStream {
+ fn from_inner((inner, peer_addr): (Socket, Option<String>)) -> TcpStream {
+ TcpStream { inner, peer_addr }
+ }
+}
+
+#[derive(Clone)]
+pub struct TcpListener {
+ inner: Socket,
+}
+
+impl fmt::Debug for TcpListener {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ let mut res = f.debug_struct("TcpListener");
+
+ if let Some(ref addr) = self.inner.local_addr {
+ res.field("addr", addr);
+ }
+
+ res.field("fd", &self.inner.inner.as_inner())
+ .finish()
+ }
+}
+
+impl TcpListener {
+ pub fn bind(addr: io::Result<&SocketAddr>) -> io::Result<TcpListener> {
+ let addr = io_err_to_addr(addr)?;
+ let (fd, local_addr) = usercalls::bind_stream(&addr)?;
+ Ok(TcpListener { inner: Socket::new(fd, local_addr) })
+ }
+
+ pub fn socket_addr(&self) -> io::Result<SocketAddr> {
+ addr_to_sockaddr(&self.inner.local_addr)
+ }
+
+ pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> {
+ let (fd, local_addr, peer_addr) = usercalls::accept_stream(self.inner.inner.raw())?;
+ let peer_addr = Some(peer_addr);
+ let ret_peer = addr_to_sockaddr(&peer_addr).unwrap_or_else(|_| ([0; 4], 0).into());
+ Ok((TcpStream { inner: Socket::new(fd, local_addr), peer_addr }, ret_peer))
+ }
+
+ pub fn duplicate(&self) -> io::Result<TcpListener> {
+ Ok(self.clone())
+ }
+
+ pub fn set_ttl(&self, _: u32) -> io::Result<()> {
+ sgx_ineffective(())
+ }
+
+ pub fn ttl(&self) -> io::Result<u32> {
+ sgx_ineffective(DEFAULT_FAKE_TTL)
+ }
+
+ pub fn set_only_v6(&self, _: bool) -> io::Result<()> {
+ sgx_ineffective(())
+ }
+
+ pub fn only_v6(&self) -> io::Result<bool> {
+ sgx_ineffective(false)
+ }
+
+ pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+ Ok(None)
+ }
+
+ pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
+ sgx_ineffective(())
+ }
+}
+
+impl AsInner<Socket> for TcpListener {
+ fn as_inner(&self) -> &Socket { &self.inner }
+}
+
+impl IntoInner<Socket> for TcpListener {
+ fn into_inner(self) -> Socket {
+ self.inner
+ }
+}
+
+impl FromInner<Socket> for TcpListener {
+ fn from_inner(inner: Socket) -> TcpListener {
+ TcpListener { inner }
+ }
+}
+
+pub struct UdpSocket(Void);
+
+impl UdpSocket {
+ pub fn bind(_: io::Result<&SocketAddr>) -> io::Result<UdpSocket> {
+ unsupported()
+ }
+
+ pub fn peer_addr(&self) -> io::Result<SocketAddr> {
+ match self.0 {}
+ }
+
+ pub fn socket_addr(&self) -> io::Result<SocketAddr> {
+ match self.0 {}
+ }
+
+ pub fn recv_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+ match self.0 {}
+ }
+
+ pub fn peek_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+ match self.0 {}
+ }
+
+ pub fn send_to(&self, _: &[u8], _: &SocketAddr) -> io::Result<usize> {
+ match self.0 {}
+ }
+
+ pub fn duplicate(&self) -> io::Result<UdpSocket> {
+ match self.0 {}
+ }
+
+ pub fn set_read_timeout(&self, _: Option<Duration>) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn set_write_timeout(&self, _: Option<Duration>) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
+ match self.0 {}
+ }
+
+ pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
+ match self.0 {}
+ }
+
+ pub fn set_broadcast(&self, _: bool) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn broadcast(&self) -> io::Result<bool> {
+ match self.0 {}
+ }
+
+ pub fn set_multicast_loop_v4(&self, _: bool) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn multicast_loop_v4(&self) -> io::Result<bool> {
+ match self.0 {}
+ }
+
+ pub fn set_multicast_ttl_v4(&self, _: u32) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn multicast_ttl_v4(&self) -> io::Result<u32> {
+ match self.0 {}
+ }
+
+ pub fn set_multicast_loop_v6(&self, _: bool) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn multicast_loop_v6(&self) -> io::Result<bool> {
+ match self.0 {}
+ }
+
+ pub fn join_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr)
+ -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn join_multicast_v6(&self, _: &Ipv6Addr, _: u32)
+ -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn leave_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr)
+ -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn leave_multicast_v6(&self, _: &Ipv6Addr, _: u32)
+ -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn set_ttl(&self, _: u32) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn ttl(&self) -> io::Result<u32> {
+ match self.0 {}
+ }
+
+ pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+ match self.0 {}
+ }
+
+ pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn recv(&self, _: &mut [u8]) -> io::Result<usize> {
+ match self.0 {}
+ }
+
+ pub fn peek(&self, _: &mut [u8]) -> io::Result<usize> {
+ match self.0 {}
+ }
+
+ pub fn send(&self, _: &[u8]) -> io::Result<usize> {
+ match self.0 {}
+ }
+
+ pub fn connect(&self, _: io::Result<&SocketAddr>) -> io::Result<()> {
+ match self.0 {}
+ }
+}
+
+impl fmt::Debug for UdpSocket {
+ fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self.0 {}
+ }
+}
+
+#[derive(Debug)]
+pub struct NonIpSockAddr {
+ host: String
+}
+
+impl error::Error for NonIpSockAddr {
+ fn description(&self) -> &str {
+ "Failed to convert address to SocketAddr"
+ }
+}
+
+impl fmt::Display for NonIpSockAddr {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "Failed to convert address to SocketAddr: {}", self.host)
+ }
+}
+
+pub struct LookupHost(Void);
+
+impl LookupHost {
+ fn new(host: String) -> io::Result<LookupHost> {
+ Err(io::Error::new(io::ErrorKind::Other, NonIpSockAddr { host }))
+ }
+
+ pub fn port(&self) -> u16 {
+ match self.0 {}
+ }
+}
+
+impl Iterator for LookupHost {
+ type Item = SocketAddr;
+ fn next(&mut self) -> Option<SocketAddr> {
+ match self.0 {}
+ }
+}
+
+impl TryFrom<&str> for LookupHost {
+ type Error = io::Error;
+
+ fn try_from(v: &str) -> io::Result<LookupHost> {
+ LookupHost::new(v.to_owned())
+ }
+}
+
+impl<'a> TryFrom<(&'a str, u16)> for LookupHost {
+ type Error = io::Error;
+
+ fn try_from((host, port): (&'a str, u16)) -> io::Result<LookupHost> {
+ LookupHost::new(format!("{}:{}", host, port))
+ }
+}
+
+#[allow(bad_style)]
+pub mod netc {
+ pub const AF_INET: u8 = 0;
+ pub const AF_INET6: u8 = 1;
+ pub type sa_family_t = u8;
+
+ #[derive(Copy, Clone)]
+ pub struct in_addr {
+ pub s_addr: u32,
+ }
+
+ #[derive(Copy, Clone)]
+ pub struct sockaddr_in {
+ pub sin_family: sa_family_t,
+ pub sin_port: u16,
+ pub sin_addr: in_addr,
+ }
+
+ #[derive(Copy, Clone)]
+ pub struct in6_addr {
+ pub s6_addr: [u8; 16],
+ }
+
+ #[derive(Copy, Clone)]
+ pub struct sockaddr_in6 {
+ pub sin6_family: sa_family_t,
+ pub sin6_port: u16,
+ pub sin6_addr: in6_addr,
+ pub sin6_flowinfo: u32,
+ pub sin6_scope_id: u32,
+ }
+
+ #[derive(Copy, Clone)]
+ pub struct sockaddr {
+ }
+
+ pub type socklen_t = usize;
+}
diff --git a/src/libstd/sys/sgx/os.rs b/src/libstd/sys/sgx/os.rs
new file mode 100644
index 0000000..8b12c49
--- /dev/null
+++ b/src/libstd/sys/sgx/os.rs
@@ -0,0 +1,141 @@
+use fortanix_sgx_abi::{Error, RESULT_SUCCESS};
+
+use crate::error::Error as StdError;
+use crate::ffi::{OsString, OsStr};
+use crate::fmt;
+use crate::io;
+use crate::path::{self, PathBuf};
+use crate::str;
+use crate::sys::{unsupported, Void, sgx_ineffective, decode_error_kind};
+use crate::collections::HashMap;
+use crate::vec;
+use crate::sync::Mutex;
+use crate::sync::atomic::{AtomicUsize, Ordering};
+use crate::sync::Once;
+
+pub fn errno() -> i32 {
+ RESULT_SUCCESS
+}
+
+pub fn error_string(errno: i32) -> String {
+ if errno == RESULT_SUCCESS {
+ "operation succesful".into()
+ } else if ((Error::UserRangeStart as _)..=(Error::UserRangeEnd as _)).contains(&errno) {
+ format!("user-specified error {:08x}", errno)
+ } else {
+ decode_error_kind(errno).as_str().into()
+ }
+}
+
+pub fn getcwd() -> io::Result<PathBuf> {
+ unsupported()
+}
+
+pub fn chdir(_: &path::Path) -> io::Result<()> {
+ sgx_ineffective(())
+}
+
+pub struct SplitPaths<'a>(&'a Void);
+
+pub fn split_paths(_unparsed: &OsStr) -> SplitPaths<'_> {
+ panic!("unsupported")
+}
+
+impl<'a> Iterator for SplitPaths<'a> {
+ type Item = PathBuf;
+ fn next(&mut self) -> Option<PathBuf> {
+ match *self.0 {}
+ }
+}
+
+#[derive(Debug)]
+pub struct JoinPathsError;
+
+pub fn join_paths<I, T>(_paths: I) -> Result<OsString, JoinPathsError>
+ where I: Iterator<Item=T>, T: AsRef<OsStr>
+{
+ Err(JoinPathsError)
+}
+
+impl fmt::Display for JoinPathsError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ "not supported in SGX yet".fmt(f)
+ }
+}
+
+impl StdError for JoinPathsError {
+ fn description(&self) -> &str {
+ "not supported in SGX yet"
+ }
+}
+
+pub fn current_exe() -> io::Result<PathBuf> {
+ unsupported()
+}
+
+#[cfg_attr(test, linkage = "available_externally")]
+#[export_name = "_ZN16__rust_internals3std3sys3sgx2os3ENVE"]
+static ENV: AtomicUsize = AtomicUsize::new(0);
+#[cfg_attr(test, linkage = "available_externally")]
+#[export_name = "_ZN16__rust_internals3std3sys3sgx2os8ENV_INITE"]
+static ENV_INIT: Once = Once::new();
+type EnvStore = Mutex<HashMap<OsString, OsString>>;
+
+fn get_env_store() -> Option<&'static EnvStore> {
+ unsafe { (ENV.load(Ordering::Relaxed) as *const EnvStore).as_ref() }
+}
+
+fn create_env_store() -> &'static EnvStore {
+ ENV_INIT.call_once(|| {
+ ENV.store(Box::into_raw(Box::new(EnvStore::default())) as _, Ordering::Relaxed)
+ });
+ unsafe {
+ &*(ENV.load(Ordering::Relaxed) as *const EnvStore)
+ }
+}
+
+pub type Env = vec::IntoIter<(OsString, OsString)>;
+
+pub fn env() -> Env {
+ let clone_to_vec = |map: &HashMap<OsString, OsString>| -> Vec<_> {
+ map.iter().map(|(k, v)| (k.clone(), v.clone()) ).collect()
+ };
+
+ get_env_store()
+ .map(|env| clone_to_vec(&env.lock().unwrap()) )
+ .unwrap_or_default()
+ .into_iter()
+}
+
+pub fn getenv(k: &OsStr) -> io::Result<Option<OsString>> {
+ Ok(get_env_store().and_then(|s| s.lock().unwrap().get(k).cloned() ))
+}
+
+pub fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> {
+ let (k, v) = (k.to_owned(), v.to_owned());
+ create_env_store().lock().unwrap().insert(k, v);
+ Ok(())
+}
+
+pub fn unsetenv(k: &OsStr) -> io::Result<()> {
+ if let Some(env) = get_env_store() {
+ env.lock().unwrap().remove(k);
+ }
+ Ok(())
+}
+
+pub fn temp_dir() -> PathBuf {
+ panic!("no filesystem in SGX")
+}
+
+pub fn home_dir() -> Option<PathBuf> {
+ None
+}
+
+pub fn exit(code: i32) -> ! {
+ super::abi::exit_with_code(code as _)
+}
+
+pub fn getpid() -> u32 {
+ panic!("no pids in SGX")
+}
diff --git a/src/libstd/sys/sgx/path.rs b/src/libstd/sys/sgx/path.rs
new file mode 100644
index 0000000..b5fd7e3
--- /dev/null
+++ b/src/libstd/sys/sgx/path.rs
@@ -0,0 +1,19 @@
+use crate::path::Prefix;
+use crate::ffi::OsStr;
+
+#[inline]
+pub fn is_sep_byte(b: u8) -> bool {
+ b == b'/'
+}
+
+#[inline]
+pub fn is_verbatim_sep(b: u8) -> bool {
+ b == b'/'
+}
+
+pub fn parse_prefix(_: &OsStr) -> Option<Prefix<'_>> {
+ None
+}
+
+pub const MAIN_SEP_STR: &'static str = "/";
+pub const MAIN_SEP: char = '/';
diff --git a/src/libstd/sys/sgx/pipe.rs b/src/libstd/sys/sgx/pipe.rs
new file mode 100644
index 0000000..2582b99
--- /dev/null
+++ b/src/libstd/sys/sgx/pipe.rs
@@ -0,0 +1,25 @@
+use crate::io;
+use crate::sys::Void;
+
+pub struct AnonPipe(Void);
+
+impl AnonPipe {
+ pub fn read(&self, _buf: &mut [u8]) -> io::Result<usize> {
+ match self.0 {}
+ }
+
+ pub fn write(&self, _buf: &[u8]) -> io::Result<usize> {
+ match self.0 {}
+ }
+
+ pub fn diverge(&self) -> ! {
+ match self.0 {}
+ }
+}
+
+pub fn read2(p1: AnonPipe,
+ _v1: &mut Vec<u8>,
+ _p2: AnonPipe,
+ _v2: &mut Vec<u8>) -> io::Result<()> {
+ match p1.0 {}
+}
diff --git a/src/libstd/sys/sgx/process.rs b/src/libstd/sys/sgx/process.rs
new file mode 100644
index 0000000..a02e009
--- /dev/null
+++ b/src/libstd/sys/sgx/process.rs
@@ -0,0 +1,152 @@
+use crate::ffi::OsStr;
+use crate::fmt;
+use crate::io;
+use crate::sys::fs::File;
+use crate::sys::pipe::AnonPipe;
+use crate::sys::{unsupported, Void};
+use crate::sys_common::process::{CommandEnv, DefaultEnvKey};
+
+////////////////////////////////////////////////////////////////////////////////
+// Command
+////////////////////////////////////////////////////////////////////////////////
+
+pub struct Command {
+ env: CommandEnv<DefaultEnvKey>
+}
+
+// passed back to std::process with the pipes connected to the child, if any
+// were requested
+pub struct StdioPipes {
+ pub stdin: Option<AnonPipe>,
+ pub stdout: Option<AnonPipe>,
+ pub stderr: Option<AnonPipe>,
+}
+
+pub enum Stdio {
+ Inherit,
+ Null,
+ MakePipe,
+}
+
+impl Command {
+ pub fn new(_program: &OsStr) -> Command {
+ Command {
+ env: Default::default()
+ }
+ }
+
+ pub fn arg(&mut self, _arg: &OsStr) {
+ }
+
+ pub fn env_mut(&mut self) -> &mut CommandEnv<DefaultEnvKey> {
+ &mut self.env
+ }
+
+ pub fn cwd(&mut self, _dir: &OsStr) {
+ }
+
+ pub fn stdin(&mut self, _stdin: Stdio) {
+ }
+
+ pub fn stdout(&mut self, _stdout: Stdio) {
+ }
+
+ pub fn stderr(&mut self, _stderr: Stdio) {
+ }
+
+ pub fn spawn(&mut self, _default: Stdio, _needs_stdin: bool)
+ -> io::Result<(Process, StdioPipes)> {
+ unsupported()
+ }
+}
+
+impl From<AnonPipe> for Stdio {
+ fn from(pipe: AnonPipe) -> Stdio {
+ pipe.diverge()
+ }
+}
+
+impl From<File> for Stdio {
+ fn from(file: File) -> Stdio {
+ file.diverge()
+ }
+}
+
+impl fmt::Debug for Command {
+ fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ Ok(())
+ }
+}
+
+pub struct ExitStatus(Void);
+
+impl ExitStatus {
+ pub fn success(&self) -> bool {
+ match self.0 {}
+ }
+
+ pub fn code(&self) -> Option<i32> {
+ match self.0 {}
+ }
+}
+
+impl Clone for ExitStatus {
+ fn clone(&self) -> ExitStatus {
+ match self.0 {}
+ }
+}
+
+impl Copy for ExitStatus {}
+
+impl PartialEq for ExitStatus {
+ fn eq(&self, _other: &ExitStatus) -> bool {
+ match self.0 {}
+ }
+}
+
+impl Eq for ExitStatus {
+}
+
+impl fmt::Debug for ExitStatus {
+ fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self.0 {}
+ }
+}
+
+impl fmt::Display for ExitStatus {
+ fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self.0 {}
+ }
+}
+
+#[derive(PartialEq, Eq, Clone, Copy, Debug)]
+pub struct ExitCode(bool);
+
+impl ExitCode {
+ pub const SUCCESS: ExitCode = ExitCode(false);
+ pub const FAILURE: ExitCode = ExitCode(true);
+
+ pub fn as_i32(&self) -> i32 {
+ self.0 as i32
+ }
+}
+
+pub struct Process(Void);
+
+impl Process {
+ pub fn id(&self) -> u32 {
+ match self.0 {}
+ }
+
+ pub fn kill(&mut self) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn wait(&mut self) -> io::Result<ExitStatus> {
+ match self.0 {}
+ }
+
+ pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
+ match self.0 {}
+ }
+}
diff --git a/src/libstd/sys/sgx/rwlock.rs b/src/libstd/sys/sgx/rwlock.rs
new file mode 100644
index 0000000..30c47e4
--- /dev/null
+++ b/src/libstd/sys/sgx/rwlock.rs
@@ -0,0 +1,250 @@
+use crate::num::NonZeroUsize;
+
+use super::waitqueue::{
+ try_lock_or_false, NotifiedTcs, SpinMutex, SpinMutexGuard, WaitQueue, WaitVariable,
+};
+use crate::mem;
+
+pub struct RWLock {
+ readers: SpinMutex<WaitVariable<Option<NonZeroUsize>>>,
+ writer: SpinMutex<WaitVariable<bool>>,
+}
+
+// Below is to check at compile time, that RWLock has size of 128 bytes.
+#[allow(dead_code)]
+unsafe fn rw_lock_size_assert(r: RWLock) {
+ mem::transmute::<RWLock, [u8; 128]>(r);
+}
+
+impl RWLock {
+ pub const fn new() -> RWLock {
+ RWLock {
+ readers: SpinMutex::new(WaitVariable::new(None)),
+ writer: SpinMutex::new(WaitVariable::new(false)),
+ }
+ }
+
+ #[inline]
+ pub unsafe fn read(&self) {
+ let mut rguard = self.readers.lock();
+ let wguard = self.writer.lock();
+ if *wguard.lock_var() || !wguard.queue_empty() {
+ // Another thread has or is waiting for the write lock, wait
+ drop(wguard);
+ WaitQueue::wait(rguard);
+ // Another thread has passed the lock to us
+ } else {
+ // No waiting writers, acquire the read lock
+ *rguard.lock_var_mut() =
+ NonZeroUsize::new(rguard.lock_var().map_or(0, |n| n.get()) + 1);
+ }
+ }
+
+ #[inline]
+ pub unsafe fn try_read(&self) -> bool {
+ let mut rguard = try_lock_or_false!(self.readers);
+ let wguard = try_lock_or_false!(self.writer);
+ if *wguard.lock_var() || !wguard.queue_empty() {
+ // Another thread has or is waiting for the write lock
+ false
+ } else {
+ // No waiting writers, acquire the read lock
+ *rguard.lock_var_mut() =
+ NonZeroUsize::new(rguard.lock_var().map_or(0, |n| n.get()) + 1);
+ true
+ }
+ }
+
+ #[inline]
+ pub unsafe fn write(&self) {
+ let rguard = self.readers.lock();
+ let mut wguard = self.writer.lock();
+ if *wguard.lock_var() || rguard.lock_var().is_some() {
+ // Another thread has the lock, wait
+ drop(rguard);
+ WaitQueue::wait(wguard);
+ // Another thread has passed the lock to us
+ } else {
+ // We are just now obtaining the lock
+ *wguard.lock_var_mut() = true;
+ }
+ }
+
+ #[inline]
+ pub unsafe fn try_write(&self) -> bool {
+ let rguard = try_lock_or_false!(self.readers);
+ let mut wguard = try_lock_or_false!(self.writer);
+ if *wguard.lock_var() || rguard.lock_var().is_some() {
+ // Another thread has the lock
+ false
+ } else {
+ // We are just now obtaining the lock
+ *wguard.lock_var_mut() = true;
+ true
+ }
+ }
+
+ #[inline]
+ unsafe fn __read_unlock(
+ &self,
+ mut rguard: SpinMutexGuard<'_, WaitVariable<Option<NonZeroUsize>>>,
+ wguard: SpinMutexGuard<'_, WaitVariable<bool>>,
+ ) {
+ *rguard.lock_var_mut() = NonZeroUsize::new(rguard.lock_var().unwrap().get() - 1);
+ if rguard.lock_var().is_some() {
+ // There are other active readers
+ } else {
+ if let Ok(mut wguard) = WaitQueue::notify_one(wguard) {
+ // A writer was waiting, pass the lock
+ *wguard.lock_var_mut() = true;
+ } else {
+ // No writers were waiting, the lock is released
+ rtassert!(rguard.queue_empty());
+ }
+ }
+ }
+
+ #[inline]
+ pub unsafe fn read_unlock(&self) {
+ let rguard = self.readers.lock();
+ let wguard = self.writer.lock();
+ self.__read_unlock(rguard, wguard);
+ }
+
+ #[inline]
+ unsafe fn __write_unlock(
+ &self,
+ rguard: SpinMutexGuard<'_, WaitVariable<Option<NonZeroUsize>>>,
+ wguard: SpinMutexGuard<'_, WaitVariable<bool>>,
+ ) {
+ if let Err(mut wguard) = WaitQueue::notify_one(wguard) {
+ // No writers waiting, release the write lock
+ *wguard.lock_var_mut() = false;
+ if let Ok(mut rguard) = WaitQueue::notify_all(rguard) {
+ // One or more readers were waiting, pass the lock to them
+ if let NotifiedTcs::All { count } = rguard.notified_tcs() {
+ *rguard.lock_var_mut() = Some(count)
+ } else {
+ unreachable!() // called notify_all
+ }
+ } else {
+ // No readers waiting, the lock is released
+ }
+ } else {
+ // There was a thread waiting for write, just pass the lock
+ }
+ }
+
+ #[inline]
+ pub unsafe fn write_unlock(&self) {
+ let rguard = self.readers.lock();
+ let wguard = self.writer.lock();
+ self.__write_unlock(rguard, wguard);
+ }
+
+ // only used by __rust_rwlock_unlock below
+ #[inline]
+ #[cfg_attr(test, allow(dead_code))]
+ unsafe fn unlock(&self) {
+ let rguard = self.readers.lock();
+ let wguard = self.writer.lock();
+ if *wguard.lock_var() == true {
+ self.__write_unlock(rguard, wguard);
+ } else {
+ self.__read_unlock(rguard, wguard);
+ }
+ }
+
+ #[inline]
+ pub unsafe fn destroy(&self) {}
+}
+
+// The following functions are needed by libunwind. These symbols are named
+// in pre-link args for the target specification, so keep that in sync.
+#[cfg(not(test))]
+const EINVAL: i32 = 22;
+
+#[cfg(not(test))]
+#[no_mangle]
+pub unsafe extern "C" fn __rust_rwlock_rdlock(p: *mut RWLock) -> i32 {
+ if p.is_null() {
+ return EINVAL;
+ }
+ (*p).read();
+ return 0;
+}
+
+#[cfg(not(test))]
+#[no_mangle]
+pub unsafe extern "C" fn __rust_rwlock_wrlock(p: *mut RWLock) -> i32 {
+ if p.is_null() {
+ return EINVAL;
+ }
+ (*p).write();
+ return 0;
+}
+#[cfg(not(test))]
+#[no_mangle]
+pub unsafe extern "C" fn __rust_rwlock_unlock(p: *mut RWLock) -> i32 {
+ if p.is_null() {
+ return EINVAL;
+ }
+ (*p).unlock();
+ return 0;
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use core::array::FixedSizeArray;
+ use crate::mem::{self, MaybeUninit};
+
+ // Verify that the bytes of initialized RWLock are the same as in
+ // libunwind. If they change, `src/UnwindRustSgx.h` in libunwind needs to
+ // be changed too.
+ #[test]
+ fn test_c_rwlock_initializer() {
+ const RWLOCK_INIT: &[u8] = &[
+ 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ];
+
+ #[inline(never)]
+ fn zero_stack() {
+ test::black_box(MaybeUninit::<[RWLock; 16]>::zeroed());
+ }
+
+ #[inline(never)]
+ unsafe fn rwlock_new(init: &mut MaybeUninit<RWLock>) {
+ init.write(RWLock::new());
+ }
+
+ unsafe {
+ // try hard to make sure that the padding/unused bytes in RWLock
+ // get initialized as 0. If the assertion below fails, that might
+ // just be an issue with the test code and not with the value of
+ // RWLOCK_INIT.
+ zero_stack();
+ let mut init = MaybeUninit::<RWLock>::zeroed();
+ rwlock_new(&mut init);
+ assert_eq!(
+ mem::transmute::<_, [u8; 128]>(init.assume_init()).as_slice(),
+ RWLOCK_INIT
+ )
+ };
+ }
+}
diff --git a/src/libstd/sys/sgx/stack_overflow.rs b/src/libstd/sys/sgx/stack_overflow.rs
new file mode 100644
index 0000000..e63fa2b
--- /dev/null
+++ b/src/libstd/sys/sgx/stack_overflow.rs
@@ -0,0 +1,14 @@
+pub struct Handler;
+
+impl Handler {
+ pub unsafe fn new() -> Handler {
+ Handler
+ }
+}
+
+#[cfg_attr(test, allow(dead_code))]
+pub unsafe fn init() {
+}
+
+pub unsafe fn cleanup() {
+}
diff --git a/src/libstd/sys/sgx/stdio.rs b/src/libstd/sys/sgx/stdio.rs
new file mode 100644
index 0000000..a575401
--- /dev/null
+++ b/src/libstd/sys/sgx/stdio.rs
@@ -0,0 +1,82 @@
+use fortanix_sgx_abi as abi;
+
+use crate::io;
+use crate::sys::fd::FileDesc;
+#[cfg(not(test))]
+use crate::slice;
+#[cfg(not(test))]
+use crate::str;
+
+pub struct Stdin(());
+pub struct Stdout(());
+pub struct Stderr(());
+
+fn with_std_fd<F: FnOnce(&FileDesc) -> R, R>(fd: abi::Fd, f: F) -> R {
+ let fd = FileDesc::new(fd);
+ let ret = f(&fd);
+ fd.into_raw();
+ ret
+}
+
+impl Stdin {
+ pub fn new() -> io::Result<Stdin> { Ok(Stdin(())) }
+}
+
+impl io::Read for Stdin {
+ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+ with_std_fd(abi::FD_STDIN, |fd| fd.read(buf))
+ }
+}
+
+impl Stdout {
+ pub fn new() -> io::Result<Stdout> { Ok(Stdout(())) }
+}
+
+impl io::Write for Stdout {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ with_std_fd(abi::FD_STDOUT, |fd| fd.write(buf))
+ }
+
+ fn flush(&mut self) -> io::Result<()> {
+ with_std_fd(abi::FD_STDOUT, |fd| fd.flush())
+ }
+}
+
+impl Stderr {
+ pub fn new() -> io::Result<Stderr> { Ok(Stderr(())) }
+}
+
+impl io::Write for Stderr {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ with_std_fd(abi::FD_STDERR, |fd| fd.write(buf))
+ }
+
+ fn flush(&mut self) -> io::Result<()> {
+ with_std_fd(abi::FD_STDERR, |fd| fd.flush())
+ }
+}
+
+pub const STDIN_BUF_SIZE: usize = crate::sys_common::io::DEFAULT_BUF_SIZE;
+
+pub fn is_ebadf(err: &io::Error) -> bool {
+ // FIXME: Rust normally maps Unix EBADF to `Other`
+ err.raw_os_error() == Some(abi::Error::BrokenPipe as _)
+}
+
+pub fn panic_output() -> Option<impl io::Write> {
+ super::abi::panic::SgxPanicOutput::new()
+}
+
+// This function is needed by libunwind. The symbol is named in pre-link args
+// for the target specification, so keep that in sync.
+#[cfg(not(test))]
+#[no_mangle]
+pub unsafe extern "C" fn __rust_print_err(m: *mut u8, s: i32) {
+ if s < 0 {
+ return;
+ }
+ let buf = slice::from_raw_parts(m as *const u8, s as _);
+ if let Ok(s) = str::from_utf8(&buf[..buf.iter().position(|&b| b == 0).unwrap_or(buf.len())]) {
+ eprint!("{}", s);
+ }
+}
diff --git a/src/libstd/sys/sgx/thread.rs b/src/libstd/sys/sgx/thread.rs
new file mode 100644
index 0000000..565a523
--- /dev/null
+++ b/src/libstd/sys/sgx/thread.rs
@@ -0,0 +1,93 @@
+#![cfg_attr(test, allow(dead_code))] // why is this necessary?
+use crate::boxed::FnBox;
+use crate::ffi::CStr;
+use crate::io;
+use crate::time::Duration;
+
+use super::abi::usercalls;
+
+pub struct Thread(task_queue::JoinHandle);
+
+pub const DEFAULT_MIN_STACK_SIZE: usize = 4096;
+
+mod task_queue {
+ use crate::sync::{Mutex, MutexGuard, Once};
+ use crate::sync::mpsc;
+ use crate::boxed::FnBox;
+
+ pub type JoinHandle = mpsc::Receiver<()>;
+
+ pub(super) struct Task {
+ p: Box<dyn FnBox()>,
+ done: mpsc::Sender<()>,
+ }
+
+ impl Task {
+ pub(super) fn new(p: Box<dyn FnBox()>) -> (Task, JoinHandle) {
+ let (done, recv) = mpsc::channel();
+ (Task { p, done }, recv)
+ }
+
+ pub(super) fn run(self) {
+ (self.p)();
+ let _ = self.done.send(());
+ }
+ }
+
+ #[cfg_attr(test, linkage = "available_externally")]
+ #[export_name = "_ZN16__rust_internals3std3sys3sgx6thread15TASK_QUEUE_INITE"]
+ static TASK_QUEUE_INIT: Once = Once::new();
+ #[cfg_attr(test, linkage = "available_externally")]
+ #[export_name = "_ZN16__rust_internals3std3sys3sgx6thread10TASK_QUEUEE"]
+ static mut TASK_QUEUE: Option<Mutex<Vec<Task>>> = None;
+
+ pub(super) fn lock() -> MutexGuard<'static, Vec<Task>> {
+ unsafe {
+ TASK_QUEUE_INIT.call_once(|| TASK_QUEUE = Some(Default::default()) );
+ TASK_QUEUE.as_ref().unwrap().lock().unwrap()
+ }
+ }
+}
+
+impl Thread {
+ // unsafe: see thread::Builder::spawn_unchecked for safety requirements
+ pub unsafe fn new(_stack: usize, p: Box<dyn FnBox()>)
+ -> io::Result<Thread>
+ {
+ let mut queue_lock = task_queue::lock();
+ usercalls::launch_thread()?;
+ let (task, handle) = task_queue::Task::new(p);
+ queue_lock.push(task);
+ Ok(Thread(handle))
+ }
+
+ pub(super) fn entry() {
+ let mut pending_tasks = task_queue::lock();
+ let task = rtunwrap!(Some, pending_tasks.pop());
+ drop(pending_tasks); // make sure to not hold the task queue lock longer than necessary
+ task.run()
+ }
+
+ pub fn yield_now() {
+ let wait_error = rtunwrap!(Err, usercalls::wait(0, usercalls::raw::WAIT_NO));
+ rtassert!(wait_error.kind() == io::ErrorKind::WouldBlock);
+ }
+
+ pub fn set_name(_name: &CStr) {
+ // FIXME: could store this pointer in TLS somewhere
+ }
+
+ pub fn sleep(_dur: Duration) {
+ rtabort!("can't sleep"); // FIXME
+ }
+
+ pub fn join(self) {
+ let _ = self.0.recv();
+ }
+}
+
+pub mod guard {
+ pub type Guard = !;
+ pub unsafe fn current() -> Option<Guard> { None }
+ pub unsafe fn init() -> Option<Guard> { None }
+}
diff --git a/src/libstd/sys/sgx/thread_local.rs b/src/libstd/sys/sgx/thread_local.rs
new file mode 100644
index 0000000..e0d0fe7
--- /dev/null
+++ b/src/libstd/sys/sgx/thread_local.rs
@@ -0,0 +1,28 @@
+use super::abi::tls::{Tls, Key as AbiKey};
+
+pub type Key = usize;
+
+#[inline]
+pub unsafe fn create(dtor: Option<unsafe extern fn(*mut u8)>) -> Key {
+ Tls::create(dtor).as_usize()
+}
+
+#[inline]
+pub unsafe fn set(key: Key, value: *mut u8) {
+ Tls::set(AbiKey::from_usize(key), value)
+}
+
+#[inline]
+pub unsafe fn get(key: Key) -> *mut u8 {
+ Tls::get(AbiKey::from_usize(key))
+}
+
+#[inline]
+pub unsafe fn destroy(key: Key) {
+ Tls::destroy(AbiKey::from_usize(key))
+}
+
+#[inline]
+pub fn requires_synchronized_create() -> bool {
+ false
+}
diff --git a/src/libstd/sys/sgx/time.rs b/src/libstd/sys/sgx/time.rs
new file mode 100644
index 0000000..4659f7b
--- /dev/null
+++ b/src/libstd/sys/sgx/time.rs
@@ -0,0 +1,55 @@
+use crate::time::Duration;
+use super::abi::usercalls;
+
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
+pub struct Instant(Duration);
+
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
+pub struct SystemTime(Duration);
+
+pub const UNIX_EPOCH: SystemTime = SystemTime(Duration::from_secs(0));
+
+impl Instant {
+ pub fn now() -> Instant {
+ Instant(usercalls::insecure_time())
+ }
+
+ pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
+ self.0.checked_sub(other.0)
+ }
+
+ pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
+ Some(Instant(self.0.checked_add(*other)?))
+ }
+
+ pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
+ Some(Instant(self.0.checked_sub(*other)?))
+ }
+
+ pub fn actually_monotonic() -> bool {
+ false
+ }
+
+ pub const fn zero() -> Instant {
+ Instant(Duration::from_secs(0))
+ }
+}
+
+impl SystemTime {
+ pub fn now() -> SystemTime {
+ SystemTime(usercalls::insecure_time())
+ }
+
+ pub fn sub_time(&self, other: &SystemTime)
+ -> Result<Duration, Duration> {
+ self.0.checked_sub(other.0).ok_or_else(|| other.0 - self.0)
+ }
+
+ pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
+ Some(SystemTime(self.0.checked_add(*other)?))
+ }
+
+ pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
+ Some(SystemTime(self.0.checked_sub(*other)?))
+ }
+}
diff --git a/src/libstd/sys/sgx/waitqueue.rs b/src/libstd/sys/sgx/waitqueue.rs
new file mode 100644
index 0000000..d542f9b
--- /dev/null
+++ b/src/libstd/sys/sgx/waitqueue.rs
@@ -0,0 +1,552 @@
+/// A simple queue implementation for synchronization primitives.
+///
+/// This queue is used to implement condition variable and mutexes.
+///
+/// Users of this API are expected to use the `WaitVariable<T>` type. Since
+/// that type is not `Sync`, it needs to be protected by e.g., a `SpinMutex` to
+/// allow shared access.
+///
+/// Since userspace may send spurious wake-ups, the wakeup event state is
+/// recorded in the enclave. The wakeup event state is protected by a spinlock.
+/// The queue and associated wait state are stored in a `WaitVariable`.
+
+use crate::ops::{Deref, DerefMut};
+use crate::num::NonZeroUsize;
+
+use fortanix_sgx_abi::{Tcs, EV_UNPARK, WAIT_INDEFINITE};
+use super::abi::usercalls;
+use super::abi::thread;
+
+use self::unsafe_list::{UnsafeList, UnsafeListEntry};
+pub use self::spin_mutex::{SpinMutex, SpinMutexGuard, try_lock_or_false};
+
+/// An queue entry in a `WaitQueue`.
+struct WaitEntry {
+ /// TCS address of the thread that is waiting
+ tcs: Tcs,
+ /// Whether this thread has been notified to be awoken
+ wake: bool
+}
+
+/// Data stored with a `WaitQueue` alongside it. This ensures accesses to the
+/// queue and the data are synchronized, since the type itself is not `Sync`.
+///
+/// Consumers of this API should use a synchronization primitive for shared
+/// access, such as `SpinMutex`.
+#[derive(Default)]
+pub struct WaitVariable<T> {
+ queue: WaitQueue,
+ lock: T
+}
+
+impl<T> WaitVariable<T> {
+ pub const fn new(var: T) -> Self {
+ WaitVariable {
+ queue: WaitQueue::new(),
+ lock: var
+ }
+ }
+
+ pub fn queue_empty(&self) -> bool {
+ self.queue.is_empty()
+ }
+
+ pub fn lock_var(&self) -> &T {
+ &self.lock
+ }
+
+ pub fn lock_var_mut(&mut self) -> &mut T {
+ &mut self.lock
+ }
+}
+
+#[derive(Copy, Clone)]
+pub enum NotifiedTcs {
+ Single(Tcs),
+ All { count: NonZeroUsize }
+}
+
+/// An RAII guard that will notify a set of target threads as well as unlock
+/// a mutex on drop.
+pub struct WaitGuard<'a, T: 'a> {
+ mutex_guard: Option<SpinMutexGuard<'a, WaitVariable<T>>>,
+ notified_tcs: NotifiedTcs
+}
+
+/// A queue of threads that are waiting on some synchronization primitive.
+///
+/// `UnsafeList` entries are allocated on the waiting thread's stack. This
+/// avoids any global locking that might happen in the heap allocator. This is
+/// safe because the waiting thread will not return from that stack frame until
+/// after it is notified. The notifying thread ensures to clean up any
+/// references to the list entries before sending the wakeup event.
+pub struct WaitQueue {
+ // We use an inner Mutex here to protect the data in the face of spurious
+ // wakeups.
+ inner: UnsafeList<SpinMutex<WaitEntry>>,
+}
+unsafe impl Send for WaitQueue {}
+
+impl Default for WaitQueue {
+ fn default() -> Self {
+ Self::new()
+ }
+}
+
+impl<'a, T> WaitGuard<'a, T> {
+ /// Returns which TCSes will be notified when this guard drops.
+ pub fn notified_tcs(&self) -> NotifiedTcs {
+ self.notified_tcs
+ }
+}
+
+impl<'a, T> Deref for WaitGuard<'a, T> {
+ type Target = SpinMutexGuard<'a, WaitVariable<T>>;
+
+ fn deref(&self) -> &Self::Target {
+ self.mutex_guard.as_ref().unwrap()
+ }
+}
+
+impl<'a, T> DerefMut for WaitGuard<'a, T> {
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ self.mutex_guard.as_mut().unwrap()
+ }
+}
+
+impl<'a, T> Drop for WaitGuard<'a, T> {
+ fn drop(&mut self) {
+ drop(self.mutex_guard.take());
+ let target_tcs = match self.notified_tcs {
+ NotifiedTcs::Single(tcs) => Some(tcs),
+ NotifiedTcs::All { .. } => None
+ };
+ rtunwrap!(Ok, usercalls::send(EV_UNPARK, target_tcs));
+ }
+}
+
+impl WaitQueue {
+ pub const fn new() -> Self {
+ WaitQueue {
+ inner: UnsafeList::new()
+ }
+ }
+
+ pub fn is_empty(&self) -> bool {
+ self.inner.is_empty()
+ }
+
+ /// Adds the calling thread to the `WaitVariable`'s wait queue, then wait
+ /// until a wakeup event.
+ ///
+ /// This function does not return until this thread has been awoken.
+ pub fn wait<T>(mut guard: SpinMutexGuard<'_, WaitVariable<T>>) {
+ // very unsafe: check requirements of UnsafeList::push
+ unsafe {
+ let mut entry = UnsafeListEntry::new(SpinMutex::new(WaitEntry {
+ tcs: thread::current(),
+ wake: false
+ }));
+ let entry = guard.queue.inner.push(&mut entry);
+ drop(guard);
+ while !entry.lock().wake {
+ // don't panic, this would invalidate `entry` during unwinding
+ let eventset = rtunwrap!(Ok, usercalls::wait(EV_UNPARK, WAIT_INDEFINITE));
+ rtassert!(eventset & EV_UNPARK == EV_UNPARK);
+ }
+ }
+ }
+
+ /// Either find the next waiter on the wait queue, or return the mutex
+ /// guard unchanged.
+ ///
+ /// If a waiter is found, a `WaitGuard` is returned which will notify the
+ /// waiter when it is dropped.
+ pub fn notify_one<T>(mut guard: SpinMutexGuard<'_, WaitVariable<T>>)
+ -> Result<WaitGuard<'_, T>, SpinMutexGuard<'_, WaitVariable<T>>>
+ {
+ unsafe {
+ if let Some(entry) = guard.queue.inner.pop() {
+ let mut entry_guard = entry.lock();
+ let tcs = entry_guard.tcs;
+ entry_guard.wake = true;
+ drop(entry);
+ Ok(WaitGuard {
+ mutex_guard: Some(guard),
+ notified_tcs: NotifiedTcs::Single(tcs)
+ })
+ } else {
+ Err(guard)
+ }
+ }
+ }
+
+ /// Either find any and all waiters on the wait queue, or return the mutex
+ /// guard unchanged.
+ ///
+ /// If at least one waiter is found, a `WaitGuard` is returned which will
+ /// notify all waiters when it is dropped.
+ pub fn notify_all<T>(mut guard: SpinMutexGuard<'_, WaitVariable<T>>)
+ -> Result<WaitGuard<'_, T>, SpinMutexGuard<'_, WaitVariable<T>>>
+ {
+ unsafe {
+ let mut count = 0;
+ while let Some(entry) = guard.queue.inner.pop() {
+ count += 1;
+ let mut entry_guard = entry.lock();
+ entry_guard.wake = true;
+ }
+ if let Some(count) = NonZeroUsize::new(count) {
+ Ok(WaitGuard {
+ mutex_guard: Some(guard),
+ notified_tcs: NotifiedTcs::All { count }
+ })
+ } else {
+ Err(guard)
+ }
+ }
+ }
+}
+
+/// A doubly-linked list where callers are in charge of memory allocation
+/// of the nodes in the list.
+mod unsafe_list {
+ use crate::ptr::NonNull;
+ use crate::mem;
+
+ pub struct UnsafeListEntry<T> {
+ next: NonNull<UnsafeListEntry<T>>,
+ prev: NonNull<UnsafeListEntry<T>>,
+ value: Option<T>
+ }
+
+ impl<T> UnsafeListEntry<T> {
+ fn dummy() -> Self {
+ UnsafeListEntry {
+ next: NonNull::dangling(),
+ prev: NonNull::dangling(),
+ value: None
+ }
+ }
+
+ pub fn new(value: T) -> Self {
+ UnsafeListEntry {
+ value: Some(value),
+ ..Self::dummy()
+ }
+ }
+ }
+
+ pub struct UnsafeList<T> {
+ head_tail: NonNull<UnsafeListEntry<T>>,
+ head_tail_entry: Option<UnsafeListEntry<T>>,
+ }
+
+ impl<T> UnsafeList<T> {
+ pub const fn new() -> Self {
+ unsafe {
+ UnsafeList {
+ head_tail: NonNull::new_unchecked(1 as _),
+ head_tail_entry: None
+ }
+ }
+ }
+
+ unsafe fn init(&mut self) {
+ if self.head_tail_entry.is_none() {
+ self.head_tail_entry = Some(UnsafeListEntry::dummy());
+ self.head_tail = NonNull::new_unchecked(self.head_tail_entry.as_mut().unwrap());
+ self.head_tail.as_mut().next = self.head_tail;
+ self.head_tail.as_mut().prev = self.head_tail;
+ }
+ }
+
+ pub fn is_empty(&self) -> bool {
+ unsafe {
+ if self.head_tail_entry.is_some() {
+ let first = self.head_tail.as_ref().next;
+ if first == self.head_tail {
+ // ,-------> /---------\ next ---,
+ // | |head_tail| |
+ // `--- prev \---------/ <-------`
+ rtassert!(self.head_tail.as_ref().prev == first);
+ true
+ } else {
+ false
+ }
+ } else {
+ true
+ }
+ }
+ }
+
+ /// Pushes an entry onto the back of the list.
+ ///
+ /// # Safety
+ ///
+ /// The entry must remain allocated until the entry is removed from the
+ /// list AND the caller who popped is done using the entry. Special
+ /// care must be taken in the caller of `push` to ensure unwinding does
+ /// not destroy the stack frame containing the entry.
+ pub unsafe fn push<'a>(&mut self, entry: &'a mut UnsafeListEntry<T>) -> &'a T {
+ self.init();
+
+ // BEFORE:
+ // /---------\ next ---> /---------\
+ // ... |prev_tail| |head_tail| ...
+ // \---------/ <--- prev \---------/
+ //
+ // AFTER:
+ // /---------\ next ---> /-----\ next ---> /---------\
+ // ... |prev_tail| |entry| |head_tail| ...
+ // \---------/ <--- prev \-----/ <--- prev \---------/
+ let mut entry = NonNull::new_unchecked(entry);
+ let mut prev_tail = mem::replace(&mut self.head_tail.as_mut().prev, entry);
+ entry.as_mut().prev = prev_tail;
+ entry.as_mut().next = self.head_tail;
+ prev_tail.as_mut().next = entry;
+ // unwrap ok: always `Some` on non-dummy entries
+ (*entry.as_ptr()).value.as_ref().unwrap()
+ }
+
+ /// Pops an entry from the front of the list.
+ ///
+ /// # Safety
+ ///
+ /// The caller must make sure to synchronize ending the borrow of the
+ /// return value and deallocation of the containing entry.
+ pub unsafe fn pop<'a>(&mut self) -> Option<&'a T> {
+ self.init();
+
+ if self.is_empty() {
+ None
+ } else {
+ // BEFORE:
+ // /---------\ next ---> /-----\ next ---> /------\
+ // ... |head_tail| |first| |second| ...
+ // \---------/ <--- prev \-----/ <--- prev \------/
+ //
+ // AFTER:
+ // /---------\ next ---> /------\
+ // ... |head_tail| |second| ...
+ // \---------/ <--- prev \------/
+ let mut first = self.head_tail.as_mut().next;
+ let mut second = first.as_mut().next;
+ self.head_tail.as_mut().next = second;
+ second.as_mut().prev = self.head_tail;
+ first.as_mut().next = NonNull::dangling();
+ first.as_mut().prev = NonNull::dangling();
+ // unwrap ok: always `Some` on non-dummy entries
+ Some((*first.as_ptr()).value.as_ref().unwrap())
+ }
+ }
+ }
+
+ #[cfg(test)]
+ mod tests {
+ use super::*;
+ use crate::cell::Cell;
+
+ unsafe fn assert_empty<T>(list: &mut UnsafeList<T>) {
+ assert!(list.pop().is_none(), "assertion failed: list is not empty");
+ }
+
+ #[test]
+ fn init_empty() {
+ unsafe {
+ assert_empty(&mut UnsafeList::<i32>::new());
+ }
+ }
+
+ #[test]
+ fn push_pop() {
+ unsafe {
+ let mut node = UnsafeListEntry::new(1234);
+ let mut list = UnsafeList::new();
+ assert_eq!(list.push(&mut node), &1234);
+ assert_eq!(list.pop().unwrap(), &1234);
+ assert_empty(&mut list);
+ }
+ }
+
+ #[test]
+ fn complex_pushes_pops() {
+ unsafe {
+ let mut node1 = UnsafeListEntry::new(1234);
+ let mut node2 = UnsafeListEntry::new(4567);
+ let mut node3 = UnsafeListEntry::new(9999);
+ let mut node4 = UnsafeListEntry::new(8642);
+ let mut list = UnsafeList::new();
+ list.push(&mut node1);
+ list.push(&mut node2);
+ assert_eq!(list.pop().unwrap(), &1234);
+ list.push(&mut node3);
+ assert_eq!(list.pop().unwrap(), &4567);
+ assert_eq!(list.pop().unwrap(), &9999);
+ assert_empty(&mut list);
+ list.push(&mut node4);
+ assert_eq!(list.pop().unwrap(), &8642);
+ assert_empty(&mut list);
+ }
+ }
+
+ #[test]
+ fn cell() {
+ unsafe {
+ let mut node = UnsafeListEntry::new(Cell::new(0));
+ let mut list = UnsafeList::new();
+ let noderef = list.push(&mut node);
+ assert_eq!(noderef.get(), 0);
+ list.pop().unwrap().set(1);
+ assert_empty(&mut list);
+ assert_eq!(noderef.get(), 1);
+ }
+ }
+ }
+}
+
+/// Trivial spinlock-based implementation of `sync::Mutex`.
+// FIXME: Perhaps use Intel TSX to avoid locking?
+mod spin_mutex {
+ use crate::cell::UnsafeCell;
+ use crate::sync::atomic::{AtomicBool, Ordering, spin_loop_hint};
+ use crate::ops::{Deref, DerefMut};
+
+ #[derive(Default)]
+ pub struct SpinMutex<T> {
+ value: UnsafeCell<T>,
+ lock: AtomicBool,
+ }
+
+ unsafe impl<T: Send> Send for SpinMutex<T> {}
+ unsafe impl<T: Send> Sync for SpinMutex<T> {}
+
+ pub struct SpinMutexGuard<'a, T: 'a> {
+ mutex: &'a SpinMutex<T>,
+ }
+
+ impl<'a, T> !Send for SpinMutexGuard<'a, T> {}
+ unsafe impl<'a, T: Sync> Sync for SpinMutexGuard<'a, T> {}
+
+ impl<T> SpinMutex<T> {
+ pub const fn new(value: T) -> Self {
+ SpinMutex {
+ value: UnsafeCell::new(value),
+ lock: AtomicBool::new(false)
+ }
+ }
+
+ #[inline(always)]
+ pub fn lock(&self) -> SpinMutexGuard<'_, T> {
+ loop {
+ match self.try_lock() {
+ None => while self.lock.load(Ordering::Relaxed) {
+ spin_loop_hint()
+ },
+ Some(guard) => return guard
+ }
+ }
+ }
+
+ #[inline(always)]
+ pub fn try_lock(&self) -> Option<SpinMutexGuard<'_, T>> {
+ if !self.lock.compare_and_swap(false, true, Ordering::Acquire) {
+ Some(SpinMutexGuard {
+ mutex: self,
+ })
+ } else {
+ None
+ }
+ }
+ }
+
+ /// Lock the Mutex or return false.
+ pub macro try_lock_or_false {
+ ($e:expr) => {
+ if let Some(v) = $e.try_lock() {
+ v
+ } else {
+ return false
+ }
+ }
+ }
+
+ impl<'a, T> Deref for SpinMutexGuard<'a, T> {
+ type Target = T;
+
+ fn deref(&self) -> &T {
+ unsafe {
+ &*self.mutex.value.get()
+ }
+ }
+ }
+
+ impl<'a, T> DerefMut for SpinMutexGuard<'a, T> {
+ fn deref_mut(&mut self) -> &mut T {
+ unsafe {
+ &mut*self.mutex.value.get()
+ }
+ }
+ }
+
+ impl<'a, T> Drop for SpinMutexGuard<'a, T> {
+ fn drop(&mut self) {
+ self.mutex.lock.store(false, Ordering::Release)
+ }
+ }
+
+ #[cfg(test)]
+ mod tests {
+ #![allow(deprecated)]
+
+ use super::*;
+ use crate::sync::Arc;
+ use crate::thread;
+ use crate::time::{SystemTime, Duration};
+
+ #[test]
+ fn sleep() {
+ let mutex = Arc::new(SpinMutex::<i32>::default());
+ let mutex2 = mutex.clone();
+ let guard = mutex.lock();
+ let t1 = thread::spawn(move || {
+ *mutex2.lock() = 1;
+ });
+
+ // "sleep" for 50ms
+ // FIXME: https://github.com/fortanix/rust-sgx/issues/31
+ let start = SystemTime::now();
+ let max = Duration::from_millis(50);
+ while start.elapsed().unwrap() < max {}
+
+ assert_eq!(*guard, 0);
+ drop(guard);
+ t1.join().unwrap();
+ assert_eq!(*mutex.lock(), 1);
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use crate::sync::Arc;
+ use crate::thread;
+
+ #[test]
+ fn queue() {
+ let wq = Arc::new(SpinMutex::<WaitVariable<()>>::default());
+ let wq2 = wq.clone();
+
+ let locked = wq.lock();
+
+ let t1 = thread::spawn(move || {
+ // if we obtain the lock, the main thread should be waiting
+ assert!(WaitQueue::notify_one(wq2.lock()).is_ok());
+ });
+
+ WaitQueue::wait(locked);
+
+ t1.join().unwrap();
+ }
+}
diff --git a/src/libstd/sys/unix/alloc.rs b/src/libstd/sys/unix/alloc.rs
new file mode 100644
index 0000000..8e8f501
--- /dev/null
+++ b/src/libstd/sys/unix/alloc.rs
@@ -0,0 +1,89 @@
+use crate::ptr;
+use crate::sys_common::alloc::{MIN_ALIGN, realloc_fallback};
+use crate::alloc::{GlobalAlloc, Layout, System};
+
+#[stable(feature = "alloc_system_type", since = "1.28.0")]
+unsafe impl GlobalAlloc for System {
+ #[inline]
+ unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
+ if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() {
+ libc::malloc(layout.size()) as *mut u8
+ } else {
+ #[cfg(target_os = "macos")]
+ {
+ if layout.align() > (1 << 31) {
+ return ptr::null_mut()
+ }
+ }
+ aligned_malloc(&layout)
+ }
+ }
+
+ #[inline]
+ unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
+ if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() {
+ libc::calloc(layout.size(), 1) as *mut u8
+ } else {
+ let ptr = self.alloc(layout.clone());
+ if !ptr.is_null() {
+ ptr::write_bytes(ptr, 0, layout.size());
+ }
+ ptr
+ }
+ }
+
+ #[inline]
+ unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {
+ libc::free(ptr as *mut libc::c_void)
+ }
+
+ #[inline]
+ unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
+ if layout.align() <= MIN_ALIGN && layout.align() <= new_size {
+ libc::realloc(ptr as *mut libc::c_void, new_size) as *mut u8
+ } else {
+ realloc_fallback(self, ptr, layout, new_size)
+ }
+ }
+}
+
+#[cfg(any(target_os = "android",
+ target_os = "hermit",
+ target_os = "redox",
+ target_os = "solaris"))]
+#[inline]
+unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 {
+ // On android we currently target API level 9 which unfortunately
+ // doesn't have the `posix_memalign` API used below. Instead we use
+ // `memalign`, but this unfortunately has the property on some systems
+ // where the memory returned cannot be deallocated by `free`!
+ //
+ // Upon closer inspection, however, this appears to work just fine with
+ // Android, so for this platform we should be fine to call `memalign`
+ // (which is present in API level 9). Some helpful references could
+ // possibly be chromium using memalign [1], attempts at documenting that
+ // memalign + free is ok [2] [3], or the current source of chromium
+ // which still uses memalign on android [4].
+ //
+ // [1]: https://codereview.chromium.org/10796020/
+ // [2]: https://code.google.com/p/android/issues/detail?id=35391
+ // [3]: https://bugs.chromium.org/p/chromium/issues/detail?id=138579
+ // [4]: https://chromium.googlesource.com/chromium/src/base/+/master/
+ // /memory/aligned_memory.cc
+ libc::memalign(layout.align(), layout.size()) as *mut u8
+}
+
+#[cfg(not(any(target_os = "android",
+ target_os = "hermit",
+ target_os = "redox",
+ target_os = "solaris")))]
+#[inline]
+unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 {
+ let mut out = ptr::null_mut();
+ let ret = libc::posix_memalign(&mut out, layout.align(), layout.size());
+ if ret != 0 {
+ ptr::null_mut()
+ } else {
+ out as *mut u8
+ }
+}
diff --git a/src/libstd/sys/unix/android.rs b/src/libstd/sys/unix/android.rs
new file mode 100644
index 0000000..6774160
--- /dev/null
+++ b/src/libstd/sys/unix/android.rs
@@ -0,0 +1,160 @@
+//! Android ABI-compatibility module
+//!
+//! The ABI of Android has changed quite a bit over time, and libstd attempts to
+//! be both forwards and backwards compatible as much as possible. We want to
+//! always work with the most recent version of Android, but we also want to
+//! work with older versions of Android for whenever projects need to.
+//!
+//! Our current minimum supported Android version is `android-9`, e.g., Android
+//! with API level 9. We then in theory want to work on that and all future
+//! versions of Android!
+//!
+//! Some of the detection here is done at runtime via `dlopen` and
+//! introspection. Other times no detection is performed at all and we just
+//! provide a fallback implementation as some versions of Android we support
+//! don't have the function.
+//!
+//! You'll find more details below about why each compatibility shim is needed.
+
+#![cfg(target_os = "android")]
+
+use libc::{c_int, c_void, sighandler_t, size_t, ssize_t};
+use libc::{ftruncate, pread, pwrite};
+
+use crate::io;
+use super::{cvt, cvt_r};
+
+// The `log2` and `log2f` functions apparently appeared in android-18, or at
+// least you can see they're not present in the android-17 header [1] and they
+// are present in android-18 [2].
+//
+// [1]: https://chromium.googlesource.com/android_tools/+/20ee6d20/ndk/platforms
+// /android-17/arch-arm/usr/include/math.h
+// [2]: https://chromium.googlesource.com/android_tools/+/20ee6d20/ndk/platforms
+// /android-18/arch-arm/usr/include/math.h
+//
+// Note that these shims are likely less precise than directly calling `log2`,
+// but hopefully that should be enough for now...
+//
+// Note that mathematically, for any arbitrary `y`:
+//
+// log_2(x) = log_y(x) / log_y(2)
+// = log_y(x) / (1 / log_2(y))
+// = log_y(x) * log_2(y)
+//
+// Hence because `ln` (log_e) is available on all Android we just choose `y = e`
+// and get:
+//
+// log_2(x) = ln(x) * log_2(e)
+
+#[cfg(not(test))]
+pub fn log2f32(f: f32) -> f32 {
+ f.ln() * crate::f32::consts::LOG2_E
+}
+
+#[cfg(not(test))]
+pub fn log2f64(f: f64) -> f64 {
+ f.ln() * crate::f64::consts::LOG2_E
+}
+
+// Back in the day [1] the `signal` function was just an inline wrapper
+// around `bsd_signal`, but starting in API level android-20 the `signal`
+// symbols was introduced [2]. Finally, in android-21 the API `bsd_signal` was
+// removed [3].
+//
+// Basically this means that if we want to be binary compatible with multiple
+// Android releases (oldest being 9 and newest being 21) then we need to check
+// for both symbols and not actually link against either.
+//
+// [1]: https://chromium.googlesource.com/android_tools/+/20ee6d20/ndk/platforms
+// /android-18/arch-arm/usr/include/signal.h
+// [2]: https://chromium.googlesource.com/android_tools/+/fbd420/ndk_experimental
+// /platforms/android-20/arch-arm
+// /usr/include/signal.h
+// [3]: https://chromium.googlesource.com/android_tools/+/20ee6d/ndk/platforms
+// /android-21/arch-arm/usr/include/signal.h
+pub unsafe fn signal(signum: c_int, handler: sighandler_t) -> sighandler_t {
+ weak!(fn signal(c_int, sighandler_t) -> sighandler_t);
+ weak!(fn bsd_signal(c_int, sighandler_t) -> sighandler_t);
+
+ let f = signal.get().or_else(|| bsd_signal.get());
+ let f = f.expect("neither `signal` nor `bsd_signal` symbols found");
+ f(signum, handler)
+}
+
+// The `ftruncate64` symbol apparently appeared in android-12, so we do some
+// dynamic detection to see if we can figure out whether `ftruncate64` exists.
+//
+// If it doesn't we just fall back to `ftruncate`, generating an error for
+// too-large values.
+#[cfg(target_pointer_width = "32")]
+pub fn ftruncate64(fd: c_int, size: u64) -> io::Result<()> {
+ weak!(fn ftruncate64(c_int, i64) -> c_int);
+
+ unsafe {
+ match ftruncate64.get() {
+ Some(f) => cvt_r(|| f(fd, size as i64)).map(|_| ()),
+ None => {
+ if size > i32::max_value() as u64 {
+ Err(io::Error::new(io::ErrorKind::InvalidInput,
+ "cannot truncate >2GB"))
+ } else {
+ cvt_r(|| ftruncate(fd, size as i32)).map(|_| ())
+ }
+ }
+ }
+ }
+}
+
+#[cfg(target_pointer_width = "64")]
+pub fn ftruncate64(fd: c_int, size: u64) -> io::Result<()> {
+ unsafe {
+ cvt_r(|| ftruncate(fd, size as i64)).map(|_| ())
+ }
+}
+
+#[cfg(target_pointer_width = "32")]
+pub unsafe fn cvt_pread64(fd: c_int, buf: *mut c_void, count: size_t, offset: i64)
+ -> io::Result<ssize_t>
+{
+ use crate::convert::TryInto;
+ weak!(fn pread64(c_int, *mut c_void, size_t, i64) -> ssize_t);
+ pread64.get().map(|f| cvt(f(fd, buf, count, offset))).unwrap_or_else(|| {
+ if let Ok(o) = offset.try_into() {
+ cvt(pread(fd, buf, count, o))
+ } else {
+ Err(io::Error::new(io::ErrorKind::InvalidInput,
+ "cannot pread >2GB"))
+ }
+ })
+}
+
+#[cfg(target_pointer_width = "32")]
+pub unsafe fn cvt_pwrite64(fd: c_int, buf: *const c_void, count: size_t, offset: i64)
+ -> io::Result<ssize_t>
+{
+ use crate::convert::TryInto;
+ weak!(fn pwrite64(c_int, *const c_void, size_t, i64) -> ssize_t);
+ pwrite64.get().map(|f| cvt(f(fd, buf, count, offset))).unwrap_or_else(|| {
+ if let Ok(o) = offset.try_into() {
+ cvt(pwrite(fd, buf, count, o))
+ } else {
+ Err(io::Error::new(io::ErrorKind::InvalidInput,
+ "cannot pwrite >2GB"))
+ }
+ })
+}
+
+#[cfg(target_pointer_width = "64")]
+pub unsafe fn cvt_pread64(fd: c_int, buf: *mut c_void, count: size_t, offset: i64)
+ -> io::Result<ssize_t>
+{
+ cvt(pread(fd, buf, count, offset))
+}
+
+#[cfg(target_pointer_width = "64")]
+pub unsafe fn cvt_pwrite64(fd: c_int, buf: *const c_void, count: size_t, offset: i64)
+ -> io::Result<ssize_t>
+{
+ cvt(pwrite(fd, buf, count, offset))
+}
diff --git a/src/libstd/sys/unix/args.rs b/src/libstd/sys/unix/args.rs
new file mode 100644
index 0000000..18de109
--- /dev/null
+++ b/src/libstd/sys/unix/args.rs
@@ -0,0 +1,207 @@
+//! Global initialization and retrieval of command line arguments.
+//!
+//! On some platforms these are stored during runtime startup,
+//! and on some they are retrieved from the system on demand.
+
+#![allow(dead_code)] // runtime init functions not used during testing
+
+use crate::ffi::OsString;
+use crate::marker::PhantomData;
+use crate::vec;
+
+/// One-time global initialization.
+pub unsafe fn init(argc: isize, argv: *const *const u8) { imp::init(argc, argv) }
+
+/// One-time global cleanup.
+pub unsafe fn cleanup() { imp::cleanup() }
+
+/// Returns the command line arguments
+pub fn args() -> Args {
+ imp::args()
+}
+
+pub struct Args {
+ iter: vec::IntoIter<OsString>,
+ _dont_send_or_sync_me: PhantomData<*mut ()>,
+}
+
+impl Args {
+ pub fn inner_debug(&self) -> &[OsString] {
+ self.iter.as_slice()
+ }
+}
+
+impl Iterator for Args {
+ type Item = OsString;
+ fn next(&mut self) -> Option<OsString> { self.iter.next() }
+ fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
+}
+
+impl ExactSizeIterator for Args {
+ fn len(&self) -> usize { self.iter.len() }
+}
+
+impl DoubleEndedIterator for Args {
+ fn next_back(&mut self) -> Option<OsString> { self.iter.next_back() }
+}
+
+#[cfg(any(target_os = "linux",
+ target_os = "android",
+ target_os = "freebsd",
+ target_os = "dragonfly",
+ target_os = "bitrig",
+ target_os = "netbsd",
+ target_os = "openbsd",
+ target_os = "solaris",
+ target_os = "emscripten",
+ target_os = "haiku",
+ target_os = "l4re",
+ target_os = "fuchsia",
+ target_os = "hermit"))]
+mod imp {
+ use crate::os::unix::prelude::*;
+ use crate::ptr;
+ use crate::ffi::{CStr, OsString};
+ use crate::marker::PhantomData;
+ use super::Args;
+
+ use crate::sys_common::mutex::Mutex;
+
+ static mut ARGC: isize = 0;
+ static mut ARGV: *const *const u8 = ptr::null();
+ // We never call `ENV_LOCK.init()`, so it is UB to attempt to
+ // acquire this mutex reentrantly!
+ static LOCK: Mutex = Mutex::new();
+
+ pub unsafe fn init(argc: isize, argv: *const *const u8) {
+ let _guard = LOCK.lock();
+ ARGC = argc;
+ ARGV = argv;
+ }
+
+ pub unsafe fn cleanup() {
+ let _guard = LOCK.lock();
+ ARGC = 0;
+ ARGV = ptr::null();
+ }
+
+ pub fn args() -> Args {
+ Args {
+ iter: clone().into_iter(),
+ _dont_send_or_sync_me: PhantomData
+ }
+ }
+
+ fn clone() -> Vec<OsString> {
+ unsafe {
+ let _guard = LOCK.lock();
+ (0..ARGC).map(|i| {
+ let cstr = CStr::from_ptr(*ARGV.offset(i) as *const libc::c_char);
+ OsStringExt::from_vec(cstr.to_bytes().to_vec())
+ }).collect()
+ }
+ }
+}
+
+#[cfg(any(target_os = "macos",
+ target_os = "ios"))]
+mod imp {
+ use crate::ffi::CStr;
+ use crate::marker::PhantomData;
+ use super::Args;
+
+ pub unsafe fn init(_argc: isize, _argv: *const *const u8) {
+ }
+
+ pub fn cleanup() {
+ }
+
+ #[cfg(target_os = "macos")]
+ pub fn args() -> Args {
+ use crate::os::unix::prelude::*;
+ extern {
+ // These functions are in crt_externs.h.
+ fn _NSGetArgc() -> *mut libc::c_int;
+ fn _NSGetArgv() -> *mut *mut *mut libc::c_char;
+ }
+
+ let vec = unsafe {
+ let (argc, argv) = (*_NSGetArgc() as isize,
+ *_NSGetArgv() as *const *const libc::c_char);
+ (0.. argc as isize).map(|i| {
+ let bytes = CStr::from_ptr(*argv.offset(i)).to_bytes().to_vec();
+ OsStringExt::from_vec(bytes)
+ }).collect::<Vec<_>>()
+ };
+ Args {
+ iter: vec.into_iter(),
+ _dont_send_or_sync_me: PhantomData,
+ }
+ }
+
+ // As _NSGetArgc and _NSGetArgv aren't mentioned in iOS docs
+ // and use underscores in their names - they're most probably
+ // are considered private and therefore should be avoided
+ // Here is another way to get arguments using Objective C
+ // runtime
+ //
+ // In general it looks like:
+ // res = Vec::new()
+ // let args = [[NSProcessInfo processInfo] arguments]
+ // for i in (0..[args count])
+ // res.push([args objectAtIndex:i])
+ // res
+ #[cfg(target_os = "ios")]
+ pub fn args() -> Args {
+ use crate::ffi::OsString;
+ use crate::mem;
+ use crate::str;
+
+ extern {
+ fn sel_registerName(name: *const libc::c_uchar) -> Sel;
+ fn objc_getClass(class_name: *const libc::c_uchar) -> NsId;
+ }
+
+ #[cfg(target_arch="aarch64")]
+ extern {
+ fn objc_msgSend(obj: NsId, sel: Sel) -> NsId;
+ #[link_name="objc_msgSend"]
+ fn objc_msgSend_ul(obj: NsId, sel: Sel, i: libc::c_ulong) -> NsId;
+ }
+
+ #[cfg(not(target_arch="aarch64"))]
+ extern {
+ fn objc_msgSend(obj: NsId, sel: Sel, ...) -> NsId;
+ #[link_name="objc_msgSend"]
+ fn objc_msgSend_ul(obj: NsId, sel: Sel, ...) -> NsId;
+ }
+
+ type Sel = *const libc::c_void;
+ type NsId = *const libc::c_void;
+
+ let mut res = Vec::new();
+
+ unsafe {
+ let process_info_sel = sel_registerName("processInfo\0".as_ptr());
+ let arguments_sel = sel_registerName("arguments\0".as_ptr());
+ let utf8_sel = sel_registerName("UTF8String\0".as_ptr());
+ let count_sel = sel_registerName("count\0".as_ptr());
+ let object_at_sel = sel_registerName("objectAtIndex:\0".as_ptr());
+
+ let klass = objc_getClass("NSProcessInfo\0".as_ptr());
+ let info = objc_msgSend(klass, process_info_sel);
+ let args = objc_msgSend(info, arguments_sel);
+
+ let cnt: usize = mem::transmute(objc_msgSend(args, count_sel));
+ for i in 0..cnt {
+ let tmp = objc_msgSend_ul(args, object_at_sel, i as libc::c_ulong);
+ let utf_c_str: *const libc::c_char =
+ mem::transmute(objc_msgSend(tmp, utf8_sel));
+ let bytes = CStr::from_ptr(utf_c_str).to_bytes();
+ res.push(OsString::from(str::from_utf8(bytes).unwrap()))
+ }
+ }
+
+ Args { iter: res.into_iter(), _dont_send_or_sync_me: PhantomData }
+ }
+}
diff --git a/src/libstd/sys/unix/backtrace/mod.rs b/src/libstd/sys/unix/backtrace/mod.rs
new file mode 100644
index 0000000..0887e5a
--- /dev/null
+++ b/src/libstd/sys/unix/backtrace/mod.rs
@@ -0,0 +1,110 @@
+/// Backtrace support built on libgcc with some extra OS-specific support
+///
+/// Some methods of getting a backtrace:
+///
+/// * The backtrace() functions on unix. It turns out this doesn't work very
+/// well for green threads on macOS, and the address to symbol portion of it
+/// suffers problems that are described below.
+///
+/// * Using libunwind. This is more difficult than it sounds because libunwind
+/// isn't installed everywhere by default. It's also a bit of a hefty library,
+/// so possibly not the best option. When testing, libunwind was excellent at
+/// getting both accurate backtraces and accurate symbols across platforms.
+/// This route was not chosen in favor of the next option, however.
+///
+/// * We're already using libgcc_s for exceptions in rust (triggering thread
+/// unwinding and running destructors on the stack), and it turns out that it
+/// conveniently comes with a function that also gives us a backtrace. All of
+/// these functions look like _Unwind_*, but it's not quite the full
+/// repertoire of the libunwind API. Due to it already being in use, this was
+/// the chosen route of getting a backtrace.
+///
+/// After choosing libgcc_s for backtraces, the sad part is that it will only
+/// give us a stack trace of instruction pointers. Thankfully these instruction
+/// pointers are accurate (they work for green and native threads), but it's
+/// then up to us again to figure out how to translate these addresses to
+/// symbols. As with before, we have a few options. Before, that, a little bit
+/// of an interlude about symbols. This is my very limited knowledge about
+/// symbol tables, and this information is likely slightly wrong, but the
+/// general idea should be correct.
+///
+/// When talking about symbols, it's helpful to know a few things about where
+/// symbols are located. Some symbols are located in the dynamic symbol table
+/// of the executable which in theory means that they're available for dynamic
+/// linking and lookup. Other symbols end up only in the local symbol table of
+/// the file. This loosely corresponds to pub and priv functions in Rust.
+///
+/// Armed with this knowledge, we know that our solution for address to symbol
+/// translation will need to consult both the local and dynamic symbol tables.
+/// With that in mind, here's our options of translating an address to
+/// a symbol.
+///
+/// * Use dladdr(). The original backtrace()-based idea actually uses dladdr()
+/// behind the scenes to translate, and this is why backtrace() was not used.
+/// Conveniently, this method works fantastically on macOS. It appears dladdr()
+/// uses magic to consult the local symbol table, or we're putting everything
+/// in the dynamic symbol table anyway. Regardless, for macOS, this is the
+/// method used for translation. It's provided by the system and easy to do.o
+///
+/// Sadly, all other systems have a dladdr() implementation that does not
+/// consult the local symbol table. This means that most functions are blank
+/// because they don't have symbols. This means that we need another solution.
+///
+/// * Use unw_get_proc_name(). This is part of the libunwind api (not the
+/// libgcc_s version of the libunwind api), but involves taking a dependency
+/// to libunwind. We may pursue this route in the future if we bundle
+/// libunwind, but libunwind was unwieldy enough that it was not chosen at
+/// this time to provide this functionality.
+///
+/// * Shell out to a utility like `readelf`. Crazy though it may sound, it's a
+/// semi-reasonable solution. The stdlib already knows how to spawn processes,
+/// so in theory it could invoke readelf, parse the output, and consult the
+/// local/dynamic symbol tables from there. This ended up not getting chosen
+/// due to the craziness of the idea plus the advent of the next option.
+///
+/// * Use `libbacktrace`. It turns out that this is a small library bundled in
+/// the gcc repository which provides backtrace and symbol translation
+/// functionality. All we really need from it is the backtrace functionality,
+/// and we only really need this on everything that's not macOS, so this is the
+/// chosen route for now.
+///
+/// In summary, the current situation uses libgcc_s to get a trace of stack
+/// pointers, and we use dladdr() or libbacktrace to translate these addresses
+/// to symbols. This is a bit of a hokey implementation as-is, but it works for
+/// all unix platforms we support right now, so it at least gets the job done.
+
+pub use self::tracing::unwind_backtrace;
+pub use self::printing::{foreach_symbol_fileline, resolve_symname};
+
+// tracing impls:
+mod tracing;
+// symbol resolvers:
+mod printing;
+
+#[cfg(not(target_os = "emscripten"))]
+pub mod gnu {
+ use crate::io;
+ use crate::fs;
+
+ use libc::c_char;
+
+ #[cfg(not(any(target_os = "macos", target_os = "ios")))]
+ pub fn get_executable_filename() -> io::Result<(Vec<c_char>, fs::File)> {
+ Err(io::Error::new(io::ErrorKind::Other, "Not implemented"))
+ }
+
+ #[cfg(any(target_os = "macos", target_os = "ios"))]
+ pub fn get_executable_filename() -> io::Result<(Vec<c_char>, fs::File)> {
+ use crate::env;
+ use crate::os::unix::ffi::OsStrExt;
+
+ let filename = env::current_exe()?;
+ let file = fs::File::open(&filename)?;
+ let mut filename_cstr: Vec<_> = filename.as_os_str().as_bytes().iter()
+ .map(|&x| x as c_char).collect();
+ filename_cstr.push(0); // Null terminate
+ Ok((filename_cstr, file))
+ }
+}
+
+pub struct BacktraceContext;
diff --git a/src/libstd/sys/unix/backtrace/printing/dladdr.rs b/src/libstd/sys/unix/backtrace/printing/dladdr.rs
new file mode 100644
index 0000000..cf3bda6
--- /dev/null
+++ b/src/libstd/sys/unix/backtrace/printing/dladdr.rs
@@ -0,0 +1,34 @@
+use crate::io;
+use crate::intrinsics;
+use crate::ffi::CStr;
+use crate::sys::backtrace::BacktraceContext;
+use crate::sys_common::backtrace::Frame;
+
+pub fn resolve_symname<F>(frame: Frame,
+ callback: F,
+ _: &BacktraceContext) -> io::Result<()>
+ where F: FnOnce(Option<&str>) -> io::Result<()>
+{
+ unsafe {
+ let mut info: Dl_info = intrinsics::init();
+ let symname = if dladdr(frame.exact_position as *mut _, &mut info) == 0 ||
+ info.dli_sname.is_null() {
+ None
+ } else {
+ CStr::from_ptr(info.dli_sname).to_str().ok()
+ };
+ callback(symname)
+ }
+}
+
+#[repr(C)]
+struct Dl_info {
+ dli_fname: *const libc::c_char,
+ dli_fbase: *mut libc::c_void,
+ dli_sname: *const libc::c_char,
+ dli_saddr: *mut libc::c_void,
+}
+
+extern {
+ fn dladdr(addr: *const libc::c_void, info: *mut Dl_info) -> libc::c_int;
+}
diff --git a/src/libstd/sys/unix/backtrace/printing/mod.rs b/src/libstd/sys/unix/backtrace/printing/mod.rs
new file mode 100644
index 0000000..d090cae
--- /dev/null
+++ b/src/libstd/sys/unix/backtrace/printing/mod.rs
@@ -0,0 +1,33 @@
+mod dladdr;
+
+use crate::sys::backtrace::BacktraceContext;
+use crate::sys_common::backtrace::Frame;
+use crate::io;
+
+#[cfg(target_os = "emscripten")]
+pub use self::dladdr::resolve_symname;
+
+#[cfg(target_os = "emscripten")]
+pub fn foreach_symbol_fileline<F>(_: Frame, _: F, _: &BacktraceContext) -> io::Result<bool>
+where
+ F: FnMut(&[u8], u32) -> io::Result<()>
+{
+ Ok(false)
+}
+
+#[cfg(not(target_os = "emscripten"))]
+pub use crate::sys_common::gnu::libbacktrace::foreach_symbol_fileline;
+
+#[cfg(not(target_os = "emscripten"))]
+pub fn resolve_symname<F>(frame: Frame, callback: F, bc: &BacktraceContext) -> io::Result<()>
+where
+ F: FnOnce(Option<&str>) -> io::Result<()>
+{
+ crate::sys_common::gnu::libbacktrace::resolve_symname(frame, |symname| {
+ if symname.is_some() {
+ callback(symname)
+ } else {
+ dladdr::resolve_symname(frame, callback, bc)
+ }
+ }, bc)
+}
diff --git a/src/libstd/sys/unix/backtrace/tracing/backtrace_fn.rs b/src/libstd/sys/unix/backtrace/tracing/backtrace_fn.rs
new file mode 100644
index 0000000..a628d10
--- /dev/null
+++ b/src/libstd/sys/unix/backtrace/tracing/backtrace_fn.rs
@@ -0,0 +1,39 @@
+/// As always - iOS on arm uses SjLj exceptions and
+/// _Unwind_Backtrace is even not available there. Still,
+/// backtraces could be extracted using a backtrace function,
+/// which thanks god is public
+///
+/// As mentioned in a huge comment block in `super::super`, backtrace
+/// doesn't play well with green threads, so while it is extremely nice and
+/// simple to use it should be used only on iOS devices as the only viable
+/// option.
+
+use crate::io;
+use crate::ptr;
+use crate::sys::backtrace::BacktraceContext;
+use crate::sys_common::backtrace::Frame;
+
+#[inline(never)] // if we know this is a function call, we can skip it when
+ // tracing
+pub fn unwind_backtrace(frames: &mut [Frame])
+ -> io::Result<(usize, BacktraceContext)>
+{
+ const FRAME_LEN: usize = 100;
+ assert!(FRAME_LEN >= frames.len());
+ let mut raw_frames = [ptr::null_mut(); FRAME_LEN];
+ let nb_frames = unsafe {
+ backtrace(raw_frames.as_mut_ptr(), raw_frames.len() as libc::c_int)
+ } as usize;
+ for (from, to) in raw_frames.iter().zip(frames.iter_mut()).take(nb_frames) {
+ *to = Frame {
+ exact_position: *from as *mut u8,
+ symbol_addr: *from as *mut u8,
+ inline_context: 0,
+ };
+ }
+ Ok((nb_frames as usize, BacktraceContext))
+}
+
+extern {
+ fn backtrace(buf: *mut *mut libc::c_void, sz: libc::c_int) -> libc::c_int;
+}
diff --git a/src/libstd/sys/unix/backtrace/tracing/gcc_s.rs b/src/libstd/sys/unix/backtrace/tracing/gcc_s.rs
new file mode 100644
index 0000000..e637913
--- /dev/null
+++ b/src/libstd/sys/unix/backtrace/tracing/gcc_s.rs
@@ -0,0 +1,99 @@
+use crate::error::Error;
+use crate::fmt;
+use crate::io;
+use crate::sys::backtrace::BacktraceContext;
+use crate::sys_common::backtrace::Frame;
+
+use unwind as uw;
+
+struct Context<'a> {
+ idx: usize,
+ frames: &'a mut [Frame],
+}
+
+#[derive(Debug)]
+struct UnwindError(uw::_Unwind_Reason_Code);
+
+impl Error for UnwindError {
+ fn description(&self) -> &'static str {
+ "unexpected return value while unwinding"
+ }
+}
+
+impl fmt::Display for UnwindError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "{}: {:?}", self.description(), self.0)
+ }
+}
+
+#[inline(never)] // if we know this is a function call, we can skip it when
+ // tracing
+pub fn unwind_backtrace(frames: &mut [Frame])
+ -> io::Result<(usize, BacktraceContext)>
+{
+ let mut cx = Context {
+ idx: 0,
+ frames,
+ };
+ let result_unwind = unsafe {
+ uw::_Unwind_Backtrace(trace_fn,
+ &mut cx as *mut Context<'_>
+ as *mut libc::c_void)
+ };
+ // See libunwind:src/unwind/Backtrace.c for the return values.
+ // No, there is no doc.
+ match result_unwind {
+ // These return codes seem to be benign and need to be ignored for backtraces
+ // to show up properly on all tested platforms.
+ uw::_URC_END_OF_STACK | uw::_URC_FATAL_PHASE1_ERROR | uw::_URC_FAILURE => {
+ Ok((cx.idx, BacktraceContext))
+ }
+ _ => {
+ Err(io::Error::new(io::ErrorKind::Other,
+ UnwindError(result_unwind)))
+ }
+ }
+}
+
+extern fn trace_fn(ctx: *mut uw::_Unwind_Context,
+ arg: *mut libc::c_void) -> uw::_Unwind_Reason_Code {
+ let cx = unsafe { &mut *(arg as *mut Context<'_>) };
+ if cx.idx >= cx.frames.len() {
+ return uw::_URC_NORMAL_STOP;
+ }
+
+ let mut ip_before_insn = 0;
+ let mut ip = unsafe {
+ uw::_Unwind_GetIPInfo(ctx, &mut ip_before_insn) as *mut libc::c_void
+ };
+ if !ip.is_null() && ip_before_insn == 0 {
+ // this is a non-signaling frame, so `ip` refers to the address
+ // after the calling instruction. account for that.
+ ip = (ip as usize - 1) as *mut _;
+ }
+
+ // dladdr() on osx gets whiny when we use FindEnclosingFunction, and
+ // it appears to work fine without it, so we only use
+ // FindEnclosingFunction on non-osx platforms. In doing so, we get a
+ // slightly more accurate stack trace in the process.
+ //
+ // This is often because panic involves the last instruction of a
+ // function being "call std::rt::begin_unwind", with no ret
+ // instructions after it. This means that the return instruction
+ // pointer points *outside* of the calling function, and by
+ // unwinding it we go back to the original function.
+ let symaddr = if cfg!(target_os = "macos") || cfg!(target_os = "ios") {
+ ip
+ } else {
+ unsafe { uw::_Unwind_FindEnclosingFunction(ip) }
+ };
+
+ cx.frames[cx.idx] = Frame {
+ symbol_addr: symaddr as *mut u8,
+ exact_position: ip as *mut u8,
+ inline_context: 0,
+ };
+ cx.idx += 1;
+
+ uw::_URC_NO_REASON
+}
diff --git a/src/libstd/sys/unix/backtrace/tracing/mod.rs b/src/libstd/sys/unix/backtrace/tracing/mod.rs
new file mode 100644
index 0000000..11863e6
--- /dev/null
+++ b/src/libstd/sys/unix/backtrace/tracing/mod.rs
@@ -0,0 +1,8 @@
+pub use self::imp::*;
+
+#[cfg(not(all(target_os = "ios", target_arch = "arm")))]
+#[path = "gcc_s.rs"]
+mod imp;
+#[cfg(all(target_os = "ios", target_arch = "arm"))]
+#[path = "backtrace_fn.rs"]
+mod imp;
diff --git a/src/libstd/sys/unix/cmath.rs b/src/libstd/sys/unix/cmath.rs
new file mode 100644
index 0000000..f6bb589
--- /dev/null
+++ b/src/libstd/sys/unix/cmath.rs
@@ -0,0 +1,33 @@
+#![cfg(not(test))]
+
+use libc::{c_float, c_double};
+
+#[link_name = "m"]
+extern {
+ pub fn acos(n: c_double) -> c_double;
+ pub fn acosf(n: c_float) -> c_float;
+ pub fn asin(n: c_double) -> c_double;
+ pub fn asinf(n: c_float) -> c_float;
+ pub fn atan(n: c_double) -> c_double;
+ pub fn atan2(a: c_double, b: c_double) -> c_double;
+ pub fn atan2f(a: c_float, b: c_float) -> c_float;
+ pub fn atanf(n: c_float) -> c_float;
+ pub fn cbrt(n: c_double) -> c_double;
+ pub fn cbrtf(n: c_float) -> c_float;
+ pub fn cosh(n: c_double) -> c_double;
+ pub fn coshf(n: c_float) -> c_float;
+ pub fn expm1(n: c_double) -> c_double;
+ pub fn expm1f(n: c_float) -> c_float;
+ pub fn fdim(a: c_double, b: c_double) -> c_double;
+ pub fn fdimf(a: c_float, b: c_float) -> c_float;
+ pub fn hypot(x: c_double, y: c_double) -> c_double;
+ pub fn hypotf(x: c_float, y: c_float) -> c_float;
+ pub fn log1p(n: c_double) -> c_double;
+ pub fn log1pf(n: c_float) -> c_float;
+ pub fn sinh(n: c_double) -> c_double;
+ pub fn sinhf(n: c_float) -> c_float;
+ pub fn tan(n: c_double) -> c_double;
+ pub fn tanf(n: c_float) -> c_float;
+ pub fn tanh(n: c_double) -> c_double;
+ pub fn tanhf(n: c_float) -> c_float;
+}
diff --git a/src/libstd/sys/unix/condvar.rs b/src/libstd/sys/unix/condvar.rs
new file mode 100644
index 0000000..47fb679
--- /dev/null
+++ b/src/libstd/sys/unix/condvar.rs
@@ -0,0 +1,181 @@
+use crate::cell::UnsafeCell;
+use crate::sys::mutex::{self, Mutex};
+use crate::time::Duration;
+
+pub struct Condvar { inner: UnsafeCell<libc::pthread_cond_t> }
+
+unsafe impl Send for Condvar {}
+unsafe impl Sync for Condvar {}
+
+const TIMESPEC_MAX: libc::timespec = libc::timespec {
+ tv_sec: <libc::time_t>::max_value(),
+ tv_nsec: 1_000_000_000 - 1,
+};
+
+fn saturating_cast_to_time_t(value: u64) -> libc::time_t {
+ if value > <libc::time_t>::max_value() as u64 {
+ <libc::time_t>::max_value()
+ } else {
+ value as libc::time_t
+ }
+}
+
+impl Condvar {
+ pub const fn new() -> Condvar {
+ // Might be moved and address is changing it is better to avoid
+ // initialization of potentially opaque OS data before it landed
+ Condvar { inner: UnsafeCell::new(libc::PTHREAD_COND_INITIALIZER) }
+ }
+
+ #[cfg(any(target_os = "macos",
+ target_os = "ios",
+ target_os = "l4re",
+ target_os = "android",
+ target_os = "hermit"))]
+ pub unsafe fn init(&mut self) {}
+
+ #[cfg(not(any(target_os = "macos",
+ target_os = "ios",
+ target_os = "l4re",
+ target_os = "android",
+ target_os = "hermit")))]
+ pub unsafe fn init(&mut self) {
+ use crate::mem;
+ let mut attr: libc::pthread_condattr_t = mem::uninitialized();
+ let r = libc::pthread_condattr_init(&mut attr);
+ assert_eq!(r, 0);
+ let r = libc::pthread_condattr_setclock(&mut attr, libc::CLOCK_MONOTONIC);
+ assert_eq!(r, 0);
+ let r = libc::pthread_cond_init(self.inner.get(), &attr);
+ assert_eq!(r, 0);
+ let r = libc::pthread_condattr_destroy(&mut attr);
+ assert_eq!(r, 0);
+ }
+
+ #[inline]
+ pub unsafe fn notify_one(&self) {
+ let r = libc::pthread_cond_signal(self.inner.get());
+ debug_assert_eq!(r, 0);
+ }
+
+ #[inline]
+ pub unsafe fn notify_all(&self) {
+ let r = libc::pthread_cond_broadcast(self.inner.get());
+ debug_assert_eq!(r, 0);
+ }
+
+ #[inline]
+ pub unsafe fn wait(&self, mutex: &Mutex) {
+ let r = libc::pthread_cond_wait(self.inner.get(), mutex::raw(mutex));
+ debug_assert_eq!(r, 0);
+ }
+
+ // This implementation is used on systems that support pthread_condattr_setclock
+ // where we configure condition variable to use monotonic clock (instead of
+ // default system clock). This approach avoids all problems that result
+ // from changes made to the system time.
+ #[cfg(not(any(target_os = "macos",
+ target_os = "ios",
+ target_os = "android",
+ target_os = "hermit")))]
+ pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
+ use crate::mem;
+
+ let mut now: libc::timespec = mem::zeroed();
+ let r = libc::clock_gettime(libc::CLOCK_MONOTONIC, &mut now);
+ assert_eq!(r, 0);
+
+ // Nanosecond calculations can't overflow because both values are below 1e9.
+ let nsec = dur.subsec_nanos() + now.tv_nsec as u32;
+
+ let sec = saturating_cast_to_time_t(dur.as_secs())
+ .checked_add((nsec / 1_000_000_000) as libc::time_t)
+ .and_then(|s| s.checked_add(now.tv_sec));
+ let nsec = nsec % 1_000_000_000;
+
+ let timeout = sec.map(|s| {
+ libc::timespec { tv_sec: s, tv_nsec: nsec as _}
+ }).unwrap_or(TIMESPEC_MAX);
+
+ let r = libc::pthread_cond_timedwait(self.inner.get(), mutex::raw(mutex),
+ &timeout);
+ assert!(r == libc::ETIMEDOUT || r == 0);
+ r == 0
+ }
+
+
+ // This implementation is modeled after libcxx's condition_variable
+ // https://github.com/llvm-mirror/libcxx/blob/release_35/src/condition_variable.cpp#L46
+ // https://github.com/llvm-mirror/libcxx/blob/release_35/include/__mutex_base#L367
+ #[cfg(any(target_os = "macos", target_os = "ios", target_os = "android", target_os = "hermit"))]
+ pub unsafe fn wait_timeout(&self, mutex: &Mutex, mut dur: Duration) -> bool {
+ use crate::ptr;
+ use crate::time::Instant;
+
+ // 1000 years
+ let max_dur = Duration::from_secs(1000 * 365 * 86400);
+
+ if dur > max_dur {
+ // OSX implementation of `pthread_cond_timedwait` is buggy
+ // with super long durations. When duration is greater than
+ // 0x100_0000_0000_0000 seconds, `pthread_cond_timedwait`
+ // in macOS Sierra return error 316.
+ //
+ // This program demonstrates the issue:
+ // https://gist.github.com/stepancheg/198db4623a20aad2ad7cddb8fda4a63c
+ //
+ // To work around this issue, and possible bugs of other OSes, timeout
+ // is clamped to 1000 years, which is allowable per the API of `wait_timeout`
+ // because of spurious wakeups.
+
+ dur = max_dur;
+ }
+
+ // First, figure out what time it currently is, in both system and
+ // stable time. pthread_cond_timedwait uses system time, but we want to
+ // report timeout based on stable time.
+ let mut sys_now = libc::timeval { tv_sec: 0, tv_usec: 0 };
+ let stable_now = Instant::now();
+ let r = libc::gettimeofday(&mut sys_now, ptr::null_mut());
+ debug_assert_eq!(r, 0);
+
+ let nsec = dur.subsec_nanos() as libc::c_long +
+ (sys_now.tv_usec * 1000) as libc::c_long;
+ let extra = (nsec / 1_000_000_000) as libc::time_t;
+ let nsec = nsec % 1_000_000_000;
+ let seconds = saturating_cast_to_time_t(dur.as_secs());
+
+ let timeout = sys_now.tv_sec.checked_add(extra).and_then(|s| {
+ s.checked_add(seconds)
+ }).map(|s| {
+ libc::timespec { tv_sec: s, tv_nsec: nsec }
+ }).unwrap_or(TIMESPEC_MAX);
+
+ // And wait!
+ let r = libc::pthread_cond_timedwait(self.inner.get(), mutex::raw(mutex),
+ &timeout);
+ debug_assert!(r == libc::ETIMEDOUT || r == 0);
+
+ // ETIMEDOUT is not a totally reliable method of determining timeout due
+ // to clock shifts, so do the check ourselves
+ stable_now.elapsed() < dur
+ }
+
+ #[inline]
+ #[cfg(not(target_os = "dragonfly"))]
+ pub unsafe fn destroy(&self) {
+ let r = libc::pthread_cond_destroy(self.inner.get());
+ debug_assert_eq!(r, 0);
+ }
+
+ #[inline]
+ #[cfg(target_os = "dragonfly")]
+ pub unsafe fn destroy(&self) {
+ let r = libc::pthread_cond_destroy(self.inner.get());
+ // On DragonFly pthread_cond_destroy() returns EINVAL if called on
+ // a condvar that was just initialized with
+ // libc::PTHREAD_COND_INITIALIZER. Once it is used or
+ // pthread_cond_init() is called, this behaviour no longer occurs.
+ debug_assert!(r == 0 || r == libc::EINVAL);
+ }
+}
diff --git a/src/libstd/sys/unix/env.rs b/src/libstd/sys/unix/env.rs
new file mode 100644
index 0000000..f9592d5
--- /dev/null
+++ b/src/libstd/sys/unix/env.rs
@@ -0,0 +1,175 @@
+#[cfg(target_os = "linux")]
+pub mod os {
+ pub const FAMILY: &str = "unix";
+ pub const OS: &str = "linux";
+ pub const DLL_PREFIX: &str = "lib";
+ pub const DLL_SUFFIX: &str = ".so";
+ pub const DLL_EXTENSION: &str = "so";
+ pub const EXE_SUFFIX: &str = "";
+ pub const EXE_EXTENSION: &str = "";
+}
+
+#[cfg(target_os = "macos")]
+pub mod os {
+ pub const FAMILY: &str = "unix";
+ pub const OS: &str = "macos";
+ pub const DLL_PREFIX: &str = "lib";
+ pub const DLL_SUFFIX: &str = ".dylib";
+ pub const DLL_EXTENSION: &str = "dylib";
+ pub const EXE_SUFFIX: &str = "";
+ pub const EXE_EXTENSION: &str = "";
+}
+
+#[cfg(target_os = "ios")]
+pub mod os {
+ pub const FAMILY: &str = "unix";
+ pub const OS: &str = "ios";
+ pub const DLL_PREFIX: &str = "lib";
+ pub const DLL_SUFFIX: &str = ".dylib";
+ pub const DLL_EXTENSION: &str = "dylib";
+ pub const EXE_SUFFIX: &str = "";
+ pub const EXE_EXTENSION: &str = "";
+}
+
+#[cfg(target_os = "freebsd")]
+pub mod os {
+ pub const FAMILY: &str = "unix";
+ pub const OS: &str = "freebsd";
+ pub const DLL_PREFIX: &str = "lib";
+ pub const DLL_SUFFIX: &str = ".so";
+ pub const DLL_EXTENSION: &str = "so";
+ pub const EXE_SUFFIX: &str = "";
+ pub const EXE_EXTENSION: &str = "";
+}
+
+#[cfg(target_os = "dragonfly")]
+pub mod os {
+ pub const FAMILY: &str = "unix";
+ pub const OS: &str = "dragonfly";
+ pub const DLL_PREFIX: &str = "lib";
+ pub const DLL_SUFFIX: &str = ".so";
+ pub const DLL_EXTENSION: &str = "so";
+ pub const EXE_SUFFIX: &str = "";
+ pub const EXE_EXTENSION: &str = "";
+}
+
+#[cfg(target_os = "bitrig")]
+pub mod os {
+ pub const FAMILY: &str = "unix";
+ pub const OS: &str = "bitrig";
+ pub const DLL_PREFIX: &str = "lib";
+ pub const DLL_SUFFIX: &str = ".so";
+ pub const DLL_EXTENSION: &str = "so";
+ pub const EXE_SUFFIX: &str = "";
+ pub const EXE_EXTENSION: &str = "";
+}
+
+#[cfg(target_os = "netbsd")]
+pub mod os {
+ pub const FAMILY: &str = "unix";
+ pub const OS: &str = "netbsd";
+ pub const DLL_PREFIX: &str = "lib";
+ pub const DLL_SUFFIX: &str = ".so";
+ pub const DLL_EXTENSION: &str = "so";
+ pub const EXE_SUFFIX: &str = "";
+ pub const EXE_EXTENSION: &str = "";
+}
+
+#[cfg(target_os = "openbsd")]
+pub mod os {
+ pub const FAMILY: &str = "unix";
+ pub const OS: &str = "openbsd";
+ pub const DLL_PREFIX: &str = "lib";
+ pub const DLL_SUFFIX: &str = ".so";
+ pub const DLL_EXTENSION: &str = "so";
+ pub const EXE_SUFFIX: &str = "";
+ pub const EXE_EXTENSION: &str = "";
+}
+
+#[cfg(target_os = "android")]
+pub mod os {
+ pub const FAMILY: &str = "unix";
+ pub const OS: &str = "android";
+ pub const DLL_PREFIX: &str = "lib";
+ pub const DLL_SUFFIX: &str = ".so";
+ pub const DLL_EXTENSION: &str = "so";
+ pub const EXE_SUFFIX: &str = "";
+ pub const EXE_EXTENSION: &str = "";
+}
+
+#[cfg(target_os = "solaris")]
+pub mod os {
+ pub const FAMILY: &str = "unix";
+ pub const OS: &str = "solaris";
+ pub const DLL_PREFIX: &str = "lib";
+ pub const DLL_SUFFIX: &str = ".so";
+ pub const DLL_EXTENSION: &str = "so";
+ pub const EXE_SUFFIX: &str = "";
+ pub const EXE_EXTENSION: &str = "";
+}
+
+#[cfg(target_os = "haiku")]
+pub mod os {
+ pub const FAMILY: &str = "unix";
+ pub const OS: &str = "haiku";
+ pub const DLL_PREFIX: &str = "lib";
+ pub const DLL_SUFFIX: &str = ".so";
+ pub const DLL_EXTENSION: &str = "so";
+ pub const EXE_SUFFIX: &str = "";
+ pub const EXE_EXTENSION: &str = "";
+}
+
+#[cfg(all(target_os = "emscripten", target_arch = "asmjs"))]
+pub mod os {
+ pub const FAMILY: &str = "unix";
+ pub const OS: &str = "emscripten";
+ pub const DLL_PREFIX: &str = "lib";
+ pub const DLL_SUFFIX: &str = ".so";
+ pub const DLL_EXTENSION: &str = "so";
+ pub const EXE_SUFFIX: &str = ".js";
+ pub const EXE_EXTENSION: &str = "js";
+}
+
+#[cfg(all(target_os = "emscripten", target_arch = "wasm32"))]
+pub mod os {
+ pub const FAMILY: &str = "unix";
+ pub const OS: &str = "emscripten";
+ pub const DLL_PREFIX: &str = "lib";
+ pub const DLL_SUFFIX: &str = ".so";
+ pub const DLL_EXTENSION: &str = "so";
+ pub const EXE_SUFFIX: &str = ".js";
+ pub const EXE_EXTENSION: &str = "js";
+}
+
+#[cfg(target_os = "fuchsia")]
+pub mod os {
+ pub const FAMILY: &str = "unix";
+ pub const OS: &str = "fuchsia";
+ pub const DLL_PREFIX: &str = "lib";
+ pub const DLL_SUFFIX: &str = ".so";
+ pub const DLL_EXTENSION: &str = "so";
+ pub const EXE_SUFFIX: &str = "";
+ pub const EXE_EXTENSION: &str = "";
+}
+
+#[cfg(target_os = "l4re")]
+pub mod os {
+ pub const FAMILY: &str = "unix";
+ pub const OS: &str = "l4re";
+ pub const DLL_PREFIX: &str = "lib";
+ pub const DLL_SUFFIX: &str = ".so";
+ pub const DLL_EXTENSION: &str = "so";
+ pub const EXE_SUFFIX: &str = "";
+ pub const EXE_EXTENSION: &str = "";
+}
+
+#[cfg(target_os = "hermit")]
+pub mod os {
+ pub const FAMILY: &str = "unix";
+ pub const OS: &str = "hermit";
+ pub const DLL_PREFIX: &str = "lib";
+ pub const DLL_SUFFIX: &str = ".so";
+ pub const DLL_EXTENSION: &str = "so";
+ pub const EXE_SUFFIX: &str = "";
+ pub const EXE_EXTENSION: &str = "";
+}
diff --git a/src/libstd/sys/unix/ext/ffi.rs b/src/libstd/sys/unix/ext/ffi.rs
new file mode 100644
index 0000000..76b34a6
--- /dev/null
+++ b/src/libstd/sys/unix/ext/ffi.rs
@@ -0,0 +1,38 @@
+//! Unix-specific extension to the primitives in the `std::ffi` module
+//!
+//! # Examples
+//!
+//! ```
+//! use std::ffi::OsString;
+//! use std::os::unix::ffi::OsStringExt;
+//!
+//! let bytes = b"foo".to_vec();
+//!
+//! // OsStringExt::from_vec
+//! let os_string = OsString::from_vec(bytes);
+//! assert_eq!(os_string.to_str(), Some("foo"));
+//!
+//! // OsStringExt::into_vec
+//! let bytes = os_string.into_vec();
+//! assert_eq!(bytes, b"foo");
+//! ```
+//!
+//! ```
+//! use std::ffi::OsStr;
+//! use std::os::unix::ffi::OsStrExt;
+//!
+//! let bytes = b"foo";
+//!
+//! // OsStrExt::from_bytes
+//! let os_str = OsStr::from_bytes(bytes);
+//! assert_eq!(os_str.to_str(), Some("foo"));
+//!
+//! // OsStrExt::as_bytes
+//! let bytes = os_str.as_bytes();
+//! assert_eq!(bytes, b"foo");
+//! ```
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use crate::sys_common::os_str_bytes::*;
diff --git a/src/libstd/sys/unix/ext/fs.rs b/src/libstd/sys/unix/ext/fs.rs
new file mode 100644
index 0000000..d9baac9
--- /dev/null
+++ b/src/libstd/sys/unix/ext/fs.rs
@@ -0,0 +1,856 @@
+//! Unix-specific extensions to primitives in the `std::fs` module.
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+use crate::fs::{self, Permissions, OpenOptions};
+use crate::io;
+use crate::path::Path;
+use crate::sys;
+use crate::sys_common::{FromInner, AsInner, AsInnerMut};
+use crate::sys::platform::fs::MetadataExt as UnixMetadataExt;
+
+/// Unix-specific extensions to [`File`].
+///
+/// [`File`]: ../../../../std/fs/struct.File.html
+#[stable(feature = "file_offset", since = "1.15.0")]
+pub trait FileExt {
+ /// Reads a number of bytes starting from a given offset.
+ ///
+ /// Returns the number of bytes read.
+ ///
+ /// 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.
+ ///
+ /// Note that similar to [`File::read`], it is not an error to return with a
+ /// short read.
+ ///
+ /// [`File::read`]: ../../../../std/fs/struct.File.html#method.read
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// 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 8 bytes from the offset 10.
+ /// let num_bytes_read = file.read_at(&mut buf, 10)?;
+ /// println!("read {} bytes: {:?}", num_bytes_read, buf);
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "file_offset", since = "1.15.0")]
+ fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize>;
+
+ /// Reads the exact number of byte required to fill `buf` from the given offset.
+ ///
+ /// The offset is relative to the start of the file and thus independent
+ /// from the current cursor.
+ ///
+ /// The current file cursor is not affected by this function.
+ ///
+ /// Similar to [`Read::read_exact`] but uses [`read_at`] instead of `read`.
+ ///
+ /// [`Read::read_exact`]: ../../../../std/io/trait.Read.html#method.read_exact
+ /// [`read_at`]: #tymethod.read_at
+ ///
+ /// # Errors
+ ///
+ /// If this function encounters an error of the kind
+ /// [`ErrorKind::Interrupted`] then the error is ignored and the operation
+ /// will continue.
+ ///
+ /// If this function encounters an "end of file" before completely filling
+ /// the buffer, it returns an error of the kind [`ErrorKind::UnexpectedEof`].
+ /// The contents of `buf` are unspecified in this case.
+ ///
+ /// If any other read error is encountered then this function immediately
+ /// returns. The contents of `buf` are unspecified in this case.
+ ///
+ /// If this function returns an error, it is unspecified how many bytes it
+ /// has read, but it will never read more than would be necessary to
+ /// completely fill the buffer.
+ ///
+ /// [`ErrorKind::Interrupted`]: ../../../../std/io/enum.ErrorKind.html#variant.Interrupted
+ /// [`ErrorKind::UnexpectedEof`]: ../../../../std/io/enum.ErrorKind.html#variant.UnexpectedEof
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// 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(())
+ /// }
+ /// ```
+ #[stable(feature = "rw_exact_all_at", since = "1.33.0")]
+ fn read_exact_at(&self, mut buf: &mut [u8], mut offset: u64) -> io::Result<()> {
+ while !buf.is_empty() {
+ match self.read_at(buf, offset) {
+ Ok(0) => break,
+ Ok(n) => {
+ let tmp = buf;
+ buf = &mut tmp[n..];
+ offset += n as u64;
+ }
+ Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
+ Err(e) => return Err(e),
+ }
+ }
+ if !buf.is_empty() {
+ Err(io::Error::new(io::ErrorKind::UnexpectedEof,
+ "failed to fill whole buffer"))
+ } else {
+ Ok(())
+ }
+ }
+
+ /// Writes a number of bytes starting from a given offset.
+ ///
+ /// Returns the number of bytes written.
+ ///
+ /// 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.
+ ///
+ /// When writing beyond the end of the file, the file is appropriately
+ /// extended and the intermediate bytes are initialized with the value 0.
+ ///
+ /// Note that similar to [`File::write`], it is not an error to return a
+ /// short write.
+ ///
+ /// [`File::write`]: ../../../../std/fs/struct.File.html#write.v
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// 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_at(b"sushi", 10)?;
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "file_offset", since = "1.15.0")]
+ fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize>;
+
+ /// Attempts to write an entire buffer starting from a given offset.
+ ///
+ /// The offset is relative to the start of the file and thus independent
+ /// from the current cursor.
+ ///
+ /// The current file cursor is not affected by this function.
+ ///
+ /// This method will continuously call [`write_at`] until there is no more data
+ /// to be written or an error of non-[`ErrorKind::Interrupted`] kind is
+ /// returned. This method will not return until the entire buffer has been
+ /// successfully written or such an error occurs. The first error that is
+ /// not of [`ErrorKind::Interrupted`] kind generated from this method will be
+ /// returned.
+ ///
+ /// # Errors
+ ///
+ /// This function will return the first error of
+ /// non-[`ErrorKind::Interrupted`] kind that [`write_at`] returns.
+ ///
+ /// [`ErrorKind::Interrupted`]: ../../../../std/io/enum.ErrorKind.html#variant.Interrupted
+ /// [`write_at`]: #tymethod.write_at
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// 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(())
+ /// }
+ /// ```
+ #[stable(feature = "rw_exact_all_at", since = "1.33.0")]
+ 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")]
+impl FileExt for fs::File {
+ fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
+ self.as_inner().read_at(buf, offset)
+ }
+ fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
+ self.as_inner().write_at(buf, offset)
+ }
+}
+
+/// Unix-specific extensions to [`fs::Permissions`].
+///
+/// [`fs::Permissions`]: ../../../../std/fs/struct.Permissions.html
+#[stable(feature = "fs_ext", since = "1.1.0")]
+pub trait PermissionsExt {
+ /// Returns the underlying raw `st_mode` bits that contain the standard
+ /// Unix permissions for this file.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs::File;
+ /// use std::os::unix::fs::PermissionsExt;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let f = File::create("foo.txt")?;
+ /// let metadata = f.metadata()?;
+ /// let permissions = metadata.permissions();
+ ///
+ /// println!("permissions: {}", permissions.mode());
+ /// Ok(()) }
+ /// ```
+ #[stable(feature = "fs_ext", since = "1.1.0")]
+ fn mode(&self) -> u32;
+
+ /// Sets the underlying raw bits for this set of permissions.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs::File;
+ /// use std::os::unix::fs::PermissionsExt;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let f = File::create("foo.txt")?;
+ /// let metadata = f.metadata()?;
+ /// let mut permissions = metadata.permissions();
+ ///
+ /// permissions.set_mode(0o644); // Read/write for owner and read for others.
+ /// assert_eq!(permissions.mode(), 0o644);
+ /// Ok(()) }
+ /// ```
+ #[stable(feature = "fs_ext", since = "1.1.0")]
+ fn set_mode(&mut self, mode: u32);
+
+ /// Creates a new instance of `Permissions` from the given set of Unix
+ /// permission bits.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::fs::Permissions;
+ /// use std::os::unix::fs::PermissionsExt;
+ ///
+ /// // Read/write for owner and read for others.
+ /// let permissions = Permissions::from_mode(0o644);
+ /// assert_eq!(permissions.mode(), 0o644);
+ /// ```
+ #[stable(feature = "fs_ext", since = "1.1.0")]
+ fn from_mode(mode: u32) -> Self;
+}
+
+#[stable(feature = "fs_ext", since = "1.1.0")]
+impl PermissionsExt for Permissions {
+ fn mode(&self) -> u32 {
+ self.as_inner().mode()
+ }
+
+ fn set_mode(&mut self, mode: u32) {
+ *self = Permissions::from_inner(FromInner::from_inner(mode));
+ }
+
+ fn from_mode(mode: u32) -> Permissions {
+ Permissions::from_inner(FromInner::from_inner(mode))
+ }
+}
+
+/// Unix-specific extensions to [`fs::OpenOptions`].
+///
+/// [`fs::OpenOptions`]: ../../../../std/fs/struct.OpenOptions.html
+#[stable(feature = "fs_ext", since = "1.1.0")]
+pub trait OpenOptionsExt {
+ /// Sets the mode bits that a new file will be created with.
+ ///
+ /// If a new file is created as part of a `File::open_opts` call then this
+ /// specified `mode` will be used as the permission bits for the new file.
+ /// If no `mode` is set, the default of `0o666` will be used.
+ /// The operating system masks out bits with the systems `umask`, to produce
+ /// the final permissions.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs::OpenOptions;
+ /// use std::os::unix::fs::OpenOptionsExt;
+ ///
+ /// # fn main() {
+ /// let mut options = OpenOptions::new();
+ /// options.mode(0o644); // Give read/write for owner and read for others.
+ /// let file = options.open("foo.txt");
+ /// # }
+ /// ```
+ #[stable(feature = "fs_ext", since = "1.1.0")]
+ fn mode(&mut self, mode: u32) -> &mut Self;
+
+ /// Pass custom flags to the `flags` argument of `open`.
+ ///
+ /// The bits that define the access mode are masked out with `O_ACCMODE`, to
+ /// ensure they do not interfere with the access mode set by Rusts options.
+ ///
+ /// Custom flags can only set flags, not remove flags set by Rusts options.
+ /// This options overwrites any previously set custom flags.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # #![feature(rustc_private)]
+ /// extern crate libc;
+ /// use std::fs::OpenOptions;
+ /// use std::os::unix::fs::OpenOptionsExt;
+ ///
+ /// # fn main() {
+ /// let mut options = OpenOptions::new();
+ /// options.write(true);
+ /// if cfg!(unix) {
+ /// options.custom_flags(libc::O_NOFOLLOW);
+ /// }
+ /// let file = options.open("foo.txt");
+ /// # }
+ /// ```
+ #[stable(feature = "open_options_ext", since = "1.10.0")]
+ fn custom_flags(&mut self, flags: i32) -> &mut Self;
+}
+
+#[stable(feature = "fs_ext", since = "1.1.0")]
+impl OpenOptionsExt for OpenOptions {
+ fn mode(&mut self, mode: u32) -> &mut OpenOptions {
+ self.as_inner_mut().mode(mode); self
+ }
+
+ fn custom_flags(&mut self, flags: i32) -> &mut OpenOptions {
+ self.as_inner_mut().custom_flags(flags); self
+ }
+}
+
+/// Unix-specific extensions to [`fs::Metadata`].
+///
+/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+pub trait MetadataExt {
+ /// Returns the ID of the device containing the file.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::io;
+ /// use std::fs;
+ /// use std::os::unix::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// let dev_id = meta.dev();
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn dev(&self) -> u64;
+ /// Returns the inode number.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::os::unix::fs::MetadataExt;
+ /// use std::io;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// let inode = meta.ino();
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn ino(&self) -> u64;
+ /// Returns the rights applied to this file.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::os::unix::fs::MetadataExt;
+ /// use std::io;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// let mode = meta.mode();
+ /// let user_has_write_access = mode & 0o200;
+ /// let user_has_read_write_access = mode & 0o600;
+ /// let group_has_read_access = mode & 0o040;
+ /// let others_have_exec_access = mode & 0o001;
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn mode(&self) -> u32;
+ /// Returns the number of hard links pointing to this file.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::os::unix::fs::MetadataExt;
+ /// use std::io;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// let nb_hard_links = meta.nlink();
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn nlink(&self) -> u64;
+ /// Returns the user ID of the owner of this file.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::os::unix::fs::MetadataExt;
+ /// use std::io;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// let user_id = meta.uid();
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn uid(&self) -> u32;
+ /// Returns the group ID of the owner of this file.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::os::unix::fs::MetadataExt;
+ /// use std::io;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// let group_id = meta.gid();
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn gid(&self) -> u32;
+ /// Returns the device ID of this file (if it is a special one).
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::os::unix::fs::MetadataExt;
+ /// use std::io;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// let device_id = meta.rdev();
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn rdev(&self) -> u64;
+ /// Returns the total size of this file in bytes.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::os::unix::fs::MetadataExt;
+ /// use std::io;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// let file_size = meta.size();
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn size(&self) -> u64;
+ /// Returns the last access time of the file, in seconds since Unix Epoch.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::os::unix::fs::MetadataExt;
+ /// use std::io;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// let last_access_time = meta.atime();
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn atime(&self) -> i64;
+ /// Returns the last access time of the file, in nanoseconds since [`atime`].
+ ///
+ /// [`atime`]: #tymethod.atime
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::os::unix::fs::MetadataExt;
+ /// use std::io;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// let nano_last_access_time = meta.atime_nsec();
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn atime_nsec(&self) -> i64;
+ /// Returns the last modification time of the file, in seconds since Unix Epoch.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::os::unix::fs::MetadataExt;
+ /// use std::io;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// let last_modification_time = meta.mtime();
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn mtime(&self) -> i64;
+ /// Returns the last modification time of the file, in nanoseconds since [`mtime`].
+ ///
+ /// [`mtime`]: #tymethod.mtime
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::os::unix::fs::MetadataExt;
+ /// use std::io;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// let nano_last_modification_time = meta.mtime_nsec();
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn mtime_nsec(&self) -> i64;
+ /// Returns the last status change time of the file, in seconds since Unix Epoch.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::os::unix::fs::MetadataExt;
+ /// use std::io;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// let last_status_change_time = meta.ctime();
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn ctime(&self) -> i64;
+ /// Returns the last status change time of the file, in nanoseconds since [`ctime`].
+ ///
+ /// [`ctime`]: #tymethod.ctime
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::os::unix::fs::MetadataExt;
+ /// use std::io;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// let nano_last_status_change_time = meta.ctime_nsec();
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn ctime_nsec(&self) -> i64;
+ /// Returns the blocksize for filesystem I/O.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::os::unix::fs::MetadataExt;
+ /// use std::io;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// let blocksize = meta.blksize();
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn blksize(&self) -> u64;
+ /// Returns the number of blocks allocated to the file, in 512-byte units.
+ ///
+ /// Please note that this may be smaller than `st_size / 512` when the file has holes.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::os::unix::fs::MetadataExt;
+ /// use std::io;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// let blocks = meta.blocks();
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn blocks(&self) -> u64;
+}
+
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+impl MetadataExt for fs::Metadata {
+ fn dev(&self) -> u64 { self.st_dev() }
+ fn ino(&self) -> u64 { self.st_ino() }
+ fn mode(&self) -> u32 { self.st_mode() }
+ fn nlink(&self) -> u64 { self.st_nlink() }
+ fn uid(&self) -> u32 { self.st_uid() }
+ fn gid(&self) -> u32 { self.st_gid() }
+ fn rdev(&self) -> u64 { self.st_rdev() }
+ fn size(&self) -> u64 { self.st_size() }
+ fn atime(&self) -> i64 { self.st_atime() }
+ fn atime_nsec(&self) -> i64 { self.st_atime_nsec() }
+ fn mtime(&self) -> i64 { self.st_mtime() }
+ fn mtime_nsec(&self) -> i64 { self.st_mtime_nsec() }
+ fn ctime(&self) -> i64 { self.st_ctime() }
+ fn ctime_nsec(&self) -> i64 { self.st_ctime_nsec() }
+ fn blksize(&self) -> u64 { self.st_blksize() }
+ fn blocks(&self) -> u64 { self.st_blocks() }
+}
+
+/// Unix-specific extensions for [`FileType`].
+///
+/// Adds support for special Unix file types such as block/character devices,
+/// pipes, and sockets.
+///
+/// [`FileType`]: ../../../../std/fs/struct.FileType.html
+#[stable(feature = "file_type_ext", since = "1.5.0")]
+pub trait FileTypeExt {
+ /// Returns `true` if this file type is a block device.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::os::unix::fs::FileTypeExt;
+ /// use std::io;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("block_device_file")?;
+ /// let file_type = meta.file_type();
+ /// assert!(file_type.is_block_device());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "file_type_ext", since = "1.5.0")]
+ fn is_block_device(&self) -> bool;
+ /// Returns `true` if this file type is a char device.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::os::unix::fs::FileTypeExt;
+ /// use std::io;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("char_device_file")?;
+ /// let file_type = meta.file_type();
+ /// assert!(file_type.is_char_device());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "file_type_ext", since = "1.5.0")]
+ fn is_char_device(&self) -> bool;
+ /// Returns `true` if this file type is a fifo.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::os::unix::fs::FileTypeExt;
+ /// use std::io;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("fifo_file")?;
+ /// let file_type = meta.file_type();
+ /// assert!(file_type.is_fifo());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "file_type_ext", since = "1.5.0")]
+ fn is_fifo(&self) -> bool;
+ /// Returns `true` if this file type is a socket.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::os::unix::fs::FileTypeExt;
+ /// use std::io;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("unix.socket")?;
+ /// let file_type = meta.file_type();
+ /// assert!(file_type.is_socket());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "file_type_ext", since = "1.5.0")]
+ fn is_socket(&self) -> bool;
+}
+
+#[stable(feature = "file_type_ext", since = "1.5.0")]
+impl FileTypeExt for fs::FileType {
+ fn is_block_device(&self) -> bool { self.as_inner().is(libc::S_IFBLK) }
+ fn is_char_device(&self) -> bool { self.as_inner().is(libc::S_IFCHR) }
+ fn is_fifo(&self) -> bool { self.as_inner().is(libc::S_IFIFO) }
+ fn is_socket(&self) -> bool { self.as_inner().is(libc::S_IFSOCK) }
+}
+
+/// Unix-specific extension methods for [`fs::DirEntry`].
+///
+/// [`fs::DirEntry`]: ../../../../std/fs/struct.DirEntry.html
+#[stable(feature = "dir_entry_ext", since = "1.1.0")]
+pub trait DirEntryExt {
+ /// Returns the underlying `d_ino` field in the contained `dirent`
+ /// structure.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::fs;
+ /// use std::os::unix::fs::DirEntryExt;
+ ///
+ /// if let Ok(entries) = fs::read_dir(".") {
+ /// for entry in entries {
+ /// if let Ok(entry) = entry {
+ /// // Here, `entry` is a `DirEntry`.
+ /// println!("{:?}: {}", entry.file_name(), entry.ino());
+ /// }
+ /// }
+ /// }
+ /// ```
+ #[stable(feature = "dir_entry_ext", since = "1.1.0")]
+ fn ino(&self) -> u64;
+}
+
+#[stable(feature = "dir_entry_ext", since = "1.1.0")]
+impl DirEntryExt for fs::DirEntry {
+ fn ino(&self) -> u64 { self.as_inner().ino() }
+}
+
+/// Creates a new symbolic link on the filesystem.
+///
+/// The `dst` path will be a symbolic link pointing to the `src` path.
+///
+/// # Note
+///
+/// On Windows, you must specify whether a symbolic link points to a file
+/// or directory. Use `os::windows::fs::symlink_file` to create a
+/// symbolic link to a file, or `os::windows::fs::symlink_dir` to create a
+/// symbolic link to a directory. Additionally, the process must have
+/// `SeCreateSymbolicLinkPrivilege` in order to be able to create a
+/// symbolic link.
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::os::unix::fs;
+///
+/// fn main() -> std::io::Result<()> {
+/// fs::symlink("a.txt", "b.txt")?;
+/// Ok(())
+/// }
+/// ```
+#[stable(feature = "symlink", since = "1.1.0")]
+pub fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()>
+{
+ sys::fs::symlink(src.as_ref(), dst.as_ref())
+}
+
+/// Unix-specific extensions to [`fs::DirBuilder`].
+///
+/// [`fs::DirBuilder`]: ../../../../std/fs/struct.DirBuilder.html
+#[stable(feature = "dir_builder", since = "1.6.0")]
+pub trait DirBuilderExt {
+ /// Sets the mode to create new directories with. This option defaults to
+ /// 0o777.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs::DirBuilder;
+ /// use std::os::unix::fs::DirBuilderExt;
+ ///
+ /// let mut builder = DirBuilder::new();
+ /// builder.mode(0o755);
+ /// ```
+ #[stable(feature = "dir_builder", since = "1.6.0")]
+ fn mode(&mut self, mode: u32) -> &mut Self;
+}
+
+#[stable(feature = "dir_builder", since = "1.6.0")]
+impl DirBuilderExt for fs::DirBuilder {
+ fn mode(&mut self, mode: u32) -> &mut fs::DirBuilder {
+ self.as_inner_mut().set_mode(mode);
+ self
+ }
+}
diff --git a/src/libstd/sys/unix/ext/io.rs b/src/libstd/sys/unix/ext/io.rs
new file mode 100644
index 0000000..6bcc594
--- /dev/null
+++ b/src/libstd/sys/unix/ext/io.rs
@@ -0,0 +1,112 @@
+//! Unix-specific extensions to general I/O primitives
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+use crate::fs;
+use crate::os::raw;
+use crate::sys;
+use crate::io;
+use crate::sys_common::{AsInner, FromInner, IntoInner};
+
+/// Raw file descriptors.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub type RawFd = raw::c_int;
+
+/// A trait to extract the raw unix file descriptor from an underlying
+/// object.
+///
+/// This is only available on unix platforms and must be imported in order
+/// to call the method. Windows platforms have a corresponding `AsRawHandle`
+/// and `AsRawSocket` set of traits.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub trait AsRawFd {
+ /// Extracts the raw file descriptor.
+ ///
+ /// This method does **not** pass ownership of the raw file descriptor
+ /// to the caller. The descriptor is only guaranteed to be valid while
+ /// the original object has not yet been destroyed.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ fn as_raw_fd(&self) -> RawFd;
+}
+
+/// A trait to express the ability to construct an object from a raw file
+/// descriptor.
+#[stable(feature = "from_raw_os", since = "1.1.0")]
+pub trait FromRawFd {
+ /// Constructs a new instance of `Self` from the given raw file
+ /// descriptor.
+ ///
+ /// This function **consumes ownership** of the specified file
+ /// descriptor. The returned object will take responsibility for closing
+ /// it when the object goes out of scope.
+ ///
+ /// This function is also unsafe as the primitives currently returned
+ /// have the contract that they are the sole owner of the file
+ /// descriptor they are wrapping. Usage of this function could
+ /// accidentally allow violating this contract which can cause memory
+ /// unsafety in code that relies on it being true.
+ #[stable(feature = "from_raw_os", since = "1.1.0")]
+ unsafe fn from_raw_fd(fd: RawFd) -> Self;
+}
+
+/// A trait to express the ability to consume an object and acquire ownership of
+/// its raw file descriptor.
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+pub trait IntoRawFd {
+ /// Consumes this object, returning the raw underlying file descriptor.
+ ///
+ /// This function **transfers ownership** of the underlying file descriptor
+ /// to the caller. Callers are then the unique owners of the file descriptor
+ /// and must close the descriptor once it's no longer needed.
+ #[stable(feature = "into_raw_os", since = "1.4.0")]
+ fn into_raw_fd(self) -> RawFd;
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRawFd for fs::File {
+ fn as_raw_fd(&self) -> RawFd {
+ self.as_inner().fd().raw()
+ }
+}
+#[stable(feature = "from_raw_os", since = "1.1.0")]
+impl FromRawFd for fs::File {
+ unsafe fn from_raw_fd(fd: RawFd) -> fs::File {
+ fs::File::from_inner(sys::fs::File::from_inner(fd))
+ }
+}
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+impl IntoRawFd for fs::File {
+ fn into_raw_fd(self) -> RawFd {
+ self.into_inner().into_fd().into_raw()
+ }
+}
+
+#[stable(feature = "asraw_stdio", since = "1.21.0")]
+impl AsRawFd for io::Stdin {
+ fn as_raw_fd(&self) -> RawFd { libc::STDIN_FILENO }
+}
+
+#[stable(feature = "asraw_stdio", since = "1.21.0")]
+impl AsRawFd for io::Stdout {
+ fn as_raw_fd(&self) -> RawFd { libc::STDOUT_FILENO }
+}
+
+#[stable(feature = "asraw_stdio", since = "1.21.0")]
+impl AsRawFd for io::Stderr {
+ fn as_raw_fd(&self) -> RawFd { libc::STDERR_FILENO }
+}
+
+#[stable(feature = "asraw_stdio_locks", since = "1.35.0")]
+impl<'a> AsRawFd for io::StdinLock<'a> {
+ fn as_raw_fd(&self) -> RawFd { libc::STDIN_FILENO }
+}
+
+#[stable(feature = "asraw_stdio_locks", since = "1.35.0")]
+impl<'a> AsRawFd for io::StdoutLock<'a> {
+ fn as_raw_fd(&self) -> RawFd { libc::STDOUT_FILENO }
+}
+
+#[stable(feature = "asraw_stdio_locks", since = "1.35.0")]
+impl<'a> AsRawFd for io::StderrLock<'a> {
+ fn as_raw_fd(&self) -> RawFd { libc::STDERR_FILENO }
+}
diff --git a/src/libstd/sys/unix/ext/mod.rs b/src/libstd/sys/unix/ext/mod.rs
new file mode 100644
index 0000000..ccbac1a
--- /dev/null
+++ b/src/libstd/sys/unix/ext/mod.rs
@@ -0,0 +1,57 @@
+//! Platform-specific extensions to `std` for Unix platforms.
+//!
+//! Provides access to platform-level information on Unix platforms, and
+//! exposes Unix-specific functions that would otherwise be inappropriate as
+//! part of the core `std` library.
+//!
+//! It exposes more ways to deal with platform-specific strings (`OsStr`,
+//! `OsString`), allows to set permissions more granularly, extract low-level
+//! file descriptors from files and sockets, and has platform-specific helpers
+//! for spawning processes.
+//!
+//! # Examples
+//!
+//! ```no_run
+//! use std::fs::File;
+//! use std::os::unix::prelude::*;
+//!
+//! fn main() {
+//! let f = File::create("foo.txt").unwrap();
+//! let fd = f.as_raw_fd();
+//!
+//! // use fd with native unix bindings
+//! }
+//! ```
+
+#![stable(feature = "rust1", since = "1.0.0")]
+#![doc(cfg(unix))]
+#![allow(missing_docs)]
+
+pub mod io;
+pub mod ffi;
+pub mod fs;
+pub mod process;
+pub mod raw;
+pub mod thread;
+pub mod net;
+
+/// A prelude for conveniently writing platform-specific code.
+///
+/// Includes all extension traits, and some important type definitions.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub mod prelude {
+ #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
+ pub use super::io::{RawFd, AsRawFd, FromRawFd, IntoRawFd};
+ #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
+ pub use super::ffi::{OsStrExt, OsStringExt};
+ #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
+ pub use super::fs::{PermissionsExt, OpenOptionsExt, MetadataExt, FileTypeExt};
+ #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
+ pub use super::fs::DirEntryExt;
+ #[doc(no_inline)] #[stable(feature = "file_offset", since = "1.15.0")]
+ pub use super::fs::FileExt;
+ #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
+ pub use super::thread::JoinHandleExt;
+ #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
+ pub use super::process::{CommandExt, ExitStatusExt};
+}
diff --git a/src/libstd/sys/unix/ext/net.rs b/src/libstd/sys/unix/ext/net.rs
new file mode 100644
index 0000000..406863a
--- /dev/null
+++ b/src/libstd/sys/unix/ext/net.rs
@@ -0,0 +1,1851 @@
+#![stable(feature = "unix_socket", since = "1.10.0")]
+
+//! Unix-specific networking functionality
+
+#[cfg(unix)]
+use libc;
+
+// FIXME(#43348): Make libc adapt #[doc(cfg(...))] so we don't need these fake definitions here?
+#[cfg(not(unix))]
+mod libc {
+ pub use libc::c_int;
+ pub type socklen_t = u32;
+ pub struct sockaddr;
+ #[derive(Clone)]
+ pub struct sockaddr_un;
+}
+
+use crate::ascii;
+use crate::ffi::OsStr;
+use crate::fmt;
+use crate::io::{self, Initializer, IoVec, IoVecMut};
+use crate::mem;
+use crate::net::{self, Shutdown};
+use crate::os::unix::ffi::OsStrExt;
+use crate::os::unix::io::{RawFd, AsRawFd, FromRawFd, IntoRawFd};
+use crate::path::Path;
+use crate::time::Duration;
+use crate::sys::{self, cvt};
+use crate::sys::net::Socket;
+use crate::sys_common::{self, AsInner, FromInner, IntoInner};
+
+#[cfg(any(target_os = "linux", target_os = "android",
+ target_os = "dragonfly", target_os = "freebsd",
+ target_os = "openbsd", target_os = "netbsd",
+ target_os = "haiku", target_os = "bitrig"))]
+use libc::MSG_NOSIGNAL;
+#[cfg(not(any(target_os = "linux", target_os = "android",
+ target_os = "dragonfly", target_os = "freebsd",
+ target_os = "openbsd", target_os = "netbsd",
+ target_os = "haiku", target_os = "bitrig")))]
+const MSG_NOSIGNAL: libc::c_int = 0x0;
+
+fn sun_path_offset() -> usize {
+ // Work with an actual instance of the type since using a null pointer is UB
+ let addr: libc::sockaddr_un = unsafe { mem::uninitialized() };
+ let base = &addr as *const _ as usize;
+ let path = &addr.sun_path as *const _ as usize;
+ path - base
+}
+
+unsafe fn sockaddr_un(path: &Path) -> io::Result<(libc::sockaddr_un, libc::socklen_t)> {
+ let mut addr: libc::sockaddr_un = mem::zeroed();
+ addr.sun_family = libc::AF_UNIX as libc::sa_family_t;
+
+ let bytes = path.as_os_str().as_bytes();
+
+ if bytes.contains(&0) {
+ return Err(io::Error::new(io::ErrorKind::InvalidInput,
+ "paths may not contain interior null bytes"));
+ }
+
+ if bytes.len() >= addr.sun_path.len() {
+ return Err(io::Error::new(io::ErrorKind::InvalidInput,
+ "path must be shorter than SUN_LEN"));
+ }
+ for (dst, src) in addr.sun_path.iter_mut().zip(bytes.iter()) {
+ *dst = *src as libc::c_char;
+ }
+ // null byte for pathname addresses is already there because we zeroed the
+ // struct
+
+ let mut len = sun_path_offset() + bytes.len();
+ match bytes.get(0) {
+ Some(&0) | None => {}
+ Some(_) => len += 1,
+ }
+ Ok((addr, len as libc::socklen_t))
+}
+
+enum AddressKind<'a> {
+ Unnamed,
+ Pathname(&'a Path),
+ Abstract(&'a [u8]),
+}
+
+/// 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", since = "1.10.0")]
+pub struct SocketAddr {
+ addr: libc::sockaddr_un,
+ len: libc::socklen_t,
+}
+
+impl SocketAddr {
+ fn new<F>(f: F) -> io::Result<SocketAddr>
+ where F: FnOnce(*mut libc::sockaddr, *mut libc::socklen_t) -> libc::c_int
+ {
+ unsafe {
+ let mut addr: libc::sockaddr_un = mem::zeroed();
+ let mut len = mem::size_of::<libc::sockaddr_un>() as libc::socklen_t;
+ cvt(f(&mut addr as *mut _ as *mut _, &mut len))?;
+ SocketAddr::from_parts(addr, len)
+ }
+ }
+
+ fn from_parts(addr: libc::sockaddr_un, mut len: libc::socklen_t) -> io::Result<SocketAddr> {
+ if len == 0 {
+ // When there is a datagram from unnamed unix socket
+ // linux returns zero bytes of address
+ len = sun_path_offset() as libc::socklen_t; // i.e., zero-length address
+ } else if addr.sun_family != libc::AF_UNIX as libc::sa_family_t {
+ return Err(io::Error::new(io::ErrorKind::InvalidInput,
+ "file descriptor did not correspond to a Unix socket"));
+ }
+
+ Ok(SocketAddr {
+ addr,
+ len,
+ })
+ }
+
+ /// Returns `true` 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", since = "1.10.0")]
+ pub fn is_unnamed(&self) -> bool {
+ if let AddressKind::Unnamed = self.address() {
+ true
+ } else {
+ false
+ }
+ }
+
+ /// 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", since = "1.10.0")]
+ pub fn as_pathname(&self) -> Option<&Path> {
+ if let AddressKind::Pathname(path) = self.address() {
+ Some(path)
+ } else {
+ None
+ }
+ }
+
+ fn address<'a>(&'a self) -> AddressKind<'a> {
+ let len = self.len as usize - sun_path_offset();
+ let path = unsafe { mem::transmute::<&[libc::c_char], &[u8]>(&self.addr.sun_path) };
+
+ // macOS seems to return a len of 16 and a zeroed sun_path for unnamed addresses
+ if len == 0
+ || (cfg!(not(any(target_os = "linux", target_os = "android")))
+ && self.addr.sun_path[0] == 0)
+ {
+ AddressKind::Unnamed
+ } else if self.addr.sun_path[0] == 0 {
+ AddressKind::Abstract(&path[1..len])
+ } else {
+ AddressKind::Pathname(OsStr::from_bytes(&path[..len - 1]).as_ref())
+ }
+ }
+}
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl fmt::Debug for SocketAddr {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self.address() {
+ AddressKind::Unnamed => write!(fmt, "(unnamed)"),
+ AddressKind::Abstract(name) => write!(fmt, "{} (abstract)", AsciiEscaped(name)),
+ AddressKind::Pathname(path) => write!(fmt, "{:?} (pathname)", path),
+ }
+ }
+}
+
+struct AsciiEscaped<'a>(&'a [u8]);
+
+impl<'a> fmt::Display for AsciiEscaped<'a> {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(fmt, "\"")?;
+ for byte in self.0.iter().cloned().flat_map(ascii::escape_default) {
+ write!(fmt, "{}", byte as char)?;
+ }
+ write!(fmt, "\"")
+ }
+}
+
+/// 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", since = "1.10.0")]
+pub struct UnixStream(Socket);
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+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.as_inner());
+ 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", since = "1.10.0")]
+ pub fn connect<P: AsRef<Path>>(path: P) -> io::Result<UnixStream> {
+ fn inner(path: &Path) -> io::Result<UnixStream> {
+ unsafe {
+ let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?;
+ let (addr, len) = sockaddr_un(path)?;
+
+ cvt(libc::connect(*inner.as_inner(), &addr as *const _ as *const _, len))?;
+ Ok(UnixStream(inner))
+ }
+ }
+ inner(path.as_ref())
+ }
+
+ /// 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", since = "1.10.0")]
+ pub fn pair() -> io::Result<(UnixStream, UnixStream)> {
+ let (i1, i2) = Socket::new_pair(libc::AF_UNIX, libc::SOCK_STREAM)?;
+ Ok((UnixStream(i1), UnixStream(i2)))
+ }
+
+ /// 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", since = "1.10.0")]
+ 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", since = "1.10.0")]
+ pub fn local_addr(&self) -> io::Result<SocketAddr> {
+ SocketAddr::new(|addr, len| unsafe { libc::getsockname(*self.0.as_inner(), addr, len) })
+ }
+
+ /// 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", since = "1.10.0")]
+ pub fn peer_addr(&self) -> io::Result<SocketAddr> {
+ SocketAddr::new(|addr, len| unsafe { libc::getpeername(*self.0.as_inner(), addr, len) })
+ }
+
+ /// 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", since = "1.10.0")]
+ pub fn set_read_timeout(&self, timeout: Option<Duration>) -> io::Result<()> {
+ self.0.set_timeout(timeout, libc::SO_RCVTIMEO)
+ }
+
+ /// 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", since = "1.10.0")]
+ pub fn set_write_timeout(&self, timeout: Option<Duration>) -> io::Result<()> {
+ self.0.set_timeout(timeout, libc::SO_SNDTIMEO)
+ }
+
+ /// 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", since = "1.10.0")]
+ pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
+ self.0.timeout(libc::SO_RCVTIMEO)
+ }
+
+ /// 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", since = "1.10.0")]
+ pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
+ self.0.timeout(libc::SO_SNDTIMEO)
+ }
+
+ /// 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", since = "1.10.0")]
+ 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", since = "1.10.0")]
+ pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+ self.0.take_error()
+ }
+
+ /// 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", since = "1.10.0")]
+ pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
+ self.0.shutdown(how)
+ }
+}
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl io::Read for UnixStream {
+ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+ io::Read::read(&mut &*self, buf)
+ }
+
+ fn read_vectored(&mut self, bufs: &mut [IoVecMut<'_>]) -> io::Result<usize> {
+ io::Read::read_vectored(&mut &*self, bufs)
+ }
+
+ #[inline]
+ unsafe fn initializer(&self) -> Initializer {
+ Initializer::nop()
+ }
+}
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl<'a> io::Read for &'a UnixStream {
+ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+ self.0.read(buf)
+ }
+
+ fn read_vectored(&mut self, bufs: &mut [IoVecMut<'_>]) -> io::Result<usize> {
+ self.0.read_vectored(bufs)
+ }
+
+ #[inline]
+ unsafe fn initializer(&self) -> Initializer {
+ Initializer::nop()
+ }
+}
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl io::Write for UnixStream {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ io::Write::write(&mut &*self, buf)
+ }
+
+ fn write_vectored(&mut self, bufs: &[IoVec<'_>]) -> io::Result<usize> {
+ io::Write::write_vectored(&mut &*self, bufs)
+ }
+
+ fn flush(&mut self) -> io::Result<()> {
+ io::Write::flush(&mut &*self)
+ }
+}
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl<'a> io::Write for &'a UnixStream {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ self.0.write(buf)
+ }
+
+ fn write_vectored(&mut self, bufs: &[IoVec<'_>]) -> io::Result<usize> {
+ self.0.write_vectored(bufs)
+ }
+
+ fn flush(&mut self) -> io::Result<()> {
+ Ok(())
+ }
+}
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl AsRawFd for UnixStream {
+ fn as_raw_fd(&self) -> RawFd {
+ *self.0.as_inner()
+ }
+}
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl FromRawFd for UnixStream {
+ unsafe fn from_raw_fd(fd: RawFd) -> UnixStream {
+ UnixStream(Socket::from_inner(fd))
+ }
+}
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl IntoRawFd for UnixStream {
+ fn into_raw_fd(self) -> RawFd {
+ self.0.into_inner()
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRawFd for net::TcpStream {
+ fn as_raw_fd(&self) -> RawFd { *self.as_inner().socket().as_inner() }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRawFd for net::TcpListener {
+ fn as_raw_fd(&self) -> RawFd { *self.as_inner().socket().as_inner() }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRawFd for net::UdpSocket {
+ fn as_raw_fd(&self) -> RawFd { *self.as_inner().socket().as_inner() }
+}
+
+#[stable(feature = "from_raw_os", since = "1.1.0")]
+impl FromRawFd for net::TcpStream {
+ unsafe fn from_raw_fd(fd: RawFd) -> net::TcpStream {
+ let socket = sys::net::Socket::from_inner(fd);
+ net::TcpStream::from_inner(sys_common::net::TcpStream::from_inner(socket))
+ }
+}
+
+#[stable(feature = "from_raw_os", since = "1.1.0")]
+impl FromRawFd for net::TcpListener {
+ unsafe fn from_raw_fd(fd: RawFd) -> net::TcpListener {
+ let socket = sys::net::Socket::from_inner(fd);
+ net::TcpListener::from_inner(sys_common::net::TcpListener::from_inner(socket))
+ }
+}
+
+#[stable(feature = "from_raw_os", since = "1.1.0")]
+impl FromRawFd for net::UdpSocket {
+ unsafe fn from_raw_fd(fd: RawFd) -> net::UdpSocket {
+ let socket = sys::net::Socket::from_inner(fd);
+ net::UdpSocket::from_inner(sys_common::net::UdpSocket::from_inner(socket))
+ }
+}
+
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+impl IntoRawFd for net::TcpStream {
+ fn into_raw_fd(self) -> RawFd {
+ self.into_inner().into_socket().into_inner()
+ }
+}
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+impl IntoRawFd for net::TcpListener {
+ fn into_raw_fd(self) -> RawFd {
+ self.into_inner().into_socket().into_inner()
+ }
+}
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+impl IntoRawFd for net::UdpSocket {
+ fn into_raw_fd(self) -> RawFd {
+ self.into_inner().into_socket().into_inner()
+ }
+}
+
+/// 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", since = "1.10.0")]
+pub struct UnixListener(Socket);
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+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.as_inner());
+ 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", since = "1.10.0")]
+ pub fn bind<P: AsRef<Path>>(path: P) -> io::Result<UnixListener> {
+ fn inner(path: &Path) -> io::Result<UnixListener> {
+ unsafe {
+ let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?;
+ let (addr, len) = sockaddr_un(path)?;
+
+ cvt(libc::bind(*inner.as_inner(), &addr as *const _ as *const _, len as _))?;
+ cvt(libc::listen(*inner.as_inner(), 128))?;
+
+ Ok(UnixListener(inner))
+ }
+ }
+ inner(path.as_ref())
+ }
+
+ /// 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", since = "1.10.0")]
+ pub fn accept(&self) -> io::Result<(UnixStream, SocketAddr)> {
+ let mut storage: libc::sockaddr_un = unsafe { mem::zeroed() };
+ let mut len = mem::size_of_val(&storage) as libc::socklen_t;
+ let sock = self.0.accept(&mut storage as *mut _ as *mut _, &mut len)?;
+ let addr = SocketAddr::from_parts(storage, len)?;
+ Ok((UnixStream(sock), addr))
+ }
+
+ /// 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", since = "1.10.0")]
+ 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", since = "1.10.0")]
+ pub fn local_addr(&self) -> io::Result<SocketAddr> {
+ SocketAddr::new(|addr, len| unsafe { libc::getsockname(*self.0.as_inner(), addr, len) })
+ }
+
+ /// 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", since = "1.10.0")]
+ 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", since = "1.10.0")]
+ pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+ self.0.take_error()
+ }
+
+ /// 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", since = "1.10.0")]
+ pub fn incoming<'a>(&'a self) -> Incoming<'a> {
+ Incoming { listener: self }
+ }
+}
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl AsRawFd for UnixListener {
+ fn as_raw_fd(&self) -> RawFd {
+ *self.0.as_inner()
+ }
+}
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl FromRawFd for UnixListener {
+ unsafe fn from_raw_fd(fd: RawFd) -> UnixListener {
+ UnixListener(Socket::from_inner(fd))
+ }
+}
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl IntoRawFd for UnixListener {
+ fn into_raw_fd(self) -> RawFd {
+ self.0.into_inner()
+ }
+}
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+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", since = "1.10.0")]
+pub struct Incoming<'a> {
+ listener: &'a UnixListener,
+}
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+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)
+ }
+}
+
+/// A Unix datagram socket.
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::os::unix::net::UnixDatagram;
+///
+/// let socket = UnixDatagram::bind("/path/to/my/socket").unwrap();
+/// socket.send_to(b"hello world", "/path/to/other/socket").unwrap();
+/// let mut buf = [0; 100];
+/// let (count, address) = socket.recv_from(&mut buf).unwrap();
+/// println!("socket {:?} sent {:?}", address, &buf[..count]);
+/// ```
+#[stable(feature = "unix_socket", since = "1.10.0")]
+pub struct UnixDatagram(Socket);
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl fmt::Debug for UnixDatagram {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ let mut builder = fmt.debug_struct("UnixDatagram");
+ builder.field("fd", self.0.as_inner());
+ 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 UnixDatagram {
+ /// Creates a Unix datagram socket bound to the given path.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixDatagram;
+ ///
+ /// let sock = match UnixDatagram::bind("/path/to/the/socket") {
+ /// Ok(sock) => sock,
+ /// Err(e) => {
+ /// println!("Couldn't bind: {:?}", e);
+ /// return
+ /// }
+ /// };
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn bind<P: AsRef<Path>>(path: P) -> io::Result<UnixDatagram> {
+ fn inner(path: &Path) -> io::Result<UnixDatagram> {
+ unsafe {
+ let socket = UnixDatagram::unbound()?;
+ let (addr, len) = sockaddr_un(path)?;
+
+ cvt(libc::bind(*socket.0.as_inner(), &addr as *const _ as *const _, len as _))?;
+
+ Ok(socket)
+ }
+ }
+ inner(path.as_ref())
+ }
+
+ /// Creates a Unix Datagram socket which is not bound to any address.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixDatagram;
+ ///
+ /// let sock = match UnixDatagram::unbound() {
+ /// Ok(sock) => sock,
+ /// Err(e) => {
+ /// println!("Couldn't unbound: {:?}", e);
+ /// return
+ /// }
+ /// };
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn unbound() -> io::Result<UnixDatagram> {
+ let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_DGRAM)?;
+ Ok(UnixDatagram(inner))
+ }
+
+ /// Creates an unnamed pair of connected sockets.
+ ///
+ /// Returns two `UnixDatagrams`s which are connected to each other.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixDatagram;
+ ///
+ /// let (sock1, sock2) = match UnixDatagram::pair() {
+ /// Ok((sock1, sock2)) => (sock1, sock2),
+ /// Err(e) => {
+ /// println!("Couldn't unbound: {:?}", e);
+ /// return
+ /// }
+ /// };
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn pair() -> io::Result<(UnixDatagram, UnixDatagram)> {
+ let (i1, i2) = Socket::new_pair(libc::AF_UNIX, libc::SOCK_DGRAM)?;
+ Ok((UnixDatagram(i1), UnixDatagram(i2)))
+ }
+
+ /// Connects the socket to the specified address.
+ ///
+ /// The [`send`] method may be used to send data to the specified address.
+ /// [`recv`] and [`recv_from`] will only receive data from that address.
+ ///
+ /// [`send`]: #method.send
+ /// [`recv`]: #method.recv
+ /// [`recv_from`]: #method.recv_from
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixDatagram;
+ ///
+ /// let sock = UnixDatagram::unbound().unwrap();
+ /// match sock.connect("/path/to/the/socket") {
+ /// Ok(sock) => sock,
+ /// Err(e) => {
+ /// println!("Couldn't connect: {:?}", e);
+ /// return
+ /// }
+ /// };
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn connect<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
+ fn inner(d: &UnixDatagram, path: &Path) -> io::Result<()> {
+ unsafe {
+ let (addr, len) = sockaddr_un(path)?;
+
+ cvt(libc::connect(*d.0.as_inner(), &addr as *const _ as *const _, len))?;
+
+ Ok(())
+ }
+ }
+ inner(self, path.as_ref())
+ }
+
+ /// Creates a new independently owned handle to the underlying socket.
+ ///
+ /// The returned `UnixDatagram` 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 side will affect the other.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixDatagram;
+ ///
+ /// let sock = UnixDatagram::bind("/path/to/the/socket").unwrap();
+ ///
+ /// let sock_copy = sock.try_clone().expect("try_clone failed");
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn try_clone(&self) -> io::Result<UnixDatagram> {
+ self.0.duplicate().map(UnixDatagram)
+ }
+
+ /// Returns the address of this socket.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixDatagram;
+ ///
+ /// let sock = UnixDatagram::bind("/path/to/the/socket").unwrap();
+ ///
+ /// let addr = sock.local_addr().expect("Couldn't get local address");
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn local_addr(&self) -> io::Result<SocketAddr> {
+ SocketAddr::new(|addr, len| unsafe { libc::getsockname(*self.0.as_inner(), addr, len) })
+ }
+
+ /// Returns the address of this socket's peer.
+ ///
+ /// The [`connect`] method will connect the socket to a peer.
+ ///
+ /// [`connect`]: #method.connect
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixDatagram;
+ ///
+ /// let sock = UnixDatagram::unbound().unwrap();
+ /// sock.connect("/path/to/the/socket").unwrap();
+ ///
+ /// let addr = sock.peer_addr().expect("Couldn't get peer address");
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn peer_addr(&self) -> io::Result<SocketAddr> {
+ SocketAddr::new(|addr, len| unsafe { libc::getpeername(*self.0.as_inner(), addr, len) })
+ }
+
+ /// Receives data from the socket.
+ ///
+ /// On success, returns the number of bytes read and the address from
+ /// whence the data came.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixDatagram;
+ ///
+ /// let sock = UnixDatagram::unbound().unwrap();
+ /// let mut buf = vec![0; 10];
+ /// match sock.recv_from(buf.as_mut_slice()) {
+ /// Ok((size, sender)) => println!("received {} bytes from {:?}", size, sender),
+ /// Err(e) => println!("recv_from function failed: {:?}", e),
+ /// }
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+ let mut count = 0;
+ let addr = SocketAddr::new(|addr, len| {
+ unsafe {
+ count = libc::recvfrom(*self.0.as_inner(),
+ buf.as_mut_ptr() as *mut _,
+ buf.len(),
+ 0,
+ addr,
+ len);
+ if count > 0 {
+ 1
+ } else if count == 0 {
+ 0
+ } else {
+ -1
+ }
+ }
+ })?;
+
+ Ok((count as usize, addr))
+ }
+
+ /// Receives data from the socket.
+ ///
+ /// On success, returns the number of bytes read.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixDatagram;
+ ///
+ /// let sock = UnixDatagram::bind("/path/to/the/socket").unwrap();
+ /// let mut buf = vec![0; 10];
+ /// sock.recv(buf.as_mut_slice()).expect("recv function failed");
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn recv(&self, buf: &mut [u8]) -> io::Result<usize> {
+ self.0.read(buf)
+ }
+
+ /// Sends data on the socket to the specified address.
+ ///
+ /// On success, returns the number of bytes written.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixDatagram;
+ ///
+ /// let sock = UnixDatagram::unbound().unwrap();
+ /// sock.send_to(b"omelette au fromage", "/some/sock").expect("send_to function failed");
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn send_to<P: AsRef<Path>>(&self, buf: &[u8], path: P) -> io::Result<usize> {
+ fn inner(d: &UnixDatagram, buf: &[u8], path: &Path) -> io::Result<usize> {
+ unsafe {
+ let (addr, len) = sockaddr_un(path)?;
+
+ let count = cvt(libc::sendto(*d.0.as_inner(),
+ buf.as_ptr() as *const _,
+ buf.len(),
+ MSG_NOSIGNAL,
+ &addr as *const _ as *const _,
+ len))?;
+ Ok(count as usize)
+ }
+ }
+ inner(self, buf, path.as_ref())
+ }
+
+ /// Sends data on the socket to the socket's peer.
+ ///
+ /// The peer address may be set by the `connect` method, and this method
+ /// will return an error if the socket has not already been connected.
+ ///
+ /// On success, returns the number of bytes written.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixDatagram;
+ ///
+ /// let sock = UnixDatagram::unbound().unwrap();
+ /// sock.connect("/some/sock").expect("Couldn't connect");
+ /// sock.send(b"omelette au fromage").expect("send_to function failed");
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn send(&self, buf: &[u8]) -> io::Result<usize> {
+ self.0.write(buf)
+ }
+
+ /// Sets the read timeout for the socket.
+ ///
+ /// If the provided value is [`None`], then [`recv`] and [`recv_from`] 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
+ /// [`recv`]: #method.recv
+ /// [`recv_from`]: #method.recv_from
+ /// [`Duration`]: ../../../../std/time/struct.Duration.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::os::unix::net::UnixDatagram;
+ /// use std::time::Duration;
+ ///
+ /// let sock = UnixDatagram::unbound().unwrap();
+ /// sock.set_read_timeout(Some(Duration::new(1, 0))).expect("set_read_timeout function failed");
+ /// ```
+ ///
+ /// An [`Err`] is returned if the zero [`Duration`] is passed to this
+ /// method:
+ ///
+ /// ```no_run
+ /// use std::io;
+ /// use std::os::unix::net::UnixDatagram;
+ /// use std::time::Duration;
+ ///
+ /// let socket = UnixDatagram::unbound().unwrap();
+ /// let result = socket.set_read_timeout(Some(Duration::new(0, 0)));
+ /// let err = result.unwrap_err();
+ /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput)
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn set_read_timeout(&self, timeout: Option<Duration>) -> io::Result<()> {
+ self.0.set_timeout(timeout, libc::SO_RCVTIMEO)
+ }
+
+ /// Sets the write timeout for the socket.
+ ///
+ /// If the provided value is [`None`], then [`send`] and [`send_to`] 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
+ /// [`send`]: #method.send
+ /// [`send_to`]: #method.send_to
+ /// [`Duration`]: ../../../../std/time/struct.Duration.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::os::unix::net::UnixDatagram;
+ /// use std::time::Duration;
+ ///
+ /// let sock = UnixDatagram::unbound().unwrap();
+ /// sock.set_write_timeout(Some(Duration::new(1, 0)))
+ /// .expect("set_write_timeout function failed");
+ /// ```
+ ///
+ /// An [`Err`] is returned if the zero [`Duration`] is passed to this
+ /// method:
+ ///
+ /// ```no_run
+ /// use std::io;
+ /// use std::os::unix::net::UnixDatagram;
+ /// use std::time::Duration;
+ ///
+ /// let socket = UnixDatagram::unbound().unwrap();
+ /// let result = socket.set_write_timeout(Some(Duration::new(0, 0)));
+ /// let err = result.unwrap_err();
+ /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput)
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn set_write_timeout(&self, timeout: Option<Duration>) -> io::Result<()> {
+ self.0.set_timeout(timeout, libc::SO_SNDTIMEO)
+ }
+
+ /// Returns the read timeout of this socket.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::os::unix::net::UnixDatagram;
+ /// use std::time::Duration;
+ ///
+ /// let sock = UnixDatagram::unbound().unwrap();
+ /// sock.set_read_timeout(Some(Duration::new(1, 0))).expect("set_read_timeout function failed");
+ /// assert_eq!(sock.read_timeout().unwrap(), Some(Duration::new(1, 0)));
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
+ self.0.timeout(libc::SO_RCVTIMEO)
+ }
+
+ /// Returns the write timeout of this socket.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::os::unix::net::UnixDatagram;
+ /// use std::time::Duration;
+ ///
+ /// let sock = UnixDatagram::unbound().unwrap();
+ /// sock.set_write_timeout(Some(Duration::new(1, 0)))
+ /// .expect("set_write_timeout function failed");
+ /// assert_eq!(sock.write_timeout().unwrap(), Some(Duration::new(1, 0)));
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
+ self.0.timeout(libc::SO_SNDTIMEO)
+ }
+
+ /// Moves the socket into or out of nonblocking mode.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::os::unix::net::UnixDatagram;
+ ///
+ /// let sock = UnixDatagram::unbound().unwrap();
+ /// sock.set_nonblocking(true).expect("set_nonblocking function failed");
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ 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::UnixDatagram;
+ ///
+ /// let sock = UnixDatagram::unbound().unwrap();
+ /// if let Ok(Some(err)) = sock.take_error() {
+ /// println!("Got error: {:?}", err);
+ /// }
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+ self.0.take_error()
+ }
+
+ /// Shut 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
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixDatagram;
+ /// use std::net::Shutdown;
+ ///
+ /// let sock = UnixDatagram::unbound().unwrap();
+ /// sock.shutdown(Shutdown::Both).expect("shutdown function failed");
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
+ self.0.shutdown(how)
+ }
+}
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl AsRawFd for UnixDatagram {
+ fn as_raw_fd(&self) -> RawFd {
+ *self.0.as_inner()
+ }
+}
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl FromRawFd for UnixDatagram {
+ unsafe fn from_raw_fd(fd: RawFd) -> UnixDatagram {
+ UnixDatagram(Socket::from_inner(fd))
+ }
+}
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl IntoRawFd for UnixDatagram {
+ fn into_raw_fd(self) -> RawFd {
+ self.0.into_inner()
+ }
+}
+
+#[cfg(all(test, not(target_os = "emscripten")))]
+mod test {
+ use crate::thread;
+ use crate::io::{self, ErrorKind};
+ use crate::io::prelude::*;
+ use crate::time::Duration;
+ use crate::sys_common::io::test::tmpdir;
+
+ use super::*;
+
+ macro_rules! or_panic {
+ ($e:expr) => {
+ match $e {
+ Ok(e) => e,
+ Err(e) => panic!("{}", e),
+ }
+ }
+ }
+
+ #[test]
+ fn basic() {
+ let dir = tmpdir();
+ let socket_path = dir.path().join("sock");
+ let msg1 = b"hello";
+ let msg2 = b"world!";
+
+ let listener = or_panic!(UnixListener::bind(&socket_path));
+ let thread = thread::spawn(move || {
+ let mut stream = or_panic!(listener.accept()).0;
+ let mut buf = [0; 5];
+ or_panic!(stream.read(&mut buf));
+ assert_eq!(&msg1[..], &buf[..]);
+ or_panic!(stream.write_all(msg2));
+ });
+
+ let mut stream = or_panic!(UnixStream::connect(&socket_path));
+ assert_eq!(Some(&*socket_path),
+ stream.peer_addr().unwrap().as_pathname());
+ or_panic!(stream.write_all(msg1));
+ let mut buf = vec![];
+ or_panic!(stream.read_to_end(&mut buf));
+ assert_eq!(&msg2[..], &buf[..]);
+ drop(stream);
+
+ thread.join().unwrap();
+ }
+
+ #[test]
+ fn vectored() {
+ let (mut s1, mut s2) = or_panic!(UnixStream::pair());
+
+ let len = or_panic!(s1.write_vectored(
+ &[IoVec::new(b"hello"), IoVec::new(b" "), IoVec::new(b"world!")],
+ ));
+ assert_eq!(len, 12);
+
+ let mut buf1 = [0; 6];
+ let mut buf2 = [0; 7];
+ let len = or_panic!(s2.read_vectored(
+ &mut [IoVecMut::new(&mut buf1), IoVecMut::new(&mut buf2)],
+ ));
+ assert_eq!(len, 12);
+ assert_eq!(&buf1, b"hello ");
+ assert_eq!(&buf2, b"world!\0");
+ }
+
+ #[test]
+ fn pair() {
+ let msg1 = b"hello";
+ let msg2 = b"world!";
+
+ let (mut s1, mut s2) = or_panic!(UnixStream::pair());
+ let thread = thread::spawn(move || {
+ // s1 must be moved in or the test will hang!
+ let mut buf = [0; 5];
+ or_panic!(s1.read(&mut buf));
+ assert_eq!(&msg1[..], &buf[..]);
+ or_panic!(s1.write_all(msg2));
+ });
+
+ or_panic!(s2.write_all(msg1));
+ let mut buf = vec![];
+ or_panic!(s2.read_to_end(&mut buf));
+ assert_eq!(&msg2[..], &buf[..]);
+ drop(s2);
+
+ thread.join().unwrap();
+ }
+
+ #[test]
+ fn try_clone() {
+ let dir = tmpdir();
+ let socket_path = dir.path().join("sock");
+ let msg1 = b"hello";
+ let msg2 = b"world";
+
+ let listener = or_panic!(UnixListener::bind(&socket_path));
+ let thread = thread::spawn(move || {
+ let mut stream = or_panic!(listener.accept()).0;
+ or_panic!(stream.write_all(msg1));
+ or_panic!(stream.write_all(msg2));
+ });
+
+ let mut stream = or_panic!(UnixStream::connect(&socket_path));
+ let mut stream2 = or_panic!(stream.try_clone());
+
+ let mut buf = [0; 5];
+ or_panic!(stream.read(&mut buf));
+ assert_eq!(&msg1[..], &buf[..]);
+ or_panic!(stream2.read(&mut buf));
+ assert_eq!(&msg2[..], &buf[..]);
+
+ thread.join().unwrap();
+ }
+
+ #[test]
+ fn iter() {
+ let dir = tmpdir();
+ let socket_path = dir.path().join("sock");
+
+ let listener = or_panic!(UnixListener::bind(&socket_path));
+ let thread = thread::spawn(move || {
+ for stream in listener.incoming().take(2) {
+ let mut stream = or_panic!(stream);
+ let mut buf = [0];
+ or_panic!(stream.read(&mut buf));
+ }
+ });
+
+ for _ in 0..2 {
+ let mut stream = or_panic!(UnixStream::connect(&socket_path));
+ or_panic!(stream.write_all(&[0]));
+ }
+
+ thread.join().unwrap();
+ }
+
+ #[test]
+ fn long_path() {
+ let dir = tmpdir();
+ let socket_path = dir.path()
+ .join("asdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfa\
+ sasdfasdfasdasdfasdfasdfadfasdfasdfasdfasdfasdf");
+ match UnixStream::connect(&socket_path) {
+ Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {}
+ Err(e) => panic!("unexpected error {}", e),
+ Ok(_) => panic!("unexpected success"),
+ }
+
+ match UnixListener::bind(&socket_path) {
+ Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {}
+ Err(e) => panic!("unexpected error {}", e),
+ Ok(_) => panic!("unexpected success"),
+ }
+
+ match UnixDatagram::bind(&socket_path) {
+ Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {}
+ Err(e) => panic!("unexpected error {}", e),
+ Ok(_) => panic!("unexpected success"),
+ }
+ }
+
+ #[test]
+ fn timeouts() {
+ let dir = tmpdir();
+ let socket_path = dir.path().join("sock");
+
+ let _listener = or_panic!(UnixListener::bind(&socket_path));
+
+ let stream = or_panic!(UnixStream::connect(&socket_path));
+ let dur = Duration::new(15410, 0);
+
+ assert_eq!(None, or_panic!(stream.read_timeout()));
+
+ or_panic!(stream.set_read_timeout(Some(dur)));
+ assert_eq!(Some(dur), or_panic!(stream.read_timeout()));
+
+ assert_eq!(None, or_panic!(stream.write_timeout()));
+
+ or_panic!(stream.set_write_timeout(Some(dur)));
+ assert_eq!(Some(dur), or_panic!(stream.write_timeout()));
+
+ or_panic!(stream.set_read_timeout(None));
+ assert_eq!(None, or_panic!(stream.read_timeout()));
+
+ or_panic!(stream.set_write_timeout(None));
+ assert_eq!(None, or_panic!(stream.write_timeout()));
+ }
+
+ #[test]
+ fn test_read_timeout() {
+ let dir = tmpdir();
+ let socket_path = dir.path().join("sock");
+
+ let _listener = or_panic!(UnixListener::bind(&socket_path));
+
+ let mut stream = or_panic!(UnixStream::connect(&socket_path));
+ or_panic!(stream.set_read_timeout(Some(Duration::from_millis(1000))));
+
+ let mut buf = [0; 10];
+ let kind = stream.read_exact(&mut buf).err().expect("expected error").kind();
+ assert!(kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut,
+ "unexpected_error: {:?}", kind);
+ }
+
+ #[test]
+ fn test_read_with_timeout() {
+ let dir = tmpdir();
+ let socket_path = dir.path().join("sock");
+
+ let listener = or_panic!(UnixListener::bind(&socket_path));
+
+ let mut stream = or_panic!(UnixStream::connect(&socket_path));
+ or_panic!(stream.set_read_timeout(Some(Duration::from_millis(1000))));
+
+ let mut other_end = or_panic!(listener.accept()).0;
+ or_panic!(other_end.write_all(b"hello world"));
+
+ let mut buf = [0; 11];
+ or_panic!(stream.read(&mut buf));
+ assert_eq!(b"hello world", &buf[..]);
+
+ let kind = stream.read_exact(&mut buf).err().expect("expected error").kind();
+ assert!(kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut,
+ "unexpected_error: {:?}", kind);
+ }
+
+ // Ensure the `set_read_timeout` and `set_write_timeout` calls return errors
+ // when passed zero Durations
+ #[test]
+ fn test_unix_stream_timeout_zero_duration() {
+ let dir = tmpdir();
+ let socket_path = dir.path().join("sock");
+
+ let listener = or_panic!(UnixListener::bind(&socket_path));
+ let stream = or_panic!(UnixStream::connect(&socket_path));
+
+ let result = stream.set_write_timeout(Some(Duration::new(0, 0)));
+ let err = result.unwrap_err();
+ assert_eq!(err.kind(), ErrorKind::InvalidInput);
+
+ let result = stream.set_read_timeout(Some(Duration::new(0, 0)));
+ let err = result.unwrap_err();
+ assert_eq!(err.kind(), ErrorKind::InvalidInput);
+
+ drop(listener);
+ }
+
+ #[test]
+ fn test_unix_datagram() {
+ let dir = tmpdir();
+ let path1 = dir.path().join("sock1");
+ let path2 = dir.path().join("sock2");
+
+ let sock1 = or_panic!(UnixDatagram::bind(&path1));
+ let sock2 = or_panic!(UnixDatagram::bind(&path2));
+
+ let msg = b"hello world";
+ or_panic!(sock1.send_to(msg, &path2));
+ let mut buf = [0; 11];
+ or_panic!(sock2.recv_from(&mut buf));
+ assert_eq!(msg, &buf[..]);
+ }
+
+ #[test]
+ fn test_unnamed_unix_datagram() {
+ let dir = tmpdir();
+ let path1 = dir.path().join("sock1");
+
+ let sock1 = or_panic!(UnixDatagram::bind(&path1));
+ let sock2 = or_panic!(UnixDatagram::unbound());
+
+ let msg = b"hello world";
+ or_panic!(sock2.send_to(msg, &path1));
+ let mut buf = [0; 11];
+ let (usize, addr) = or_panic!(sock1.recv_from(&mut buf));
+ assert_eq!(usize, 11);
+ assert!(addr.is_unnamed());
+ assert_eq!(msg, &buf[..]);
+ }
+
+ #[test]
+ fn test_connect_unix_datagram() {
+ let dir = tmpdir();
+ let path1 = dir.path().join("sock1");
+ let path2 = dir.path().join("sock2");
+
+ let bsock1 = or_panic!(UnixDatagram::bind(&path1));
+ let bsock2 = or_panic!(UnixDatagram::bind(&path2));
+ let sock = or_panic!(UnixDatagram::unbound());
+ or_panic!(sock.connect(&path1));
+
+ // Check send()
+ let msg = b"hello there";
+ or_panic!(sock.send(msg));
+ let mut buf = [0; 11];
+ let (usize, addr) = or_panic!(bsock1.recv_from(&mut buf));
+ assert_eq!(usize, 11);
+ assert!(addr.is_unnamed());
+ assert_eq!(msg, &buf[..]);
+
+ // Changing default socket works too
+ or_panic!(sock.connect(&path2));
+ or_panic!(sock.send(msg));
+ or_panic!(bsock2.recv_from(&mut buf));
+ }
+
+ #[test]
+ fn test_unix_datagram_recv() {
+ let dir = tmpdir();
+ let path1 = dir.path().join("sock1");
+
+ let sock1 = or_panic!(UnixDatagram::bind(&path1));
+ let sock2 = or_panic!(UnixDatagram::unbound());
+ or_panic!(sock2.connect(&path1));
+
+ let msg = b"hello world";
+ or_panic!(sock2.send(msg));
+ let mut buf = [0; 11];
+ let size = or_panic!(sock1.recv(&mut buf));
+ assert_eq!(size, 11);
+ assert_eq!(msg, &buf[..]);
+ }
+
+ #[test]
+ fn datagram_pair() {
+ let msg1 = b"hello";
+ let msg2 = b"world!";
+
+ let (s1, s2) = or_panic!(UnixDatagram::pair());
+ let thread = thread::spawn(move || {
+ // s1 must be moved in or the test will hang!
+ let mut buf = [0; 5];
+ or_panic!(s1.recv(&mut buf));
+ assert_eq!(&msg1[..], &buf[..]);
+ or_panic!(s1.send(msg2));
+ });
+
+ or_panic!(s2.send(msg1));
+ let mut buf = [0; 6];
+ or_panic!(s2.recv(&mut buf));
+ assert_eq!(&msg2[..], &buf[..]);
+ drop(s2);
+
+ thread.join().unwrap();
+ }
+
+ // Ensure the `set_read_timeout` and `set_write_timeout` calls return errors
+ // when passed zero Durations
+ #[test]
+ fn test_unix_datagram_timeout_zero_duration() {
+ let dir = tmpdir();
+ let path = dir.path().join("sock");
+
+ let datagram = or_panic!(UnixDatagram::bind(&path));
+
+ let result = datagram.set_write_timeout(Some(Duration::new(0, 0)));
+ let err = result.unwrap_err();
+ assert_eq!(err.kind(), ErrorKind::InvalidInput);
+
+ let result = datagram.set_read_timeout(Some(Duration::new(0, 0)));
+ let err = result.unwrap_err();
+ assert_eq!(err.kind(), ErrorKind::InvalidInput);
+ }
+
+ #[test]
+ fn abstract_namespace_not_allowed() {
+ assert!(UnixStream::connect("\0asdf").is_err());
+ }
+}
diff --git a/src/libstd/sys/unix/ext/process.rs b/src/libstd/sys/unix/ext/process.rs
new file mode 100644
index 0000000..7ace95e
--- /dev/null
+++ b/src/libstd/sys/unix/ext/process.rs
@@ -0,0 +1,213 @@
+//! Unix-specific extensions to primitives in the `std::process` module.
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+use crate::io;
+use crate::os::unix::io::{FromRawFd, RawFd, AsRawFd, IntoRawFd};
+use crate::process;
+use crate::sys;
+use crate::sys_common::{AsInnerMut, AsInner, FromInner, IntoInner};
+
+/// Unix-specific extensions to the [`process::Command`] builder.
+///
+/// [`process::Command`]: ../../../../std/process/struct.Command.html
+#[stable(feature = "rust1", since = "1.0.0")]
+pub trait CommandExt {
+ /// Sets the child process's user ID. This translates to a
+ /// `setuid` call in the child process. Failure in the `setuid`
+ /// call will cause the spawn to fail.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ fn uid(&mut self, id: u32) -> &mut process::Command;
+
+ /// Similar to `uid`, but sets the group ID of the child process. This has
+ /// the same semantics as the `uid` field.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ fn gid(&mut self, id: u32) -> &mut process::Command;
+
+ /// Schedules a closure to be run just before the `exec` function is
+ /// invoked.
+ ///
+ /// The closure is allowed to return an I/O error whose OS error code will
+ /// be communicated back to the parent and returned as an error from when
+ /// the spawn was requested.
+ ///
+ /// Multiple closures can be registered and they will be called in order of
+ /// their registration. If a closure returns `Err` then no further closures
+ /// will be called and the spawn operation will immediately return with a
+ /// failure.
+ ///
+ /// # Notes and Safety
+ ///
+ /// This closure will be run in the context of the child process after a
+ /// `fork`. This primarily means that any modifications made to memory on
+ /// behalf of this closure will **not** be visible to the parent process.
+ /// This is often a very constrained environment where normal operations
+ /// like `malloc` or acquiring a mutex are not guaranteed to work (due to
+ /// other threads perhaps still running when the `fork` was run).
+ ///
+ /// This also means that all resources such as file descriptors and
+ /// memory-mapped regions got duplicated. It is your responsibility to make
+ /// sure that the closure does not violate library invariants by making
+ /// invalid use of these duplicates.
+ ///
+ /// When this closure is run, aspects such as the stdio file descriptors and
+ /// working directory have successfully been changed, so output to these
+ /// locations may not appear where intended.
+ #[stable(feature = "process_pre_exec", since = "1.34.0")]
+ unsafe fn pre_exec<F>(&mut self, f: F) -> &mut process::Command
+ where F: FnMut() -> io::Result<()> + Send + Sync + 'static;
+
+ /// Schedules a closure to be run just before the `exec` function is
+ /// invoked.
+ ///
+ /// This method is stable and usable, but it should be unsafe. To fix
+ /// that, it got deprecated in favor of the unsafe [`pre_exec`].
+ ///
+ /// [`pre_exec`]: #tymethod.pre_exec
+ #[stable(feature = "process_exec", since = "1.15.0")]
+ #[rustc_deprecated(since = "1.37.0", reason = "should be unsafe, use `pre_exec` instead")]
+ fn before_exec<F>(&mut self, f: F) -> &mut process::Command
+ where F: FnMut() -> io::Result<()> + Send + Sync + 'static
+ {
+ unsafe { self.pre_exec(f) }
+ }
+
+ /// Performs all the required setup by this `Command`, followed by calling
+ /// the `execvp` syscall.
+ ///
+ /// On success this function will not return, and otherwise it will return
+ /// an error indicating why the exec (or another part of the setup of the
+ /// `Command`) failed.
+ ///
+ /// `exec` not returning has the same implications as calling
+ /// [`process::exit`] – no destructors on the current stack or any other
+ /// thread’s stack will be run. Therefore, it is recommended to only call
+ /// `exec` at a point where it is fine to not run any destructors. Note,
+ /// that the `execvp` syscall independently guarantees that all memory is
+ /// freed and all file descriptors with the `CLOEXEC` option (set by default
+ /// on all file descriptors opened by the standard library) are closed.
+ ///
+ /// This function, unlike `spawn`, will **not** `fork` the process to create
+ /// a new child. Like spawn, however, the default behavior for the stdio
+ /// descriptors will be to inherited from the current process.
+ ///
+ /// [`process::exit`]: ../../../process/fn.exit.html
+ ///
+ /// # Notes
+ ///
+ /// The process may be in a "broken state" if this function returns in
+ /// error. For example the working directory, environment variables, signal
+ /// handling settings, various user/group information, or aspects of stdio
+ /// file descriptors may have changed. If a "transactional spawn" is
+ /// required to gracefully handle errors it is recommended to use the
+ /// cross-platform `spawn` instead.
+ #[stable(feature = "process_exec2", since = "1.9.0")]
+ fn exec(&mut self) -> io::Error;
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl CommandExt for process::Command {
+ fn uid(&mut self, id: u32) -> &mut process::Command {
+ self.as_inner_mut().uid(id);
+ self
+ }
+
+ fn gid(&mut self, id: u32) -> &mut process::Command {
+ self.as_inner_mut().gid(id);
+ self
+ }
+
+ unsafe fn pre_exec<F>(&mut self, f: F) -> &mut process::Command
+ where F: FnMut() -> io::Result<()> + Send + Sync + 'static
+ {
+ self.as_inner_mut().pre_exec(Box::new(f));
+ self
+ }
+
+ fn exec(&mut self) -> io::Error {
+ self.as_inner_mut().exec(sys::process::Stdio::Inherit)
+ }
+}
+
+/// Unix-specific extensions to [`process::ExitStatus`].
+///
+/// [`process::ExitStatus`]: ../../../../std/process/struct.ExitStatus.html
+#[stable(feature = "rust1", since = "1.0.0")]
+pub trait ExitStatusExt {
+ /// Creates a new `ExitStatus` from the raw underlying `i32` return value of
+ /// a process.
+ #[stable(feature = "exit_status_from", since = "1.12.0")]
+ fn from_raw(raw: i32) -> Self;
+
+ /// If the process was terminated by a signal, returns that signal.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ fn signal(&self) -> Option<i32>;
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl ExitStatusExt for process::ExitStatus {
+ fn from_raw(raw: i32) -> Self {
+ process::ExitStatus::from_inner(From::from(raw))
+ }
+
+ fn signal(&self) -> Option<i32> {
+ self.as_inner().signal()
+ }
+}
+
+#[stable(feature = "process_extensions", since = "1.2.0")]
+impl FromRawFd for process::Stdio {
+ unsafe fn from_raw_fd(fd: RawFd) -> process::Stdio {
+ let fd = sys::fd::FileDesc::new(fd);
+ let io = sys::process::Stdio::Fd(fd);
+ process::Stdio::from_inner(io)
+ }
+}
+
+#[stable(feature = "process_extensions", since = "1.2.0")]
+impl AsRawFd for process::ChildStdin {
+ fn as_raw_fd(&self) -> RawFd {
+ self.as_inner().fd().raw()
+ }
+}
+
+#[stable(feature = "process_extensions", since = "1.2.0")]
+impl AsRawFd for process::ChildStdout {
+ fn as_raw_fd(&self) -> RawFd {
+ self.as_inner().fd().raw()
+ }
+}
+
+#[stable(feature = "process_extensions", since = "1.2.0")]
+impl AsRawFd for process::ChildStderr {
+ fn as_raw_fd(&self) -> RawFd {
+ self.as_inner().fd().raw()
+ }
+}
+
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+impl IntoRawFd for process::ChildStdin {
+ fn into_raw_fd(self) -> RawFd {
+ self.into_inner().into_fd().into_raw()
+ }
+}
+
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+impl IntoRawFd for process::ChildStdout {
+ fn into_raw_fd(self) -> RawFd {
+ self.into_inner().into_fd().into_raw()
+ }
+}
+
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+impl IntoRawFd for process::ChildStderr {
+ fn into_raw_fd(self) -> RawFd {
+ self.into_inner().into_fd().into_raw()
+ }
+}
+
+/// Returns the OS-assigned process identifier associated with this process's parent.
+#[stable(feature = "unix_ppid", since = "1.27.0")]
+pub fn parent_id() -> u32 {
+ crate::sys::os::getppid()
+}
diff --git a/src/libstd/sys/unix/ext/raw.rs b/src/libstd/sys/unix/ext/raw.rs
new file mode 100644
index 0000000..75ae54a
--- /dev/null
+++ b/src/libstd/sys/unix/ext/raw.rs
@@ -0,0 +1,23 @@
+//! Unix-specific primitives available on all unix platforms
+
+#![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)]
+
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type uid_t = u32;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type gid_t = u32;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type pid_t = i32;
+
+#[doc(inline)]
+#[stable(feature = "pthread_t", since = "1.8.0")]
+pub use crate::sys::platform::raw::pthread_t;
+#[doc(inline)]
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub use crate::sys::platform::raw::{dev_t, ino_t, mode_t, nlink_t, off_t, blksize_t};
+#[doc(inline)]
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub use crate::sys::platform::raw::{blkcnt_t, time_t};
diff --git a/src/libstd/sys/unix/ext/thread.rs b/src/libstd/sys/unix/ext/thread.rs
new file mode 100644
index 0000000..759ef62
--- /dev/null
+++ b/src/libstd/sys/unix/ext/thread.rs
@@ -0,0 +1,41 @@
+//! Unix-specific extensions to primitives in the `std::thread` module.
+
+#![stable(feature = "thread_extensions", since = "1.9.0")]
+
+#[allow(deprecated)]
+use crate::os::unix::raw::pthread_t;
+use crate::sys_common::{AsInner, IntoInner};
+use crate::thread::JoinHandle;
+
+#[stable(feature = "thread_extensions", since = "1.9.0")]
+#[allow(deprecated)]
+pub type RawPthread = pthread_t;
+
+/// Unix-specific extensions to [`thread::JoinHandle`].
+///
+/// [`thread::JoinHandle`]: ../../../../std/thread/struct.JoinHandle.html
+#[stable(feature = "thread_extensions", since = "1.9.0")]
+pub trait JoinHandleExt {
+ /// Extracts the raw pthread_t without taking ownership
+ #[stable(feature = "thread_extensions", since = "1.9.0")]
+ fn as_pthread_t(&self) -> RawPthread;
+
+ /// Consumes the thread, returning the raw pthread_t
+ ///
+ /// This function **transfers ownership** of the underlying pthread_t to
+ /// the caller. Callers are then the unique owners of the pthread_t and
+ /// must either detach or join the pthread_t once it's no longer needed.
+ #[stable(feature = "thread_extensions", since = "1.9.0")]
+ fn into_pthread_t(self) -> RawPthread;
+}
+
+#[stable(feature = "thread_extensions", since = "1.9.0")]
+impl<T> JoinHandleExt for JoinHandle<T> {
+ fn as_pthread_t(&self) -> RawPthread {
+ self.as_inner().id() as RawPthread
+ }
+
+ fn into_pthread_t(self) -> RawPthread {
+ self.into_inner().into_id() as RawPthread
+ }
+}
diff --git a/src/libstd/sys/unix/fast_thread_local.rs b/src/libstd/sys/unix/fast_thread_local.rs
new file mode 100644
index 0000000..17478dc
--- /dev/null
+++ b/src/libstd/sys/unix/fast_thread_local.rs
@@ -0,0 +1,88 @@
+#![cfg(target_thread_local)]
+#![unstable(feature = "thread_local_internals", issue = "0")]
+
+// Since what appears to be glibc 2.18 this symbol has been shipped which
+// GCC and clang both use to invoke destructors in thread_local globals, so
+// let's do the same!
+//
+// Note, however, that we run on lots older linuxes, as well as cross
+// compiling from a newer linux to an older linux, so we also have a
+// fallback implementation to use as well.
+//
+// Due to rust-lang/rust#18804, make sure this is not generic!
+#[cfg(any(target_os = "linux", target_os = "fuchsia", target_os = "hermit"))]
+pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) {
+ use crate::mem;
+ use crate::sys_common::thread_local::register_dtor_fallback;
+
+ extern {
+ #[linkage = "extern_weak"]
+ static __dso_handle: *mut u8;
+ #[linkage = "extern_weak"]
+ static __cxa_thread_atexit_impl: *const libc::c_void;
+ }
+ if !__cxa_thread_atexit_impl.is_null() {
+ type F = unsafe extern fn(dtor: unsafe extern fn(*mut u8),
+ arg: *mut u8,
+ dso_handle: *mut u8) -> libc::c_int;
+ mem::transmute::<*const libc::c_void, F>(__cxa_thread_atexit_impl)
+ (dtor, t, &__dso_handle as *const _ as *mut _);
+ return
+ }
+ register_dtor_fallback(t, dtor);
+}
+
+// This implementation is very similar to register_dtor_fallback in
+// sys_common/thread_local.rs. The main difference is that we want to hook into
+// macOS's analog of the above linux function, _tlv_atexit. OSX will run the
+// registered dtors before any TLS slots get freed, and when the main thread
+// exits.
+//
+// Unfortunately, calling _tlv_atexit while tls dtors are running is UB. The
+// workaround below is to register, via _tlv_atexit, a custom DTOR list once per
+// thread. thread_local dtors are pushed to the DTOR list without calling
+// _tlv_atexit.
+#[cfg(target_os = "macos")]
+pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) {
+ use crate::cell::Cell;
+ use crate::ptr;
+
+ #[thread_local]
+ static REGISTERED: Cell<bool> = Cell::new(false);
+ if !REGISTERED.get() {
+ _tlv_atexit(run_dtors, ptr::null_mut());
+ REGISTERED.set(true);
+ }
+
+ type List = Vec<(*mut u8, unsafe extern fn(*mut u8))>;
+
+ #[thread_local]
+ static DTORS: Cell<*mut List> = Cell::new(ptr::null_mut());
+ if DTORS.get().is_null() {
+ let v: Box<List> = box Vec::new();
+ DTORS.set(Box::into_raw(v));
+ }
+
+ extern {
+ fn _tlv_atexit(dtor: unsafe extern fn(*mut u8),
+ arg: *mut u8);
+ }
+
+ let list: &mut List = &mut *DTORS.get();
+ list.push((t, dtor));
+
+ unsafe extern fn run_dtors(_: *mut u8) {
+ let mut ptr = DTORS.replace(ptr::null_mut());
+ while !ptr.is_null() {
+ let list = Box::from_raw(ptr);
+ for (ptr, dtor) in list.into_iter() {
+ dtor(ptr);
+ }
+ ptr = DTORS.replace(ptr::null_mut());
+ }
+ }
+}
+
+pub fn requires_move_before_drop() -> bool {
+ false
+}
diff --git a/src/libstd/sys/unix/fd.rs b/src/libstd/sys/unix/fd.rs
new file mode 100644
index 0000000..c274ad2
--- /dev/null
+++ b/src/libstd/sys/unix/fd.rs
@@ -0,0 +1,302 @@
+#![unstable(reason = "not public", issue = "0", feature = "fd")]
+
+use crate::cmp;
+use crate::io::{self, Read, Initializer, IoVec, IoVecMut};
+use crate::mem;
+use crate::sync::atomic::{AtomicBool, Ordering};
+use crate::sys::cvt;
+use crate::sys_common::AsInner;
+
+use libc::{c_int, c_void, ssize_t};
+
+#[derive(Debug)]
+pub struct FileDesc {
+ fd: c_int,
+}
+
+fn max_len() -> usize {
+ // The maximum read limit on most posix-like systems is `SSIZE_MAX`,
+ // with the man page quoting that if the count of bytes to read is
+ // greater than `SSIZE_MAX` the result is "unspecified".
+ //
+ // On macOS, however, apparently the 64-bit libc is either buggy or
+ // intentionally showing odd behavior by rejecting any read with a size
+ // larger than or equal to INT_MAX. To handle both of these the read
+ // size is capped on both platforms.
+ if cfg!(target_os = "macos") {
+ <c_int>::max_value() as usize - 1
+ } else {
+ <ssize_t>::max_value() as usize
+ }
+}
+
+impl FileDesc {
+ pub fn new(fd: c_int) -> FileDesc {
+ FileDesc { fd }
+ }
+
+ pub fn raw(&self) -> c_int { self.fd }
+
+ /// Extracts the actual file descriptor without closing it.
+ pub fn into_raw(self) -> c_int {
+ let fd = self.fd;
+ mem::forget(self);
+ fd
+ }
+
+ pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
+ let ret = cvt(unsafe {
+ libc::read(self.fd,
+ buf.as_mut_ptr() as *mut c_void,
+ cmp::min(buf.len(), max_len()))
+ })?;
+ Ok(ret as usize)
+ }
+
+ pub fn read_vectored(&self, bufs: &mut [IoVecMut<'_>]) -> io::Result<usize> {
+ let ret = cvt(unsafe {
+ libc::readv(self.fd,
+ bufs.as_ptr() as *const libc::iovec,
+ cmp::min(bufs.len(), c_int::max_value() as usize) as c_int)
+ })?;
+ Ok(ret as usize)
+ }
+
+ pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
+ let mut me = self;
+ (&mut me).read_to_end(buf)
+ }
+
+ pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
+ #[cfg(target_os = "android")]
+ use super::android::cvt_pread64;
+
+ #[cfg(target_os = "emscripten")]
+ unsafe fn cvt_pread64(fd: c_int, buf: *mut c_void, count: usize, offset: i64)
+ -> io::Result<isize>
+ {
+ use crate::convert::TryInto;
+ use libc::pread64;
+ // pread64 on emscripten actually takes a 32 bit offset
+ if let Ok(o) = offset.try_into() {
+ cvt(pread64(fd, buf, count, o))
+ } else {
+ Err(io::Error::new(io::ErrorKind::InvalidInput,
+ "cannot pread >2GB"))
+ }
+ }
+
+ #[cfg(not(any(target_os = "android", target_os = "emscripten")))]
+ unsafe fn cvt_pread64(fd: c_int, buf: *mut c_void, count: usize, offset: i64)
+ -> io::Result<isize>
+ {
+ #[cfg(target_os = "linux")]
+ use libc::pread64;
+ #[cfg(not(target_os = "linux"))]
+ use libc::pread as pread64;
+ cvt(pread64(fd, buf, count, offset))
+ }
+
+ unsafe {
+ cvt_pread64(self.fd,
+ buf.as_mut_ptr() as *mut c_void,
+ cmp::min(buf.len(), max_len()),
+ offset as i64)
+ .map(|n| n as usize)
+ }
+ }
+
+ pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
+ let ret = cvt(unsafe {
+ libc::write(self.fd,
+ buf.as_ptr() as *const c_void,
+ cmp::min(buf.len(), max_len()))
+ })?;
+ Ok(ret as usize)
+ }
+
+ pub fn write_vectored(&self, bufs: &[IoVec<'_>]) -> io::Result<usize> {
+ let ret = cvt(unsafe {
+ libc::writev(self.fd,
+ bufs.as_ptr() as *const libc::iovec,
+ cmp::min(bufs.len(), c_int::max_value() as usize) as c_int)
+ })?;
+ Ok(ret as usize)
+ }
+
+ pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
+ #[cfg(target_os = "android")]
+ use super::android::cvt_pwrite64;
+
+ #[cfg(target_os = "emscripten")]
+ unsafe fn cvt_pwrite64(fd: c_int, buf: *const c_void, count: usize, offset: i64)
+ -> io::Result<isize>
+ {
+ use crate::convert::TryInto;
+ use libc::pwrite64;
+ // pwrite64 on emscripten actually takes a 32 bit offset
+ if let Ok(o) = offset.try_into() {
+ cvt(pwrite64(fd, buf, count, o))
+ } else {
+ Err(io::Error::new(io::ErrorKind::InvalidInput,
+ "cannot pwrite >2GB"))
+ }
+ }
+
+ #[cfg(not(any(target_os = "android", target_os = "emscripten")))]
+ unsafe fn cvt_pwrite64(fd: c_int, buf: *const c_void, count: usize, offset: i64)
+ -> io::Result<isize>
+ {
+ #[cfg(target_os = "linux")]
+ use libc::pwrite64;
+ #[cfg(not(target_os = "linux"))]
+ use libc::pwrite as pwrite64;
+ cvt(pwrite64(fd, buf, count, offset))
+ }
+
+ unsafe {
+ cvt_pwrite64(self.fd,
+ buf.as_ptr() as *const c_void,
+ cmp::min(buf.len(), max_len()),
+ offset as i64)
+ .map(|n| n as usize)
+ }
+ }
+
+ #[cfg(target_os = "linux")]
+ pub fn get_cloexec(&self) -> io::Result<bool> {
+ unsafe {
+ Ok((cvt(libc::fcntl(self.fd, libc::F_GETFD))? & libc::FD_CLOEXEC) != 0)
+ }
+ }
+
+ #[cfg(not(any(target_env = "newlib",
+ target_os = "solaris",
+ target_os = "emscripten",
+ target_os = "fuchsia",
+ target_os = "l4re",
+ target_os = "haiku")))]
+ pub fn set_cloexec(&self) -> io::Result<()> {
+ unsafe {
+ cvt(libc::ioctl(self.fd, libc::FIOCLEX))?;
+ Ok(())
+ }
+ }
+ #[cfg(any(target_env = "newlib",
+ target_os = "solaris",
+ target_os = "emscripten",
+ target_os = "fuchsia",
+ target_os = "l4re",
+ target_os = "haiku"))]
+ pub fn set_cloexec(&self) -> io::Result<()> {
+ unsafe {
+ let previous = cvt(libc::fcntl(self.fd, libc::F_GETFD))?;
+ let new = previous | libc::FD_CLOEXEC;
+ if new != previous {
+ cvt(libc::fcntl(self.fd, libc::F_SETFD, new))?;
+ }
+ Ok(())
+ }
+ }
+
+ #[cfg(target_os = "linux")]
+ pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
+ unsafe {
+ let v = nonblocking as c_int;
+ cvt(libc::ioctl(self.fd, libc::FIONBIO, &v))?;
+ Ok(())
+ }
+ }
+
+ #[cfg(not(target_os = "linux"))]
+ pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
+ unsafe {
+ let previous = cvt(libc::fcntl(self.fd, libc::F_GETFL))?;
+ let new = if nonblocking {
+ previous | libc::O_NONBLOCK
+ } else {
+ previous & !libc::O_NONBLOCK
+ };
+ if new != previous {
+ cvt(libc::fcntl(self.fd, libc::F_SETFL, new))?;
+ }
+ Ok(())
+ }
+ }
+
+ pub fn duplicate(&self) -> io::Result<FileDesc> {
+ // We want to atomically duplicate this file descriptor and set the
+ // CLOEXEC flag, and currently that's done via F_DUPFD_CLOEXEC. This
+ // flag, however, isn't supported on older Linux kernels (earlier than
+ // 2.6.24).
+ //
+ // To detect this and ensure that CLOEXEC is still set, we
+ // follow a strategy similar to musl [1] where if passing
+ // F_DUPFD_CLOEXEC causes `fcntl` to return EINVAL it means it's not
+ // supported (the third parameter, 0, is always valid), so we stop
+ // trying that.
+ //
+ // Also note that Android doesn't have F_DUPFD_CLOEXEC, but get it to
+ // resolve so we at least compile this.
+ //
+ // [1]: http://comments.gmane.org/gmane.linux.lib.musl.general/2963
+ #[cfg(any(target_os = "android", target_os = "haiku"))]
+ use libc::F_DUPFD as F_DUPFD_CLOEXEC;
+ #[cfg(not(any(target_os = "android", target_os="haiku")))]
+ use libc::F_DUPFD_CLOEXEC;
+
+ let make_filedesc = |fd| {
+ let fd = FileDesc::new(fd);
+ fd.set_cloexec()?;
+ Ok(fd)
+ };
+ static TRY_CLOEXEC: AtomicBool =
+ AtomicBool::new(!cfg!(target_os = "android"));
+ let fd = self.raw();
+ if TRY_CLOEXEC.load(Ordering::Relaxed) {
+ match cvt(unsafe { libc::fcntl(fd, F_DUPFD_CLOEXEC, 0) }) {
+ // We *still* call the `set_cloexec` method as apparently some
+ // linux kernel at some point stopped setting CLOEXEC even
+ // though it reported doing so on F_DUPFD_CLOEXEC.
+ Ok(fd) => {
+ return Ok(if cfg!(target_os = "linux") {
+ make_filedesc(fd)?
+ } else {
+ FileDesc::new(fd)
+ })
+ }
+ Err(ref e) if e.raw_os_error() == Some(libc::EINVAL) => {
+ TRY_CLOEXEC.store(false, Ordering::Relaxed);
+ }
+ Err(e) => return Err(e),
+ }
+ }
+ cvt(unsafe { libc::fcntl(fd, libc::F_DUPFD, 0) }).and_then(make_filedesc)
+ }
+}
+
+impl<'a> Read for &'a FileDesc {
+ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+ (**self).read(buf)
+ }
+
+ #[inline]
+ unsafe fn initializer(&self) -> Initializer {
+ Initializer::nop()
+ }
+}
+
+impl AsInner<c_int> for FileDesc {
+ fn as_inner(&self) -> &c_int { &self.fd }
+}
+
+impl Drop for FileDesc {
+ fn drop(&mut self) {
+ // Note that errors are ignored when closing a file descriptor. The
+ // reason for this is that if an error occurs we don't actually know if
+ // the file descriptor was closed or not, and if we retried (for
+ // something like EINTR), we might close another valid file descriptor
+ // opened after we closed ours.
+ let _ = unsafe { libc::close(self.fd) };
+ }
+}
diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs
new file mode 100644
index 0000000..dc3dcb5
--- /dev/null
+++ b/src/libstd/sys/unix/fs.rs
@@ -0,0 +1,1024 @@
+use crate::os::unix::prelude::*;
+
+use crate::ffi::{CString, CStr, OsString, OsStr};
+use crate::fmt;
+use crate::io::{self, Error, ErrorKind, SeekFrom};
+use crate::mem;
+use crate::path::{Path, PathBuf};
+use crate::ptr;
+use crate::sync::Arc;
+use crate::sys::fd::FileDesc;
+use crate::sys::time::SystemTime;
+use crate::sys::{cvt, cvt_r};
+use crate::sys_common::{AsInner, FromInner};
+
+use libc::{c_int, mode_t};
+
+#[cfg(any(target_os = "linux", target_os = "emscripten", target_os = "l4re"))]
+use libc::{stat64, fstat64, lstat64, off64_t, ftruncate64, lseek64, dirent64, readdir64_r, open64};
+#[cfg(any(target_os = "linux", target_os = "emscripten"))]
+use libc::fstatat64;
+#[cfg(any(target_os = "linux", target_os = "emscripten", target_os = "android"))]
+use libc::dirfd;
+#[cfg(target_os = "android")]
+use libc::{stat as stat64, fstat as fstat64, fstatat as fstatat64, lstat as lstat64, lseek64,
+ dirent as dirent64, open as open64};
+#[cfg(not(any(target_os = "linux",
+ target_os = "emscripten",
+ target_os = "l4re",
+ target_os = "android")))]
+use libc::{stat as stat64, fstat as fstat64, lstat as lstat64, off_t as off64_t,
+ ftruncate as ftruncate64, lseek as lseek64, dirent as dirent64, open as open64};
+#[cfg(not(any(target_os = "linux",
+ target_os = "emscripten",
+ target_os = "solaris",
+ target_os = "l4re",
+ target_os = "fuchsia")))]
+use libc::{readdir_r as readdir64_r};
+
+pub use crate::sys_common::fs::remove_dir_all;
+
+pub struct File(FileDesc);
+
+#[derive(Clone)]
+pub struct FileAttr {
+ stat: stat64,
+}
+
+// all DirEntry's will have a reference to this struct
+struct InnerReadDir {
+ dirp: Dir,
+ root: PathBuf,
+}
+
+#[derive(Clone)]
+pub struct ReadDir {
+ inner: Arc<InnerReadDir>,
+ end_of_stream: bool,
+}
+
+struct Dir(*mut libc::DIR);
+
+unsafe impl Send for Dir {}
+unsafe impl Sync for Dir {}
+
+pub struct DirEntry {
+ entry: dirent64,
+ dir: ReadDir,
+ // We need to store an owned copy of the entry name
+ // on Solaris and Fuchsia because a) it uses a zero-length
+ // array to store the name, b) its lifetime between readdir
+ // calls is not guaranteed.
+ #[cfg(any(target_os = "solaris", target_os = "fuchsia"))]
+ name: Box<[u8]>
+}
+
+#[derive(Clone, Debug)]
+pub struct OpenOptions {
+ // generic
+ read: bool,
+ write: bool,
+ append: bool,
+ truncate: bool,
+ create: bool,
+ create_new: bool,
+ // system-specific
+ custom_flags: i32,
+ mode: mode_t,
+}
+
+#[derive(Clone, PartialEq, Eq, Debug)]
+pub struct FilePermissions { mode: mode_t }
+
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
+pub struct FileType { mode: mode_t }
+
+#[derive(Debug)]
+pub struct DirBuilder { mode: mode_t }
+
+impl FileAttr {
+ pub fn size(&self) -> u64 { self.stat.st_size as u64 }
+ pub fn perm(&self) -> FilePermissions {
+ FilePermissions { mode: (self.stat.st_mode as mode_t) }
+ }
+
+ pub fn file_type(&self) -> FileType {
+ FileType { mode: self.stat.st_mode as mode_t }
+ }
+}
+
+#[cfg(target_os = "netbsd")]
+impl FileAttr {
+ pub fn modified(&self) -> io::Result<SystemTime> {
+ Ok(SystemTime::from(libc::timespec {
+ tv_sec: self.stat.st_mtime as libc::time_t,
+ tv_nsec: self.stat.st_mtimensec as libc::c_long,
+ }))
+ }
+
+ pub fn accessed(&self) -> io::Result<SystemTime> {
+ Ok(SystemTime::from(libc::timespec {
+ tv_sec: self.stat.st_atime as libc::time_t,
+ tv_nsec: self.stat.st_atimensec as libc::c_long,
+ }))
+ }
+
+ pub fn created(&self) -> io::Result<SystemTime> {
+ Ok(SystemTime::from(libc::timespec {
+ tv_sec: self.stat.st_birthtime as libc::time_t,
+ tv_nsec: self.stat.st_birthtimensec as libc::c_long,
+ }))
+ }
+}
+
+#[cfg(not(target_os = "netbsd"))]
+impl FileAttr {
+ pub fn modified(&self) -> io::Result<SystemTime> {
+ Ok(SystemTime::from(libc::timespec {
+ tv_sec: self.stat.st_mtime as libc::time_t,
+ tv_nsec: self.stat.st_mtime_nsec as _,
+ }))
+ }
+
+ pub fn accessed(&self) -> io::Result<SystemTime> {
+ Ok(SystemTime::from(libc::timespec {
+ tv_sec: self.stat.st_atime as libc::time_t,
+ tv_nsec: self.stat.st_atime_nsec as _,
+ }))
+ }
+
+ #[cfg(any(target_os = "bitrig",
+ target_os = "freebsd",
+ target_os = "openbsd",
+ target_os = "macos",
+ target_os = "ios"))]
+ pub fn created(&self) -> io::Result<SystemTime> {
+ Ok(SystemTime::from(libc::timespec {
+ tv_sec: self.stat.st_birthtime as libc::time_t,
+ tv_nsec: self.stat.st_birthtime_nsec as libc::c_long,
+ }))
+ }
+
+ #[cfg(not(any(target_os = "bitrig",
+ target_os = "freebsd",
+ target_os = "openbsd",
+ target_os = "macos",
+ target_os = "ios")))]
+ pub fn created(&self) -> io::Result<SystemTime> {
+ Err(io::Error::new(io::ErrorKind::Other,
+ "creation time is not available on this platform \
+ currently"))
+ }
+}
+
+impl AsInner<stat64> for FileAttr {
+ fn as_inner(&self) -> &stat64 { &self.stat }
+}
+
+impl FilePermissions {
+ pub fn readonly(&self) -> bool {
+ // check if any class (owner, group, others) has write permission
+ self.mode & 0o222 == 0
+ }
+
+ pub fn set_readonly(&mut self, readonly: bool) {
+ if readonly {
+ // remove write permission for all classes; equivalent to `chmod a-w <file>`
+ self.mode &= !0o222;
+ } else {
+ // add write permission for all classes; equivalent to `chmod a+w <file>`
+ self.mode |= 0o222;
+ }
+ }
+ pub fn mode(&self) -> u32 { self.mode as u32 }
+}
+
+impl FileType {
+ pub fn is_dir(&self) -> bool { self.is(libc::S_IFDIR) }
+ pub fn is_file(&self) -> bool { self.is(libc::S_IFREG) }
+ pub fn is_symlink(&self) -> bool { self.is(libc::S_IFLNK) }
+
+ pub fn is(&self, mode: mode_t) -> bool { self.mode & libc::S_IFMT == mode }
+}
+
+impl FromInner<u32> for FilePermissions {
+ fn from_inner(mode: u32) -> FilePermissions {
+ FilePermissions { mode: mode as mode_t }
+ }
+}
+
+impl fmt::Debug for ReadDir {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ // This will only be called from std::fs::ReadDir, which will add a "ReadDir()" frame.
+ // Thus the result will be e g 'ReadDir("/home")'
+ fmt::Debug::fmt(&*self.inner.root, f)
+ }
+}
+
+impl Iterator for ReadDir {
+ type Item = io::Result<DirEntry>;
+
+ #[cfg(any(target_os = "solaris", target_os = "fuchsia"))]
+ fn next(&mut self) -> Option<io::Result<DirEntry>> {
+ use crate::slice;
+
+ unsafe {
+ loop {
+ // Although readdir_r(3) would be a correct function to use here because
+ // of the thread safety, on Illumos and Fuchsia the readdir(3C) function
+ // is safe to use in threaded applications and it is generally preferred
+ // over the readdir_r(3C) function.
+ super::os::set_errno(0);
+ let entry_ptr = libc::readdir(self.inner.dirp.0);
+ if entry_ptr.is_null() {
+ // NULL can mean either the end is reached or an error occurred.
+ // So we had to clear errno beforehand to check for an error now.
+ return match super::os::errno() {
+ 0 => None,
+ e => Some(Err(Error::from_raw_os_error(e))),
+ }
+ }
+
+ let name = (*entry_ptr).d_name.as_ptr();
+ let namelen = libc::strlen(name) as usize;
+
+ let ret = DirEntry {
+ entry: *entry_ptr,
+ name: slice::from_raw_parts(name as *const u8,
+ namelen as usize).to_owned().into_boxed_slice(),
+ dir: self.clone()
+ };
+ if ret.name_bytes() != b"." && ret.name_bytes() != b".." {
+ return Some(Ok(ret))
+ }
+ }
+ }
+ }
+
+ #[cfg(not(any(target_os = "solaris", target_os = "fuchsia")))]
+ fn next(&mut self) -> Option<io::Result<DirEntry>> {
+ if self.end_of_stream {
+ return None;
+ }
+
+ unsafe {
+ let mut ret = DirEntry {
+ entry: mem::zeroed(),
+ dir: self.clone(),
+ };
+ let mut entry_ptr = ptr::null_mut();
+ loop {
+ if readdir64_r(self.inner.dirp.0, &mut ret.entry, &mut entry_ptr) != 0 {
+ if entry_ptr.is_null() {
+ // We encountered an error (which will be returned in this iteration), but
+ // we also reached the end of the directory stream. The `end_of_stream`
+ // flag is enabled to make sure that we return `None` in the next iteration
+ // (instead of looping forever)
+ self.end_of_stream = true;
+ }
+ return Some(Err(Error::last_os_error()))
+ }
+ if entry_ptr.is_null() {
+ return None
+ }
+ if ret.name_bytes() != b"." && ret.name_bytes() != b".." {
+ return Some(Ok(ret))
+ }
+ }
+ }
+ }
+}
+
+impl Drop for Dir {
+ fn drop(&mut self) {
+ let r = unsafe { libc::closedir(self.0) };
+ debug_assert_eq!(r, 0);
+ }
+}
+
+impl DirEntry {
+ pub fn path(&self) -> PathBuf {
+ self.dir.inner.root.join(OsStr::from_bytes(self.name_bytes()))
+ }
+
+ pub fn file_name(&self) -> OsString {
+ OsStr::from_bytes(self.name_bytes()).to_os_string()
+ }
+
+ #[cfg(any(target_os = "linux", target_os = "emscripten", target_os = "android"))]
+ pub fn metadata(&self) -> io::Result<FileAttr> {
+ let fd = cvt(unsafe {dirfd(self.dir.inner.dirp.0)})?;
+ let mut stat: stat64 = unsafe { mem::zeroed() };
+ cvt(unsafe {
+ fstatat64(fd, self.entry.d_name.as_ptr(), &mut stat, libc::AT_SYMLINK_NOFOLLOW)
+ })?;
+ Ok(FileAttr { stat })
+ }
+
+ #[cfg(not(any(target_os = "linux", target_os = "emscripten", target_os = "android")))]
+ pub fn metadata(&self) -> io::Result<FileAttr> {
+ lstat(&self.path())
+ }
+
+ #[cfg(any(target_os = "solaris", target_os = "haiku", target_os = "hermit"))]
+ pub fn file_type(&self) -> io::Result<FileType> {
+ lstat(&self.path()).map(|m| m.file_type())
+ }
+
+ #[cfg(not(any(target_os = "solaris", target_os = "haiku", target_os = "hermit")))]
+ pub fn file_type(&self) -> io::Result<FileType> {
+ match self.entry.d_type {
+ libc::DT_CHR => Ok(FileType { mode: libc::S_IFCHR }),
+ libc::DT_FIFO => Ok(FileType { mode: libc::S_IFIFO }),
+ libc::DT_LNK => Ok(FileType { mode: libc::S_IFLNK }),
+ libc::DT_REG => Ok(FileType { mode: libc::S_IFREG }),
+ libc::DT_SOCK => Ok(FileType { mode: libc::S_IFSOCK }),
+ libc::DT_DIR => Ok(FileType { mode: libc::S_IFDIR }),
+ libc::DT_BLK => Ok(FileType { mode: libc::S_IFBLK }),
+ _ => lstat(&self.path()).map(|m| m.file_type()),
+ }
+ }
+
+ #[cfg(any(target_os = "macos",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "emscripten",
+ target_os = "android",
+ target_os = "solaris",
+ target_os = "haiku",
+ target_os = "l4re",
+ target_os = "fuchsia",
+ target_os = "hermit"))]
+ pub fn ino(&self) -> u64 {
+ self.entry.d_ino as u64
+ }
+
+ #[cfg(any(target_os = "freebsd",
+ target_os = "openbsd",
+ target_os = "bitrig",
+ target_os = "netbsd",
+ target_os = "dragonfly"))]
+ pub fn ino(&self) -> u64 {
+ self.entry.d_fileno as u64
+ }
+
+ #[cfg(any(target_os = "macos",
+ target_os = "ios",
+ target_os = "netbsd",
+ target_os = "openbsd",
+ target_os = "freebsd",
+ target_os = "dragonfly",
+ target_os = "bitrig"))]
+ fn name_bytes(&self) -> &[u8] {
+ use crate::slice;
+ unsafe {
+ slice::from_raw_parts(self.entry.d_name.as_ptr() as *const u8,
+ self.entry.d_namlen as usize)
+ }
+ }
+ #[cfg(any(target_os = "android",
+ target_os = "linux",
+ target_os = "emscripten",
+ target_os = "l4re",
+ target_os = "haiku",
+ target_os = "hermit"))]
+ fn name_bytes(&self) -> &[u8] {
+ unsafe {
+ CStr::from_ptr(self.entry.d_name.as_ptr()).to_bytes()
+ }
+ }
+ #[cfg(any(target_os = "solaris",
+ target_os = "fuchsia"))]
+ fn name_bytes(&self) -> &[u8] {
+ &*self.name
+ }
+}
+
+impl OpenOptions {
+ pub fn new() -> OpenOptions {
+ OpenOptions {
+ // generic
+ read: false,
+ write: false,
+ append: false,
+ truncate: false,
+ create: false,
+ create_new: false,
+ // system-specific
+ custom_flags: 0,
+ mode: 0o666,
+ }
+ }
+
+ pub fn read(&mut self, read: bool) { self.read = read; }
+ pub fn write(&mut self, write: bool) { self.write = write; }
+ pub fn append(&mut self, append: bool) { self.append = append; }
+ pub fn truncate(&mut self, truncate: bool) { self.truncate = truncate; }
+ pub fn create(&mut self, create: bool) { self.create = create; }
+ pub fn create_new(&mut self, create_new: bool) { self.create_new = create_new; }
+
+ pub fn custom_flags(&mut self, flags: i32) { self.custom_flags = flags; }
+ pub fn mode(&mut self, mode: u32) { self.mode = mode as mode_t; }
+
+ fn get_access_mode(&self) -> io::Result<c_int> {
+ match (self.read, self.write, self.append) {
+ (true, false, false) => Ok(libc::O_RDONLY),
+ (false, true, false) => Ok(libc::O_WRONLY),
+ (true, true, false) => Ok(libc::O_RDWR),
+ (false, _, true) => Ok(libc::O_WRONLY | libc::O_APPEND),
+ (true, _, true) => Ok(libc::O_RDWR | libc::O_APPEND),
+ (false, false, false) => Err(Error::from_raw_os_error(libc::EINVAL)),
+ }
+ }
+
+ fn get_creation_mode(&self) -> io::Result<c_int> {
+ match (self.write, self.append) {
+ (true, false) => {}
+ (false, false) =>
+ if self.truncate || self.create || self.create_new {
+ return Err(Error::from_raw_os_error(libc::EINVAL));
+ },
+ (_, true) =>
+ if self.truncate && !self.create_new {
+ return Err(Error::from_raw_os_error(libc::EINVAL));
+ },
+ }
+
+ Ok(match (self.create, self.truncate, self.create_new) {
+ (false, false, false) => 0,
+ (true, false, false) => libc::O_CREAT,
+ (false, true, false) => libc::O_TRUNC,
+ (true, true, false) => libc::O_CREAT | libc::O_TRUNC,
+ (_, _, true) => libc::O_CREAT | libc::O_EXCL,
+ })
+ }
+}
+
+impl File {
+ pub fn open(path: &Path, opts: &OpenOptions) -> io::Result<File> {
+ let path = cstr(path)?;
+ File::open_c(&path, opts)
+ }
+
+ pub fn open_c(path: &CStr, opts: &OpenOptions) -> io::Result<File> {
+ let flags = libc::O_CLOEXEC |
+ opts.get_access_mode()? |
+ opts.get_creation_mode()? |
+ (opts.custom_flags as c_int & !libc::O_ACCMODE);
+ let fd = cvt_r(|| unsafe {
+ open64(path.as_ptr(), flags, opts.mode as c_int)
+ })?;
+ let fd = FileDesc::new(fd);
+
+ // Currently the standard library supports Linux 2.6.18 which did not
+ // have the O_CLOEXEC flag (passed above). If we're running on an older
+ // Linux kernel then the flag is just ignored by the OS. After we open
+ // the first file, we check whether it has CLOEXEC set. If it doesn't,
+ // we will explicitly ask for a CLOEXEC fd for every further file we
+ // open, if it does, we will skip that step.
+ //
+ // The CLOEXEC flag, however, is supported on versions of macOS/BSD/etc
+ // that we support, so we only do this on Linux currently.
+ #[cfg(target_os = "linux")]
+ fn ensure_cloexec(fd: &FileDesc) -> io::Result<()> {
+ use crate::sync::atomic::{AtomicUsize, Ordering};
+
+ const OPEN_CLOEXEC_UNKNOWN: usize = 0;
+ const OPEN_CLOEXEC_SUPPORTED: usize = 1;
+ const OPEN_CLOEXEC_NOTSUPPORTED: usize = 2;
+ static OPEN_CLOEXEC: AtomicUsize = AtomicUsize::new(OPEN_CLOEXEC_UNKNOWN);
+
+ let need_to_set;
+ match OPEN_CLOEXEC.load(Ordering::Relaxed) {
+ OPEN_CLOEXEC_UNKNOWN => {
+ need_to_set = !fd.get_cloexec()?;
+ OPEN_CLOEXEC.store(if need_to_set {
+ OPEN_CLOEXEC_NOTSUPPORTED
+ } else {
+ OPEN_CLOEXEC_SUPPORTED
+ }, Ordering::Relaxed);
+ },
+ OPEN_CLOEXEC_SUPPORTED => need_to_set = false,
+ OPEN_CLOEXEC_NOTSUPPORTED => need_to_set = true,
+ _ => unreachable!(),
+ }
+ if need_to_set {
+ fd.set_cloexec()?;
+ }
+ Ok(())
+ }
+
+ #[cfg(not(target_os = "linux"))]
+ fn ensure_cloexec(_: &FileDesc) -> io::Result<()> {
+ Ok(())
+ }
+
+ ensure_cloexec(&fd)?;
+ Ok(File(fd))
+ }
+
+ pub fn file_attr(&self) -> io::Result<FileAttr> {
+ let mut stat: stat64 = unsafe { mem::zeroed() };
+ cvt(unsafe {
+ fstat64(self.0.raw(), &mut stat)
+ })?;
+ Ok(FileAttr { stat })
+ }
+
+ pub fn fsync(&self) -> io::Result<()> {
+ cvt_r(|| unsafe { libc::fsync(self.0.raw()) })?;
+ Ok(())
+ }
+
+ pub fn datasync(&self) -> io::Result<()> {
+ cvt_r(|| unsafe { os_datasync(self.0.raw()) })?;
+ return Ok(());
+
+ #[cfg(any(target_os = "macos", target_os = "ios"))]
+ unsafe fn os_datasync(fd: c_int) -> c_int {
+ libc::fcntl(fd, libc::F_FULLFSYNC)
+ }
+ #[cfg(target_os = "linux")]
+ unsafe fn os_datasync(fd: c_int) -> c_int { libc::fdatasync(fd) }
+ #[cfg(not(any(target_os = "macos",
+ target_os = "ios",
+ target_os = "linux")))]
+ unsafe fn os_datasync(fd: c_int) -> c_int { libc::fsync(fd) }
+ }
+
+ pub fn truncate(&self, size: u64) -> io::Result<()> {
+ #[cfg(target_os = "android")]
+ return crate::sys::android::ftruncate64(self.0.raw(), size);
+
+ #[cfg(not(target_os = "android"))]
+ return cvt_r(|| unsafe {
+ ftruncate64(self.0.raw(), size as off64_t)
+ }).map(|_| ());
+ }
+
+ pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
+ self.0.read(buf)
+ }
+
+ pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
+ self.0.read_at(buf, offset)
+ }
+
+ pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
+ self.0.write(buf)
+ }
+
+ pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
+ self.0.write_at(buf, offset)
+ }
+
+ pub fn flush(&self) -> io::Result<()> { Ok(()) }
+
+ pub fn seek(&self, pos: SeekFrom) -> io::Result<u64> {
+ let (whence, pos) = match pos {
+ // Casting to `i64` is fine, too large values will end up as
+ // negative which will cause an error in `lseek64`.
+ SeekFrom::Start(off) => (libc::SEEK_SET, off as i64),
+ SeekFrom::End(off) => (libc::SEEK_END, off),
+ SeekFrom::Current(off) => (libc::SEEK_CUR, off),
+ };
+ #[cfg(target_os = "emscripten")]
+ let pos = pos as i32;
+ let n = cvt(unsafe { lseek64(self.0.raw(), pos, whence) })?;
+ Ok(n as u64)
+ }
+
+ pub fn duplicate(&self) -> io::Result<File> {
+ self.0.duplicate().map(File)
+ }
+
+ pub fn fd(&self) -> &FileDesc { &self.0 }
+
+ pub fn into_fd(self) -> FileDesc { self.0 }
+
+ pub fn set_permissions(&self, perm: FilePermissions) -> io::Result<()> {
+ cvt_r(|| unsafe { libc::fchmod(self.0.raw(), perm.mode) })?;
+ Ok(())
+ }
+}
+
+impl DirBuilder {
+ pub fn new() -> DirBuilder {
+ DirBuilder { mode: 0o777 }
+ }
+
+ pub fn mkdir(&self, p: &Path) -> io::Result<()> {
+ let p = cstr(p)?;
+ cvt(unsafe { libc::mkdir(p.as_ptr(), self.mode) })?;
+ Ok(())
+ }
+
+ pub fn set_mode(&mut self, mode: u32) {
+ self.mode = mode as mode_t;
+ }
+}
+
+fn cstr(path: &Path) -> io::Result<CString> {
+ Ok(CString::new(path.as_os_str().as_bytes())?)
+}
+
+impl FromInner<c_int> for File {
+ fn from_inner(fd: c_int) -> File {
+ File(FileDesc::new(fd))
+ }
+}
+
+impl fmt::Debug for File {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ #[cfg(target_os = "linux")]
+ fn get_path(fd: c_int) -> Option<PathBuf> {
+ let mut p = PathBuf::from("/proc/self/fd");
+ p.push(&fd.to_string());
+ readlink(&p).ok()
+ }
+
+ #[cfg(target_os = "macos")]
+ fn get_path(fd: c_int) -> Option<PathBuf> {
+ // FIXME: The use of PATH_MAX is generally not encouraged, but it
+ // is inevitable in this case because macOS defines `fcntl` with
+ // `F_GETPATH` in terms of `MAXPATHLEN`, and there are no
+ // alternatives. If a better method is invented, it should be used
+ // instead.
+ let mut buf = vec![0;libc::PATH_MAX as usize];
+ let n = unsafe { libc::fcntl(fd, libc::F_GETPATH, buf.as_ptr()) };
+ if n == -1 {
+ return None;
+ }
+ let l = buf.iter().position(|&c| c == 0).unwrap();
+ buf.truncate(l as usize);
+ buf.shrink_to_fit();
+ Some(PathBuf::from(OsString::from_vec(buf)))
+ }
+
+ #[cfg(not(any(target_os = "linux", target_os = "macos")))]
+ fn get_path(_fd: c_int) -> Option<PathBuf> {
+ // FIXME(#24570): implement this for other Unix platforms
+ None
+ }
+
+ #[cfg(any(target_os = "linux", target_os = "macos"))]
+ fn get_mode(fd: c_int) -> Option<(bool, bool)> {
+ let mode = unsafe { libc::fcntl(fd, libc::F_GETFL) };
+ if mode == -1 {
+ return None;
+ }
+ match mode & libc::O_ACCMODE {
+ libc::O_RDONLY => Some((true, false)),
+ libc::O_RDWR => Some((true, true)),
+ libc::O_WRONLY => Some((false, true)),
+ _ => None
+ }
+ }
+
+ #[cfg(not(any(target_os = "linux", target_os = "macos")))]
+ fn get_mode(_fd: c_int) -> Option<(bool, bool)> {
+ // FIXME(#24570): implement this for other Unix platforms
+ None
+ }
+
+ let fd = self.0.raw();
+ let mut b = f.debug_struct("File");
+ b.field("fd", &fd);
+ if let Some(path) = get_path(fd) {
+ b.field("path", &path);
+ }
+ if let Some((read, write)) = get_mode(fd) {
+ b.field("read", &read).field("write", &write);
+ }
+ b.finish()
+ }
+}
+
+pub fn readdir(p: &Path) -> io::Result<ReadDir> {
+ let root = p.to_path_buf();
+ let p = cstr(p)?;
+ unsafe {
+ let ptr = libc::opendir(p.as_ptr());
+ if ptr.is_null() {
+ Err(Error::last_os_error())
+ } else {
+ let inner = InnerReadDir { dirp: Dir(ptr), root };
+ Ok(ReadDir{
+ inner: Arc::new(inner),
+ end_of_stream: false,
+ })
+ }
+ }
+}
+
+pub fn unlink(p: &Path) -> io::Result<()> {
+ let p = cstr(p)?;
+ cvt(unsafe { libc::unlink(p.as_ptr()) })?;
+ Ok(())
+}
+
+pub fn rename(old: &Path, new: &Path) -> io::Result<()> {
+ let old = cstr(old)?;
+ let new = cstr(new)?;
+ cvt(unsafe { libc::rename(old.as_ptr(), new.as_ptr()) })?;
+ Ok(())
+}
+
+pub fn set_perm(p: &Path, perm: FilePermissions) -> io::Result<()> {
+ let p = cstr(p)?;
+ cvt_r(|| unsafe { libc::chmod(p.as_ptr(), perm.mode) })?;
+ Ok(())
+}
+
+pub fn rmdir(p: &Path) -> io::Result<()> {
+ let p = cstr(p)?;
+ cvt(unsafe { libc::rmdir(p.as_ptr()) })?;
+ Ok(())
+}
+
+pub fn readlink(p: &Path) -> io::Result<PathBuf> {
+ let c_path = cstr(p)?;
+ let p = c_path.as_ptr();
+
+ let mut buf = Vec::with_capacity(256);
+
+ loop {
+ let buf_read = cvt(unsafe {
+ libc::readlink(p, buf.as_mut_ptr() as *mut _, buf.capacity())
+ })? as usize;
+
+ unsafe { buf.set_len(buf_read); }
+
+ if buf_read != buf.capacity() {
+ buf.shrink_to_fit();
+
+ return Ok(PathBuf::from(OsString::from_vec(buf)));
+ }
+
+ // Trigger the internal buffer resizing logic of `Vec` by requiring
+ // more space than the current capacity. The length is guaranteed to be
+ // the same as the capacity due to the if statement above.
+ buf.reserve(1);
+ }
+}
+
+pub fn symlink(src: &Path, dst: &Path) -> io::Result<()> {
+ let src = cstr(src)?;
+ let dst = cstr(dst)?;
+ cvt(unsafe { libc::symlink(src.as_ptr(), dst.as_ptr()) })?;
+ Ok(())
+}
+
+pub fn link(src: &Path, dst: &Path) -> io::Result<()> {
+ let src = cstr(src)?;
+ let dst = cstr(dst)?;
+ cvt(unsafe { libc::link(src.as_ptr(), dst.as_ptr()) })?;
+ Ok(())
+}
+
+pub fn stat(p: &Path) -> io::Result<FileAttr> {
+ let p = cstr(p)?;
+ let mut stat: stat64 = unsafe { mem::zeroed() };
+ cvt(unsafe {
+ stat64(p.as_ptr(), &mut stat)
+ })?;
+ Ok(FileAttr { stat })
+}
+
+pub fn lstat(p: &Path) -> io::Result<FileAttr> {
+ let p = cstr(p)?;
+ let mut stat: stat64 = unsafe { mem::zeroed() };
+ cvt(unsafe {
+ lstat64(p.as_ptr(), &mut stat)
+ })?;
+ Ok(FileAttr { stat })
+}
+
+pub fn canonicalize(p: &Path) -> io::Result<PathBuf> {
+ let path = CString::new(p.as_os_str().as_bytes())?;
+ let buf;
+ unsafe {
+ let r = libc::realpath(path.as_ptr(), ptr::null_mut());
+ if r.is_null() {
+ return Err(io::Error::last_os_error())
+ }
+ buf = CStr::from_ptr(r).to_bytes().to_vec();
+ libc::free(r as *mut _);
+ }
+ Ok(PathBuf::from(OsString::from_vec(buf)))
+}
+
+fn open_and_set_permissions(
+ from: &Path,
+ to: &Path,
+) -> io::Result<(crate::fs::File, crate::fs::File, u64, crate::fs::Metadata)> {
+ use crate::fs::{File, OpenOptions};
+ use crate::os::unix::fs::{OpenOptionsExt, PermissionsExt};
+
+ let reader = File::open(from)?;
+ let (perm, len) = {
+ let metadata = reader.metadata()?;
+ if !metadata.is_file() {
+ return Err(Error::new(
+ ErrorKind::InvalidInput,
+ "the source path is not an existing regular file",
+ ));
+ }
+ (metadata.permissions(), metadata.len())
+ };
+ let writer = OpenOptions::new()
+ // create the file with the correct mode right away
+ .mode(perm.mode())
+ .write(true)
+ .create(true)
+ .truncate(true)
+ .open(to)?;
+ let writer_metadata = writer.metadata()?;
+ if writer_metadata.is_file() {
+ // Set the correct file permissions, in case the file already existed.
+ // Don't set the permissions on already existing non-files like
+ // pipes/FIFOs or device nodes.
+ writer.set_permissions(perm)?;
+ }
+ Ok((reader, writer, len, writer_metadata))
+}
+
+#[cfg(not(any(target_os = "linux",
+ target_os = "android",
+ target_os = "macos",
+ target_os = "ios")))]
+pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
+ let (mut reader, mut writer, _, _) = open_and_set_permissions(from, to)?;
+
+ io::copy(&mut reader, &mut writer)
+}
+
+#[cfg(any(target_os = "linux", target_os = "android"))]
+pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
+ use crate::cmp;
+ use crate::sync::atomic::{AtomicBool, Ordering};
+
+ // Kernel prior to 4.5 don't have copy_file_range
+ // We store the availability in a global to avoid unnecessary syscalls
+ static HAS_COPY_FILE_RANGE: AtomicBool = AtomicBool::new(true);
+
+ unsafe fn copy_file_range(
+ fd_in: libc::c_int,
+ off_in: *mut libc::loff_t,
+ fd_out: libc::c_int,
+ off_out: *mut libc::loff_t,
+ len: libc::size_t,
+ flags: libc::c_uint,
+ ) -> libc::c_long {
+ libc::syscall(
+ libc::SYS_copy_file_range,
+ fd_in,
+ off_in,
+ fd_out,
+ off_out,
+ len,
+ flags,
+ )
+ }
+
+ let (mut reader, mut writer, len, _) = open_and_set_permissions(from, to)?;
+
+ let has_copy_file_range = HAS_COPY_FILE_RANGE.load(Ordering::Relaxed);
+ let mut written = 0u64;
+ while written < len {
+ let copy_result = if has_copy_file_range {
+ let bytes_to_copy = cmp::min(len - written, usize::max_value() as u64) as usize;
+ let copy_result = unsafe {
+ // We actually don't have to adjust the offsets,
+ // because copy_file_range adjusts the file offset automatically
+ cvt(copy_file_range(
+ reader.as_raw_fd(),
+ ptr::null_mut(),
+ writer.as_raw_fd(),
+ ptr::null_mut(),
+ bytes_to_copy,
+ 0,
+ ))
+ };
+ if let Err(ref copy_err) = copy_result {
+ match copy_err.raw_os_error() {
+ Some(libc::ENOSYS) | Some(libc::EPERM) => {
+ HAS_COPY_FILE_RANGE.store(false, Ordering::Relaxed);
+ }
+ _ => {}
+ }
+ }
+ copy_result
+ } else {
+ Err(io::Error::from_raw_os_error(libc::ENOSYS))
+ };
+ match copy_result {
+ Ok(ret) => written += ret as u64,
+ Err(err) => {
+ match err.raw_os_error() {
+ Some(os_err)
+ if os_err == libc::ENOSYS
+ || os_err == libc::EXDEV
+ || os_err == libc::EINVAL
+ || os_err == libc::EPERM =>
+ {
+ // Try fallback io::copy if either:
+ // - Kernel version is < 4.5 (ENOSYS)
+ // - Files are mounted on different fs (EXDEV)
+ // - copy_file_range is disallowed, for example by seccomp (EPERM)
+ // - copy_file_range cannot be used with pipes or device nodes (EINVAL)
+ assert_eq!(written, 0);
+ return io::copy(&mut reader, &mut writer);
+ }
+ _ => return Err(err),
+ }
+ }
+ }
+ }
+ Ok(written)
+}
+
+#[cfg(any(target_os = "macos", target_os = "ios"))]
+pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
+ const COPYFILE_ACL: u32 = 1 << 0;
+ const COPYFILE_STAT: u32 = 1 << 1;
+ const COPYFILE_XATTR: u32 = 1 << 2;
+ const COPYFILE_DATA: u32 = 1 << 3;
+
+ const COPYFILE_SECURITY: u32 = COPYFILE_STAT | COPYFILE_ACL;
+ const COPYFILE_METADATA: u32 = COPYFILE_SECURITY | COPYFILE_XATTR;
+ const COPYFILE_ALL: u32 = COPYFILE_METADATA | COPYFILE_DATA;
+
+ const COPYFILE_STATE_COPIED: u32 = 8;
+
+ #[allow(non_camel_case_types)]
+ type copyfile_state_t = *mut libc::c_void;
+ #[allow(non_camel_case_types)]
+ type copyfile_flags_t = u32;
+
+ extern "C" {
+ fn fcopyfile(
+ from: libc::c_int,
+ to: libc::c_int,
+ state: copyfile_state_t,
+ flags: copyfile_flags_t,
+ ) -> libc::c_int;
+ fn copyfile_state_alloc() -> copyfile_state_t;
+ fn copyfile_state_free(state: copyfile_state_t) -> libc::c_int;
+ fn copyfile_state_get(
+ state: copyfile_state_t,
+ flag: u32,
+ dst: *mut libc::c_void,
+ ) -> libc::c_int;
+ }
+
+ struct FreeOnDrop(copyfile_state_t);
+ impl Drop for FreeOnDrop {
+ fn drop(&mut self) {
+ // The code below ensures that `FreeOnDrop` is never a null pointer
+ unsafe {
+ // `copyfile_state_free` returns -1 if the `to` or `from` files
+ // cannot be closed. However, this is not considerd this an
+ // error.
+ copyfile_state_free(self.0);
+ }
+ }
+ }
+
+ let (reader, writer, _, writer_metadata) = open_and_set_permissions(from, to)?;
+
+ // We ensure that `FreeOnDrop` never contains a null pointer so it is
+ // always safe to call `copyfile_state_free`
+ let state = unsafe {
+ let state = copyfile_state_alloc();
+ if state.is_null() {
+ return Err(crate::io::Error::last_os_error());
+ }
+ FreeOnDrop(state)
+ };
+
+ let flags = if writer_metadata.is_file() {
+ COPYFILE_ALL
+ } else {
+ COPYFILE_DATA
+ };
+
+ cvt(unsafe {
+ fcopyfile(
+ reader.as_raw_fd(),
+ writer.as_raw_fd(),
+ state.0,
+ flags,
+ )
+ })?;
+
+ let mut bytes_copied: libc::off_t = 0;
+ cvt(unsafe {
+ copyfile_state_get(
+ state.0,
+ COPYFILE_STATE_COPIED,
+ &mut bytes_copied as *mut libc::off_t as *mut libc::c_void,
+ )
+ })?;
+ Ok(bytes_copied as u64)
+}
diff --git a/src/libstd/sys/unix/io.rs b/src/libstd/sys/unix/io.rs
new file mode 100644
index 0000000..eb3fa47
--- /dev/null
+++ b/src/libstd/sys/unix/io.rs
@@ -0,0 +1,62 @@
+use crate::marker::PhantomData;
+use crate::slice;
+
+use libc::{iovec, c_void};
+
+#[repr(transparent)]
+pub struct IoVec<'a> {
+ vec: iovec,
+ _p: PhantomData<&'a [u8]>,
+}
+
+impl<'a> IoVec<'a> {
+ #[inline]
+ pub fn new(buf: &'a [u8]) -> IoVec<'a> {
+ IoVec {
+ vec: iovec {
+ iov_base: buf.as_ptr() as *mut u8 as *mut c_void,
+ iov_len: buf.len()
+ },
+ _p: PhantomData,
+ }
+ }
+
+ #[inline]
+ pub fn as_slice(&self) -> &[u8] {
+ unsafe {
+ slice::from_raw_parts(self.vec.iov_base as *mut u8, self.vec.iov_len)
+ }
+ }
+}
+
+pub struct IoVecMut<'a> {
+ vec: iovec,
+ _p: PhantomData<&'a mut [u8]>,
+}
+
+impl<'a> IoVecMut<'a> {
+ #[inline]
+ pub fn new(buf: &'a mut [u8]) -> IoVecMut<'a> {
+ IoVecMut {
+ vec: iovec {
+ iov_base: buf.as_mut_ptr() as *mut c_void,
+ iov_len: buf.len()
+ },
+ _p: PhantomData,
+ }
+ }
+
+ #[inline]
+ pub fn as_slice(&self) -> &[u8] {
+ unsafe {
+ slice::from_raw_parts(self.vec.iov_base as *mut u8, self.vec.iov_len)
+ }
+ }
+
+ #[inline]
+ pub fn as_mut_slice(&mut self) -> &mut [u8] {
+ unsafe {
+ slice::from_raw_parts_mut(self.vec.iov_base as *mut u8, self.vec.iov_len)
+ }
+ }
+}
diff --git a/src/libstd/sys/unix/l4re.rs b/src/libstd/sys/unix/l4re.rs
new file mode 100644
index 0000000..f52fe80
--- /dev/null
+++ b/src/libstd/sys/unix/l4re.rs
@@ -0,0 +1,469 @@
+macro_rules! unimpl {
+ () => (return Err(io::Error::new(io::ErrorKind::Other, "No networking available on L4Re."));)
+}
+
+pub mod net {
+ #![allow(warnings)]
+ use crate::fmt;
+ use crate::io::{self, IoVec, IoVecMut};
+ use crate::net::{SocketAddr, Shutdown, Ipv4Addr, Ipv6Addr};
+ use crate::sys_common::{AsInner, FromInner, IntoInner};
+ use crate::sys::fd::FileDesc;
+ use crate::time::Duration;
+ use crate::convert::TryFrom;
+
+ #[allow(unused_extern_crates)]
+ pub extern crate libc as netc;
+
+ pub struct Socket(FileDesc);
+ impl Socket {
+ pub fn new(_: &SocketAddr, _: libc::c_int) -> io::Result<Socket> {
+ unimpl!();
+ }
+
+ pub fn new_raw(_: libc::c_int, _: libc::c_int) -> io::Result<Socket> {
+ unimpl!();
+ }
+
+ pub fn new_pair(_: libc::c_int, _: libc::c_int) -> io::Result<(Socket, Socket)> {
+ unimpl!();
+ }
+
+ pub fn connect_timeout(&self, _: &SocketAddr, _: Duration) -> io::Result<()> {
+ unimpl!();
+ }
+
+ pub fn accept(&self, _: *mut libc::sockaddr, _: *mut libc::socklen_t)
+ -> io::Result<Socket> {
+ unimpl!();
+ }
+
+ pub fn duplicate(&self) -> io::Result<Socket> {
+ unimpl!();
+ }
+
+ pub fn read(&self, _: &mut [u8]) -> io::Result<usize> {
+ unimpl!();
+ }
+
+ pub fn read_vectored(&self, _: &mut [IoVecMut<'_>]) -> io::Result<usize> {
+ unimpl!();
+ }
+
+ pub fn peek(&self, _: &mut [u8]) -> io::Result<usize> {
+ unimpl!();
+ }
+
+ pub fn recv_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+ unimpl!();
+ }
+
+ pub fn peek_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+ unimpl!();
+ }
+
+ pub fn write(&self, _: &[u8]) -> io::Result<usize> {
+ unimpl!();
+ }
+
+ pub fn write_vectored(&self, _: &[IoVec<'_>]) -> io::Result<usize> {
+ unimpl!();
+ }
+
+ pub fn set_timeout(&self, _: Option<Duration>, _: libc::c_int) -> io::Result<()> {
+ unimpl!();
+ }
+
+ pub fn timeout(&self, _: libc::c_int) -> io::Result<Option<Duration>> {
+ unimpl!();
+ }
+
+ pub fn shutdown(&self, _: Shutdown) -> io::Result<()> {
+ unimpl!();
+ }
+
+ pub fn set_nodelay(&self, _: bool) -> io::Result<()> {
+ unimpl!();
+ }
+
+ pub fn nodelay(&self) -> io::Result<bool> {
+ unimpl!();
+ }
+
+ pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
+ unimpl!();
+ }
+
+ pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+ unimpl!();
+ }
+ }
+
+ impl AsInner<libc::c_int> for Socket {
+ fn as_inner(&self) -> &libc::c_int { self.0.as_inner() }
+ }
+
+ impl FromInner<libc::c_int> for Socket {
+ fn from_inner(fd: libc::c_int) -> Socket { Socket(FileDesc::new(fd)) }
+ }
+
+ impl IntoInner<libc::c_int> for Socket {
+ fn into_inner(self) -> libc::c_int { self.0.into_raw() }
+ }
+
+ pub struct TcpStream {
+ inner: Socket,
+ }
+
+ impl TcpStream {
+ pub fn connect(_: io::Result<&SocketAddr>) -> io::Result<TcpStream> {
+ unimpl!();
+ }
+
+ pub fn connect_timeout(_: &SocketAddr, _: Duration) -> io::Result<TcpStream> {
+ unimpl!();
+ }
+
+ pub fn socket(&self) -> &Socket { &self.inner }
+
+ pub fn into_socket(self) -> Socket { self.inner }
+
+ pub fn set_read_timeout(&self, _: Option<Duration>) -> io::Result<()> {
+ unimpl!();
+ }
+
+ pub fn set_write_timeout(&self, _: Option<Duration>) -> io::Result<()> {
+ unimpl!();
+ }
+
+ pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
+ unimpl!();
+ }
+
+ pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
+ unimpl!();
+ }
+
+ pub fn peek(&self, _: &mut [u8]) -> io::Result<usize> {
+ unimpl!();
+ }
+
+ pub fn read(&self, _: &mut [u8]) -> io::Result<usize> {
+ unimpl!();
+ }
+
+ pub fn read_vectored(&self, _: &mut [IoVecMut<'_>]) -> io::Result<usize> {
+ unimpl!();
+ }
+
+ pub fn write(&self, _: &[u8]) -> io::Result<usize> {
+ unimpl!();
+ }
+
+ pub fn write_vectored(&self, _: &[IoVec<'_>]) -> io::Result<usize> {
+ unimpl!();
+ }
+
+ pub fn peer_addr(&self) -> io::Result<SocketAddr> {
+ unimpl!();
+ }
+
+ pub fn socket_addr(&self) -> io::Result<SocketAddr> {
+ unimpl!();
+ }
+
+ pub fn shutdown(&self, _: Shutdown) -> io::Result<()> {
+ unimpl!();
+ }
+
+ pub fn duplicate(&self) -> io::Result<TcpStream> {
+ unimpl!();
+ }
+
+ pub fn set_nodelay(&self, _: bool) -> io::Result<()> {
+ unimpl!();
+ }
+
+ pub fn nodelay(&self) -> io::Result<bool> {
+ unimpl!();
+ }
+
+ pub fn set_ttl(&self, _: u32) -> io::Result<()> {
+ unimpl!();
+ }
+
+ pub fn ttl(&self) -> io::Result<u32> {
+ unimpl!();
+ }
+
+ pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+ unimpl!();
+ }
+
+ pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
+ unimpl!();
+ }
+ }
+
+ impl FromInner<Socket> for TcpStream {
+ fn from_inner(socket: Socket) -> TcpStream {
+ TcpStream { inner: socket }
+ }
+ }
+
+ impl fmt::Debug for TcpStream {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "No networking support available on L4Re")
+ }
+ }
+
+ pub struct TcpListener {
+ inner: Socket,
+ }
+
+ impl TcpListener {
+ pub fn bind(_: io::Result<&SocketAddr>) -> io::Result<TcpListener> {
+ unimpl!();
+ }
+
+ pub fn socket(&self) -> &Socket { &self.inner }
+
+ pub fn into_socket(self) -> Socket { self.inner }
+
+ pub fn socket_addr(&self) -> io::Result<SocketAddr> {
+ unimpl!();
+ }
+
+ pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> {
+ unimpl!();
+ }
+
+ pub fn duplicate(&self) -> io::Result<TcpListener> {
+ unimpl!();
+ }
+
+ pub fn set_ttl(&self, _: u32) -> io::Result<()> {
+ unimpl!();
+ }
+
+ pub fn ttl(&self) -> io::Result<u32> {
+ unimpl!();
+ }
+
+ pub fn set_only_v6(&self, _: bool) -> io::Result<()> {
+ unimpl!();
+ }
+
+ pub fn only_v6(&self) -> io::Result<bool> {
+ unimpl!();
+ }
+
+ pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+ unimpl!();
+ }
+
+ pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
+ unimpl!();
+ }
+ }
+
+ impl FromInner<Socket> for TcpListener {
+ fn from_inner(socket: Socket) -> TcpListener {
+ TcpListener { inner: socket }
+ }
+ }
+
+ impl fmt::Debug for TcpListener {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "No networking support available on L4Re.")
+ }
+ }
+
+ pub struct UdpSocket {
+ inner: Socket,
+ }
+
+ impl UdpSocket {
+ pub fn bind(_: io::Result<&SocketAddr>) -> io::Result<UdpSocket> {
+ unimpl!();
+ }
+
+ pub fn socket(&self) -> &Socket { &self.inner }
+
+ pub fn into_socket(self) -> Socket { self.inner }
+
+ pub fn peer_addr(&self) -> io::Result<SocketAddr> {
+ unimpl!();
+ }
+
+ pub fn socket_addr(&self) -> io::Result<SocketAddr> {
+ unimpl!();
+ }
+
+ pub fn recv_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+ unimpl!();
+ }
+
+ pub fn peek_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+ unimpl!();
+ }
+
+ pub fn send_to(&self, _: &[u8], _: &SocketAddr) -> io::Result<usize> {
+ unimpl!();
+ }
+
+ pub fn duplicate(&self) -> io::Result<UdpSocket> {
+ unimpl!();
+ }
+
+ pub fn set_read_timeout(&self, _: Option<Duration>) -> io::Result<()> {
+ unimpl!();
+ }
+
+ pub fn set_write_timeout(&self, _: Option<Duration>) -> io::Result<()> {
+ unimpl!();
+ }
+
+ pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
+ unimpl!();
+ }
+
+ pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
+ unimpl!();
+ }
+
+ pub fn set_broadcast(&self, _: bool) -> io::Result<()> {
+ unimpl!();
+ }
+
+ pub fn broadcast(&self) -> io::Result<bool> {
+ unimpl!();
+ }
+
+ pub fn set_multicast_loop_v4(&self, _: bool) -> io::Result<()> {
+ unimpl!();
+ }
+
+ pub fn multicast_loop_v4(&self) -> io::Result<bool> {
+ unimpl!();
+ }
+
+ pub fn set_multicast_ttl_v4(&self, _: u32) -> io::Result<()> {
+ unimpl!();
+ }
+
+ pub fn multicast_ttl_v4(&self) -> io::Result<u32> {
+ unimpl!();
+ }
+
+ pub fn set_multicast_loop_v6(&self, _: bool) -> io::Result<()> {
+ unimpl!();
+ }
+
+ pub fn multicast_loop_v6(&self) -> io::Result<bool> {
+ unimpl!();
+ }
+
+ pub fn join_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr)
+ -> io::Result<()> {
+ unimpl!();
+ }
+
+ pub fn join_multicast_v6(&self, _: &Ipv6Addr, _: u32)
+ -> io::Result<()> {
+ unimpl!();
+ }
+
+ pub fn leave_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr)
+ -> io::Result<()> {
+ unimpl!();
+ }
+
+ pub fn leave_multicast_v6(&self, _: &Ipv6Addr, _: u32)
+ -> io::Result<()> {
+ unimpl!();
+ }
+
+ pub fn set_ttl(&self, _: u32) -> io::Result<()> {
+ unimpl!();
+ }
+
+ pub fn ttl(&self) -> io::Result<u32> {
+ unimpl!();
+ }
+
+ pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+ unimpl!();
+ }
+
+ pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
+ unimpl!();
+ }
+
+ pub fn recv(&self, _: &mut [u8]) -> io::Result<usize> {
+ unimpl!();
+ }
+
+ pub fn peek(&self, _: &mut [u8]) -> io::Result<usize> {
+ unimpl!();
+ }
+
+ pub fn send(&self, _: &[u8]) -> io::Result<usize> {
+ unimpl!();
+ }
+
+ pub fn connect(&self, _: io::Result<&SocketAddr>) -> io::Result<()> {
+ unimpl!();
+ }
+ }
+
+ impl FromInner<Socket> for UdpSocket {
+ fn from_inner(socket: Socket) -> UdpSocket {
+ UdpSocket { inner: socket }
+ }
+ }
+
+ impl fmt::Debug for UdpSocket {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "No networking support on L4Re available.")
+ }
+ }
+
+ pub struct LookupHost {
+ original: *mut libc::addrinfo,
+ cur: *mut libc::addrinfo,
+ }
+
+ impl Iterator for LookupHost {
+ type Item = SocketAddr;
+ fn next(&mut self) -> Option<SocketAddr> {
+ None
+ }
+ }
+
+ impl LookupHost {
+ pub fn port(&self) -> u16 {
+ unimpl!();
+ }
+ }
+
+ unsafe impl Sync for LookupHost {}
+ unsafe impl Send for LookupHost {}
+
+
+ impl TryFrom<&str> for LookupHost {
+ type Error = io::Error;
+
+ fn try_from(_v: &str) -> io::Result<LookupHost> {
+ unimpl!();
+ }
+ }
+
+ impl<'a> TryFrom<(&'a str, u16)> for LookupHost {
+ type Error = io::Error;
+
+ fn try_from(_v: (&'a str, u16)) -> io::Result<LookupHost> {
+ unimpl!();
+ }
+ }
+}
diff --git a/src/libstd/sys/unix/memchr.rs b/src/libstd/sys/unix/memchr.rs
new file mode 100644
index 0000000..1984678
--- /dev/null
+++ b/src/libstd/sys/unix/memchr.rs
@@ -0,0 +1,43 @@
+// Original implementation taken from rust-memchr.
+// Copyright 2015 Andrew Gallant, bluss and Nicolas Koch
+
+pub fn memchr(needle: u8, haystack: &[u8]) -> Option<usize> {
+ let p = unsafe {
+ libc::memchr(
+ haystack.as_ptr() as *const libc::c_void,
+ needle as libc::c_int,
+ haystack.len())
+ };
+ if p.is_null() {
+ None
+ } else {
+ Some(p as usize - (haystack.as_ptr() as usize))
+ }
+}
+
+pub fn memrchr(needle: u8, haystack: &[u8]) -> Option<usize> {
+
+ #[cfg(target_os = "linux")]
+ fn memrchr_specific(needle: u8, haystack: &[u8]) -> Option<usize> {
+ // GNU's memrchr() will - unlike memchr() - error if haystack is empty.
+ if haystack.is_empty() {return None}
+ let p = unsafe {
+ libc::memrchr(
+ haystack.as_ptr() as *const libc::c_void,
+ needle as libc::c_int,
+ haystack.len())
+ };
+ if p.is_null() {
+ None
+ } else {
+ Some(p as usize - (haystack.as_ptr() as usize))
+ }
+ }
+
+ #[cfg(not(target_os = "linux"))]
+ fn memrchr_specific(needle: u8, haystack: &[u8]) -> Option<usize> {
+ core::slice::memchr::memrchr(needle, haystack)
+ }
+
+ memrchr_specific(needle, haystack)
+}
diff --git a/src/libstd/sys/unix/mod.rs b/src/libstd/sys/unix/mod.rs
new file mode 100644
index 0000000..90e2644
--- /dev/null
+++ b/src/libstd/sys/unix/mod.rs
@@ -0,0 +1,159 @@
+#![allow(missing_docs, nonstandard_style)]
+
+use crate::io::ErrorKind;
+
+#[cfg(any(rustdoc, target_os = "linux"))] pub use crate::os::linux as platform;
+
+#[cfg(all(not(rustdoc), target_os = "android"))] pub use crate::os::android as platform;
+#[cfg(all(not(rustdoc), target_os = "bitrig"))] pub use crate::os::bitrig as platform;
+#[cfg(all(not(rustdoc), target_os = "dragonfly"))] pub use crate::os::dragonfly as platform;
+#[cfg(all(not(rustdoc), target_os = "freebsd"))] pub use crate::os::freebsd as platform;
+#[cfg(all(not(rustdoc), target_os = "haiku"))] pub use crate::os::haiku as platform;
+#[cfg(all(not(rustdoc), target_os = "ios"))] pub use crate::os::ios as platform;
+#[cfg(all(not(rustdoc), target_os = "macos"))] pub use crate::os::macos as platform;
+#[cfg(all(not(rustdoc), target_os = "netbsd"))] pub use crate::os::netbsd as platform;
+#[cfg(all(not(rustdoc), target_os = "openbsd"))] pub use crate::os::openbsd as platform;
+#[cfg(all(not(rustdoc), target_os = "solaris"))] pub use crate::os::solaris as platform;
+#[cfg(all(not(rustdoc), target_os = "emscripten"))] pub use crate::os::emscripten as platform;
+#[cfg(all(not(rustdoc), target_os = "fuchsia"))] pub use crate::os::fuchsia as platform;
+#[cfg(all(not(rustdoc), target_os = "l4re"))] pub use crate::os::linux as platform;
+#[cfg(all(not(rustdoc), target_os = "hermit"))] pub use crate::os::hermit as platform;
+
+pub use self::rand::hashmap_random_keys;
+pub use libc::strlen;
+
+#[macro_use]
+pub mod weak;
+
+pub mod alloc;
+pub mod args;
+pub mod android;
+#[cfg(feature = "backtrace")]
+pub mod backtrace;
+pub mod cmath;
+pub mod condvar;
+pub mod env;
+pub mod ext;
+pub mod fast_thread_local;
+pub mod fd;
+pub mod fs;
+pub mod memchr;
+pub mod io;
+pub mod mutex;
+#[cfg(not(target_os = "l4re"))]
+pub mod net;
+#[cfg(target_os = "l4re")]
+mod l4re;
+#[cfg(target_os = "l4re")]
+pub use self::l4re::net;
+pub mod os;
+pub mod path;
+pub mod pipe;
+pub mod process;
+pub mod rand;
+pub mod rwlock;
+pub mod stack_overflow;
+pub mod thread;
+pub mod thread_local;
+pub mod time;
+pub mod stdio;
+
+pub use crate::sys_common::os_str_bytes as os_str;
+
+#[cfg(not(test))]
+pub fn init() {
+ // By default, some platforms will send a *signal* when an EPIPE error
+ // would otherwise be delivered. This runtime doesn't install a SIGPIPE
+ // handler, causing it to kill the program, which isn't exactly what we
+ // want!
+ //
+ // Hence, we set SIGPIPE to ignore when the program starts up in order
+ // to prevent this problem.
+ unsafe {
+ reset_sigpipe();
+ }
+
+ #[cfg(not(any(target_os = "emscripten", target_os = "fuchsia")))]
+ unsafe fn reset_sigpipe() {
+ assert!(signal(libc::SIGPIPE, libc::SIG_IGN) != libc::SIG_ERR);
+ }
+ #[cfg(any(target_os = "emscripten", target_os = "fuchsia"))]
+ unsafe fn reset_sigpipe() {}
+}
+
+#[cfg(target_os = "android")]
+pub use crate::sys::android::signal;
+#[cfg(not(target_os = "android"))]
+pub use libc::signal;
+
+pub fn decode_error_kind(errno: i32) -> ErrorKind {
+ match errno as libc::c_int {
+ libc::ECONNREFUSED => ErrorKind::ConnectionRefused,
+ libc::ECONNRESET => ErrorKind::ConnectionReset,
+ libc::EPERM | libc::EACCES => ErrorKind::PermissionDenied,
+ libc::EPIPE => ErrorKind::BrokenPipe,
+ libc::ENOTCONN => ErrorKind::NotConnected,
+ libc::ECONNABORTED => ErrorKind::ConnectionAborted,
+ libc::EADDRNOTAVAIL => ErrorKind::AddrNotAvailable,
+ libc::EADDRINUSE => ErrorKind::AddrInUse,
+ libc::ENOENT => ErrorKind::NotFound,
+ libc::EINTR => ErrorKind::Interrupted,
+ libc::EINVAL => ErrorKind::InvalidInput,
+ libc::ETIMEDOUT => ErrorKind::TimedOut,
+ libc::EEXIST => ErrorKind::AlreadyExists,
+
+ // These two constants can have the same value on some systems,
+ // but different values on others, so we can't use a match
+ // clause
+ x if x == libc::EAGAIN || x == libc::EWOULDBLOCK =>
+ ErrorKind::WouldBlock,
+
+ _ => ErrorKind::Other,
+ }
+}
+
+#[doc(hidden)]
+pub trait IsMinusOne {
+ fn is_minus_one(&self) -> bool;
+}
+
+macro_rules! impl_is_minus_one {
+ ($($t:ident)*) => ($(impl IsMinusOne for $t {
+ fn is_minus_one(&self) -> bool {
+ *self == -1
+ }
+ })*)
+}
+
+impl_is_minus_one! { i8 i16 i32 i64 isize }
+
+pub fn cvt<T: IsMinusOne>(t: T) -> crate::io::Result<T> {
+ if t.is_minus_one() {
+ Err(crate::io::Error::last_os_error())
+ } else {
+ Ok(t)
+ }
+}
+
+pub fn cvt_r<T, F>(mut f: F) -> crate::io::Result<T>
+ where T: IsMinusOne,
+ F: FnMut() -> T
+{
+ loop {
+ match cvt(f()) {
+ Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
+ other => return other,
+ }
+ }
+}
+
+// On Unix-like platforms, libc::abort will unregister signal handlers
+// including the SIGABRT handler, preventing the abort from being blocked, and
+// fclose streams, with the side effect of flushing them so libc bufferred
+// output will be printed. Additionally the shell will generally print a more
+// understandable error message like "Abort trap" rather than "Illegal
+// instruction" that intrinsics::abort would cause, as intrinsics::abort is
+// implemented as an illegal instruction.
+pub unsafe fn abort_internal() -> ! {
+ libc::abort()
+}
diff --git a/src/libstd/sys/unix/mutex.rs b/src/libstd/sys/unix/mutex.rs
new file mode 100644
index 0000000..b6a22e1
--- /dev/null
+++ b/src/libstd/sys/unix/mutex.rs
@@ -0,0 +1,127 @@
+use crate::cell::UnsafeCell;
+use crate::mem;
+
+pub struct Mutex { inner: UnsafeCell<libc::pthread_mutex_t> }
+
+#[inline]
+pub unsafe fn raw(m: &Mutex) -> *mut libc::pthread_mutex_t {
+ m.inner.get()
+}
+
+unsafe impl Send for Mutex {}
+unsafe impl Sync for Mutex {}
+
+#[allow(dead_code)] // sys isn't exported yet
+impl Mutex {
+ pub const fn new() -> Mutex {
+ // Might be moved to a different address, so it is better to avoid
+ // initialization of potentially opaque OS data before it landed.
+ // Be very careful using this newly constructed `Mutex`, reentrant
+ // locking is undefined behavior until `init` is called!
+ Mutex { inner: UnsafeCell::new(libc::PTHREAD_MUTEX_INITIALIZER) }
+ }
+ #[inline]
+ pub unsafe fn init(&mut self) {
+ // Issue #33770
+ //
+ // A pthread mutex initialized with PTHREAD_MUTEX_INITIALIZER will have
+ // a type of PTHREAD_MUTEX_DEFAULT, which has undefined behavior if you
+ // try to re-lock it from the same thread when you already hold a lock.
+ //
+ // In practice, glibc takes advantage of this undefined behavior to
+ // implement hardware lock elision, which uses hardware transactional
+ // memory to avoid acquiring the lock. While a transaction is in
+ // progress, the lock appears to be unlocked. This isn't a problem for
+ // other threads since the transactional memory will abort if a conflict
+ // is detected, however no abort is generated if re-locking from the
+ // same thread.
+ //
+ // Since locking the same mutex twice will result in two aliasing &mut
+ // references, we instead create the mutex with type
+ // PTHREAD_MUTEX_NORMAL which is guaranteed to deadlock if we try to
+ // re-lock it from the same thread, thus avoiding undefined behavior.
+ let mut attr: libc::pthread_mutexattr_t = mem::uninitialized();
+ let r = libc::pthread_mutexattr_init(&mut attr);
+ debug_assert_eq!(r, 0);
+ let r = libc::pthread_mutexattr_settype(&mut attr, libc::PTHREAD_MUTEX_NORMAL);
+ debug_assert_eq!(r, 0);
+ let r = libc::pthread_mutex_init(self.inner.get(), &attr);
+ debug_assert_eq!(r, 0);
+ let r = libc::pthread_mutexattr_destroy(&mut attr);
+ debug_assert_eq!(r, 0);
+ }
+ #[inline]
+ pub unsafe fn lock(&self) {
+ let r = libc::pthread_mutex_lock(self.inner.get());
+ debug_assert_eq!(r, 0);
+ }
+ #[inline]
+ pub unsafe fn unlock(&self) {
+ let r = libc::pthread_mutex_unlock(self.inner.get());
+ debug_assert_eq!(r, 0);
+ }
+ #[inline]
+ pub unsafe fn try_lock(&self) -> bool {
+ libc::pthread_mutex_trylock(self.inner.get()) == 0
+ }
+ #[inline]
+ #[cfg(not(target_os = "dragonfly"))]
+ pub unsafe fn destroy(&self) {
+ let r = libc::pthread_mutex_destroy(self.inner.get());
+ debug_assert_eq!(r, 0);
+ }
+ #[inline]
+ #[cfg(target_os = "dragonfly")]
+ pub unsafe fn destroy(&self) {
+ let r = libc::pthread_mutex_destroy(self.inner.get());
+ // On DragonFly pthread_mutex_destroy() returns EINVAL if called on a
+ // mutex that was just initialized with libc::PTHREAD_MUTEX_INITIALIZER.
+ // Once it is used (locked/unlocked) or pthread_mutex_init() is called,
+ // this behaviour no longer occurs.
+ debug_assert!(r == 0 || r == libc::EINVAL);
+ }
+}
+
+pub struct ReentrantMutex { inner: UnsafeCell<libc::pthread_mutex_t> }
+
+unsafe impl Send for ReentrantMutex {}
+unsafe impl Sync for ReentrantMutex {}
+
+impl ReentrantMutex {
+ pub unsafe fn uninitialized() -> ReentrantMutex {
+ ReentrantMutex { inner: mem::uninitialized() }
+ }
+
+ pub unsafe fn init(&mut self) {
+ let mut attr: libc::pthread_mutexattr_t = mem::uninitialized();
+ let result = libc::pthread_mutexattr_init(&mut attr as *mut _);
+ debug_assert_eq!(result, 0);
+ let result = libc::pthread_mutexattr_settype(&mut attr as *mut _,
+ libc::PTHREAD_MUTEX_RECURSIVE);
+ debug_assert_eq!(result, 0);
+ let result = libc::pthread_mutex_init(self.inner.get(), &attr as *const _);
+ debug_assert_eq!(result, 0);
+ let result = libc::pthread_mutexattr_destroy(&mut attr as *mut _);
+ debug_assert_eq!(result, 0);
+ }
+
+ pub unsafe fn lock(&self) {
+ let result = libc::pthread_mutex_lock(self.inner.get());
+ debug_assert_eq!(result, 0);
+ }
+
+ #[inline]
+ pub unsafe fn try_lock(&self) -> bool {
+ libc::pthread_mutex_trylock(self.inner.get()) == 0
+ }
+
+ pub unsafe fn unlock(&self) {
+ let result = libc::pthread_mutex_unlock(self.inner.get());
+ debug_assert_eq!(result, 0);
+ }
+
+ pub unsafe fn destroy(&self) {
+ let result = libc::pthread_mutex_destroy(self.inner.get());
+ debug_assert_eq!(result, 0);
+ }
+}
diff --git a/src/libstd/sys/unix/net.rs b/src/libstd/sys/unix/net.rs
new file mode 100644
index 0000000..7712a41
--- /dev/null
+++ b/src/libstd/sys/unix/net.rs
@@ -0,0 +1,401 @@
+use crate::ffi::CStr;
+use crate::io::{self, IoVec, IoVecMut};
+use crate::mem;
+use crate::net::{SocketAddr, Shutdown};
+use crate::str;
+use crate::sys::fd::FileDesc;
+use crate::sys_common::{AsInner, FromInner, IntoInner};
+use crate::sys_common::net::{getsockopt, setsockopt, sockaddr_to_addr};
+use crate::time::{Duration, Instant};
+use crate::cmp;
+
+use libc::{c_int, c_void, size_t, sockaddr, socklen_t, EAI_SYSTEM, MSG_PEEK};
+
+pub use crate::sys::{cvt, cvt_r};
+
+#[allow(unused_extern_crates)]
+pub extern crate libc as netc;
+
+pub type wrlen_t = size_t;
+
+// See below for the usage of SOCK_CLOEXEC, but this constant is only defined on
+// Linux currently (e.g., support doesn't exist on other platforms). In order to
+// get name resolution to work and things to compile we just define a dummy
+// SOCK_CLOEXEC here for other platforms. Note that the dummy constant isn't
+// actually ever used (the blocks below are wrapped in `if cfg!` as well.
+#[cfg(target_os = "linux")]
+use libc::SOCK_CLOEXEC;
+#[cfg(not(target_os = "linux"))]
+const SOCK_CLOEXEC: c_int = 0;
+
+// Another conditional constant for name resolution: Macos et iOS use
+// SO_NOSIGPIPE as a setsockopt flag to disable SIGPIPE emission on socket.
+// Other platforms do otherwise.
+#[cfg(target_vendor = "apple")]
+use libc::SO_NOSIGPIPE;
+#[cfg(not(target_vendor = "apple"))]
+const SO_NOSIGPIPE: c_int = 0;
+
+pub struct Socket(FileDesc);
+
+pub fn init() {}
+
+pub fn cvt_gai(err: c_int) -> io::Result<()> {
+ if err == 0 {
+ return Ok(())
+ }
+
+ // We may need to trigger a glibc workaround. See on_resolver_failure() for details.
+ on_resolver_failure();
+
+ if err == EAI_SYSTEM {
+ return Err(io::Error::last_os_error())
+ }
+
+ let detail = unsafe {
+ str::from_utf8(CStr::from_ptr(libc::gai_strerror(err)).to_bytes()).unwrap()
+ .to_owned()
+ };
+ Err(io::Error::new(io::ErrorKind::Other,
+ &format!("failed to lookup address information: {}",
+ detail)[..]))
+}
+
+impl Socket {
+ pub fn new(addr: &SocketAddr, ty: c_int) -> io::Result<Socket> {
+ let fam = match *addr {
+ SocketAddr::V4(..) => libc::AF_INET,
+ SocketAddr::V6(..) => libc::AF_INET6,
+ };
+ Socket::new_raw(fam, ty)
+ }
+
+ pub fn new_raw(fam: c_int, ty: c_int) -> io::Result<Socket> {
+ unsafe {
+ // On linux we first attempt to pass the SOCK_CLOEXEC flag to
+ // atomically create the socket and set it as CLOEXEC. Support for
+ // this option, however, was added in 2.6.27, and we still support
+ // 2.6.18 as a kernel, so if the returned error is EINVAL we
+ // fallthrough to the fallback.
+ if cfg!(target_os = "linux") {
+ match cvt(libc::socket(fam, ty | SOCK_CLOEXEC, 0)) {
+ Ok(fd) => return Ok(Socket(FileDesc::new(fd))),
+ Err(ref e) if e.raw_os_error() == Some(libc::EINVAL) => {}
+ Err(e) => return Err(e),
+ }
+ }
+
+ let fd = cvt(libc::socket(fam, ty, 0))?;
+ let fd = FileDesc::new(fd);
+ fd.set_cloexec()?;
+ let socket = Socket(fd);
+ if cfg!(target_vendor = "apple") {
+ setsockopt(&socket, libc::SOL_SOCKET, SO_NOSIGPIPE, 1)?;
+ }
+ Ok(socket)
+ }
+ }
+
+ pub fn new_pair(fam: c_int, ty: c_int) -> io::Result<(Socket, Socket)> {
+ unsafe {
+ let mut fds = [0, 0];
+
+ // Like above, see if we can set cloexec atomically
+ if cfg!(target_os = "linux") {
+ match cvt(libc::socketpair(fam, ty | SOCK_CLOEXEC, 0, fds.as_mut_ptr())) {
+ Ok(_) => {
+ return Ok((Socket(FileDesc::new(fds[0])), Socket(FileDesc::new(fds[1]))));
+ }
+ Err(ref e) if e.raw_os_error() == Some(libc::EINVAL) => {},
+ Err(e) => return Err(e),
+ }
+ }
+
+ cvt(libc::socketpair(fam, ty, 0, fds.as_mut_ptr()))?;
+ let a = FileDesc::new(fds[0]);
+ let b = FileDesc::new(fds[1]);
+ a.set_cloexec()?;
+ b.set_cloexec()?;
+ Ok((Socket(a), Socket(b)))
+ }
+ }
+
+ pub fn connect_timeout(&self, addr: &SocketAddr, timeout: Duration) -> io::Result<()> {
+ self.set_nonblocking(true)?;
+ let r = unsafe {
+ let (addrp, len) = addr.into_inner();
+ cvt(libc::connect(self.0.raw(), addrp, len))
+ };
+ self.set_nonblocking(false)?;
+
+ match r {
+ Ok(_) => return Ok(()),
+ // there's no ErrorKind for EINPROGRESS :(
+ Err(ref e) if e.raw_os_error() == Some(libc::EINPROGRESS) => {}
+ Err(e) => return Err(e),
+ }
+
+ let mut pollfd = libc::pollfd {
+ fd: self.0.raw(),
+ events: libc::POLLOUT,
+ revents: 0,
+ };
+
+ if timeout.as_secs() == 0 && timeout.subsec_nanos() == 0 {
+ return Err(io::Error::new(io::ErrorKind::InvalidInput,
+ "cannot set a 0 duration timeout"));
+ }
+
+ let start = Instant::now();
+
+ loop {
+ let elapsed = start.elapsed();
+ if elapsed >= timeout {
+ return Err(io::Error::new(io::ErrorKind::TimedOut, "connection timed out"));
+ }
+
+ let timeout = timeout - elapsed;
+ let mut timeout = timeout.as_secs()
+ .saturating_mul(1_000)
+ .saturating_add(timeout.subsec_nanos() as u64 / 1_000_000);
+ if timeout == 0 {
+ timeout = 1;
+ }
+
+ let timeout = cmp::min(timeout, c_int::max_value() as u64) as c_int;
+
+ match unsafe { libc::poll(&mut pollfd, 1, timeout) } {
+ -1 => {
+ let err = io::Error::last_os_error();
+ if err.kind() != io::ErrorKind::Interrupted {
+ return Err(err);
+ }
+ }
+ 0 => {}
+ _ => {
+ // linux returns POLLOUT|POLLERR|POLLHUP for refused connections (!), so look
+ // for POLLHUP rather than read readiness
+ if pollfd.revents & libc::POLLHUP != 0 {
+ let e = self.take_error()?
+ .unwrap_or_else(|| {
+ io::Error::new(io::ErrorKind::Other, "no error set after POLLHUP")
+ });
+ return Err(e);
+ }
+
+ return Ok(());
+ }
+ }
+ }
+ }
+
+ pub fn accept(&self, storage: *mut sockaddr, len: *mut socklen_t)
+ -> io::Result<Socket> {
+ // Unfortunately the only known way right now to accept a socket and
+ // atomically set the CLOEXEC flag is to use the `accept4` syscall on
+ // Linux. This was added in 2.6.28, however, and because we support
+ // 2.6.18 we must detect this support dynamically.
+ if cfg!(target_os = "linux") {
+ syscall! {
+ fn accept4(
+ fd: c_int,
+ addr: *mut sockaddr,
+ addr_len: *mut socklen_t,
+ flags: c_int
+ ) -> c_int
+ }
+ let res = cvt_r(|| unsafe {
+ accept4(self.0.raw(), storage, len, SOCK_CLOEXEC)
+ });
+ match res {
+ Ok(fd) => return Ok(Socket(FileDesc::new(fd))),
+ Err(ref e) if e.raw_os_error() == Some(libc::ENOSYS) => {}
+ Err(e) => return Err(e),
+ }
+ }
+
+ let fd = cvt_r(|| unsafe {
+ libc::accept(self.0.raw(), storage, len)
+ })?;
+ let fd = FileDesc::new(fd);
+ fd.set_cloexec()?;
+ Ok(Socket(fd))
+ }
+
+ pub fn duplicate(&self) -> io::Result<Socket> {
+ self.0.duplicate().map(Socket)
+ }
+
+ fn recv_with_flags(&self, buf: &mut [u8], flags: c_int) -> io::Result<usize> {
+ let ret = cvt(unsafe {
+ libc::recv(self.0.raw(),
+ buf.as_mut_ptr() as *mut c_void,
+ buf.len(),
+ flags)
+ })?;
+ Ok(ret as usize)
+ }
+
+ pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
+ self.recv_with_flags(buf, 0)
+ }
+
+ pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
+ self.recv_with_flags(buf, MSG_PEEK)
+ }
+
+ pub fn read_vectored(&self, bufs: &mut [IoVecMut<'_>]) -> io::Result<usize> {
+ self.0.read_vectored(bufs)
+ }
+
+ fn recv_from_with_flags(&self, buf: &mut [u8], flags: c_int)
+ -> io::Result<(usize, SocketAddr)> {
+ let mut storage: libc::sockaddr_storage = unsafe { mem::zeroed() };
+ let mut addrlen = mem::size_of_val(&storage) as libc::socklen_t;
+
+ let n = cvt(unsafe {
+ libc::recvfrom(self.0.raw(),
+ buf.as_mut_ptr() as *mut c_void,
+ buf.len(),
+ flags,
+ &mut storage as *mut _ as *mut _,
+ &mut addrlen)
+ })?;
+ Ok((n as usize, sockaddr_to_addr(&storage, addrlen as usize)?))
+ }
+
+ pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+ self.recv_from_with_flags(buf, 0)
+ }
+
+ pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+ self.recv_from_with_flags(buf, MSG_PEEK)
+ }
+
+ pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
+ self.0.write(buf)
+ }
+
+ pub fn write_vectored(&self, bufs: &[IoVec<'_>]) -> io::Result<usize> {
+ self.0.write_vectored(bufs)
+ }
+
+ pub fn set_timeout(&self, dur: Option<Duration>, kind: libc::c_int) -> io::Result<()> {
+ let timeout = match dur {
+ Some(dur) => {
+ if dur.as_secs() == 0 && dur.subsec_nanos() == 0 {
+ return Err(io::Error::new(io::ErrorKind::InvalidInput,
+ "cannot set a 0 duration timeout"));
+ }
+
+ let secs = if dur.as_secs() > libc::time_t::max_value() as u64 {
+ libc::time_t::max_value()
+ } else {
+ dur.as_secs() as libc::time_t
+ };
+ let mut timeout = libc::timeval {
+ tv_sec: secs,
+ tv_usec: (dur.subsec_nanos() / 1000) as libc::suseconds_t,
+ };
+ if timeout.tv_sec == 0 && timeout.tv_usec == 0 {
+ timeout.tv_usec = 1;
+ }
+ timeout
+ }
+ None => {
+ libc::timeval {
+ tv_sec: 0,
+ tv_usec: 0,
+ }
+ }
+ };
+ setsockopt(self, libc::SOL_SOCKET, kind, timeout)
+ }
+
+ pub fn timeout(&self, kind: libc::c_int) -> io::Result<Option<Duration>> {
+ let raw: libc::timeval = getsockopt(self, libc::SOL_SOCKET, kind)?;
+ if raw.tv_sec == 0 && raw.tv_usec == 0 {
+ Ok(None)
+ } else {
+ let sec = raw.tv_sec as u64;
+ let nsec = (raw.tv_usec as u32) * 1000;
+ Ok(Some(Duration::new(sec, nsec)))
+ }
+ }
+
+ pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
+ let how = match how {
+ Shutdown::Write => libc::SHUT_WR,
+ Shutdown::Read => libc::SHUT_RD,
+ Shutdown::Both => libc::SHUT_RDWR,
+ };
+ cvt(unsafe { libc::shutdown(self.0.raw(), how) })?;
+ Ok(())
+ }
+
+ pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> {
+ setsockopt(self, libc::IPPROTO_TCP, libc::TCP_NODELAY, nodelay as c_int)
+ }
+
+ pub fn nodelay(&self) -> io::Result<bool> {
+ let raw: c_int = getsockopt(self, libc::IPPROTO_TCP, libc::TCP_NODELAY)?;
+ Ok(raw != 0)
+ }
+
+ pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
+ let mut nonblocking = nonblocking as libc::c_int;
+ cvt(unsafe { libc::ioctl(*self.as_inner(), libc::FIONBIO, &mut nonblocking) }).map(|_| ())
+ }
+
+ pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+ let raw: c_int = getsockopt(self, libc::SOL_SOCKET, libc::SO_ERROR)?;
+ if raw == 0 {
+ Ok(None)
+ } else {
+ Ok(Some(io::Error::from_raw_os_error(raw as i32)))
+ }
+ }
+}
+
+impl AsInner<c_int> for Socket {
+ fn as_inner(&self) -> &c_int { self.0.as_inner() }
+}
+
+impl FromInner<c_int> for Socket {
+ fn from_inner(fd: c_int) -> Socket { Socket(FileDesc::new(fd)) }
+}
+
+impl IntoInner<c_int> for Socket {
+ fn into_inner(self) -> c_int { self.0.into_raw() }
+}
+
+// In versions of glibc prior to 2.26, there's a bug where the DNS resolver
+// will cache the contents of /etc/resolv.conf, so changes to that file on disk
+// can be ignored by a long-running program. That can break DNS lookups on e.g.
+// laptops where the network comes and goes. See
+// https://sourceware.org/bugzilla/show_bug.cgi?id=984. Note however that some
+// distros including Debian have patched glibc to fix this for a long time.
+//
+// A workaround for this bug is to call the res_init libc function, to clear
+// the cached configs. Unfortunately, while we believe glibc's implementation
+// of res_init is thread-safe, we know that other implementations are not
+// (https://github.com/rust-lang/rust/issues/43592). Code here in libstd could
+// try to synchronize its res_init calls with a Mutex, but that wouldn't
+// protect programs that call into libc in other ways. So instead of calling
+// res_init unconditionally, we call it only when we detect we're linking
+// against glibc version < 2.26. (That is, when we both know its needed and
+// believe it's thread-safe).
+#[cfg(target_env = "gnu")]
+fn on_resolver_failure() {
+ use crate::sys;
+
+ // If the version fails to parse, we treat it the same as "not glibc".
+ if let Some(version) = sys::os::glibc_version() {
+ if version < (2, 26) {
+ unsafe { libc::res_init() };
+ }
+ }
+}
+
+#[cfg(not(target_env = "gnu"))]
+fn on_resolver_failure() {}
diff --git a/src/libstd/sys/unix/os.rs b/src/libstd/sys/unix/os.rs
new file mode 100644
index 0000000..726b179
--- /dev/null
+++ b/src/libstd/sys/unix/os.rs
@@ -0,0 +1,609 @@
+//! Implementation of `std::os` functionality for unix systems
+
+#![allow(unused_imports)] // lots of cfg code here
+
+use crate::os::unix::prelude::*;
+
+use crate::error::Error as StdError;
+use crate::ffi::{CString, CStr, OsString, OsStr};
+use crate::fmt;
+use crate::io;
+use crate::iter;
+use crate::marker::PhantomData;
+use crate::mem;
+use crate::memchr;
+use crate::path::{self, PathBuf};
+use crate::ptr;
+use crate::slice;
+use crate::str;
+use crate::sys_common::mutex::{Mutex, MutexGuard};
+use crate::sys::cvt;
+use crate::sys::fd;
+use crate::vec;
+
+use libc::{c_int, c_char, c_void};
+
+const TMPBUF_SZ: usize = 128;
+
+
+extern {
+ #[cfg(not(target_os = "dragonfly"))]
+ #[cfg_attr(any(target_os = "linux",
+ target_os = "emscripten",
+ target_os = "fuchsia",
+ target_os = "l4re"),
+ link_name = "__errno_location")]
+ #[cfg_attr(any(target_os = "bitrig",
+ target_os = "netbsd",
+ target_os = "openbsd",
+ target_os = "android",
+ target_os = "hermit",
+ target_env = "newlib"),
+ link_name = "__errno")]
+ #[cfg_attr(target_os = "solaris", link_name = "___errno")]
+ #[cfg_attr(any(target_os = "macos",
+ target_os = "ios",
+ target_os = "freebsd"),
+ link_name = "__error")]
+ #[cfg_attr(target_os = "haiku", link_name = "_errnop")]
+ fn errno_location() -> *mut c_int;
+}
+
+/// Returns the platform-specific value of errno
+#[cfg(not(target_os = "dragonfly"))]
+pub fn errno() -> i32 {
+ unsafe {
+ (*errno_location()) as i32
+ }
+}
+
+/// Sets the platform-specific value of errno
+#[cfg(all(not(target_os = "linux"),
+ not(target_os = "dragonfly")))] // needed for readdir and syscall!
+pub fn set_errno(e: i32) {
+ unsafe {
+ *errno_location() = e as c_int
+ }
+}
+
+#[cfg(target_os = "dragonfly")]
+pub fn errno() -> i32 {
+ extern {
+ #[thread_local]
+ static errno: c_int;
+ }
+
+ unsafe { errno as i32 }
+}
+
+#[cfg(target_os = "dragonfly")]
+pub fn set_errno(e: i32) {
+ extern {
+ #[thread_local]
+ static mut errno: c_int;
+ }
+
+ unsafe {
+ errno = e;
+ }
+}
+
+/// Gets a detailed string description for the given error number.
+pub fn error_string(errno: i32) -> String {
+ extern {
+ #[cfg_attr(any(target_os = "linux", target_env = "newlib"),
+ link_name = "__xpg_strerror_r")]
+ fn strerror_r(errnum: c_int, buf: *mut c_char,
+ buflen: libc::size_t) -> c_int;
+ }
+
+ let mut buf = [0 as c_char; TMPBUF_SZ];
+
+ let p = buf.as_mut_ptr();
+ unsafe {
+ if strerror_r(errno as c_int, p, buf.len()) < 0 {
+ panic!("strerror_r failure");
+ }
+
+ let p = p as *const _;
+ str::from_utf8(CStr::from_ptr(p).to_bytes()).unwrap().to_owned()
+ }
+}
+
+pub fn getcwd() -> io::Result<PathBuf> {
+ let mut buf = Vec::with_capacity(512);
+ loop {
+ unsafe {
+ let ptr = buf.as_mut_ptr() as *mut libc::c_char;
+ if !libc::getcwd(ptr, buf.capacity()).is_null() {
+ let len = CStr::from_ptr(buf.as_ptr() as *const libc::c_char).to_bytes().len();
+ buf.set_len(len);
+ buf.shrink_to_fit();
+ return Ok(PathBuf::from(OsString::from_vec(buf)));
+ } else {
+ let error = io::Error::last_os_error();
+ if error.raw_os_error() != Some(libc::ERANGE) {
+ return Err(error);
+ }
+ }
+
+ // Trigger the internal buffer resizing logic of `Vec` by requiring
+ // more space than the current capacity.
+ let cap = buf.capacity();
+ buf.set_len(cap);
+ buf.reserve(1);
+ }
+ }
+}
+
+pub fn chdir(p: &path::Path) -> io::Result<()> {
+ let p: &OsStr = p.as_ref();
+ let p = CString::new(p.as_bytes())?;
+ unsafe {
+ match libc::chdir(p.as_ptr()) == (0 as c_int) {
+ true => Ok(()),
+ false => Err(io::Error::last_os_error()),
+ }
+ }
+}
+
+pub struct SplitPaths<'a> {
+ iter: iter::Map<slice::Split<'a, u8, fn(&u8) -> bool>,
+ fn(&'a [u8]) -> PathBuf>,
+}
+
+pub fn split_paths(unparsed: &OsStr) -> SplitPaths<'_> {
+ fn bytes_to_path(b: &[u8]) -> PathBuf {
+ PathBuf::from(<OsStr as OsStrExt>::from_bytes(b))
+ }
+ fn is_colon(b: &u8) -> bool { *b == b':' }
+ let unparsed = unparsed.as_bytes();
+ SplitPaths {
+ iter: unparsed.split(is_colon as fn(&u8) -> bool)
+ .map(bytes_to_path as fn(&[u8]) -> PathBuf)
+ }
+}
+
+impl<'a> Iterator for SplitPaths<'a> {
+ type Item = PathBuf;
+ fn next(&mut self) -> Option<PathBuf> { self.iter.next() }
+ fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
+}
+
+#[derive(Debug)]
+pub struct JoinPathsError;
+
+pub fn join_paths<I, T>(paths: I) -> Result<OsString, JoinPathsError>
+ where I: Iterator<Item=T>, T: AsRef<OsStr>
+{
+ let mut joined = Vec::new();
+ let sep = b':';
+
+ for (i, path) in paths.enumerate() {
+ let path = path.as_ref().as_bytes();
+ if i > 0 { joined.push(sep) }
+ if path.contains(&sep) {
+ return Err(JoinPathsError)
+ }
+ joined.extend_from_slice(path);
+ }
+ Ok(OsStringExt::from_vec(joined))
+}
+
+impl fmt::Display for JoinPathsError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ "path segment contains separator `:`".fmt(f)
+ }
+}
+
+impl StdError for JoinPathsError {
+ fn description(&self) -> &str { "failed to join paths" }
+}
+
+#[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
+pub fn current_exe() -> io::Result<PathBuf> {
+ unsafe {
+ let mut mib = [libc::CTL_KERN as c_int,
+ libc::KERN_PROC as c_int,
+ libc::KERN_PROC_PATHNAME as c_int,
+ -1 as c_int];
+ let mut sz = 0;
+ cvt(libc::sysctl(mib.as_mut_ptr(), mib.len() as libc::c_uint,
+ ptr::null_mut(), &mut sz, ptr::null_mut(), 0))?;
+ if sz == 0 {
+ return Err(io::Error::last_os_error())
+ }
+ let mut v: Vec<u8> = Vec::with_capacity(sz);
+ cvt(libc::sysctl(mib.as_mut_ptr(), mib.len() as libc::c_uint,
+ v.as_mut_ptr() as *mut libc::c_void, &mut sz,
+ ptr::null_mut(), 0))?;
+ if sz == 0 {
+ return Err(io::Error::last_os_error());
+ }
+ v.set_len(sz - 1); // chop off trailing NUL
+ Ok(PathBuf::from(OsString::from_vec(v)))
+ }
+}
+
+#[cfg(target_os = "netbsd")]
+pub fn current_exe() -> io::Result<PathBuf> {
+ fn sysctl() -> io::Result<PathBuf> {
+ unsafe {
+ let mib = [libc::CTL_KERN, libc::KERN_PROC_ARGS, -1, libc::KERN_PROC_PATHNAME];
+ let mut path_len: usize = 0;
+ cvt(libc::sysctl(mib.as_ptr(), mib.len() as libc::c_uint,
+ ptr::null_mut(), &mut path_len,
+ ptr::null(), 0))?;
+ if path_len <= 1 {
+ return Err(io::Error::new(io::ErrorKind::Other,
+ "KERN_PROC_PATHNAME sysctl returned zero-length string"))
+ }
+ let mut path: Vec<u8> = Vec::with_capacity(path_len);
+ cvt(libc::sysctl(mib.as_ptr(), mib.len() as libc::c_uint,
+ path.as_ptr() as *mut libc::c_void, &mut path_len,
+ ptr::null(), 0))?;
+ path.set_len(path_len - 1); // chop off NUL
+ Ok(PathBuf::from(OsString::from_vec(path)))
+ }
+ }
+ fn procfs() -> io::Result<PathBuf> {
+ let curproc_exe = path::Path::new("/proc/curproc/exe");
+ if curproc_exe.is_file() {
+ return crate::fs::read_link(curproc_exe);
+ }
+ Err(io::Error::new(io::ErrorKind::Other,
+ "/proc/curproc/exe doesn't point to regular file."))
+ }
+ sysctl().or_else(|_| procfs())
+}
+
+#[cfg(any(target_os = "bitrig", target_os = "openbsd"))]
+pub fn current_exe() -> io::Result<PathBuf> {
+ unsafe {
+ let mut mib = [libc::CTL_KERN,
+ libc::KERN_PROC_ARGS,
+ libc::getpid(),
+ libc::KERN_PROC_ARGV];
+ let mib = mib.as_mut_ptr();
+ let mut argv_len = 0;
+ cvt(libc::sysctl(mib, 4, ptr::null_mut(), &mut argv_len,
+ ptr::null_mut(), 0))?;
+ let mut argv = Vec::<*const libc::c_char>::with_capacity(argv_len as usize);
+ cvt(libc::sysctl(mib, 4, argv.as_mut_ptr() as *mut _,
+ &mut argv_len, ptr::null_mut(), 0))?;
+ argv.set_len(argv_len as usize);
+ if argv[0].is_null() {
+ return Err(io::Error::new(io::ErrorKind::Other,
+ "no current exe available"))
+ }
+ let argv0 = CStr::from_ptr(argv[0]).to_bytes();
+ if argv0[0] == b'.' || argv0.iter().any(|b| *b == b'/') {
+ crate::fs::canonicalize(OsStr::from_bytes(argv0))
+ } else {
+ Ok(PathBuf::from(OsStr::from_bytes(argv0)))
+ }
+ }
+}
+
+#[cfg(any(target_os = "linux", target_os = "android", target_os = "emscripten"))]
+pub fn current_exe() -> io::Result<PathBuf> {
+ match crate::fs::read_link("/proc/self/exe") {
+ Err(ref e) if e.kind() == io::ErrorKind::NotFound => {
+ Err(io::Error::new(
+ io::ErrorKind::Other,
+ "no /proc/self/exe available. Is /proc mounted?"
+ ))
+ },
+ other => other,
+ }
+}
+
+#[cfg(any(target_os = "macos", target_os = "ios"))]
+pub fn current_exe() -> io::Result<PathBuf> {
+ extern {
+ fn _NSGetExecutablePath(buf: *mut libc::c_char,
+ bufsize: *mut u32) -> libc::c_int;
+ }
+ unsafe {
+ let mut sz: u32 = 0;
+ _NSGetExecutablePath(ptr::null_mut(), &mut sz);
+ if sz == 0 { return Err(io::Error::last_os_error()); }
+ let mut v: Vec<u8> = Vec::with_capacity(sz as usize);
+ let err = _NSGetExecutablePath(v.as_mut_ptr() as *mut i8, &mut sz);
+ if err != 0 { return Err(io::Error::last_os_error()); }
+ v.set_len(sz as usize - 1); // chop off trailing NUL
+ Ok(PathBuf::from(OsString::from_vec(v)))
+ }
+}
+
+#[cfg(any(target_os = "solaris"))]
+pub fn current_exe() -> io::Result<PathBuf> {
+ extern {
+ fn getexecname() -> *const c_char;
+ }
+ unsafe {
+ let path = getexecname();
+ if path.is_null() {
+ Err(io::Error::last_os_error())
+ } else {
+ let filename = CStr::from_ptr(path).to_bytes();
+ let path = PathBuf::from(<OsStr as OsStrExt>::from_bytes(filename));
+
+ // Prepend a current working directory to the path if
+ // it doesn't contain an absolute pathname.
+ if filename[0] == b'/' {
+ Ok(path)
+ } else {
+ getcwd().map(|cwd| cwd.join(path))
+ }
+ }
+ }
+}
+
+#[cfg(target_os = "haiku")]
+pub fn current_exe() -> io::Result<PathBuf> {
+ // Use Haiku's image info functions
+ #[repr(C)]
+ struct image_info {
+ id: i32,
+ type_: i32,
+ sequence: i32,
+ init_order: i32,
+ init_routine: *mut libc::c_void, // function pointer
+ term_routine: *mut libc::c_void, // function pointer
+ device: libc::dev_t,
+ node: libc::ino_t,
+ name: [libc::c_char; 1024], // MAXPATHLEN
+ text: *mut libc::c_void,
+ data: *mut libc::c_void,
+ text_size: i32,
+ data_size: i32,
+ api_version: i32,
+ abi: i32,
+ }
+
+ unsafe {
+ extern {
+ fn _get_next_image_info(team_id: i32, cookie: *mut i32,
+ info: *mut image_info, size: i32) -> i32;
+ }
+
+ let mut info: image_info = mem::zeroed();
+ let mut cookie: i32 = 0;
+ // the executable can be found at team id 0
+ let result = _get_next_image_info(0, &mut cookie, &mut info,
+ mem::size_of::<image_info>() as i32);
+ if result != 0 {
+ use crate::io::ErrorKind;
+ Err(io::Error::new(ErrorKind::Other, "Error getting executable path"))
+ } else {
+ let name = CStr::from_ptr(info.name.as_ptr()).to_bytes();
+ Ok(PathBuf::from(OsStr::from_bytes(name)))
+ }
+ }
+}
+
+#[cfg(any(target_os = "fuchsia", target_os = "l4re", target_os = "hermit"))]
+pub fn current_exe() -> io::Result<PathBuf> {
+ use crate::io::ErrorKind;
+ Err(io::Error::new(ErrorKind::Other, "Not yet implemented!"))
+}
+
+pub struct Env {
+ iter: vec::IntoIter<(OsString, OsString)>,
+ _dont_send_or_sync_me: PhantomData<*mut ()>,
+}
+
+impl Iterator for Env {
+ type Item = (OsString, OsString);
+ fn next(&mut self) -> Option<(OsString, OsString)> { self.iter.next() }
+ fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
+}
+
+#[cfg(target_os = "macos")]
+pub unsafe fn environ() -> *mut *const *const c_char {
+ extern { fn _NSGetEnviron() -> *mut *const *const c_char; }
+ _NSGetEnviron()
+}
+
+#[cfg(not(target_os = "macos"))]
+pub unsafe fn environ() -> *mut *const *const c_char {
+ extern { static mut environ: *const *const c_char; }
+ &mut environ
+}
+
+pub unsafe fn env_lock() -> MutexGuard<'static> {
+ // We never call `ENV_LOCK.init()`, so it is UB to attempt to
+ // acquire this mutex reentrantly!
+ static ENV_LOCK: Mutex = Mutex::new();
+ ENV_LOCK.lock()
+}
+
+/// Returns a vector of (variable, value) byte-vector pairs for all the
+/// environment variables of the current process.
+pub fn env() -> Env {
+ unsafe {
+ let _guard = env_lock();
+ let mut environ = *environ();
+ let mut result = Vec::new();
+ while environ != ptr::null() && *environ != ptr::null() {
+ if let Some(key_value) = parse(CStr::from_ptr(*environ).to_bytes()) {
+ result.push(key_value);
+ }
+ environ = environ.offset(1);
+ }
+ return Env {
+ iter: result.into_iter(),
+ _dont_send_or_sync_me: PhantomData,
+ }
+ }
+
+ fn parse(input: &[u8]) -> Option<(OsString, OsString)> {
+ // Strategy (copied from glibc): Variable name and value are separated
+ // by an ASCII equals sign '='. Since a variable name must not be
+ // empty, allow variable names starting with an equals sign. Skip all
+ // malformed lines.
+ if input.is_empty() {
+ return None;
+ }
+ let pos = memchr::memchr(b'=', &input[1..]).map(|p| p + 1);
+ pos.map(|p| (
+ OsStringExt::from_vec(input[..p].to_vec()),
+ OsStringExt::from_vec(input[p+1..].to_vec()),
+ ))
+ }
+}
+
+pub fn getenv(k: &OsStr) -> io::Result<Option<OsString>> {
+ // environment variables with a nul byte can't be set, so their value is
+ // always None as well
+ let k = CString::new(k.as_bytes())?;
+ unsafe {
+ let _guard = env_lock();
+ let s = libc::getenv(k.as_ptr()) as *const libc::c_char;
+ let ret = if s.is_null() {
+ None
+ } else {
+ Some(OsStringExt::from_vec(CStr::from_ptr(s).to_bytes().to_vec()))
+ };
+ Ok(ret)
+ }
+}
+
+pub fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> {
+ let k = CString::new(k.as_bytes())?;
+ let v = CString::new(v.as_bytes())?;
+
+ unsafe {
+ let _guard = env_lock();
+ cvt(libc::setenv(k.as_ptr(), v.as_ptr(), 1)).map(|_| ())
+ }
+}
+
+pub fn unsetenv(n: &OsStr) -> io::Result<()> {
+ let nbuf = CString::new(n.as_bytes())?;
+
+ unsafe {
+ let _guard = env_lock();
+ cvt(libc::unsetenv(nbuf.as_ptr())).map(|_| ())
+ }
+}
+
+pub fn page_size() -> usize {
+ unsafe {
+ libc::sysconf(libc::_SC_PAGESIZE) as usize
+ }
+}
+
+pub fn temp_dir() -> PathBuf {
+ crate::env::var_os("TMPDIR").map(PathBuf::from).unwrap_or_else(|| {
+ if cfg!(target_os = "android") {
+ PathBuf::from("/data/local/tmp")
+ } else {
+ PathBuf::from("/tmp")
+ }
+ })
+}
+
+pub fn home_dir() -> Option<PathBuf> {
+ return crate::env::var_os("HOME").or_else(|| unsafe {
+ fallback()
+ }).map(PathBuf::from);
+
+ #[cfg(any(target_os = "android",
+ target_os = "ios",
+ target_os = "emscripten"))]
+ unsafe fn fallback() -> Option<OsString> { None }
+ #[cfg(not(any(target_os = "android",
+ target_os = "ios",
+ target_os = "emscripten")))]
+ unsafe fn fallback() -> Option<OsString> {
+ let amt = match libc::sysconf(libc::_SC_GETPW_R_SIZE_MAX) {
+ n if n < 0 => 512 as usize,
+ n => n as usize,
+ };
+ let mut buf = Vec::with_capacity(amt);
+ let mut passwd: libc::passwd = mem::zeroed();
+ let mut result = ptr::null_mut();
+ match libc::getpwuid_r(libc::getuid(), &mut passwd, buf.as_mut_ptr(),
+ buf.capacity(), &mut result) {
+ 0 if !result.is_null() => {
+ let ptr = passwd.pw_dir as *const _;
+ let bytes = CStr::from_ptr(ptr).to_bytes().to_vec();
+ Some(OsStringExt::from_vec(bytes))
+ },
+ _ => None,
+ }
+ }
+}
+
+pub fn exit(code: i32) -> ! {
+ unsafe { libc::exit(code as c_int) }
+}
+
+pub fn getpid() -> u32 {
+ unsafe { libc::getpid() as u32 }
+}
+
+pub fn getppid() -> u32 {
+ unsafe { libc::getppid() as u32 }
+}
+
+#[cfg(target_env = "gnu")]
+pub fn glibc_version() -> Option<(usize, usize)> {
+ if let Some(Ok(version_str)) = glibc_version_cstr().map(CStr::to_str) {
+ parse_glibc_version(version_str)
+ } else {
+ None
+ }
+}
+
+#[cfg(target_env = "gnu")]
+fn glibc_version_cstr() -> Option<&'static CStr> {
+ weak! {
+ fn gnu_get_libc_version() -> *const libc::c_char
+ }
+ if let Some(f) = gnu_get_libc_version.get() {
+ unsafe { Some(CStr::from_ptr(f())) }
+ } else {
+ None
+ }
+}
+
+// Returns Some((major, minor)) if the string is a valid "x.y" version,
+// ignoring any extra dot-separated parts. Otherwise return None.
+#[cfg(target_env = "gnu")]
+fn parse_glibc_version(version: &str) -> Option<(usize, usize)> {
+ let mut parsed_ints = version.split('.').map(str::parse::<usize>).fuse();
+ match (parsed_ints.next(), parsed_ints.next()) {
+ (Some(Ok(major)), Some(Ok(minor))) => Some((major, minor)),
+ _ => None
+ }
+}
+
+#[cfg(all(test, target_env = "gnu"))]
+mod test {
+ use super::*;
+
+ #[test]
+ fn test_glibc_version() {
+ // This mostly just tests that the weak linkage doesn't panic wildly...
+ glibc_version();
+ }
+
+ #[test]
+ fn test_parse_glibc_version() {
+ let cases = [
+ ("0.0", Some((0, 0))),
+ ("01.+2", Some((1, 2))),
+ ("3.4.5.six", Some((3, 4))),
+ ("1", None),
+ ("1.-2", None),
+ ("1.foo", None),
+ ("foo.1", None),
+ ];
+ for &(version_str, parsed) in cases.iter() {
+ assert_eq!(parsed, parse_glibc_version(version_str));
+ }
+ }
+}
diff --git a/src/libstd/sys/unix/path.rs b/src/libstd/sys/unix/path.rs
new file mode 100644
index 0000000..7a18395
--- /dev/null
+++ b/src/libstd/sys/unix/path.rs
@@ -0,0 +1,19 @@
+use crate::path::Prefix;
+use crate::ffi::OsStr;
+
+#[inline]
+pub fn is_sep_byte(b: u8) -> bool {
+ b == b'/'
+}
+
+#[inline]
+pub fn is_verbatim_sep(b: u8) -> bool {
+ b == b'/'
+}
+
+pub fn parse_prefix(_: &OsStr) -> Option<Prefix<'_>> {
+ None
+}
+
+pub const MAIN_SEP_STR: &str = "/";
+pub const MAIN_SEP: char = '/';
diff --git a/src/libstd/sys/unix/pipe.rs b/src/libstd/sys/unix/pipe.rs
new file mode 100644
index 0000000..bc3c026
--- /dev/null
+++ b/src/libstd/sys/unix/pipe.rs
@@ -0,0 +1,120 @@
+use crate::io;
+use crate::mem;
+use crate::sync::atomic::{AtomicBool, Ordering};
+use crate::sys::fd::FileDesc;
+use crate::sys::{cvt, cvt_r};
+
+use libc::c_int;
+
+////////////////////////////////////////////////////////////////////////////////
+// Anonymous pipes
+////////////////////////////////////////////////////////////////////////////////
+
+pub struct AnonPipe(FileDesc);
+
+pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> {
+ syscall! { fn pipe2(fds: *mut c_int, flags: c_int) -> c_int }
+ static INVALID: AtomicBool = AtomicBool::new(false);
+
+ let mut fds = [0; 2];
+
+ // Unfortunately the only known way right now to create atomically set the
+ // CLOEXEC flag is to use the `pipe2` syscall on Linux. This was added in
+ // 2.6.27, however, and because we support 2.6.18 we must detect this
+ // support dynamically.
+ if cfg!(any(target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "linux",
+ target_os = "netbsd",
+ target_os = "openbsd")) &&
+ !INVALID.load(Ordering::SeqCst)
+ {
+
+ // Note that despite calling a glibc function here we may still
+ // get ENOSYS. Glibc has `pipe2` since 2.9 and doesn't try to
+ // emulate on older kernels, so if you happen to be running on
+ // an older kernel you may see `pipe2` as a symbol but still not
+ // see the syscall.
+ match cvt(unsafe { pipe2(fds.as_mut_ptr(), libc::O_CLOEXEC) }) {
+ Ok(_) => {
+ return Ok((AnonPipe(FileDesc::new(fds[0])),
+ AnonPipe(FileDesc::new(fds[1]))));
+ }
+ Err(ref e) if e.raw_os_error() == Some(libc::ENOSYS) => {
+ INVALID.store(true, Ordering::SeqCst);
+ }
+ Err(e) => return Err(e),
+ }
+ }
+ cvt(unsafe { libc::pipe(fds.as_mut_ptr()) })?;
+
+ let fd0 = FileDesc::new(fds[0]);
+ let fd1 = FileDesc::new(fds[1]);
+ fd0.set_cloexec()?;
+ fd1.set_cloexec()?;
+ Ok((AnonPipe(fd0), AnonPipe(fd1)))
+}
+
+impl AnonPipe {
+ pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
+ self.0.read(buf)
+ }
+
+ pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
+ self.0.write(buf)
+ }
+
+ pub fn fd(&self) -> &FileDesc { &self.0 }
+ pub fn into_fd(self) -> FileDesc { self.0 }
+}
+
+pub fn read2(p1: AnonPipe,
+ v1: &mut Vec<u8>,
+ p2: AnonPipe,
+ v2: &mut Vec<u8>) -> io::Result<()> {
+
+ // Set both pipes into nonblocking mode as we're gonna be reading from both
+ // in the `select` loop below, and we wouldn't want one to block the other!
+ let p1 = p1.into_fd();
+ let p2 = p2.into_fd();
+ p1.set_nonblocking(true)?;
+ p2.set_nonblocking(true)?;
+
+ let mut fds: [libc::pollfd; 2] = unsafe { mem::zeroed() };
+ fds[0].fd = p1.raw();
+ fds[0].events = libc::POLLIN;
+ fds[1].fd = p2.raw();
+ fds[1].events = libc::POLLIN;
+ loop {
+ // wait for either pipe to become readable using `poll`
+ cvt_r(|| unsafe { libc::poll(fds.as_mut_ptr(), 2, -1) })?;
+
+ if fds[0].revents != 0 && read(&p1, v1)? {
+ p2.set_nonblocking(false)?;
+ return p2.read_to_end(v2).map(|_| ());
+ }
+ if fds[1].revents != 0 && read(&p2, v2)? {
+ p1.set_nonblocking(false)?;
+ return p1.read_to_end(v1).map(|_| ());
+ }
+ }
+
+ // Read as much as we can from each pipe, ignoring EWOULDBLOCK or
+ // EAGAIN. If we hit EOF, then this will happen because the underlying
+ // reader will return Ok(0), in which case we'll see `Ok` ourselves. In
+ // this case we flip the other fd back into blocking mode and read
+ // whatever's leftover on that file descriptor.
+ fn read(fd: &FileDesc, dst: &mut Vec<u8>) -> Result<bool, io::Error> {
+ match fd.read_to_end(dst) {
+ Ok(_) => Ok(true),
+ Err(e) => {
+ if e.raw_os_error() == Some(libc::EWOULDBLOCK) ||
+ e.raw_os_error() == Some(libc::EAGAIN) {
+ Ok(false)
+ } else {
+ Err(e)
+ }
+ }
+ }
+ }
+}
diff --git a/src/libstd/sys/unix/process/mod.rs b/src/libstd/sys/unix/process/mod.rs
new file mode 100644
index 0000000..bba4b21
--- /dev/null
+++ b/src/libstd/sys/unix/process/mod.rs
@@ -0,0 +1,12 @@
+pub use self::process_common::{Command, ExitStatus, ExitCode, Stdio, StdioPipes};
+pub use self::process_inner::Process;
+
+mod process_common;
+#[cfg(not(target_os = "fuchsia"))]
+#[path = "process_unix.rs"]
+mod process_inner;
+#[cfg(target_os = "fuchsia")]
+#[path = "process_fuchsia.rs"]
+mod process_inner;
+#[cfg(target_os = "fuchsia")]
+mod zircon;
diff --git a/src/libstd/sys/unix/process/process_common.rs b/src/libstd/sys/unix/process/process_common.rs
new file mode 100644
index 0000000..f6a12a1
--- /dev/null
+++ b/src/libstd/sys/unix/process/process_common.rs
@@ -0,0 +1,502 @@
+use crate::os::unix::prelude::*;
+
+use crate::ffi::{OsString, OsStr, CString, CStr};
+use crate::fmt;
+use crate::io;
+use crate::ptr;
+use crate::sys::fd::FileDesc;
+use crate::sys::fs::{File, OpenOptions};
+use crate::sys::pipe::{self, AnonPipe};
+use crate::sys_common::process::{CommandEnv, DefaultEnvKey};
+use crate::collections::BTreeMap;
+
+use libc::{c_int, gid_t, uid_t, c_char, EXIT_SUCCESS, EXIT_FAILURE};
+
+////////////////////////////////////////////////////////////////////////////////
+// Command
+////////////////////////////////////////////////////////////////////////////////
+
+pub struct Command {
+ // Currently we try hard to ensure that the call to `.exec()` doesn't
+ // actually allocate any memory. While many platforms try to ensure that
+ // memory allocation works after a fork in a multithreaded process, it's
+ // been observed to be buggy and somewhat unreliable, so we do our best to
+ // just not do it at all!
+ //
+ // Along those lines, the `argv` and `envp` raw pointers here are exactly
+ // what's gonna get passed to `execvp`. The `argv` array starts with the
+ // `program` and ends with a NULL, and the `envp` pointer, if present, is
+ // also null-terminated.
+ //
+ // Right now we don't support removing arguments, so there's no much fancy
+ // support there, but we support adding and removing environment variables,
+ // so a side table is used to track where in the `envp` array each key is
+ // located. Whenever we add a key we update it in place if it's already
+ // present, and whenever we remove a key we update the locations of all
+ // other keys.
+ program: CString,
+ args: Vec<CString>,
+ argv: Argv,
+ env: CommandEnv<DefaultEnvKey>,
+
+ cwd: Option<CString>,
+ uid: Option<uid_t>,
+ gid: Option<gid_t>,
+ saw_nul: bool,
+ closures: Vec<Box<dyn FnMut() -> io::Result<()> + Send + Sync>>,
+ stdin: Option<Stdio>,
+ stdout: Option<Stdio>,
+ stderr: Option<Stdio>,
+}
+
+// Create a new type for argv, so that we can make it `Send`
+struct Argv(Vec<*const c_char>);
+
+// It is safe to make Argv Send, because it contains pointers to memory owned by `Command.args`
+unsafe impl Send for Argv {}
+
+// passed back to std::process with the pipes connected to the child, if any
+// were requested
+pub struct StdioPipes {
+ pub stdin: Option<AnonPipe>,
+ pub stdout: Option<AnonPipe>,
+ pub stderr: Option<AnonPipe>,
+}
+
+// passed to do_exec() with configuration of what the child stdio should look
+// like
+pub struct ChildPipes {
+ pub stdin: ChildStdio,
+ pub stdout: ChildStdio,
+ pub stderr: ChildStdio,
+}
+
+pub enum ChildStdio {
+ Inherit,
+ Explicit(c_int),
+ Owned(FileDesc),
+}
+
+pub enum Stdio {
+ Inherit,
+ Null,
+ MakePipe,
+ Fd(FileDesc),
+}
+
+impl Command {
+ pub fn new(program: &OsStr) -> Command {
+ let mut saw_nul = false;
+ let program = os2c(program, &mut saw_nul);
+ Command {
+ argv: Argv(vec![program.as_ptr(), ptr::null()]),
+ program,
+ args: Vec::new(),
+ env: Default::default(),
+ cwd: None,
+ uid: None,
+ gid: None,
+ saw_nul,
+ closures: Vec::new(),
+ stdin: None,
+ stdout: None,
+ stderr: None,
+ }
+ }
+
+ pub fn arg(&mut self, arg: &OsStr) {
+ // Overwrite the trailing NULL pointer in `argv` and then add a new null
+ // pointer.
+ let arg = os2c(arg, &mut self.saw_nul);
+ self.argv.0[self.args.len() + 1] = arg.as_ptr();
+ self.argv.0.push(ptr::null());
+
+ // Also make sure we keep track of the owned value to schedule a
+ // destructor for this memory.
+ self.args.push(arg);
+ }
+
+ pub fn cwd(&mut self, dir: &OsStr) {
+ self.cwd = Some(os2c(dir, &mut self.saw_nul));
+ }
+ pub fn uid(&mut self, id: uid_t) {
+ self.uid = Some(id);
+ }
+ pub fn gid(&mut self, id: gid_t) {
+ self.gid = Some(id);
+ }
+
+ pub fn saw_nul(&self) -> bool {
+ self.saw_nul
+ }
+ pub fn get_argv(&self) -> &Vec<*const c_char> {
+ &self.argv.0
+ }
+
+ #[allow(dead_code)]
+ pub fn get_cwd(&self) -> &Option<CString> {
+ &self.cwd
+ }
+ #[allow(dead_code)]
+ pub fn get_uid(&self) -> Option<uid_t> {
+ self.uid
+ }
+ #[allow(dead_code)]
+ pub fn get_gid(&self) -> Option<gid_t> {
+ self.gid
+ }
+
+ pub fn get_closures(&mut self) -> &mut Vec<Box<dyn FnMut() -> io::Result<()> + Send + Sync>> {
+ &mut self.closures
+ }
+
+ pub unsafe fn pre_exec(
+ &mut self,
+ f: Box<dyn FnMut() -> io::Result<()> + Send + Sync>,
+ ) {
+ self.closures.push(f);
+ }
+
+ pub fn stdin(&mut self, stdin: Stdio) {
+ self.stdin = Some(stdin);
+ }
+
+ pub fn stdout(&mut self, stdout: Stdio) {
+ self.stdout = Some(stdout);
+ }
+
+ pub fn stderr(&mut self, stderr: Stdio) {
+ self.stderr = Some(stderr);
+ }
+
+ pub fn env_mut(&mut self) -> &mut CommandEnv<DefaultEnvKey> {
+ &mut self.env
+ }
+
+ pub fn capture_env(&mut self) -> Option<CStringArray> {
+ let maybe_env = self.env.capture_if_changed();
+ maybe_env.map(|env| construct_envp(env, &mut self.saw_nul))
+ }
+ #[allow(dead_code)]
+ pub fn env_saw_path(&self) -> bool {
+ self.env.have_changed_path()
+ }
+
+ pub fn setup_io(&self, default: Stdio, needs_stdin: bool)
+ -> io::Result<(StdioPipes, ChildPipes)> {
+ let null = Stdio::Null;
+ let default_stdin = if needs_stdin {&default} else {&null};
+ let stdin = self.stdin.as_ref().unwrap_or(default_stdin);
+ let stdout = self.stdout.as_ref().unwrap_or(&default);
+ let stderr = self.stderr.as_ref().unwrap_or(&default);
+ let (their_stdin, our_stdin) = stdin.to_child_stdio(true)?;
+ let (their_stdout, our_stdout) = stdout.to_child_stdio(false)?;
+ let (their_stderr, our_stderr) = stderr.to_child_stdio(false)?;
+ let ours = StdioPipes {
+ stdin: our_stdin,
+ stdout: our_stdout,
+ stderr: our_stderr,
+ };
+ let theirs = ChildPipes {
+ stdin: their_stdin,
+ stdout: their_stdout,
+ stderr: their_stderr,
+ };
+ Ok((ours, theirs))
+ }
+}
+
+fn os2c(s: &OsStr, saw_nul: &mut bool) -> CString {
+ CString::new(s.as_bytes()).unwrap_or_else(|_e| {
+ *saw_nul = true;
+ CString::new("<string-with-nul>").unwrap()
+ })
+}
+
+// Helper type to manage ownership of the strings within a C-style array.
+pub struct CStringArray {
+ items: Vec<CString>,
+ ptrs: Vec<*const c_char>
+}
+
+impl CStringArray {
+ pub fn with_capacity(capacity: usize) -> Self {
+ let mut result = CStringArray {
+ items: Vec::with_capacity(capacity),
+ ptrs: Vec::with_capacity(capacity+1)
+ };
+ result.ptrs.push(ptr::null());
+ result
+ }
+ pub fn push(&mut self, item: CString) {
+ let l = self.ptrs.len();
+ self.ptrs[l-1] = item.as_ptr();
+ self.ptrs.push(ptr::null());
+ self.items.push(item);
+ }
+ pub fn as_ptr(&self) -> *const *const c_char {
+ self.ptrs.as_ptr()
+ }
+}
+
+fn construct_envp(env: BTreeMap<DefaultEnvKey, OsString>, saw_nul: &mut bool) -> CStringArray {
+ let mut result = CStringArray::with_capacity(env.len());
+ for (k, v) in env {
+ let mut k: OsString = k.into();
+
+ // Reserve additional space for '=' and null terminator
+ k.reserve_exact(v.len() + 2);
+ k.push("=");
+ k.push(&v);
+
+ // Add the new entry into the array
+ if let Ok(item) = CString::new(k.into_vec()) {
+ result.push(item);
+ } else {
+ *saw_nul = true;
+ }
+ }
+
+ result
+}
+
+impl Stdio {
+ pub fn to_child_stdio(&self, readable: bool)
+ -> io::Result<(ChildStdio, Option<AnonPipe>)> {
+ match *self {
+ Stdio::Inherit => {
+ Ok((ChildStdio::Inherit, None))
+ },
+
+ // Make sure that the source descriptors are not an stdio
+ // descriptor, otherwise the order which we set the child's
+ // descriptors may blow away a descriptor which we are hoping to
+ // save. For example, suppose we want the child's stderr to be the
+ // parent's stdout, and the child's stdout to be the parent's
+ // stderr. No matter which we dup first, the second will get
+ // overwritten prematurely.
+ Stdio::Fd(ref fd) => {
+ if fd.raw() >= 0 && fd.raw() <= libc::STDERR_FILENO {
+ Ok((ChildStdio::Owned(fd.duplicate()?), None))
+ } else {
+ Ok((ChildStdio::Explicit(fd.raw()), None))
+ }
+ }
+
+ Stdio::MakePipe => {
+ let (reader, writer) = pipe::anon_pipe()?;
+ let (ours, theirs) = if readable {
+ (writer, reader)
+ } else {
+ (reader, writer)
+ };
+ Ok((ChildStdio::Owned(theirs.into_fd()), Some(ours)))
+ }
+
+ Stdio::Null => {
+ let mut opts = OpenOptions::new();
+ opts.read(readable);
+ opts.write(!readable);
+ let path = unsafe {
+ CStr::from_ptr("/dev/null\0".as_ptr() as *const _)
+ };
+ let fd = File::open_c(&path, &opts)?;
+ Ok((ChildStdio::Owned(fd.into_fd()), None))
+ }
+ }
+ }
+}
+
+impl From<AnonPipe> for Stdio {
+ fn from(pipe: AnonPipe) -> Stdio {
+ Stdio::Fd(pipe.into_fd())
+ }
+}
+
+impl From<File> for Stdio {
+ fn from(file: File) -> Stdio {
+ Stdio::Fd(file.into_fd())
+ }
+}
+
+impl ChildStdio {
+ pub fn fd(&self) -> Option<c_int> {
+ match *self {
+ ChildStdio::Inherit => None,
+ ChildStdio::Explicit(fd) => Some(fd),
+ ChildStdio::Owned(ref fd) => Some(fd.raw()),
+ }
+ }
+}
+
+impl fmt::Debug for Command {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "{:?}", self.program)?;
+ for arg in &self.args {
+ write!(f, " {:?}", arg)?;
+ }
+ Ok(())
+ }
+}
+
+/// Unix exit statuses
+#[derive(PartialEq, Eq, Clone, Copy, Debug)]
+pub struct ExitStatus(c_int);
+
+impl ExitStatus {
+ pub fn new(status: c_int) -> ExitStatus {
+ ExitStatus(status)
+ }
+
+ fn exited(&self) -> bool {
+ unsafe { libc::WIFEXITED(self.0) }
+ }
+
+ pub fn success(&self) -> bool {
+ self.code() == Some(0)
+ }
+
+ pub fn code(&self) -> Option<i32> {
+ if self.exited() {
+ Some(unsafe { libc::WEXITSTATUS(self.0) })
+ } else {
+ None
+ }
+ }
+
+ pub fn signal(&self) -> Option<i32> {
+ if !self.exited() {
+ Some(unsafe { libc::WTERMSIG(self.0) })
+ } else {
+ None
+ }
+ }
+}
+
+impl From<c_int> for ExitStatus {
+ fn from(a: c_int) -> ExitStatus {
+ ExitStatus(a)
+ }
+}
+
+impl fmt::Display for ExitStatus {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ if let Some(code) = self.code() {
+ write!(f, "exit code: {}", code)
+ } else {
+ let signal = self.signal().unwrap();
+ write!(f, "signal: {}", signal)
+ }
+ }
+}
+
+#[derive(PartialEq, Eq, Clone, Copy, Debug)]
+pub struct ExitCode(u8);
+
+impl ExitCode {
+ pub const SUCCESS: ExitCode = ExitCode(EXIT_SUCCESS as _);
+ pub const FAILURE: ExitCode = ExitCode(EXIT_FAILURE as _);
+
+ #[inline]
+ pub fn as_i32(&self) -> i32 {
+ self.0 as i32
+ }
+}
+
+#[cfg(all(test, not(target_os = "emscripten")))]
+mod tests {
+ use super::*;
+
+ use crate::ffi::OsStr;
+ use crate::mem;
+ use crate::ptr;
+ use crate::sys::cvt;
+
+ macro_rules! t {
+ ($e:expr) => {
+ match $e {
+ Ok(t) => t,
+ Err(e) => panic!("received error for `{}`: {}", stringify!($e), e),
+ }
+ }
+ }
+
+ // Android with api less than 21 define sig* functions inline, so it is not
+ // available for dynamic link. Implementing sigemptyset and sigaddset allow us
+ // to support older Android version (independent of libc version).
+ // The following implementations are based on https://git.io/vSkNf
+
+ #[cfg(not(target_os = "android"))]
+ extern {
+ #[cfg_attr(target_os = "netbsd", link_name = "__sigemptyset14")]
+ fn sigemptyset(set: *mut libc::sigset_t) -> libc::c_int;
+
+ #[cfg_attr(target_os = "netbsd", link_name = "__sigaddset14")]
+ fn sigaddset(set: *mut libc::sigset_t, signum: libc::c_int) -> libc::c_int;
+ }
+
+ #[cfg(target_os = "android")]
+ unsafe fn sigemptyset(set: *mut libc::sigset_t) -> libc::c_int {
+ libc::memset(set as *mut _, 0, mem::size_of::<libc::sigset_t>());
+ return 0;
+ }
+
+ #[cfg(target_os = "android")]
+ unsafe fn sigaddset(set: *mut libc::sigset_t, signum: libc::c_int) -> libc::c_int {
+ use crate::slice;
+
+ let raw = slice::from_raw_parts_mut(set as *mut u8, mem::size_of::<libc::sigset_t>());
+ let bit = (signum - 1) as usize;
+ raw[bit / 8] |= 1 << (bit % 8);
+ return 0;
+ }
+
+ // See #14232 for more information, but it appears that signal delivery to a
+ // newly spawned process may just be raced in the macOS, so to prevent this
+ // test from being flaky we ignore it on macOS.
+ #[test]
+ #[cfg_attr(target_os = "macos", ignore)]
+ // When run under our current QEMU emulation test suite this test fails,
+ // although the reason isn't very clear as to why. For now this test is
+ // ignored there.
+ #[cfg_attr(target_arch = "arm", ignore)]
+ #[cfg_attr(target_arch = "aarch64", ignore)]
+ fn test_process_mask() {
+ unsafe {
+ // Test to make sure that a signal mask does not get inherited.
+ let mut cmd = Command::new(OsStr::new("cat"));
+
+ let mut set: libc::sigset_t = mem::uninitialized();
+ let mut old_set: libc::sigset_t = mem::uninitialized();
+ t!(cvt(sigemptyset(&mut set)));
+ t!(cvt(sigaddset(&mut set, libc::SIGINT)));
+ t!(cvt(libc::pthread_sigmask(libc::SIG_SETMASK, &set, &mut old_set)));
+
+ cmd.stdin(Stdio::MakePipe);
+ cmd.stdout(Stdio::MakePipe);
+
+ let (mut cat, mut pipes) = t!(cmd.spawn(Stdio::Null, true));
+ let stdin_write = pipes.stdin.take().unwrap();
+ let stdout_read = pipes.stdout.take().unwrap();
+
+ t!(cvt(libc::pthread_sigmask(libc::SIG_SETMASK, &old_set,
+ ptr::null_mut())));
+
+ t!(cvt(libc::kill(cat.id() as libc::pid_t, libc::SIGINT)));
+ // We need to wait until SIGINT is definitely delivered. The
+ // easiest way is to write something to cat, and try to read it
+ // back: if SIGINT is unmasked, it'll get delivered when cat is
+ // next scheduled.
+ let _ = stdin_write.write(b"Hello");
+ drop(stdin_write);
+
+ // Either EOF or failure (EPIPE) is okay.
+ let mut buf = [0; 5];
+ if let Ok(ret) = stdout_read.read(&mut buf) {
+ assert_eq!(ret, 0);
+ }
+
+ t!(cat.wait());
+ }
+ }
+}
diff --git a/src/libstd/sys/unix/process/process_fuchsia.rs b/src/libstd/sys/unix/process/process_fuchsia.rs
new file mode 100644
index 0000000..7c6be9b
--- /dev/null
+++ b/src/libstd/sys/unix/process/process_fuchsia.rs
@@ -0,0 +1,172 @@
+use crate::io;
+use crate::mem;
+use crate::ptr;
+
+use crate::sys::process::zircon::{Handle, zx_handle_t};
+use crate::sys::process::process_common::*;
+
+use libc::size_t;
+
+////////////////////////////////////////////////////////////////////////////////
+// Command
+////////////////////////////////////////////////////////////////////////////////
+
+impl Command {
+ pub fn spawn(&mut self, default: Stdio, needs_stdin: bool)
+ -> io::Result<(Process, StdioPipes)> {
+ let envp = self.capture_env();
+
+ if self.saw_nul() {
+ return Err(io::Error::new(io::ErrorKind::InvalidInput,
+ "nul byte found in provided data"));
+ }
+
+ let (ours, theirs) = self.setup_io(default, needs_stdin)?;
+
+ let process_handle = unsafe { self.do_exec(theirs, envp.as_ref())? };
+
+ Ok((Process { handle: Handle::new(process_handle) }, ours))
+ }
+
+ pub fn exec(&mut self, default: Stdio) -> io::Error {
+ if self.saw_nul() {
+ return io::Error::new(io::ErrorKind::InvalidInput,
+ "nul byte found in provided data")
+ }
+
+ match self.setup_io(default, true) {
+ Ok((_, _)) => {
+ // FIXME: This is tough because we don't support the exec syscalls
+ unimplemented!();
+ },
+ Err(e) => e,
+ }
+ }
+
+ unsafe fn do_exec(&mut self, stdio: ChildPipes, maybe_envp: Option<&CStringArray>)
+ -> io::Result<zx_handle_t> {
+ use crate::sys::process::zircon::*;
+
+ let envp = match maybe_envp {
+ Some(envp) => envp.as_ptr(),
+ None => ptr::null(),
+ };
+
+ let transfer_or_clone = |opt_fd, target_fd| if let Some(local_fd) = opt_fd {
+ fdio_spawn_action_t {
+ action: FDIO_SPAWN_ACTION_TRANSFER_FD,
+ local_fd,
+ target_fd,
+ ..Default::default()
+ }
+ } else {
+ fdio_spawn_action_t {
+ action: FDIO_SPAWN_ACTION_CLONE_FD,
+ local_fd: target_fd,
+ target_fd,
+ ..Default::default()
+ }
+ };
+
+ // Clone stdin, stdout, and stderr
+ let action1 = transfer_or_clone(stdio.stdin.fd(), 0);
+ let action2 = transfer_or_clone(stdio.stdout.fd(), 1);
+ let action3 = transfer_or_clone(stdio.stderr.fd(), 2);
+ let actions = [action1, action2, action3];
+
+ // We don't want FileDesc::drop to be called on any stdio. fdio_spawn_etc
+ // always consumes transferred file descriptors.
+ mem::forget(stdio);
+
+ for callback in self.get_closures().iter_mut() {
+ callback()?;
+ }
+
+ let mut process_handle: zx_handle_t = 0;
+ zx_cvt(fdio_spawn_etc(
+ 0,
+ FDIO_SPAWN_CLONE_JOB | FDIO_SPAWN_CLONE_LDSVC | FDIO_SPAWN_CLONE_NAMESPACE,
+ self.get_argv()[0], self.get_argv().as_ptr(), envp, 3, actions.as_ptr(),
+ &mut process_handle,
+ ptr::null_mut(),
+ ))?;
+ // FIXME: See if we want to do something with that err_msg
+
+ Ok(process_handle)
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Processes
+////////////////////////////////////////////////////////////////////////////////
+
+pub struct Process {
+ handle: Handle,
+}
+
+impl Process {
+ pub fn id(&self) -> u32 {
+ self.handle.raw() as u32
+ }
+
+ pub fn kill(&mut self) -> io::Result<()> {
+ use crate::sys::process::zircon::*;
+
+ unsafe { zx_cvt(zx_task_kill(self.handle.raw()))?; }
+
+ Ok(())
+ }
+
+ pub fn wait(&mut self) -> io::Result<ExitStatus> {
+ use crate::default::Default;
+ use crate::sys::process::zircon::*;
+
+ let mut proc_info: zx_info_process_t = Default::default();
+ let mut actual: size_t = 0;
+ let mut avail: size_t = 0;
+
+ unsafe {
+ zx_cvt(zx_object_wait_one(self.handle.raw(), ZX_TASK_TERMINATED,
+ ZX_TIME_INFINITE, ptr::null_mut()))?;
+ zx_cvt(zx_object_get_info(self.handle.raw(), ZX_INFO_PROCESS,
+ &mut proc_info as *mut _ as *mut libc::c_void,
+ mem::size_of::<zx_info_process_t>(), &mut actual,
+ &mut avail))?;
+ }
+ if actual != 1 {
+ return Err(io::Error::new(io::ErrorKind::InvalidData,
+ "Failed to get exit status of process"));
+ }
+ Ok(ExitStatus::new(proc_info.rec.return_code))
+ }
+
+ pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
+ use crate::default::Default;
+ use crate::sys::process::zircon::*;
+
+ let mut proc_info: zx_info_process_t = Default::default();
+ let mut actual: size_t = 0;
+ let mut avail: size_t = 0;
+
+ unsafe {
+ let status = zx_object_wait_one(self.handle.raw(), ZX_TASK_TERMINATED,
+ 0, ptr::null_mut());
+ match status {
+ 0 => { }, // Success
+ x if x == ERR_TIMED_OUT => {
+ return Ok(None);
+ },
+ _ => { panic!("Failed to wait on process handle: {}", status); },
+ }
+ zx_cvt(zx_object_get_info(self.handle.raw(), ZX_INFO_PROCESS,
+ &mut proc_info as *mut _ as *mut libc::c_void,
+ mem::size_of::<zx_info_process_t>(), &mut actual,
+ &mut avail))?;
+ }
+ if actual != 1 {
+ return Err(io::Error::new(io::ErrorKind::InvalidData,
+ "Failed to get exit status of process"));
+ }
+ Ok(Some(ExitStatus::new(proc_info.rec.return_code)))
+ }
+}
diff --git a/src/libstd/sys/unix/process/process_unix.rs b/src/libstd/sys/unix/process/process_unix.rs
new file mode 100644
index 0000000..220b1fd
--- /dev/null
+++ b/src/libstd/sys/unix/process/process_unix.rs
@@ -0,0 +1,456 @@
+use crate::io::{self, Error, ErrorKind};
+use crate::ptr;
+use crate::sys::cvt;
+use crate::sys::process::process_common::*;
+use crate::sys;
+
+use libc::{c_int, gid_t, pid_t, uid_t};
+
+////////////////////////////////////////////////////////////////////////////////
+// Command
+////////////////////////////////////////////////////////////////////////////////
+
+impl Command {
+ pub fn spawn(&mut self, default: Stdio, needs_stdin: bool)
+ -> io::Result<(Process, StdioPipes)> {
+ const CLOEXEC_MSG_FOOTER: &[u8] = b"NOEX";
+
+ let envp = self.capture_env();
+
+ if self.saw_nul() {
+ return Err(io::Error::new(ErrorKind::InvalidInput,
+ "nul byte found in provided data"));
+ }
+
+ let (ours, theirs) = self.setup_io(default, needs_stdin)?;
+
+ if let Some(ret) = self.posix_spawn(&theirs, envp.as_ref())? {
+ return Ok((ret, ours))
+ }
+
+ let (input, output) = sys::pipe::anon_pipe()?;
+
+ // Whatever happens after the fork is almost for sure going to touch or
+ // look at the environment in one way or another (PATH in `execvp` or
+ // accessing the `environ` pointer ourselves). Make sure no other thread
+ // is accessing the environment when we do the fork itself.
+ //
+ // Note that as soon as we're done with the fork there's no need to hold
+ // a lock any more because the parent won't do anything and the child is
+ // in its own process.
+ let result = unsafe {
+ let _env_lock = sys::os::env_lock();
+ cvt(libc::fork())?
+ };
+
+ let pid = unsafe {
+ match result {
+ 0 => {
+ drop(input);
+ let err = self.do_exec(theirs, envp.as_ref());
+ let errno = err.raw_os_error().unwrap_or(libc::EINVAL) as u32;
+ let bytes = [
+ (errno >> 24) as u8,
+ (errno >> 16) as u8,
+ (errno >> 8) as u8,
+ (errno >> 0) as u8,
+ CLOEXEC_MSG_FOOTER[0], CLOEXEC_MSG_FOOTER[1],
+ CLOEXEC_MSG_FOOTER[2], CLOEXEC_MSG_FOOTER[3]
+ ];
+ // pipe I/O up to PIPE_BUF bytes should be atomic, and then
+ // we want to be sure we *don't* run at_exit destructors as
+ // we're being torn down regardless
+ assert!(output.write(&bytes).is_ok());
+ libc::_exit(1)
+ }
+ n => n,
+ }
+ };
+
+ let mut p = Process { pid: pid, status: None };
+ drop(output);
+ let mut bytes = [0; 8];
+
+ // loop to handle EINTR
+ loop {
+ match input.read(&mut bytes) {
+ Ok(0) => return Ok((p, ours)),
+ Ok(8) => {
+ assert!(combine(CLOEXEC_MSG_FOOTER) == combine(&bytes[4.. 8]),
+ "Validation on the CLOEXEC pipe failed: {:?}", bytes);
+ let errno = combine(&bytes[0.. 4]);
+ assert!(p.wait().is_ok(),
+ "wait() should either return Ok or panic");
+ return Err(Error::from_raw_os_error(errno))
+ }
+ Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
+ Err(e) => {
+ assert!(p.wait().is_ok(),
+ "wait() should either return Ok or panic");
+ panic!("the CLOEXEC pipe failed: {:?}", e)
+ },
+ Ok(..) => { // pipe I/O up to PIPE_BUF bytes should be atomic
+ assert!(p.wait().is_ok(),
+ "wait() should either return Ok or panic");
+ panic!("short read on the CLOEXEC pipe")
+ }
+ }
+ }
+
+ fn combine(arr: &[u8]) -> i32 {
+ let a = arr[0] as u32;
+ let b = arr[1] as u32;
+ let c = arr[2] as u32;
+ let d = arr[3] as u32;
+
+ ((a << 24) | (b << 16) | (c << 8) | (d << 0)) as i32
+ }
+ }
+
+ pub fn exec(&mut self, default: Stdio) -> io::Error {
+ let envp = self.capture_env();
+
+ if self.saw_nul() {
+ return io::Error::new(ErrorKind::InvalidInput,
+ "nul byte found in provided data")
+ }
+
+ match self.setup_io(default, true) {
+ Ok((_, theirs)) => {
+ unsafe {
+ // Similar to when forking, we want to ensure that access to
+ // the environment is synchronized, so make sure to grab the
+ // environment lock before we try to exec.
+ let _lock = sys::os::env_lock();
+
+ self.do_exec(theirs, envp.as_ref())
+ }
+ }
+ Err(e) => e,
+ }
+ }
+
+ // And at this point we've reached a special time in the life of the
+ // child. The child must now be considered hamstrung and unable to
+ // do anything other than syscalls really. Consider the following
+ // scenario:
+ //
+ // 1. Thread A of process 1 grabs the malloc() mutex
+ // 2. Thread B of process 1 forks(), creating thread C
+ // 3. Thread C of process 2 then attempts to malloc()
+ // 4. The memory of process 2 is the same as the memory of
+ // process 1, so the mutex is locked.
+ //
+ // This situation looks a lot like deadlock, right? It turns out
+ // that this is what pthread_atfork() takes care of, which is
+ // presumably implemented across platforms. The first thing that
+ // threads to *before* forking is to do things like grab the malloc
+ // mutex, and then after the fork they unlock it.
+ //
+ // Despite this information, libnative's spawn has been witnessed to
+ // deadlock on both macOS and FreeBSD. I'm not entirely sure why, but
+ // all collected backtraces point at malloc/free traffic in the
+ // child spawned process.
+ //
+ // For this reason, the block of code below should contain 0
+ // invocations of either malloc of free (or their related friends).
+ //
+ // As an example of not having malloc/free traffic, we don't close
+ // this file descriptor by dropping the FileDesc (which contains an
+ // allocation). Instead we just close it manually. This will never
+ // have the drop glue anyway because this code never returns (the
+ // child will either exec() or invoke libc::exit)
+ unsafe fn do_exec(
+ &mut self,
+ stdio: ChildPipes,
+ maybe_envp: Option<&CStringArray>
+ ) -> io::Error {
+ use crate::sys::{self, cvt_r};
+
+ macro_rules! t {
+ ($e:expr) => (match $e {
+ Ok(e) => e,
+ Err(e) => return e,
+ })
+ }
+
+ if let Some(fd) = stdio.stdin.fd() {
+ t!(cvt_r(|| libc::dup2(fd, libc::STDIN_FILENO)));
+ }
+ if let Some(fd) = stdio.stdout.fd() {
+ t!(cvt_r(|| libc::dup2(fd, libc::STDOUT_FILENO)));
+ }
+ if let Some(fd) = stdio.stderr.fd() {
+ t!(cvt_r(|| libc::dup2(fd, libc::STDERR_FILENO)));
+ }
+
+ if cfg!(not(any(target_os = "l4re"))) {
+ if let Some(u) = self.get_gid() {
+ t!(cvt(libc::setgid(u as gid_t)));
+ }
+ if let Some(u) = self.get_uid() {
+ // When dropping privileges from root, the `setgroups` call
+ // will remove any extraneous groups. If we don't call this,
+ // then even though our uid has dropped, we may still have
+ // groups that enable us to do super-user things. This will
+ // fail if we aren't root, so don't bother checking the
+ // return value, this is just done as an optimistic
+ // privilege dropping function.
+ let _ = libc::setgroups(0, ptr::null());
+
+ t!(cvt(libc::setuid(u as uid_t)));
+ }
+ }
+ if let Some(ref cwd) = *self.get_cwd() {
+ t!(cvt(libc::chdir(cwd.as_ptr())));
+ }
+
+ // emscripten has no signal support.
+ #[cfg(not(any(target_os = "emscripten")))]
+ {
+ use crate::mem;
+ // Reset signal handling so the child process starts in a
+ // standardized state. libstd ignores SIGPIPE, and signal-handling
+ // libraries often set a mask. Child processes inherit ignored
+ // signals and the signal mask from their parent, but most
+ // UNIX programs do not reset these things on their own, so we
+ // need to clean things up now to avoid confusing the program
+ // we're about to run.
+ let mut set: libc::sigset_t = mem::uninitialized();
+ if cfg!(target_os = "android") {
+ // Implementing sigemptyset allow us to support older Android
+ // versions. See the comment about Android and sig* functions in
+ // process_common.rs
+ libc::memset(&mut set as *mut _ as *mut _,
+ 0,
+ mem::size_of::<libc::sigset_t>());
+ } else {
+ t!(cvt(libc::sigemptyset(&mut set)));
+ }
+ t!(cvt(libc::pthread_sigmask(libc::SIG_SETMASK, &set,
+ ptr::null_mut())));
+ let ret = sys::signal(libc::SIGPIPE, libc::SIG_DFL);
+ if ret == libc::SIG_ERR {
+ return io::Error::last_os_error()
+ }
+ }
+
+ for callback in self.get_closures().iter_mut() {
+ t!(callback());
+ }
+
+ // Although we're performing an exec here we may also return with an
+ // error from this function (without actually exec'ing) in which case we
+ // want to be sure to restore the global environment back to what it
+ // once was, ensuring that our temporary override, when free'd, doesn't
+ // corrupt our process's environment.
+ let mut _reset = None;
+ if let Some(envp) = maybe_envp {
+ struct Reset(*const *const libc::c_char);
+
+ impl Drop for Reset {
+ fn drop(&mut self) {
+ unsafe {
+ *sys::os::environ() = self.0;
+ }
+ }
+ }
+
+ _reset = Some(Reset(*sys::os::environ()));
+ *sys::os::environ() = envp.as_ptr();
+ }
+
+ libc::execvp(self.get_argv()[0], self.get_argv().as_ptr());
+ io::Error::last_os_error()
+ }
+
+ #[cfg(not(any(target_os = "macos", target_os = "freebsd",
+ all(target_os = "linux", target_env = "gnu"))))]
+ fn posix_spawn(&mut self, _: &ChildPipes, _: Option<&CStringArray>)
+ -> io::Result<Option<Process>>
+ {
+ Ok(None)
+ }
+
+ // Only support platforms for which posix_spawn() can return ENOENT
+ // directly.
+ #[cfg(any(target_os = "macos", target_os = "freebsd",
+ all(target_os = "linux", target_env = "gnu")))]
+ fn posix_spawn(&mut self, stdio: &ChildPipes, envp: Option<&CStringArray>)
+ -> io::Result<Option<Process>>
+ {
+ use crate::mem;
+ use crate::sys;
+
+ if self.get_gid().is_some() ||
+ self.get_uid().is_some() ||
+ self.env_saw_path() ||
+ self.get_closures().len() != 0 {
+ return Ok(None)
+ }
+
+ // Only glibc 2.24+ posix_spawn() supports returning ENOENT directly.
+ #[cfg(all(target_os = "linux", target_env = "gnu"))]
+ {
+ if let Some(version) = sys::os::glibc_version() {
+ if version < (2, 24) {
+ return Ok(None)
+ }
+ } else {
+ return Ok(None)
+ }
+ }
+
+ // Solaris and glibc 2.29+ can set a new working directory, and maybe
+ // others will gain this non-POSIX function too. We'll check for this
+ // weak symbol as soon as it's needed, so we can return early otherwise
+ // to do a manual chdir before exec.
+ weak! {
+ fn posix_spawn_file_actions_addchdir_np(
+ *mut libc::posix_spawn_file_actions_t,
+ *const libc::c_char
+ ) -> libc::c_int
+ }
+ let addchdir = match self.get_cwd() {
+ Some(cwd) => match posix_spawn_file_actions_addchdir_np.get() {
+ Some(f) => Some((f, cwd)),
+ None => return Ok(None),
+ },
+ None => None,
+ };
+
+ let mut p = Process { pid: 0, status: None };
+
+ struct PosixSpawnFileActions(libc::posix_spawn_file_actions_t);
+
+ impl Drop for PosixSpawnFileActions {
+ fn drop(&mut self) {
+ unsafe {
+ libc::posix_spawn_file_actions_destroy(&mut self.0);
+ }
+ }
+ }
+
+ struct PosixSpawnattr(libc::posix_spawnattr_t);
+
+ impl Drop for PosixSpawnattr {
+ fn drop(&mut self) {
+ unsafe {
+ libc::posix_spawnattr_destroy(&mut self.0);
+ }
+ }
+ }
+
+ unsafe {
+ let mut file_actions = PosixSpawnFileActions(mem::uninitialized());
+ let mut attrs = PosixSpawnattr(mem::uninitialized());
+
+ libc::posix_spawnattr_init(&mut attrs.0);
+ libc::posix_spawn_file_actions_init(&mut file_actions.0);
+
+ if let Some(fd) = stdio.stdin.fd() {
+ cvt(libc::posix_spawn_file_actions_adddup2(&mut file_actions.0,
+ fd,
+ libc::STDIN_FILENO))?;
+ }
+ if let Some(fd) = stdio.stdout.fd() {
+ cvt(libc::posix_spawn_file_actions_adddup2(&mut file_actions.0,
+ fd,
+ libc::STDOUT_FILENO))?;
+ }
+ if let Some(fd) = stdio.stderr.fd() {
+ cvt(libc::posix_spawn_file_actions_adddup2(&mut file_actions.0,
+ fd,
+ libc::STDERR_FILENO))?;
+ }
+ if let Some((f, cwd)) = addchdir {
+ cvt(f(&mut file_actions.0, cwd.as_ptr()))?;
+ }
+
+ let mut set: libc::sigset_t = mem::uninitialized();
+ cvt(libc::sigemptyset(&mut set))?;
+ cvt(libc::posix_spawnattr_setsigmask(&mut attrs.0,
+ &set))?;
+ cvt(libc::sigaddset(&mut set, libc::SIGPIPE))?;
+ cvt(libc::posix_spawnattr_setsigdefault(&mut attrs.0,
+ &set))?;
+
+ let flags = libc::POSIX_SPAWN_SETSIGDEF |
+ libc::POSIX_SPAWN_SETSIGMASK;
+ cvt(libc::posix_spawnattr_setflags(&mut attrs.0, flags as _))?;
+
+ // Make sure we synchronize access to the global `environ` resource
+ let _env_lock = sys::os::env_lock();
+ let envp = envp.map(|c| c.as_ptr())
+ .unwrap_or_else(|| *sys::os::environ() as *const _);
+ let ret = libc::posix_spawnp(
+ &mut p.pid,
+ self.get_argv()[0],
+ &file_actions.0,
+ &attrs.0,
+ self.get_argv().as_ptr() as *const _,
+ envp as *const _,
+ );
+ if ret == 0 {
+ Ok(Some(p))
+ } else {
+ Err(io::Error::from_raw_os_error(ret))
+ }
+ }
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Processes
+////////////////////////////////////////////////////////////////////////////////
+
+/// The unique ID of the process (this should never be negative).
+pub struct Process {
+ pid: pid_t,
+ status: Option<ExitStatus>,
+}
+
+impl Process {
+ pub fn id(&self) -> u32 {
+ self.pid as u32
+ }
+
+ pub fn kill(&mut self) -> io::Result<()> {
+ // If we've already waited on this process then the pid can be recycled
+ // and used for another process, and we probably shouldn't be killing
+ // random processes, so just return an error.
+ if self.status.is_some() {
+ Err(Error::new(ErrorKind::InvalidInput,
+ "invalid argument: can't kill an exited process"))
+ } else {
+ cvt(unsafe { libc::kill(self.pid, libc::SIGKILL) }).map(|_| ())
+ }
+ }
+
+ pub fn wait(&mut self) -> io::Result<ExitStatus> {
+ use crate::sys::cvt_r;
+ if let Some(status) = self.status {
+ return Ok(status)
+ }
+ let mut status = 0 as c_int;
+ cvt_r(|| unsafe { libc::waitpid(self.pid, &mut status, 0) })?;
+ self.status = Some(ExitStatus::new(status));
+ Ok(ExitStatus::new(status))
+ }
+
+ pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
+ if let Some(status) = self.status {
+ return Ok(Some(status))
+ }
+ let mut status = 0 as c_int;
+ let pid = cvt(unsafe {
+ libc::waitpid(self.pid, &mut status, libc::WNOHANG)
+ })?;
+ if pid == 0 {
+ Ok(None)
+ } else {
+ self.status = Some(ExitStatus::new(status));
+ Ok(Some(ExitStatus::new(status)))
+ }
+ }
+}
diff --git a/src/libstd/sys/unix/process/zircon.rs b/src/libstd/sys/unix/process/zircon.rs
new file mode 100644
index 0000000..ec715d5
--- /dev/null
+++ b/src/libstd/sys/unix/process/zircon.rs
@@ -0,0 +1,269 @@
+#![allow(non_camel_case_types, unused)]
+
+use crate::convert::TryInto;
+use crate::io;
+use crate::os::raw::c_char;
+use crate::u64;
+
+use libc::{c_int, c_void, size_t};
+
+pub type zx_handle_t = u32;
+pub type zx_vaddr_t = usize;
+pub type zx_rights_t = u32;
+pub type zx_status_t = i32;
+
+pub const ZX_HANDLE_INVALID: zx_handle_t = 0;
+
+pub type zx_time_t = u64;
+pub const ZX_TIME_INFINITE : zx_time_t = u64::MAX;
+
+pub type zx_signals_t = u32;
+
+pub const ZX_OBJECT_SIGNAL_3 : zx_signals_t = 1 << 3;
+
+pub const ZX_TASK_TERMINATED : zx_signals_t = ZX_OBJECT_SIGNAL_3;
+
+pub const ZX_RIGHT_SAME_RIGHTS : zx_rights_t = 1 << 31;
+
+pub type zx_object_info_topic_t = u32;
+
+pub const ZX_INFO_PROCESS : zx_object_info_topic_t = 3;
+
+pub fn zx_cvt<T>(t: T) -> io::Result<T> where T: TryInto<zx_status_t>+Copy {
+ if let Ok(status) = TryInto::try_into(t) {
+ if status < 0 {
+ Err(io::Error::from_raw_os_error(status))
+ } else {
+ Ok(t)
+ }
+ } else {
+ Err(io::Error::last_os_error())
+ }
+}
+
+// Safe wrapper around zx_handle_t
+pub struct Handle {
+ raw: zx_handle_t,
+}
+
+impl Handle {
+ pub fn new(raw: zx_handle_t) -> Handle {
+ Handle {
+ raw,
+ }
+ }
+
+ pub fn raw(&self) -> zx_handle_t {
+ self.raw
+ }
+}
+
+impl Drop for Handle {
+ fn drop(&mut self) {
+ unsafe { zx_cvt(zx_handle_close(self.raw)).expect("Failed to close zx_handle_t"); }
+ }
+}
+
+// Common ZX_INFO header
+#[derive(Default)]
+#[repr(C)]
+pub struct zx_info_header_t {
+ pub topic: u32, // identifies the info struct
+ pub avail_topic_size: u16, // “native” size of the struct
+ pub topic_size: u16, // size of the returned struct (<=topic_size)
+ pub avail_count: u32, // number of records the kernel has
+ pub count: u32, // number of records returned (limited by buffer size)
+}
+
+#[derive(Default)]
+#[repr(C)]
+pub struct zx_record_process_t {
+ pub return_code: c_int,
+}
+
+// Returned for topic ZX_INFO_PROCESS
+#[derive(Default)]
+#[repr(C)]
+pub struct zx_info_process_t {
+ pub hdr: zx_info_header_t,
+ pub rec: zx_record_process_t,
+}
+
+extern {
+ pub fn zx_job_default() -> zx_handle_t;
+
+ pub fn zx_task_kill(handle: zx_handle_t) -> zx_status_t;
+
+ pub fn zx_handle_close(handle: zx_handle_t) -> zx_status_t;
+
+ pub fn zx_handle_duplicate(handle: zx_handle_t, rights: zx_rights_t,
+ out: *const zx_handle_t) -> zx_handle_t;
+
+ pub fn zx_object_wait_one(handle: zx_handle_t, signals: zx_signals_t, timeout: zx_time_t,
+ pending: *mut zx_signals_t) -> zx_status_t;
+
+ pub fn zx_object_get_info(handle: zx_handle_t, topic: u32, buffer: *mut c_void,
+ buffer_size: size_t, actual_size: *mut size_t,
+ avail: *mut size_t) -> zx_status_t;
+}
+
+#[derive(Default)]
+#[repr(C)]
+pub struct fdio_spawn_action_t {
+ pub action: u32,
+ pub reserved0: u32,
+ pub local_fd: i32,
+ pub target_fd: i32,
+ pub reserved1: u64,
+}
+
+extern {
+ pub fn fdio_spawn_etc(job: zx_handle_t, flags: u32, path: *const c_char,
+ argv: *const *const c_char, envp: *const *const c_char,
+ action_count: u64, actions: *const fdio_spawn_action_t,
+ process: *mut zx_handle_t, err_msg: *mut c_char) -> zx_status_t;
+}
+
+// fdio_spawn_etc flags
+
+pub const FDIO_SPAWN_CLONE_JOB: u32 = 0x0001;
+pub const FDIO_SPAWN_CLONE_LDSVC: u32 = 0x0002;
+pub const FDIO_SPAWN_CLONE_NAMESPACE: u32 = 0x0004;
+pub const FDIO_SPAWN_CLONE_STDIO: u32 = 0x0008;
+pub const FDIO_SPAWN_CLONE_ENVIRON: u32 = 0x0010;
+pub const FDIO_SPAWN_CLONE_ALL: u32 = 0xFFFF;
+
+// fdio_spawn_etc actions
+
+pub const FDIO_SPAWN_ACTION_CLONE_FD: u32 = 0x0001;
+pub const FDIO_SPAWN_ACTION_TRANSFER_FD: u32 = 0x0002;
+
+// Errors
+
+#[allow(unused)] pub const ERR_INTERNAL: zx_status_t = -1;
+
+// ERR_NOT_SUPPORTED: The operation is not implemented, supported,
+// or enabled.
+#[allow(unused)] pub const ERR_NOT_SUPPORTED: zx_status_t = -2;
+
+// ERR_NO_RESOURCES: The system was not able to allocate some resource
+// needed for the operation.
+#[allow(unused)] pub const ERR_NO_RESOURCES: zx_status_t = -3;
+
+// ERR_NO_MEMORY: The system was not able to allocate memory needed
+// for the operation.
+#[allow(unused)] pub const ERR_NO_MEMORY: zx_status_t = -4;
+
+// ERR_CALL_FAILED: The second phase of zx_channel_call(; did not complete
+// successfully.
+#[allow(unused)] pub const ERR_CALL_FAILED: zx_status_t = -5;
+
+// ERR_INTERRUPTED_RETRY: The system call was interrupted, but should be
+// retried. This should not be seen outside of the VDSO.
+#[allow(unused)] pub const ERR_INTERRUPTED_RETRY: zx_status_t = -6;
+
+// ======= Parameter errors =======
+// ERR_INVALID_ARGS: an argument is invalid, ex. null pointer
+#[allow(unused)] pub const ERR_INVALID_ARGS: zx_status_t = -10;
+
+// ERR_BAD_HANDLE: A specified handle value does not refer to a handle.
+#[allow(unused)] pub const ERR_BAD_HANDLE: zx_status_t = -11;
+
+// ERR_WRONG_TYPE: The subject of the operation is the wrong type to
+// perform the operation.
+// Example: Attempting a message_read on a thread handle.
+#[allow(unused)] pub const ERR_WRONG_TYPE: zx_status_t = -12;
+
+// ERR_BAD_SYSCALL: The specified syscall number is invalid.
+#[allow(unused)] pub const ERR_BAD_SYSCALL: zx_status_t = -13;
+
+// ERR_OUT_OF_RANGE: An argument is outside the valid range for this
+// operation.
+#[allow(unused)] pub const ERR_OUT_OF_RANGE: zx_status_t = -14;
+
+// ERR_BUFFER_TOO_SMALL: A caller provided buffer is too small for
+// this operation.
+#[allow(unused)] pub const ERR_BUFFER_TOO_SMALL: zx_status_t = -15;
+
+// ======= Precondition or state errors =======
+// ERR_BAD_STATE: operation failed because the current state of the
+// object does not allow it, or a precondition of the operation is
+// not satisfied
+#[allow(unused)] pub const ERR_BAD_STATE: zx_status_t = -20;
+
+// ERR_TIMED_OUT: The time limit for the operation elapsed before
+// the operation completed.
+#[allow(unused)] pub const ERR_TIMED_OUT: zx_status_t = -21;
+
+// ERR_SHOULD_WAIT: The operation cannot be performed currently but
+// potentially could succeed if the caller waits for a prerequisite
+// to be satisfied, for example waiting for a handle to be readable
+// or writable.
+// Example: Attempting to read from a message pipe that has no
+// messages waiting but has an open remote will return ERR_SHOULD_WAIT.
+// Attempting to read from a message pipe that has no messages waiting
+// and has a closed remote end will return ERR_REMOTE_CLOSED.
+#[allow(unused)] pub const ERR_SHOULD_WAIT: zx_status_t = -22;
+
+// ERR_CANCELED: The in-progress operation (e.g., a wait) has been
+// // canceled.
+#[allow(unused)] pub const ERR_CANCELED: zx_status_t = -23;
+
+// ERR_PEER_CLOSED: The operation failed because the remote end
+// of the subject of the operation was closed.
+#[allow(unused)] pub const ERR_PEER_CLOSED: zx_status_t = -24;
+
+// ERR_NOT_FOUND: The requested entity is not found.
+#[allow(unused)] pub const ERR_NOT_FOUND: zx_status_t = -25;
+
+// ERR_ALREADY_EXISTS: An object with the specified identifier
+// already exists.
+// Example: Attempting to create a file when a file already exists
+// with that name.
+#[allow(unused)] pub const ERR_ALREADY_EXISTS: zx_status_t = -26;
+
+// ERR_ALREADY_BOUND: The operation failed because the named entity
+// is already owned or controlled by another entity. The operation
+// could succeed later if the current owner releases the entity.
+#[allow(unused)] pub const ERR_ALREADY_BOUND: zx_status_t = -27;
+
+// ERR_UNAVAILABLE: The subject of the operation is currently unable
+// to perform the operation.
+// Note: This is used when there's no direct way for the caller to
+// observe when the subject will be able to perform the operation
+// and should thus retry.
+#[allow(unused)] pub const ERR_UNAVAILABLE: zx_status_t = -28;
+
+// ======= Permission check errors =======
+// ERR_ACCESS_DENIED: The caller did not have permission to perform
+// the specified operation.
+#[allow(unused)] pub const ERR_ACCESS_DENIED: zx_status_t = -30;
+
+// ======= Input-output errors =======
+// ERR_IO: Otherwise unspecified error occurred during I/O.
+#[allow(unused)] pub const ERR_IO: zx_status_t = -40;
+
+// ERR_REFUSED: The entity the I/O operation is being performed on
+// rejected the operation.
+// Example: an I2C device NAK'ing a transaction or a disk controller
+// rejecting an invalid command.
+#[allow(unused)] pub const ERR_IO_REFUSED: zx_status_t = -41;
+
+// ERR_IO_DATA_INTEGRITY: The data in the operation failed an integrity
+// check and is possibly corrupted.
+// Example: CRC or Parity error.
+#[allow(unused)] pub const ERR_IO_DATA_INTEGRITY: zx_status_t = -42;
+
+// ERR_IO_DATA_LOSS: The data in the operation is currently unavailable
+// and may be permanently lost.
+// Example: A disk block is irrecoverably damaged.
+#[allow(unused)] pub const ERR_IO_DATA_LOSS: zx_status_t = -43;
+
+// Filesystem specific errors
+#[allow(unused)] pub const ERR_BAD_PATH: zx_status_t = -50;
+#[allow(unused)] pub const ERR_NOT_DIR: zx_status_t = -51;
+#[allow(unused)] pub const ERR_NOT_FILE: zx_status_t = -52;
+// ERR_FILE_BIG: A file exceeds a filesystem-specific size limit.
+#[allow(unused)] pub const ERR_FILE_BIG: zx_status_t = -53;
+// ERR_NO_SPACE: Filesystem or device space is exhausted.
+#[allow(unused)] pub const ERR_NO_SPACE: zx_status_t = -54;
diff --git a/src/libstd/sys/unix/rand.rs b/src/libstd/sys/unix/rand.rs
new file mode 100644
index 0000000..122f22b
--- /dev/null
+++ b/src/libstd/sys/unix/rand.rs
@@ -0,0 +1,164 @@
+use crate::mem;
+use crate::slice;
+
+pub fn hashmap_random_keys() -> (u64, u64) {
+ let mut v = (0, 0);
+ unsafe {
+ let view = slice::from_raw_parts_mut(&mut v as *mut _ as *mut u8,
+ mem::size_of_val(&v));
+ imp::fill_bytes(view);
+ }
+ return v
+}
+
+#[cfg(all(unix,
+ not(target_os = "ios"),
+ not(target_os = "openbsd"),
+ not(target_os = "freebsd"),
+ not(target_os = "fuchsia")))]
+mod imp {
+ use crate::fs::File;
+ use crate::io::Read;
+
+ #[cfg(any(target_os = "linux", target_os = "android"))]
+ fn getrandom(buf: &mut [u8]) -> libc::c_long {
+ unsafe {
+ libc::syscall(libc::SYS_getrandom, buf.as_mut_ptr(), buf.len(), libc::GRND_NONBLOCK)
+ }
+ }
+
+ #[cfg(not(any(target_os = "linux", target_os = "android")))]
+ fn getrandom_fill_bytes(_buf: &mut [u8]) -> bool { false }
+
+ #[cfg(any(target_os = "linux", target_os = "android"))]
+ fn getrandom_fill_bytes(v: &mut [u8]) -> bool {
+ use crate::sync::atomic::{AtomicBool, Ordering};
+ use crate::sys::os::errno;
+
+ static GETRANDOM_UNAVAILABLE: AtomicBool = AtomicBool::new(false);
+ if GETRANDOM_UNAVAILABLE.load(Ordering::Relaxed) {
+ return false;
+ }
+
+ let mut read = 0;
+ while read < v.len() {
+ let result = getrandom(&mut v[read..]);
+ if result == -1 {
+ let err = errno() as libc::c_int;
+ if err == libc::EINTR {
+ continue;
+ } else if err == libc::ENOSYS {
+ GETRANDOM_UNAVAILABLE.store(true, Ordering::Relaxed);
+ return false;
+ } else if err == libc::EAGAIN {
+ return false;
+ } else {
+ panic!("unexpected getrandom error: {}", err);
+ }
+ } else {
+ read += result as usize;
+ }
+ }
+ true
+ }
+
+ pub fn fill_bytes(v: &mut [u8]) {
+ // getrandom_fill_bytes here can fail if getrandom() returns EAGAIN,
+ // meaning it would have blocked because the non-blocking pool (urandom)
+ // has not initialized in the kernel yet due to a lack of entropy. The
+ // fallback we do here is to avoid blocking applications which could
+ // depend on this call without ever knowing they do and don't have a
+ // work around. The PRNG of /dev/urandom will still be used but over a
+ // possibly predictable entropy pool.
+ if getrandom_fill_bytes(v) {
+ return;
+ }
+
+ // getrandom failed because it is permanently or temporarily (because
+ // of missing entropy) unavailable. Open /dev/urandom, read from it,
+ // and close it again.
+ let mut file = File::open("/dev/urandom").expect("failed to open /dev/urandom");
+ file.read_exact(v).expect("failed to read /dev/urandom")
+ }
+}
+
+#[cfg(target_os = "openbsd")]
+mod imp {
+ use crate::sys::os::errno;
+
+ pub fn fill_bytes(v: &mut [u8]) {
+ // getentropy(2) permits a maximum buffer size of 256 bytes
+ for s in v.chunks_mut(256) {
+ let ret = unsafe {
+ libc::getentropy(s.as_mut_ptr() as *mut libc::c_void, s.len())
+ };
+ if ret == -1 {
+ panic!("unexpected getentropy error: {}", errno());
+ }
+ }
+ }
+}
+
+#[cfg(target_os = "ios")]
+mod imp {
+ use crate::io;
+ use crate::ptr;
+ use libc::{c_int, size_t};
+
+ enum SecRandom {}
+
+ #[allow(non_upper_case_globals)]
+ const kSecRandomDefault: *const SecRandom = ptr::null();
+
+ extern {
+ fn SecRandomCopyBytes(rnd: *const SecRandom,
+ count: size_t,
+ bytes: *mut u8) -> c_int;
+ }
+
+ pub fn fill_bytes(v: &mut [u8]) {
+ let ret = unsafe {
+ SecRandomCopyBytes(kSecRandomDefault,
+ v.len(),
+ v.as_mut_ptr())
+ };
+ if ret == -1 {
+ panic!("couldn't generate random bytes: {}",
+ io::Error::last_os_error());
+ }
+ }
+}
+
+#[cfg(target_os = "freebsd")]
+mod imp {
+ use crate::ptr;
+
+ pub fn fill_bytes(v: &mut [u8]) {
+ let mib = [libc::CTL_KERN, libc::KERN_ARND];
+ // kern.arandom permits a maximum buffer size of 256 bytes
+ for s in v.chunks_mut(256) {
+ let mut s_len = s.len();
+ let ret = unsafe {
+ libc::sysctl(mib.as_ptr(), mib.len() as libc::c_uint,
+ s.as_mut_ptr() as *mut _, &mut s_len,
+ ptr::null(), 0)
+ };
+ if ret == -1 || s_len != s.len() {
+ panic!("kern.arandom sysctl failed! (returned {}, s.len() {}, oldlenp {})",
+ ret, s.len(), s_len);
+ }
+ }
+ }
+}
+
+#[cfg(target_os = "fuchsia")]
+mod imp {
+ #[link(name = "zircon")]
+ extern {
+ fn zx_cprng_draw(buffer: *mut u8, len: usize);
+ }
+
+ pub fn fill_bytes(v: &mut [u8]) {
+ unsafe { zx_cprng_draw(v.as_mut_ptr(), v.len()) }
+ }
+}
diff --git a/src/libstd/sys/unix/rwlock.rs b/src/libstd/sys/unix/rwlock.rs
new file mode 100644
index 0000000..e48bfda
--- /dev/null
+++ b/src/libstd/sys/unix/rwlock.rs
@@ -0,0 +1,131 @@
+use crate::cell::UnsafeCell;
+use crate::sync::atomic::{AtomicUsize, Ordering};
+
+pub struct RWLock {
+ inner: UnsafeCell<libc::pthread_rwlock_t>,
+ write_locked: UnsafeCell<bool>, // guarded by the `inner` RwLock
+ num_readers: AtomicUsize,
+}
+
+unsafe impl Send for RWLock {}
+unsafe impl Sync for RWLock {}
+
+impl RWLock {
+ pub const fn new() -> RWLock {
+ RWLock {
+ inner: UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER),
+ write_locked: UnsafeCell::new(false),
+ num_readers: AtomicUsize::new(0),
+ }
+ }
+ #[inline]
+ pub unsafe fn read(&self) {
+ let r = libc::pthread_rwlock_rdlock(self.inner.get());
+
+ // According to the pthread_rwlock_rdlock spec, this function **may**
+ // fail with EDEADLK if a deadlock is detected. On the other hand
+ // pthread mutexes will *never* return EDEADLK if they are initialized
+ // as the "fast" kind (which ours always are). As a result, a deadlock
+ // situation may actually return from the call to pthread_rwlock_rdlock
+ // instead of blocking forever (as mutexes and Windows rwlocks do). Note
+ // that not all unix implementations, however, will return EDEADLK for
+ // their rwlocks.
+ //
+ // We roughly maintain the deadlocking behavior by panicking to ensure
+ // that this lock acquisition does not succeed.
+ //
+ // We also check whether this lock is already write locked. This
+ // is only possible if it was write locked by the current thread and
+ // the implementation allows recursive locking. The POSIX standard
+ // doesn't require recursively locking a rwlock to deadlock, but we can't
+ // allow that because it could lead to aliasing issues.
+ if r == libc::EAGAIN {
+ panic!("rwlock maximum reader count exceeded");
+ } else if r == libc::EDEADLK || (r == 0 && *self.write_locked.get()) {
+ if r == 0 {
+ self.raw_unlock();
+ }
+ panic!("rwlock read lock would result in deadlock");
+ } else {
+ assert_eq!(r, 0);
+ self.num_readers.fetch_add(1, Ordering::Relaxed);
+ }
+ }
+ #[inline]
+ pub unsafe fn try_read(&self) -> bool {
+ let r = libc::pthread_rwlock_tryrdlock(self.inner.get());
+ if r == 0 {
+ if *self.write_locked.get() {
+ self.raw_unlock();
+ false
+ } else {
+ self.num_readers.fetch_add(1, Ordering::Relaxed);
+ true
+ }
+ } else {
+ false
+ }
+ }
+ #[inline]
+ pub unsafe fn write(&self) {
+ let r = libc::pthread_rwlock_wrlock(self.inner.get());
+ // See comments above for why we check for EDEADLK and write_locked. We
+ // also need to check that num_readers is 0.
+ if r == libc::EDEADLK || *self.write_locked.get() ||
+ self.num_readers.load(Ordering::Relaxed) != 0 {
+ if r == 0 {
+ self.raw_unlock();
+ }
+ panic!("rwlock write lock would result in deadlock");
+ } else {
+ debug_assert_eq!(r, 0);
+ }
+ *self.write_locked.get() = true;
+ }
+ #[inline]
+ pub unsafe fn try_write(&self) -> bool {
+ let r = libc::pthread_rwlock_trywrlock(self.inner.get());
+ if r == 0 {
+ if *self.write_locked.get() || self.num_readers.load(Ordering::Relaxed) != 0 {
+ self.raw_unlock();
+ false
+ } else {
+ *self.write_locked.get() = true;
+ true
+ }
+ } else {
+ false
+ }
+ }
+ #[inline]
+ unsafe fn raw_unlock(&self) {
+ let r = libc::pthread_rwlock_unlock(self.inner.get());
+ debug_assert_eq!(r, 0);
+ }
+ #[inline]
+ pub unsafe fn read_unlock(&self) {
+ debug_assert!(!*self.write_locked.get());
+ self.num_readers.fetch_sub(1, Ordering::Relaxed);
+ self.raw_unlock();
+ }
+ #[inline]
+ pub unsafe fn write_unlock(&self) {
+ debug_assert_eq!(self.num_readers.load(Ordering::Relaxed), 0);
+ debug_assert!(*self.write_locked.get());
+ *self.write_locked.get() = false;
+ self.raw_unlock();
+ }
+ #[inline]
+ pub unsafe fn destroy(&self) {
+ let r = libc::pthread_rwlock_destroy(self.inner.get());
+ // On DragonFly pthread_rwlock_destroy() returns EINVAL if called on a
+ // rwlock that was just initialized with
+ // libc::PTHREAD_RWLOCK_INITIALIZER. Once it is used (locked/unlocked)
+ // or pthread_rwlock_init() is called, this behaviour no longer occurs.
+ if cfg!(target_os = "dragonfly") {
+ debug_assert!(r == 0 || r == libc::EINVAL);
+ } else {
+ debug_assert_eq!(r, 0);
+ }
+ }
+}
diff --git a/src/libstd/sys/unix/stack_overflow.rs b/src/libstd/sys/unix/stack_overflow.rs
new file mode 100644
index 0000000..561279e8
--- /dev/null
+++ b/src/libstd/sys/unix/stack_overflow.rs
@@ -0,0 +1,209 @@
+#![cfg_attr(test, allow(dead_code))]
+
+use self::imp::{make_handler, drop_handler};
+
+pub use self::imp::cleanup;
+pub use self::imp::init;
+
+pub struct Handler {
+ _data: *mut libc::c_void
+}
+
+impl Handler {
+ pub unsafe fn new() -> Handler {
+ make_handler()
+ }
+}
+
+impl Drop for Handler {
+ fn drop(&mut self) {
+ unsafe {
+ drop_handler(self);
+ }
+ }
+}
+
+#[cfg(any(target_os = "linux",
+ target_os = "macos",
+ target_os = "bitrig",
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "solaris",
+ all(target_os = "netbsd", not(target_vendor = "rumprun")),
+ target_os = "openbsd"))]
+mod imp {
+ use super::Handler;
+ use crate::mem;
+ use crate::ptr;
+
+ use libc::{sigaltstack, SIGSTKSZ, SS_DISABLE};
+ use libc::{sigaction, SIGBUS, SIG_DFL,
+ SA_SIGINFO, SA_ONSTACK, sighandler_t};
+ use libc::{mmap, munmap};
+ use libc::{SIGSEGV, PROT_READ, PROT_WRITE, MAP_PRIVATE, MAP_ANON};
+ use libc::MAP_FAILED;
+
+ use crate::sys_common::thread_info;
+
+
+ #[cfg(any(target_os = "linux", target_os = "android"))]
+ unsafe fn siginfo_si_addr(info: *mut libc::siginfo_t) -> usize {
+ #[repr(C)]
+ struct siginfo_t {
+ a: [libc::c_int; 3], // si_signo, si_errno, si_code
+ si_addr: *mut libc::c_void,
+ }
+
+ (*(info as *const siginfo_t)).si_addr as usize
+ }
+
+ #[cfg(not(any(target_os = "linux", target_os = "android")))]
+ unsafe fn siginfo_si_addr(info: *mut libc::siginfo_t) -> usize {
+ (*info).si_addr as usize
+ }
+
+ // Signal handler for the SIGSEGV and SIGBUS handlers. We've got guard pages
+ // (unmapped pages) at the end of every thread's stack, so if a thread ends
+ // up running into the guard page it'll trigger this handler. We want to
+ // detect these cases and print out a helpful error saying that the stack
+ // has overflowed. All other signals, however, should go back to what they
+ // were originally supposed to do.
+ //
+ // This handler currently exists purely to print an informative message
+ // whenever a thread overflows its stack. We then abort to exit and
+ // indicate a crash, but to avoid a misleading SIGSEGV that might lead
+ // users to believe that unsafe code has accessed an invalid pointer; the
+ // SIGSEGV encountered when overflowing the stack is expected and
+ // well-defined.
+ //
+ // If this is not a stack overflow, the handler un-registers itself and
+ // then returns (to allow the original signal to be delivered again).
+ // Returning from this kind of signal handler is technically not defined
+ // to work when reading the POSIX spec strictly, but in practice it turns
+ // out many large systems and all implementations allow returning from a
+ // signal handler to work. For a more detailed explanation see the
+ // comments on #26458.
+ unsafe extern fn signal_handler(signum: libc::c_int,
+ info: *mut libc::siginfo_t,
+ _data: *mut libc::c_void) {
+ use crate::sys_common::util::report_overflow;
+
+ let guard = thread_info::stack_guard().unwrap_or(0..0);
+ let addr = siginfo_si_addr(info);
+
+ // If the faulting address is within the guard page, then we print a
+ // message saying so and abort.
+ if guard.start <= addr && addr < guard.end {
+ report_overflow();
+ rtabort!("stack overflow");
+ } else {
+ // Unregister ourselves by reverting back to the default behavior.
+ let mut action: sigaction = mem::zeroed();
+ action.sa_sigaction = SIG_DFL;
+ sigaction(signum, &action, ptr::null_mut());
+
+ // See comment above for why this function returns.
+ }
+ }
+
+ static mut MAIN_ALTSTACK: *mut libc::c_void = ptr::null_mut();
+
+ pub unsafe fn init() {
+ let mut action: sigaction = mem::zeroed();
+ action.sa_flags = SA_SIGINFO | SA_ONSTACK;
+ action.sa_sigaction = signal_handler as sighandler_t;
+ sigaction(SIGSEGV, &action, ptr::null_mut());
+ sigaction(SIGBUS, &action, ptr::null_mut());
+
+ let handler = make_handler();
+ MAIN_ALTSTACK = handler._data;
+ mem::forget(handler);
+ }
+
+ pub unsafe fn cleanup() {
+ Handler { _data: MAIN_ALTSTACK };
+ }
+
+ unsafe fn get_stackp() -> *mut libc::c_void {
+ let stackp = mmap(ptr::null_mut(),
+ SIGSTKSZ,
+ PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANON,
+ -1,
+ 0);
+ if stackp == MAP_FAILED {
+ panic!("failed to allocate an alternative stack");
+ }
+ stackp
+ }
+
+ #[cfg(any(target_os = "linux",
+ target_os = "macos",
+ target_os = "bitrig",
+ target_os = "freebsd",
+ target_os = "netbsd",
+ target_os = "openbsd",
+ target_os = "solaris"))]
+ unsafe fn get_stack() -> libc::stack_t {
+ libc::stack_t { ss_sp: get_stackp(), ss_flags: 0, ss_size: SIGSTKSZ }
+ }
+
+ #[cfg(target_os = "dragonfly")]
+ unsafe fn get_stack() -> libc::stack_t {
+ libc::stack_t { ss_sp: get_stackp() as *mut i8, ss_flags: 0, ss_size: SIGSTKSZ }
+ }
+
+ pub unsafe fn make_handler() -> Handler {
+ let mut stack = mem::zeroed();
+ sigaltstack(ptr::null(), &mut stack);
+ // Configure alternate signal stack, if one is not already set.
+ if stack.ss_flags & SS_DISABLE != 0 {
+ stack = get_stack();
+ sigaltstack(&stack, ptr::null_mut());
+ Handler { _data: stack.ss_sp as *mut libc::c_void }
+ } else {
+ Handler { _data: ptr::null_mut() }
+ }
+ }
+
+ pub unsafe fn drop_handler(handler: &mut Handler) {
+ if !handler._data.is_null() {
+ let stack = libc::stack_t {
+ ss_sp: ptr::null_mut(),
+ ss_flags: SS_DISABLE,
+ // Workaround for bug in macOS implementation of sigaltstack
+ // UNIX2003 which returns ENOMEM when disabling a stack while
+ // passing ss_size smaller than MINSIGSTKSZ. According to POSIX
+ // both ss_sp and ss_size should be ignored in this case.
+ ss_size: SIGSTKSZ,
+ };
+ sigaltstack(&stack, ptr::null_mut());
+ munmap(handler._data, SIGSTKSZ);
+ }
+ }
+}
+
+#[cfg(not(any(target_os = "linux",
+ target_os = "macos",
+ target_os = "bitrig",
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "solaris",
+ all(target_os = "netbsd", not(target_vendor = "rumprun")),
+ target_os = "openbsd")))]
+mod imp {
+ use crate::ptr;
+
+ pub unsafe fn init() {
+ }
+
+ pub unsafe fn cleanup() {
+ }
+
+ pub unsafe fn make_handler() -> super::Handler {
+ super::Handler { _data: ptr::null_mut() }
+ }
+
+ pub unsafe fn drop_handler(_handler: &mut super::Handler) {
+ }
+}
diff --git a/src/libstd/sys/unix/stdio.rs b/src/libstd/sys/unix/stdio.rs
new file mode 100644
index 0000000..35f163b
--- /dev/null
+++ b/src/libstd/sys/unix/stdio.rs
@@ -0,0 +1,63 @@
+use crate::io;
+use crate::sys::fd::FileDesc;
+
+pub struct Stdin(());
+pub struct Stdout(());
+pub struct Stderr(());
+
+impl Stdin {
+ pub fn new() -> io::Result<Stdin> { Ok(Stdin(())) }
+}
+
+impl io::Read for Stdin {
+ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+ let fd = FileDesc::new(libc::STDIN_FILENO);
+ let ret = fd.read(buf);
+ fd.into_raw(); // do not close this FD
+ ret
+ }
+}
+
+impl Stdout {
+ pub fn new() -> io::Result<Stdout> { Ok(Stdout(())) }
+}
+
+impl io::Write for Stdout {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ let fd = FileDesc::new(libc::STDOUT_FILENO);
+ let ret = fd.write(buf);
+ fd.into_raw(); // do not close this FD
+ ret
+ }
+
+ fn flush(&mut self) -> io::Result<()> {
+ Ok(())
+ }
+}
+
+impl Stderr {
+ pub fn new() -> io::Result<Stderr> { Ok(Stderr(())) }
+}
+
+impl io::Write for Stderr {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ let fd = FileDesc::new(libc::STDERR_FILENO);
+ let ret = fd.write(buf);
+ fd.into_raw(); // do not close this FD
+ ret
+ }
+
+ fn flush(&mut self) -> io::Result<()> {
+ Ok(())
+ }
+}
+
+pub fn is_ebadf(err: &io::Error) -> bool {
+ err.raw_os_error() == Some(libc::EBADF as i32)
+}
+
+pub const STDIN_BUF_SIZE: usize = crate::sys_common::io::DEFAULT_BUF_SIZE;
+
+pub fn panic_output() -> Option<impl io::Write> {
+ Stderr::new().ok()
+}
diff --git a/src/libstd/sys/unix/thread.rs b/src/libstd/sys/unix/thread.rs
new file mode 100644
index 0000000..feb15e8
--- /dev/null
+++ b/src/libstd/sys/unix/thread.rs
@@ -0,0 +1,427 @@
+use crate::boxed::FnBox;
+use crate::cmp;
+use crate::ffi::CStr;
+use crate::io;
+use crate::mem;
+use crate::ptr;
+use crate::sys::os;
+use crate::time::Duration;
+
+use crate::sys_common::thread::*;
+
+#[cfg(not(target_os = "l4re"))]
+pub const DEFAULT_MIN_STACK_SIZE: usize = 2 * 1024 * 1024;
+#[cfg(target_os = "l4re")]
+pub const DEFAULT_MIN_STACK_SIZE: usize = 1024 * 1024;
+
+pub struct Thread {
+ id: libc::pthread_t,
+}
+
+// Some platforms may have pthread_t as a pointer in which case we still want
+// a thread to be Send/Sync
+unsafe impl Send for Thread {}
+unsafe impl Sync for Thread {}
+
+// The pthread_attr_setstacksize symbol doesn't exist in the emscripten libc,
+// so we have to not link to it to satisfy emcc's ERROR_ON_UNDEFINED_SYMBOLS.
+#[cfg(not(target_os = "emscripten"))]
+unsafe fn pthread_attr_setstacksize(attr: *mut libc::pthread_attr_t,
+ stack_size: libc::size_t) -> libc::c_int {
+ libc::pthread_attr_setstacksize(attr, stack_size)
+}
+
+#[cfg(target_os = "emscripten")]
+unsafe fn pthread_attr_setstacksize(_attr: *mut libc::pthread_attr_t,
+ _stack_size: libc::size_t) -> libc::c_int {
+ panic!()
+}
+
+impl Thread {
+ // unsafe: see thread::Builder::spawn_unchecked for safety requirements
+ pub unsafe fn new(stack: usize, p: Box<dyn FnBox()>)
+ -> io::Result<Thread> {
+ let p = box p;
+ let mut native: libc::pthread_t = mem::zeroed();
+ let mut attr: libc::pthread_attr_t = mem::zeroed();
+ assert_eq!(libc::pthread_attr_init(&mut attr), 0);
+
+ let stack_size = cmp::max(stack, min_stack_size(&attr));
+
+ match pthread_attr_setstacksize(&mut attr,
+ stack_size) {
+ 0 => {}
+ n => {
+ assert_eq!(n, libc::EINVAL);
+ // EINVAL means |stack_size| is either too small or not a
+ // multiple of the system page size. Because it's definitely
+ // >= PTHREAD_STACK_MIN, it must be an alignment issue.
+ // Round up to the nearest page and try again.
+ let page_size = os::page_size();
+ let stack_size = (stack_size + page_size - 1) &
+ (-(page_size as isize - 1) as usize - 1);
+ assert_eq!(libc::pthread_attr_setstacksize(&mut attr,
+ stack_size), 0);
+ }
+ };
+
+ let ret = libc::pthread_create(&mut native, &attr, thread_start,
+ &*p as *const _ as *mut _);
+ assert_eq!(libc::pthread_attr_destroy(&mut attr), 0);
+
+ return if ret != 0 {
+ Err(io::Error::from_raw_os_error(ret))
+ } else {
+ mem::forget(p); // ownership passed to pthread_create
+ Ok(Thread { id: native })
+ };
+
+ extern fn thread_start(main: *mut libc::c_void) -> *mut libc::c_void {
+ unsafe { start_thread(main as *mut u8); }
+ ptr::null_mut()
+ }
+ }
+
+ pub fn yield_now() {
+ let ret = unsafe { libc::sched_yield() };
+ debug_assert_eq!(ret, 0);
+ }
+
+ #[cfg(any(target_os = "linux",
+ target_os = "android"))]
+ pub fn set_name(name: &CStr) {
+ const PR_SET_NAME: libc::c_int = 15;
+ // pthread wrapper only appeared in glibc 2.12, so we use syscall
+ // directly.
+ unsafe {
+ libc::prctl(PR_SET_NAME, name.as_ptr() as libc::c_ulong, 0, 0, 0);
+ }
+ }
+
+ #[cfg(any(target_os = "freebsd",
+ target_os = "dragonfly",
+ target_os = "bitrig",
+ target_os = "openbsd"))]
+ pub fn set_name(name: &CStr) {
+ unsafe {
+ libc::pthread_set_name_np(libc::pthread_self(), name.as_ptr());
+ }
+ }
+
+ #[cfg(any(target_os = "macos", target_os = "ios"))]
+ pub fn set_name(name: &CStr) {
+ unsafe {
+ libc::pthread_setname_np(name.as_ptr());
+ }
+ }
+
+ #[cfg(target_os = "netbsd")]
+ pub fn set_name(name: &CStr) {
+ use crate::ffi::CString;
+ let cname = CString::new(&b"%s"[..]).unwrap();
+ unsafe {
+ libc::pthread_setname_np(libc::pthread_self(), cname.as_ptr(),
+ name.as_ptr() as *mut libc::c_void);
+ }
+ }
+ #[cfg(any(target_env = "newlib",
+ target_os = "solaris",
+ target_os = "haiku",
+ target_os = "l4re",
+ target_os = "emscripten",
+ target_os = "hermit"))]
+ pub fn set_name(_name: &CStr) {
+ // Newlib, Illumos, Haiku, and Emscripten have no way to set a thread name.
+ }
+ #[cfg(target_os = "fuchsia")]
+ pub fn set_name(_name: &CStr) {
+ // FIXME: determine whether Fuchsia has a way to set a thread name.
+ }
+
+ pub fn sleep(dur: Duration) {
+ let mut secs = dur.as_secs();
+ let mut nsecs = dur.subsec_nanos() as _;
+
+ // If we're awoken with a signal then the return value will be -1 and
+ // nanosleep will fill in `ts` with the remaining time.
+ unsafe {
+ while secs > 0 || nsecs > 0 {
+ let mut ts = libc::timespec {
+ tv_sec: cmp::min(libc::time_t::max_value() as u64, secs) as libc::time_t,
+ tv_nsec: nsecs,
+ };
+ secs -= ts.tv_sec as u64;
+ if libc::nanosleep(&ts, &mut ts) == -1 {
+ assert_eq!(os::errno(), libc::EINTR);
+ secs += ts.tv_sec as u64;
+ nsecs = ts.tv_nsec;
+ } else {
+ nsecs = 0;
+ }
+ }
+ }
+ }
+
+ pub fn join(self) {
+ unsafe {
+ let ret = libc::pthread_join(self.id, ptr::null_mut());
+ mem::forget(self);
+ assert!(ret == 0,
+ "failed to join thread: {}", io::Error::from_raw_os_error(ret));
+ }
+ }
+
+ pub fn id(&self) -> libc::pthread_t { self.id }
+
+ pub fn into_id(self) -> libc::pthread_t {
+ let id = self.id;
+ mem::forget(self);
+ id
+ }
+}
+
+impl Drop for Thread {
+ fn drop(&mut self) {
+ let ret = unsafe { libc::pthread_detach(self.id) };
+ debug_assert_eq!(ret, 0);
+ }
+}
+
+#[cfg(all(not(all(target_os = "linux", not(target_env = "musl"))),
+ not(target_os = "freebsd"),
+ not(target_os = "macos"),
+ not(target_os = "bitrig"),
+ not(all(target_os = "netbsd", not(target_vendor = "rumprun"))),
+ not(target_os = "openbsd"),
+ not(target_os = "solaris")))]
+#[cfg_attr(test, allow(dead_code))]
+pub mod guard {
+ use crate::ops::Range;
+ pub type Guard = Range<usize>;
+ pub unsafe fn current() -> Option<Guard> { None }
+ pub unsafe fn init() -> Option<Guard> { None }
+}
+
+
+#[cfg(any(all(target_os = "linux", not(target_env = "musl")),
+ target_os = "freebsd",
+ target_os = "macos",
+ target_os = "bitrig",
+ all(target_os = "netbsd", not(target_vendor = "rumprun")),
+ target_os = "openbsd",
+ target_os = "solaris"))]
+#[cfg_attr(test, allow(dead_code))]
+pub mod guard {
+ use libc::{mmap, mprotect};
+ use libc::{PROT_NONE, PROT_READ, PROT_WRITE, MAP_PRIVATE, MAP_ANON, MAP_FAILED, MAP_FIXED};
+
+ use crate::ops::Range;
+ use crate::sys::os;
+
+ // This is initialized in init() and only read from after
+ static mut PAGE_SIZE: usize = 0;
+
+ pub type Guard = Range<usize>;
+
+ #[cfg(target_os = "solaris")]
+ unsafe fn get_stack_start() -> Option<*mut libc::c_void> {
+ let mut current_stack: libc::stack_t = crate::mem::zeroed();
+ assert_eq!(libc::stack_getbounds(&mut current_stack), 0);
+ Some(current_stack.ss_sp)
+ }
+
+ #[cfg(target_os = "macos")]
+ unsafe fn get_stack_start() -> Option<*mut libc::c_void> {
+ let stackaddr = libc::pthread_get_stackaddr_np(libc::pthread_self()) as usize -
+ libc::pthread_get_stacksize_np(libc::pthread_self());
+ Some(stackaddr as *mut libc::c_void)
+ }
+
+ #[cfg(any(target_os = "openbsd", target_os = "bitrig"))]
+ unsafe fn get_stack_start() -> Option<*mut libc::c_void> {
+ let mut current_stack: libc::stack_t = crate::mem::zeroed();
+ assert_eq!(libc::pthread_stackseg_np(libc::pthread_self(),
+ &mut current_stack), 0);
+
+ let extra = if cfg!(target_os = "bitrig") {3} else {1} * PAGE_SIZE;
+ let stackaddr = if libc::pthread_main_np() == 1 {
+ // main thread
+ current_stack.ss_sp as usize - current_stack.ss_size + extra
+ } else {
+ // new thread
+ current_stack.ss_sp as usize - current_stack.ss_size
+ };
+ Some(stackaddr as *mut libc::c_void)
+ }
+
+ #[cfg(any(target_os = "android", target_os = "freebsd",
+ target_os = "linux", target_os = "netbsd", target_os = "l4re"))]
+ unsafe fn get_stack_start() -> Option<*mut libc::c_void> {
+ let mut ret = None;
+ let mut attr: libc::pthread_attr_t = crate::mem::zeroed();
+ assert_eq!(libc::pthread_attr_init(&mut attr), 0);
+ #[cfg(target_os = "freebsd")]
+ let e = libc::pthread_attr_get_np(libc::pthread_self(), &mut attr);
+ #[cfg(not(target_os = "freebsd"))]
+ let e = libc::pthread_getattr_np(libc::pthread_self(), &mut attr);
+ if e == 0 {
+ let mut stackaddr = crate::ptr::null_mut();
+ let mut stacksize = 0;
+ assert_eq!(libc::pthread_attr_getstack(&attr, &mut stackaddr,
+ &mut stacksize), 0);
+ ret = Some(stackaddr);
+ }
+ assert_eq!(libc::pthread_attr_destroy(&mut attr), 0);
+ ret
+ }
+
+ // Precondition: PAGE_SIZE is initialized.
+ unsafe fn get_stack_start_aligned() -> Option<*mut libc::c_void> {
+ assert!(PAGE_SIZE != 0);
+ let stackaddr = get_stack_start()?;
+
+ // Ensure stackaddr is page aligned! A parent process might
+ // have reset RLIMIT_STACK to be non-page aligned. The
+ // pthread_attr_getstack() reports the usable stack area
+ // stackaddr < stackaddr + stacksize, so if stackaddr is not
+ // page-aligned, calculate the fix such that stackaddr <
+ // new_page_aligned_stackaddr < stackaddr + stacksize
+ let remainder = (stackaddr as usize) % PAGE_SIZE;
+ Some(if remainder == 0 {
+ stackaddr
+ } else {
+ ((stackaddr as usize) + PAGE_SIZE - remainder) as *mut libc::c_void
+ })
+ }
+
+ pub unsafe fn init() -> Option<Guard> {
+ PAGE_SIZE = os::page_size();
+
+ let stackaddr = get_stack_start_aligned()?;
+
+ if cfg!(target_os = "linux") {
+ // Linux doesn't allocate the whole stack right away, and
+ // the kernel has its own stack-guard mechanism to fault
+ // when growing too close to an existing mapping. If we map
+ // our own guard, then the kernel starts enforcing a rather
+ // large gap above that, rendering much of the possible
+ // stack space useless. See #43052.
+ //
+ // Instead, we'll just note where we expect rlimit to start
+ // faulting, so our handler can report "stack overflow", and
+ // trust that the kernel's own stack guard will work.
+ let stackaddr = stackaddr as usize;
+ Some(stackaddr - PAGE_SIZE..stackaddr)
+ } else {
+ // Reallocate the last page of the stack.
+ // This ensures SIGBUS will be raised on
+ // stack overflow.
+ // Systems which enforce strict PAX MPROTECT do not allow
+ // to mprotect() a mapping with less restrictive permissions
+ // than the initial mmap() used, so we mmap() here with
+ // read/write permissions and only then mprotect() it to
+ // no permissions at all. See issue #50313.
+ let result = mmap(stackaddr, PAGE_SIZE, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANON | MAP_FIXED, -1, 0);
+ if result != stackaddr || result == MAP_FAILED {
+ panic!("failed to allocate a guard page");
+ }
+
+ let result = mprotect(stackaddr, PAGE_SIZE, PROT_NONE);
+ if result != 0 {
+ panic!("failed to protect the guard page");
+ }
+
+ let guardaddr = stackaddr as usize;
+ let offset = if cfg!(target_os = "freebsd") {
+ 2
+ } else {
+ 1
+ };
+
+ Some(guardaddr..guardaddr + offset * PAGE_SIZE)
+ }
+ }
+
+ #[cfg(any(target_os = "macos",
+ target_os = "bitrig",
+ target_os = "openbsd",
+ target_os = "solaris"))]
+ pub unsafe fn current() -> Option<Guard> {
+ let stackaddr = get_stack_start()? as usize;
+ Some(stackaddr - PAGE_SIZE..stackaddr)
+ }
+
+ #[cfg(any(target_os = "android", target_os = "freebsd",
+ target_os = "linux", target_os = "netbsd", target_os = "l4re"))]
+ pub unsafe fn current() -> Option<Guard> {
+ let mut ret = None;
+ let mut attr: libc::pthread_attr_t = crate::mem::zeroed();
+ assert_eq!(libc::pthread_attr_init(&mut attr), 0);
+ #[cfg(target_os = "freebsd")]
+ let e = libc::pthread_attr_get_np(libc::pthread_self(), &mut attr);
+ #[cfg(not(target_os = "freebsd"))]
+ let e = libc::pthread_getattr_np(libc::pthread_self(), &mut attr);
+ if e == 0 {
+ let mut guardsize = 0;
+ assert_eq!(libc::pthread_attr_getguardsize(&attr, &mut guardsize), 0);
+ if guardsize == 0 {
+ panic!("there is no guard page");
+ }
+ let mut stackaddr = crate::ptr::null_mut();
+ let mut size = 0;
+ assert_eq!(libc::pthread_attr_getstack(&attr, &mut stackaddr,
+ &mut size), 0);
+
+ let stackaddr = stackaddr as usize;
+ ret = if cfg!(target_os = "freebsd") {
+ // FIXME does freebsd really fault *below* the guard addr?
+ let guardaddr = stackaddr - guardsize;
+ Some(guardaddr - PAGE_SIZE..guardaddr)
+ } else if cfg!(target_os = "netbsd") {
+ Some(stackaddr - guardsize..stackaddr)
+ } else if cfg!(all(target_os = "linux", target_env = "gnu")) {
+ // glibc used to include the guard area within the stack, as noted in the BUGS
+ // section of `man pthread_attr_getguardsize`. This has been corrected starting
+ // with glibc 2.27, and in some distro backports, so the guard is now placed at the
+ // end (below) the stack. There's no easy way for us to know which we have at
+ // runtime, so we'll just match any fault in the range right above or below the
+ // stack base to call that fault a stack overflow.
+ Some(stackaddr - guardsize..stackaddr + guardsize)
+ } else {
+ Some(stackaddr..stackaddr + guardsize)
+ };
+ }
+ assert_eq!(libc::pthread_attr_destroy(&mut attr), 0);
+ ret
+ }
+}
+
+// glibc >= 2.15 has a __pthread_get_minstack() function that returns
+// PTHREAD_STACK_MIN plus however many bytes are needed for thread-local
+// storage. We need that information to avoid blowing up when a small stack
+// is created in an application with big thread-local storage requirements.
+// See #6233 for rationale and details.
+#[cfg(target_os = "linux")]
+#[allow(deprecated)]
+fn min_stack_size(attr: *const libc::pthread_attr_t) -> usize {
+ weak!(fn __pthread_get_minstack(*const libc::pthread_attr_t) -> libc::size_t);
+
+ match __pthread_get_minstack.get() {
+ None => libc::PTHREAD_STACK_MIN,
+ Some(f) => unsafe { f(attr) },
+ }
+}
+
+// No point in looking up __pthread_get_minstack() on non-glibc
+// platforms.
+#[cfg(all(not(target_os = "linux"),
+ not(target_os = "netbsd")))]
+fn min_stack_size(_: *const libc::pthread_attr_t) -> usize {
+ libc::PTHREAD_STACK_MIN
+}
+
+#[cfg(target_os = "netbsd")]
+fn min_stack_size(_: *const libc::pthread_attr_t) -> usize {
+ 2048 // just a guess
+}
diff --git a/src/libstd/sys/unix/thread_local.rs b/src/libstd/sys/unix/thread_local.rs
new file mode 100644
index 0000000..ac615b7
--- /dev/null
+++ b/src/libstd/sys/unix/thread_local.rs
@@ -0,0 +1,34 @@
+#![allow(dead_code)] // not used on all platforms
+
+use crate::mem;
+
+pub type Key = libc::pthread_key_t;
+
+#[inline]
+pub unsafe fn create(dtor: Option<unsafe extern fn(*mut u8)>) -> Key {
+ let mut key = 0;
+ assert_eq!(libc::pthread_key_create(&mut key, mem::transmute(dtor)), 0);
+ key
+}
+
+#[inline]
+pub unsafe fn set(key: Key, value: *mut u8) {
+ let r = libc::pthread_setspecific(key, value as *mut _);
+ debug_assert_eq!(r, 0);
+}
+
+#[inline]
+pub unsafe fn get(key: Key) -> *mut u8 {
+ libc::pthread_getspecific(key) as *mut u8
+}
+
+#[inline]
+pub unsafe fn destroy(key: Key) {
+ let r = libc::pthread_key_delete(key);
+ debug_assert_eq!(r, 0);
+}
+
+#[inline]
+pub fn requires_synchronized_create() -> bool {
+ false
+}
diff --git a/src/libstd/sys/unix/time.rs b/src/libstd/sys/unix/time.rs
new file mode 100644
index 0000000..e21c32c
--- /dev/null
+++ b/src/libstd/sys/unix/time.rs
@@ -0,0 +1,373 @@
+use crate::cmp::Ordering;
+use crate::time::Duration;
+
+use core::hash::{Hash, Hasher};
+
+pub use self::inner::{Instant, SystemTime, UNIX_EPOCH};
+use crate::convert::TryInto;
+
+const NSEC_PER_SEC: u64 = 1_000_000_000;
+
+#[derive(Copy, Clone)]
+struct Timespec {
+ t: libc::timespec,
+}
+
+impl Timespec {
+ const fn zero() -> Timespec {
+ Timespec {
+ t: libc::timespec { tv_sec: 0, tv_nsec: 0 },
+ }
+ }
+
+ fn sub_timespec(&self, other: &Timespec) -> Result<Duration, Duration> {
+ if self >= other {
+ Ok(if self.t.tv_nsec >= other.t.tv_nsec {
+ Duration::new((self.t.tv_sec - other.t.tv_sec) as u64,
+ (self.t.tv_nsec - other.t.tv_nsec) as u32)
+ } else {
+ Duration::new((self.t.tv_sec - 1 - other.t.tv_sec) as u64,
+ self.t.tv_nsec as u32 + (NSEC_PER_SEC as u32) -
+ other.t.tv_nsec as u32)
+ })
+ } else {
+ match other.sub_timespec(self) {
+ Ok(d) => Err(d),
+ Err(d) => Ok(d),
+ }
+ }
+ }
+
+ fn checked_add_duration(&self, other: &Duration) -> Option<Timespec> {
+ let mut secs = other
+ .as_secs()
+ .try_into() // <- target type would be `libc::time_t`
+ .ok()
+ .and_then(|secs| self.t.tv_sec.checked_add(secs))?;
+
+ // Nano calculations can't overflow because nanos are <1B which fit
+ // in a u32.
+ let mut nsec = other.subsec_nanos() + self.t.tv_nsec as u32;
+ if nsec >= NSEC_PER_SEC as u32 {
+ nsec -= NSEC_PER_SEC as u32;
+ secs = secs.checked_add(1)?;
+ }
+ Some(Timespec {
+ t: libc::timespec {
+ tv_sec: secs,
+ tv_nsec: nsec as _,
+ },
+ })
+ }
+
+ fn checked_sub_duration(&self, other: &Duration) -> Option<Timespec> {
+ let mut secs = other
+ .as_secs()
+ .try_into() // <- target type would be `libc::time_t`
+ .ok()
+ .and_then(|secs| self.t.tv_sec.checked_sub(secs))?;
+
+ // Similar to above, nanos can't overflow.
+ let mut nsec = self.t.tv_nsec as i32 - other.subsec_nanos() as i32;
+ if nsec < 0 {
+ nsec += NSEC_PER_SEC as i32;
+ secs = secs.checked_sub(1)?;
+ }
+ Some(Timespec {
+ t: libc::timespec {
+ tv_sec: secs,
+ tv_nsec: nsec as _,
+ },
+ })
+ }
+}
+
+impl PartialEq for Timespec {
+ fn eq(&self, other: &Timespec) -> bool {
+ self.t.tv_sec == other.t.tv_sec && self.t.tv_nsec == other.t.tv_nsec
+ }
+}
+
+impl Eq for Timespec {}
+
+impl PartialOrd for Timespec {
+ fn partial_cmp(&self, other: &Timespec) -> Option<Ordering> {
+ Some(self.cmp(other))
+ }
+}
+
+impl Ord for Timespec {
+ fn cmp(&self, other: &Timespec) -> Ordering {
+ let me = (self.t.tv_sec, self.t.tv_nsec);
+ let other = (other.t.tv_sec, other.t.tv_nsec);
+ me.cmp(&other)
+ }
+}
+
+impl Hash for Timespec {
+ fn hash<H : Hasher>(&self, state: &mut H) {
+ self.t.tv_sec.hash(state);
+ self.t.tv_nsec.hash(state);
+ }
+}
+
+#[cfg(any(target_os = "macos", target_os = "ios"))]
+mod inner {
+ use crate::fmt;
+ use crate::mem;
+ use crate::sync::atomic::{AtomicUsize, Ordering::SeqCst};
+ use crate::sys::cvt;
+ use crate::sys_common::mul_div_u64;
+ use crate::time::Duration;
+
+ use super::NSEC_PER_SEC;
+ use super::Timespec;
+
+ #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
+ pub struct Instant {
+ t: u64
+ }
+
+ #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
+ pub struct SystemTime {
+ t: Timespec,
+ }
+
+ pub const UNIX_EPOCH: SystemTime = SystemTime {
+ t: Timespec::zero(),
+ };
+
+ impl Instant {
+ pub fn now() -> Instant {
+ Instant { t: unsafe { libc::mach_absolute_time() } }
+ }
+
+ pub const fn zero() -> Instant {
+ Instant { t: 0 }
+ }
+
+ pub fn actually_monotonic() -> bool {
+ true
+ }
+
+ pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
+ let diff = self.t.checked_sub(other.t)?;
+ let info = info();
+ let nanos = mul_div_u64(diff, info.numer as u64, info.denom as u64);
+ Some(Duration::new(nanos / NSEC_PER_SEC, (nanos % NSEC_PER_SEC) as u32))
+ }
+
+ pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
+ Some(Instant {
+ t: self.t.checked_add(checked_dur2intervals(other)?)?,
+ })
+ }
+
+ pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
+ Some(Instant {
+ t: self.t.checked_sub(checked_dur2intervals(other)?)?,
+ })
+ }
+ }
+
+ impl SystemTime {
+ pub fn now() -> SystemTime {
+ use crate::ptr;
+
+ let mut s = libc::timeval {
+ tv_sec: 0,
+ tv_usec: 0,
+ };
+ cvt(unsafe {
+ libc::gettimeofday(&mut s, ptr::null_mut())
+ }).unwrap();
+ return SystemTime::from(s)
+ }
+
+ pub fn sub_time(&self, other: &SystemTime)
+ -> Result<Duration, Duration> {
+ self.t.sub_timespec(&other.t)
+ }
+
+ pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
+ Some(SystemTime { t: self.t.checked_add_duration(other)? })
+ }
+
+ pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
+ Some(SystemTime { t: self.t.checked_sub_duration(other)? })
+ }
+ }
+
+ impl From<libc::timeval> for SystemTime {
+ fn from(t: libc::timeval) -> SystemTime {
+ SystemTime::from(libc::timespec {
+ tv_sec: t.tv_sec,
+ tv_nsec: (t.tv_usec * 1000) as libc::c_long,
+ })
+ }
+ }
+
+ impl From<libc::timespec> for SystemTime {
+ fn from(t: libc::timespec) -> SystemTime {
+ SystemTime { t: Timespec { t } }
+ }
+ }
+
+ impl fmt::Debug for SystemTime {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("SystemTime")
+ .field("tv_sec", &self.t.t.tv_sec)
+ .field("tv_nsec", &self.t.t.tv_nsec)
+ .finish()
+ }
+ }
+
+ fn checked_dur2intervals(dur: &Duration) -> Option<u64> {
+ let nanos = dur.as_secs()
+ .checked_mul(NSEC_PER_SEC)?
+ .checked_add(dur.subsec_nanos() as u64)?;
+ let info = info();
+ Some(mul_div_u64(nanos, info.denom as u64, info.numer as u64))
+ }
+
+ fn info() -> libc::mach_timebase_info {
+ static mut INFO: libc::mach_timebase_info = libc::mach_timebase_info {
+ numer: 0,
+ denom: 0,
+ };
+ static STATE: AtomicUsize = AtomicUsize::new(0);
+
+ unsafe {
+ // If a previous thread has filled in this global state, use that.
+ if STATE.load(SeqCst) == 2 {
+ return INFO;
+ }
+
+ // ... otherwise learn for ourselves ...
+ let mut info = mem::zeroed();
+ libc::mach_timebase_info(&mut info);
+
+ // ... and attempt to be the one thread that stores it globally for
+ // all other threads
+ if STATE.compare_exchange(0, 1, SeqCst, SeqCst).is_ok() {
+ INFO = info;
+ STATE.store(2, SeqCst);
+ }
+ return info;
+ }
+ }
+}
+
+#[cfg(not(any(target_os = "macos", target_os = "ios")))]
+mod inner {
+ use crate::fmt;
+ use crate::sys::cvt;
+ use crate::time::Duration;
+
+ use super::Timespec;
+
+ #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
+ pub struct Instant {
+ t: Timespec,
+ }
+
+ #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
+ pub struct SystemTime {
+ t: Timespec,
+ }
+
+ pub const UNIX_EPOCH: SystemTime = SystemTime {
+ t: Timespec::zero(),
+ };
+
+ impl Instant {
+ pub fn now() -> Instant {
+ Instant { t: now(libc::CLOCK_MONOTONIC) }
+ }
+
+ pub const fn zero() -> Instant {
+ Instant {
+ t: Timespec::zero(),
+ }
+ }
+
+ pub fn actually_monotonic() -> bool {
+ (cfg!(target_os = "linux") && cfg!(target_arch = "x86_64")) ||
+ (cfg!(target_os = "linux") && cfg!(target_arch = "x86")) ||
+ false // last clause, used so `||` is always trailing above
+ }
+
+ pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
+ self.t.sub_timespec(&other.t).ok()
+ }
+
+ pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
+ Some(Instant { t: self.t.checked_add_duration(other)? })
+ }
+
+ pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
+ Some(Instant { t: self.t.checked_sub_duration(other)? })
+ }
+ }
+
+ impl fmt::Debug for Instant {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("Instant")
+ .field("tv_sec", &self.t.t.tv_sec)
+ .field("tv_nsec", &self.t.t.tv_nsec)
+ .finish()
+ }
+ }
+
+ impl SystemTime {
+ pub fn now() -> SystemTime {
+ SystemTime { t: now(libc::CLOCK_REALTIME) }
+ }
+
+ pub fn sub_time(&self, other: &SystemTime)
+ -> Result<Duration, Duration> {
+ self.t.sub_timespec(&other.t)
+ }
+
+ pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
+ Some(SystemTime { t: self.t.checked_add_duration(other)? })
+ }
+
+ pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
+ Some(SystemTime { t: self.t.checked_sub_duration(other)? })
+ }
+ }
+
+ impl From<libc::timespec> for SystemTime {
+ fn from(t: libc::timespec) -> SystemTime {
+ SystemTime { t: Timespec { t } }
+ }
+ }
+
+ impl fmt::Debug for SystemTime {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("SystemTime")
+ .field("tv_sec", &self.t.t.tv_sec)
+ .field("tv_nsec", &self.t.t.tv_nsec)
+ .finish()
+ }
+ }
+
+ #[cfg(not(any(target_os = "dragonfly", target_os = "hermit")))]
+ pub type clock_t = libc::c_int;
+ #[cfg(any(target_os = "dragonfly", target_os = "hermit"))]
+ pub type clock_t = libc::c_ulong;
+
+ fn now(clock: clock_t) -> Timespec {
+ let mut t = Timespec {
+ t: libc::timespec {
+ tv_sec: 0,
+ tv_nsec: 0,
+ }
+ };
+ cvt(unsafe {
+ libc::clock_gettime(clock, &mut t.t)
+ }).unwrap();
+ t
+ }
+}
diff --git a/src/libstd/sys/unix/weak.rs b/src/libstd/sys/unix/weak.rs
new file mode 100644
index 0000000..9a7691e
--- /dev/null
+++ b/src/libstd/sys/unix/weak.rs
@@ -0,0 +1,100 @@
+//! Support for "weak linkage" to symbols on Unix
+//!
+//! Some I/O operations we do in libstd require newer versions of OSes but we
+//! need to maintain binary compatibility with older releases for now. In order
+//! to use the new functionality when available we use this module for
+//! detection.
+//!
+//! One option to use here is weak linkage, but that is unfortunately only
+//! really workable on Linux. Hence, use dlsym to get the symbol value at
+//! runtime. This is also done for compatibility with older versions of glibc,
+//! and to avoid creating dependencies on GLIBC_PRIVATE symbols. It assumes that
+//! we've been dynamically linked to the library the symbol comes from, but that
+//! is currently always the case for things like libpthread/libc.
+//!
+//! A long time ago this used weak linkage for the __pthread_get_minstack
+//! symbol, but that caused Debian to detect an unnecessarily strict versioned
+//! dependency on libc6 (#23628).
+
+use crate::ffi::CStr;
+use crate::marker;
+use crate::mem;
+use crate::sync::atomic::{AtomicUsize, Ordering};
+
+macro_rules! weak {
+ (fn $name:ident($($t:ty),*) -> $ret:ty) => (
+ static $name: crate::sys::weak::Weak<unsafe extern fn($($t),*) -> $ret> =
+ crate::sys::weak::Weak::new(concat!(stringify!($name), '\0'));
+ )
+}
+
+pub struct Weak<F> {
+ name: &'static str,
+ addr: AtomicUsize,
+ _marker: marker::PhantomData<F>,
+}
+
+impl<F> Weak<F> {
+ pub const fn new(name: &'static str) -> Weak<F> {
+ Weak {
+ name,
+ addr: AtomicUsize::new(1),
+ _marker: marker::PhantomData,
+ }
+ }
+
+ pub fn get(&self) -> Option<F> {
+ assert_eq!(mem::size_of::<F>(), mem::size_of::<usize>());
+ unsafe {
+ if self.addr.load(Ordering::SeqCst) == 1 {
+ self.addr.store(fetch(self.name), Ordering::SeqCst);
+ }
+ match self.addr.load(Ordering::SeqCst) {
+ 0 => None,
+ addr => Some(mem::transmute_copy::<usize, F>(&addr)),
+ }
+ }
+ }
+}
+
+unsafe fn fetch(name: &str) -> usize {
+ let name = match CStr::from_bytes_with_nul(name.as_bytes()) {
+ Ok(cstr) => cstr,
+ Err(..) => return 0,
+ };
+ libc::dlsym(libc::RTLD_DEFAULT, name.as_ptr()) as usize
+}
+
+#[cfg(not(target_os = "linux"))]
+macro_rules! syscall {
+ (fn $name:ident($($arg_name:ident: $t:ty),*) -> $ret:ty) => (
+ unsafe fn $name($($arg_name: $t),*) -> $ret {
+ use super::os;
+
+ weak! { fn $name($($t),*) -> $ret }
+
+ if let Some(fun) = $name.get() {
+ fun($($arg_name),*)
+ } else {
+ os::set_errno(libc::ENOSYS);
+ -1
+ }
+ }
+ )
+}
+
+#[cfg(target_os = "linux")]
+macro_rules! syscall {
+ (fn $name:ident($($arg_name:ident: $t:ty),*) -> $ret:ty) => (
+ unsafe fn $name($($arg_name:$t),*) -> $ret {
+ // This looks like a hack, but concat_idents only accepts idents
+ // (not paths).
+ use libc::*;
+
+ syscall(
+ concat_idents!(SYS_, $name),
+ $($arg_name as c_long),*
+ ) as $ret
+ }
+ )
+}
diff --git a/src/libstd/sys/wasi/alloc.rs b/src/libstd/sys/wasi/alloc.rs
new file mode 100644
index 0000000..c852993
--- /dev/null
+++ b/src/libstd/sys/wasi/alloc.rs
@@ -0,0 +1,43 @@
+use crate::alloc::{GlobalAlloc, Layout, System};
+use crate::ptr;
+use crate::sys_common::alloc::{MIN_ALIGN, realloc_fallback};
+use libc;
+
+#[stable(feature = "alloc_system_type", since = "1.28.0")]
+unsafe impl GlobalAlloc for System {
+ #[inline]
+ unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
+ if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() {
+ libc::malloc(layout.size()) as *mut u8
+ } else {
+ libc::aligned_alloc(layout.size(), layout.align()) as *mut u8
+ }
+ }
+
+ #[inline]
+ unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
+ if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() {
+ libc::calloc(layout.size(), 1) as *mut u8
+ } else {
+ let ptr = self.alloc(layout.clone());
+ if !ptr.is_null() {
+ ptr::write_bytes(ptr, 0, layout.size());
+ }
+ ptr
+ }
+ }
+
+ #[inline]
+ unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {
+ libc::free(ptr as *mut libc::c_void)
+ }
+
+ #[inline]
+ unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
+ if layout.align() <= MIN_ALIGN && layout.align() <= new_size {
+ libc::realloc(ptr as *mut libc::c_void, new_size) as *mut u8
+ } else {
+ realloc_fallback(self, ptr, layout, new_size)
+ }
+ }
+}
diff --git a/src/libstd/sys/wasi/args.rs b/src/libstd/sys/wasi/args.rs
new file mode 100644
index 0000000..9c8e59e
--- /dev/null
+++ b/src/libstd/sys/wasi/args.rs
@@ -0,0 +1,76 @@
+use crate::ffi::CStr;
+use crate::io;
+use crate::sys::cvt_wasi;
+use crate::ffi::OsString;
+use crate::marker::PhantomData;
+use crate::os::wasi::ffi::OsStringExt;
+use crate::vec;
+
+pub unsafe fn init(_argc: isize, _argv: *const *const u8) {
+}
+
+pub unsafe fn cleanup() {
+}
+
+pub struct Args {
+ iter: vec::IntoIter<OsString>,
+ _dont_send_or_sync_me: PhantomData<*mut ()>,
+}
+
+/// Returns the command line arguments
+pub fn args() -> Args {
+ maybe_args().unwrap_or_else(|_| {
+ Args {
+ iter: Vec::new().into_iter(),
+ _dont_send_or_sync_me: PhantomData
+ }
+ })
+}
+
+fn maybe_args() -> io::Result<Args> {
+ unsafe {
+ let (mut argc, mut argv_buf_size) = (0, 0);
+ cvt_wasi(libc::__wasi_args_sizes_get(&mut argc, &mut argv_buf_size))?;
+
+ let mut argc = vec![0 as *mut libc::c_char; argc];
+ let mut argv_buf = vec![0; argv_buf_size];
+ cvt_wasi(libc::__wasi_args_get(argc.as_mut_ptr(), argv_buf.as_mut_ptr()))?;
+
+ let args = argc.into_iter()
+ .map(|ptr| CStr::from_ptr(ptr).to_bytes().to_vec())
+ .map(|bytes| OsString::from_vec(bytes))
+ .collect::<Vec<_>>();
+ Ok(Args {
+ iter: args.into_iter(),
+ _dont_send_or_sync_me: PhantomData,
+ })
+ }
+}
+
+impl Args {
+ pub fn inner_debug(&self) -> &[OsString] {
+ self.iter.as_slice()
+ }
+}
+
+impl Iterator for Args {
+ type Item = OsString;
+ fn next(&mut self) -> Option<OsString> {
+ self.iter.next()
+ }
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ self.iter.size_hint()
+ }
+}
+
+impl ExactSizeIterator for Args {
+ fn len(&self) -> usize {
+ self.iter.len()
+ }
+}
+
+impl DoubleEndedIterator for Args {
+ fn next_back(&mut self) -> Option<OsString> {
+ self.iter.next_back()
+ }
+}
diff --git a/src/libstd/sys/wasi/backtrace.rs b/src/libstd/sys/wasi/backtrace.rs
new file mode 100644
index 0000000..7d56b29
--- /dev/null
+++ b/src/libstd/sys/wasi/backtrace.rs
@@ -0,0 +1,27 @@
+use crate::io;
+use crate::sys::unsupported;
+use crate::sys_common::backtrace::Frame;
+
+pub struct BacktraceContext;
+
+pub fn unwind_backtrace(_frames: &mut [Frame])
+ -> io::Result<(usize, BacktraceContext)>
+{
+ unsupported()
+}
+
+pub fn resolve_symname<F>(_frame: Frame,
+ _callback: F,
+ _: &BacktraceContext) -> io::Result<()>
+ where F: FnOnce(Option<&str>) -> io::Result<()>
+{
+ unsupported()
+}
+
+pub fn foreach_symbol_fileline<F>(_: Frame,
+ _: F,
+ _: &BacktraceContext) -> io::Result<bool>
+ where F: FnMut(&[u8], u32) -> io::Result<()>
+{
+ unsupported()
+}
diff --git a/src/libstd/sys/wasi/env.rs b/src/libstd/sys/wasi/env.rs
new file mode 100644
index 0000000..730e356
--- /dev/null
+++ b/src/libstd/sys/wasi/env.rs
@@ -0,0 +1,9 @@
+pub mod os {
+ pub const FAMILY: &str = "";
+ pub const OS: &str = "";
+ pub const DLL_PREFIX: &str = "";
+ pub const DLL_SUFFIX: &str = ".wasm";
+ pub const DLL_EXTENSION: &str = "wasm";
+ pub const EXE_SUFFIX: &str = ".wasm";
+ pub const EXE_EXTENSION: &str = "wasm";
+}
diff --git a/src/libstd/sys/wasi/ext/ffi.rs b/src/libstd/sys/wasi/ext/ffi.rs
new file mode 100644
index 0000000..f71f316
--- /dev/null
+++ b/src/libstd/sys/wasi/ext/ffi.rs
@@ -0,0 +1,6 @@
+//! WASI-specific extension to the primitives in the `std::ffi` module
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use crate::sys_common::os_str_bytes::*;
diff --git a/src/libstd/sys/wasi/ext/fs.rs b/src/libstd/sys/wasi/ext/fs.rs
new file mode 100644
index 0000000..53f415c
--- /dev/null
+++ b/src/libstd/sys/wasi/ext/fs.rs
@@ -0,0 +1,412 @@
+//! WASI-specific extensions to primitives in the `std::fs` module.
+
+#![unstable(feature = "wasi_ext", issue = "0")]
+
+use crate::fs::{self, File, Metadata, OpenOptions};
+use crate::io::{self, IoVec, IoVecMut};
+use crate::os::wasi::ffi::OsStrExt;
+use crate::path::{Path, PathBuf};
+use crate::sys_common::{AsInner, AsInnerMut, FromInner};
+
+/// WASI-specific extensions to [`File`].
+///
+/// [`File`]: ../../../../std/fs/struct.File.html
+pub trait FileExt {
+ /// Reads a number of bytes starting from a given offset.
+ ///
+ /// Returns the number of bytes read.
+ ///
+ /// 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.
+ ///
+ /// Note that similar to [`File::read_vectored`], it is not an error to
+ /// return with a short read.
+ ///
+ /// [`File::read`]: ../../../../std/fs/struct.File.html#method.read_vectored
+ fn read_at(&self, bufs: &mut [IoVecMut<'_>], offset: u64) -> io::Result<usize>;
+
+ /// Writes a number of bytes starting from a given offset.
+ ///
+ /// Returns the number of bytes written.
+ ///
+ /// 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.
+ ///
+ /// When writing beyond the end of the file, the file is appropriately
+ /// extended and the intermediate bytes are initialized with the value 0.
+ ///
+ /// Note that similar to [`File::write_vectored`], it is not an error to return a
+ /// short write.
+ ///
+ /// [`File::write`]: ../../../../std/fs/struct.File.html#method.write_vectored
+ fn write_at(&self, bufs: &[IoVec<'_>], offset: u64) -> io::Result<usize>;
+
+ /// Returns the current position within the file.
+ ///
+ /// This corresponds to the `__wasi_fd_tell` syscall and is similar to
+ /// `seek` where you offset 0 bytes from the current position.
+ fn tell(&self) -> io::Result<u64>;
+
+ /// Adjust the flags associated with this file.
+ ///
+ /// This corresponds to the `__wasi_fd_fdstat_set_flags` syscall.
+ fn fdstat_set_flags(&self, flags: u16) -> io::Result<()>;
+
+ /// Adjust the rights associated with this file.
+ ///
+ /// This corresponds to the `__wasi_fd_fdstat_set_rights` syscall.
+ fn fdstat_set_rights(&self, rights: u64, inheriting: u64) -> io::Result<()>;
+
+ /// Provide file advisory information on a file descriptor.
+ ///
+ /// This corresponds to the `__wasi_fd_advise` syscall.
+ fn advise(&self, offset: u64, len: u64, advice: u8) -> io::Result<()>;
+
+ /// Force the allocation of space in a file.
+ ///
+ /// This corresponds to the `__wasi_fd_allocate` syscall.
+ fn allocate(&self, offset: u64, len: u64) -> io::Result<()>;
+
+ /// Create a directory.
+ ///
+ /// This corresponds to the `__wasi_path_create_directory` syscall.
+ fn create_directory<P: AsRef<Path>>(&self, dir: P) -> io::Result<()>;
+
+ /// Read the contents of a symbolic link.
+ ///
+ /// This corresponds to the `__wasi_path_readlink` syscall.
+ fn read_link<P: AsRef<Path>>(&self, path: P) -> io::Result<PathBuf>;
+
+ /// Return the attributes of a file or directory.
+ ///
+ /// This corresponds to the `__wasi_path_filestat_get` syscall.
+ fn metadata_at<P: AsRef<Path>>(&self, lookup_flags: u32, path: P) -> io::Result<Metadata>;
+
+ /// Unlink a file.
+ ///
+ /// This corresponds to the `__wasi_path_unlink_file` syscall.
+ fn remove_file<P: AsRef<Path>>(&self, path: P) -> io::Result<()>;
+
+ /// Remove a directory.
+ ///
+ /// This corresponds to the `__wasi_path_remove_directory` syscall.
+ fn remove_directory<P: AsRef<Path>>(&self, path: P) -> io::Result<()>;
+}
+
+// FIXME: bind __wasi_fd_fdstat_get - need to define a custom return type
+// FIXME: bind __wasi_fd_readdir - can't return `ReadDir` since we only have entry name
+// FIXME: bind __wasi_fd_filestat_set_times maybe? - on crates.io for unix
+// FIXME: bind __wasi_path_filestat_set_times maybe? - on crates.io for unix
+// FIXME: bind __wasi_poll_oneoff maybe? - probably should wait for I/O to settle
+// FIXME: bind __wasi_random_get maybe? - on crates.io for unix
+
+impl FileExt for fs::File {
+ fn read_at(&self, bufs: &mut [IoVecMut<'_>], offset: u64) -> io::Result<usize> {
+ self.as_inner().fd().pread(bufs, offset)
+ }
+
+ fn write_at(&self, bufs: &[IoVec<'_>], offset: u64) -> io::Result<usize> {
+ self.as_inner().fd().pwrite(bufs, offset)
+ }
+
+ fn tell(&self) -> io::Result<u64> {
+ self.as_inner().fd().tell()
+ }
+
+ fn fdstat_set_flags(&self, flags: u16) -> io::Result<()> {
+ self.as_inner().fd().set_flags(flags)
+ }
+
+ fn fdstat_set_rights(&self, rights: u64, inheriting: u64) -> io::Result<()> {
+ self.as_inner().fd().set_rights(rights, inheriting)
+ }
+
+ fn advise(&self, offset: u64, len: u64, advice: u8) -> io::Result<()> {
+ self.as_inner().fd().advise(offset, len, advice)
+ }
+
+ fn allocate(&self, offset: u64, len: u64) -> io::Result<()> {
+ self.as_inner().fd().allocate(offset, len)
+ }
+
+ fn create_directory<P: AsRef<Path>>(&self, dir: P) -> io::Result<()> {
+ self.as_inner()
+ .fd()
+ .create_directory(dir.as_ref().as_os_str().as_bytes())
+ }
+
+ fn read_link<P: AsRef<Path>>(&self, path: P) -> io::Result<PathBuf> {
+ self.as_inner().read_link(path.as_ref())
+ }
+
+ fn metadata_at<P: AsRef<Path>>(&self, lookup_flags: u32, path: P) -> io::Result<Metadata> {
+ let m = self.as_inner().metadata_at(lookup_flags, path.as_ref())?;
+ Ok(FromInner::from_inner(m))
+ }
+
+ fn remove_file<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
+ self.as_inner()
+ .fd()
+ .unlink_file(path.as_ref().as_os_str().as_bytes())
+ }
+
+ fn remove_directory<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
+ self.as_inner()
+ .fd()
+ .remove_directory(path.as_ref().as_os_str().as_bytes())
+ }
+}
+
+/// WASI-specific extensions to [`fs::OpenOptions`].
+///
+/// [`fs::OpenOptions`]: ../../../../std/fs/struct.OpenOptions.html
+pub trait OpenOptionsExt {
+ /// Pass custom `dirflags` argument to `__wasi_path_open`.
+ ///
+ /// This option configures the `dirflags` argument to the
+ /// `__wasi_path_open` syscall which `OpenOptions` will eventually call. The
+ /// `dirflags` argument configures how the file is looked up, currently
+ /// primarily affecting whether symlinks are followed or not.
+ ///
+ /// By default this value is `__WASI_LOOKUP_SYMLINK_FOLLOW`, or symlinks are
+ /// followed. You can call this method with 0 to disable following symlinks
+ fn lookup_flags(&mut self, flags: u32) -> &mut Self;
+
+ /// Indicates whether `OpenOptions` must open a directory or not.
+ ///
+ /// This method will configure whether the `__WASI_O_DIRECTORY` flag is
+ /// passed when opening a file. When passed it will require that the opened
+ /// path is a directory.
+ ///
+ /// This option is by default `false`
+ fn directory(&mut self, dir: bool) -> &mut Self;
+
+ /// Indicates whether `__WASI_FDFLAG_DSYNC` is passed in the `fs_flags`
+ /// field of `__wasi_path_open`.
+ ///
+ /// This option is by default `false`
+ fn dsync(&mut self, dsync: bool) -> &mut Self;
+
+ /// Indicates whether `__WASI_FDFLAG_NONBLOCK` is passed in the `fs_flags`
+ /// field of `__wasi_path_open`.
+ ///
+ /// This option is by default `false`
+ fn nonblock(&mut self, nonblock: bool) -> &mut Self;
+
+ /// Indicates whether `__WASI_FDFLAG_RSYNC` is passed in the `fs_flags`
+ /// field of `__wasi_path_open`.
+ ///
+ /// This option is by default `false`
+ fn rsync(&mut self, rsync: bool) -> &mut Self;
+
+ /// Indicates whether `__WASI_FDFLAG_SYNC` is passed in the `fs_flags`
+ /// field of `__wasi_path_open`.
+ ///
+ /// This option is by default `false`
+ fn sync(&mut self, sync: bool) -> &mut Self;
+
+ /// Indicates the value that should be passed in for the `fs_rights_base`
+ /// parameter of `__wasi_path_open`.
+ ///
+ /// This option defaults based on the `read` and `write` configuration of
+ /// this `OpenOptions` builder. If this method is called, however, the
+ /// exact mask passed in will be used instead.
+ fn fs_rights_base(&mut self, rights: u64) -> &mut Self;
+
+ /// Indicates the value that should be passed in for the
+ /// `fs_rights_inheriting` parameter of `__wasi_path_open`.
+ ///
+ /// The default for this option is the same value as what will be passed
+ /// for the `fs_rights_base` parameter but if this method is called then
+ /// the specified value will be used instead.
+ fn fs_rights_inheriting(&mut self, rights: u64) -> &mut Self;
+
+ /// Open a file or directory.
+ ///
+ /// This corresponds to the `__wasi_path_open` syscall.
+ fn open_at<P: AsRef<Path>>(&self, file: &File, path: P) -> io::Result<File>;
+}
+
+impl OpenOptionsExt for OpenOptions {
+ fn lookup_flags(&mut self, flags: u32) -> &mut OpenOptions {
+ self.as_inner_mut().lookup_flags(flags);
+ self
+ }
+
+ fn directory(&mut self, dir: bool) -> &mut OpenOptions {
+ self.as_inner_mut().directory(dir);
+ self
+ }
+
+ fn dsync(&mut self, enabled: bool) -> &mut OpenOptions {
+ self.as_inner_mut().dsync(enabled);
+ self
+ }
+
+ fn nonblock(&mut self, enabled: bool) -> &mut OpenOptions {
+ self.as_inner_mut().nonblock(enabled);
+ self
+ }
+
+ fn rsync(&mut self, enabled: bool) -> &mut OpenOptions {
+ self.as_inner_mut().rsync(enabled);
+ self
+ }
+
+ fn sync(&mut self, enabled: bool) -> &mut OpenOptions {
+ self.as_inner_mut().sync(enabled);
+ self
+ }
+
+ fn fs_rights_base(&mut self, rights: u64) -> &mut OpenOptions {
+ self.as_inner_mut().fs_rights_base(rights);
+ self
+ }
+
+ fn fs_rights_inheriting(&mut self, rights: u64) -> &mut OpenOptions {
+ self.as_inner_mut().fs_rights_inheriting(rights);
+ self
+ }
+
+ fn open_at<P: AsRef<Path>>(&self, file: &File, path: P) -> io::Result<File> {
+ let inner = file.as_inner().open_at(path.as_ref(), self.as_inner())?;
+ Ok(File::from_inner(inner))
+ }
+}
+
+/// WASI-specific extensions to [`fs::Metadata`].
+///
+/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html
+pub trait MetadataExt {
+ /// Returns the `st_dev` field of the internal `__wasi_filestat_t`
+ fn dev(&self) -> u64;
+ /// Returns the `st_ino` field of the internal `__wasi_filestat_t`
+ fn ino(&self) -> u64;
+ /// Returns the `st_nlink` field of the internal `__wasi_filestat_t`
+ fn nlink(&self) -> u32;
+ /// Returns the `st_atim` field of the internal `__wasi_filestat_t`
+ fn atim(&self) -> u64;
+ /// Returns the `st_mtim` field of the internal `__wasi_filestat_t`
+ fn mtim(&self) -> u64;
+ /// Returns the `st_ctim` field of the internal `__wasi_filestat_t`
+ fn ctim(&self) -> u64;
+}
+
+impl MetadataExt for fs::Metadata {
+ fn dev(&self) -> u64 {
+ self.as_inner().as_wasi().st_dev
+ }
+ fn ino(&self) -> u64 {
+ self.as_inner().as_wasi().st_ino
+ }
+ fn nlink(&self) -> u32 {
+ self.as_inner().as_wasi().st_nlink
+ }
+ fn atim(&self) -> u64 {
+ self.as_inner().as_wasi().st_atim
+ }
+ fn mtim(&self) -> u64 {
+ self.as_inner().as_wasi().st_mtim
+ }
+ fn ctim(&self) -> u64 {
+ self.as_inner().as_wasi().st_ctim
+ }
+}
+
+/// WASI-specific extensions for [`FileType`].
+///
+/// Adds support for special WASI file types such as block/character devices,
+/// pipes, and sockets.
+///
+/// [`FileType`]: ../../../../std/fs/struct.FileType.html
+pub trait FileTypeExt {
+ /// Returns `true` if this file type is a block device.
+ fn is_block_device(&self) -> bool;
+ /// Returns `true` if this file type is a character device.
+ fn is_character_device(&self) -> bool;
+ /// Returns `true` if this file type is a socket datagram.
+ fn is_socket_dgram(&self) -> bool;
+ /// Returns `true` if this file type is a socket stream.
+ fn is_socket_stream(&self) -> bool;
+}
+
+impl FileTypeExt for fs::FileType {
+ fn is_block_device(&self) -> bool {
+ self.as_inner().bits() == libc::__WASI_FILETYPE_BLOCK_DEVICE
+ }
+ fn is_character_device(&self) -> bool {
+ self.as_inner().bits() == libc::__WASI_FILETYPE_CHARACTER_DEVICE
+ }
+ fn is_socket_dgram(&self) -> bool {
+ self.as_inner().bits() == libc::__WASI_FILETYPE_SOCKET_DGRAM
+ }
+ fn is_socket_stream(&self) -> bool {
+ self.as_inner().bits() == libc::__WASI_FILETYPE_SOCKET_STREAM
+ }
+}
+
+/// WASI-specific extension methods for [`fs::DirEntry`].
+///
+/// [`fs::DirEntry`]: ../../../../std/fs/struct.DirEntry.html
+pub trait DirEntryExt {
+ /// Returns the underlying `d_ino` field of the `__wasi_dirent_t`
+ fn ino(&self) -> u64;
+}
+
+impl DirEntryExt for fs::DirEntry {
+ fn ino(&self) -> u64 {
+ self.as_inner().ino()
+ }
+}
+
+/// Create a hard link.
+///
+/// This corresponds to the `__wasi_path_link` syscall.
+pub fn link<P: AsRef<Path>, U: AsRef<Path>>(
+ old_fd: &File,
+ old_flags: u32,
+ old_path: P,
+ new_fd: &File,
+ new_path: U,
+) -> io::Result<()> {
+ old_fd.as_inner().fd().link(
+ old_flags,
+ old_path.as_ref().as_os_str().as_bytes(),
+ new_fd.as_inner().fd(),
+ new_path.as_ref().as_os_str().as_bytes(),
+ )
+}
+
+/// Rename a file or directory.
+///
+/// This corresponds to the `__wasi_path_rename` syscall.
+pub fn rename<P: AsRef<Path>, U: AsRef<Path>>(
+ old_fd: &File,
+ old_path: P,
+ new_fd: &File,
+ new_path: U,
+) -> io::Result<()> {
+ old_fd.as_inner().fd().rename(
+ old_path.as_ref().as_os_str().as_bytes(),
+ new_fd.as_inner().fd(),
+ new_path.as_ref().as_os_str().as_bytes(),
+ )
+}
+
+/// Create a symbolic link.
+///
+/// This corresponds to the `__wasi_path_symlink` syscall.
+pub fn symlink<P: AsRef<Path>, U: AsRef<Path>>(
+ old_path: P,
+ fd: &File,
+ new_path: U,
+) -> io::Result<()> {
+ fd.as_inner().fd().symlink(
+ old_path.as_ref().as_os_str().as_bytes(),
+ new_path.as_ref().as_os_str().as_bytes(),
+ )
+}
diff --git a/src/libstd/sys/wasi/ext/io.rs b/src/libstd/sys/wasi/ext/io.rs
new file mode 100644
index 0000000..cf75a96
--- /dev/null
+++ b/src/libstd/sys/wasi/ext/io.rs
@@ -0,0 +1,87 @@
+//! WASI-specific extensions to general I/O primitives
+
+#![unstable(feature = "wasi_ext", issue = "0")]
+
+use crate::fs;
+use crate::io;
+use crate::sys;
+use crate::sys_common::{AsInner, FromInner, IntoInner};
+
+/// Raw file descriptors.
+pub type RawFd = u32;
+
+/// A trait to extract the raw WASI file descriptor from an underlying
+/// object.
+pub trait AsRawFd {
+ /// Extracts the raw file descriptor.
+ ///
+ /// This method does **not** pass ownership of the raw file descriptor
+ /// to the caller. The descriptor is only guaranteed to be valid while
+ /// the original object has not yet been destroyed.
+ fn as_raw_fd(&self) -> RawFd;
+}
+
+/// A trait to express the ability to construct an object from a raw file
+/// descriptor.
+pub trait FromRawFd {
+ /// Constructs a new instance of `Self` from the given raw file
+ /// descriptor.
+ ///
+ /// This function **consumes ownership** of the specified file
+ /// descriptor. The returned object will take responsibility for closing
+ /// it when the object goes out of scope.
+ ///
+ /// This function is also unsafe as the primitives currently returned
+ /// have the contract that they are the sole owner of the file
+ /// descriptor they are wrapping. Usage of this function could
+ /// accidentally allow violating this contract which can cause memory
+ /// unsafety in code that relies on it being true.
+ unsafe fn from_raw_fd(fd: RawFd) -> Self;
+}
+
+/// A trait to express the ability to consume an object and acquire ownership of
+/// its raw file descriptor.
+pub trait IntoRawFd {
+ /// Consumes this object, returning the raw underlying file descriptor.
+ ///
+ /// This function **transfers ownership** of the underlying file descriptor
+ /// to the caller. Callers are then the unique owners of the file descriptor
+ /// and must close the descriptor once it's no longer needed.
+ fn into_raw_fd(self) -> RawFd;
+}
+
+impl AsRawFd for fs::File {
+ fn as_raw_fd(&self) -> RawFd {
+ self.as_inner().fd().as_raw()
+ }
+}
+
+impl FromRawFd for fs::File {
+ unsafe fn from_raw_fd(fd: RawFd) -> fs::File {
+ fs::File::from_inner(sys::fs::File::from_inner(fd))
+ }
+}
+
+impl IntoRawFd for fs::File {
+ fn into_raw_fd(self) -> RawFd {
+ self.into_inner().into_fd().into_raw()
+ }
+}
+
+impl AsRawFd for io::Stdin {
+ fn as_raw_fd(&self) -> RawFd {
+ libc::STDIN_FILENO as u32
+ }
+}
+
+impl AsRawFd for io::Stdout {
+ fn as_raw_fd(&self) -> RawFd {
+ libc::STDOUT_FILENO as u32
+ }
+}
+
+impl AsRawFd for io::Stderr {
+ fn as_raw_fd(&self) -> RawFd {
+ libc::STDERR_FILENO as u32
+ }
+}
diff --git a/src/libstd/sys/wasi/ext/mod.rs b/src/libstd/sys/wasi/ext/mod.rs
new file mode 100644
index 0000000..1c24b24
--- /dev/null
+++ b/src/libstd/sys/wasi/ext/mod.rs
@@ -0,0 +1,18 @@
+pub mod ffi;
+pub mod fs;
+pub mod io;
+
+/// A prelude for conveniently writing platform-specific code.
+///
+/// Includes all extension traits, and some important type definitions.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub mod prelude {
+ #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
+ pub use crate::sys::ext::ffi::{OsStringExt, OsStrExt};
+ #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
+ pub use crate::sys::ext::fs::{FileExt, DirEntryExt, MetadataExt, OpenOptionsExt};
+ #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
+ pub use crate::sys::ext::fs::FileTypeExt;
+ #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
+ pub use crate::sys::ext::io::{AsRawFd, IntoRawFd, FromRawFd};
+}
diff --git a/src/libstd/sys/wasi/fd.rs b/src/libstd/sys/wasi/fd.rs
new file mode 100644
index 0000000..0b68b6f
--- /dev/null
+++ b/src/libstd/sys/wasi/fd.rs
@@ -0,0 +1,350 @@
+#![allow(dead_code)]
+
+use crate::io::{self, IoVec, IoVecMut, SeekFrom};
+use crate::mem;
+use crate::net::Shutdown;
+use crate::sys::cvt_wasi;
+use libc::{self, c_char, c_void};
+
+#[derive(Debug)]
+pub struct WasiFd {
+ fd: libc::__wasi_fd_t,
+}
+
+// FIXME: these should probably all be fancier structs, builders, enums, etc
+pub type LookupFlags = u32;
+pub type FdFlags = u16;
+pub type Advice = u8;
+pub type Rights = u64;
+pub type Oflags = u16;
+pub type DirCookie = u64;
+pub type Timestamp = u64;
+pub type FstFlags = u16;
+pub type RiFlags = u16;
+pub type RoFlags = u16;
+pub type SiFlags = u16;
+
+fn iovec(a: &mut [IoVecMut<'_>]) -> (*const libc::__wasi_iovec_t, usize) {
+ assert_eq!(
+ mem::size_of::<IoVecMut<'_>>(),
+ mem::size_of::<libc::__wasi_iovec_t>()
+ );
+ assert_eq!(
+ mem::align_of::<IoVecMut<'_>>(),
+ mem::align_of::<libc::__wasi_iovec_t>()
+ );
+ (a.as_ptr() as *const libc::__wasi_iovec_t, a.len())
+}
+
+fn ciovec(a: &[IoVec<'_>]) -> (*const libc::__wasi_ciovec_t, usize) {
+ assert_eq!(
+ mem::size_of::<IoVec<'_>>(),
+ mem::size_of::<libc::__wasi_ciovec_t>()
+ );
+ assert_eq!(
+ mem::align_of::<IoVec<'_>>(),
+ mem::align_of::<libc::__wasi_ciovec_t>()
+ );
+ (a.as_ptr() as *const libc::__wasi_ciovec_t, a.len())
+}
+
+impl WasiFd {
+ pub unsafe fn from_raw(fd: libc::__wasi_fd_t) -> WasiFd {
+ WasiFd { fd }
+ }
+
+ pub fn into_raw(self) -> libc::__wasi_fd_t {
+ let ret = self.fd;
+ mem::forget(self);
+ ret
+ }
+
+ pub fn as_raw(&self) -> libc::__wasi_fd_t {
+ self.fd
+ }
+
+ pub fn datasync(&self) -> io::Result<()> {
+ cvt_wasi(unsafe { libc::__wasi_fd_datasync(self.fd) })
+ }
+
+ pub fn pread(&self, bufs: &mut [IoVecMut<'_>], offset: u64) -> io::Result<usize> {
+ let mut read = 0;
+ let (ptr, len) = iovec(bufs);
+ cvt_wasi(unsafe { libc::__wasi_fd_pread(self.fd, ptr, len, offset, &mut read) })?;
+ Ok(read)
+ }
+
+ pub fn pwrite(&self, bufs: &[IoVec<'_>], offset: u64) -> io::Result<usize> {
+ let mut read = 0;
+ let (ptr, len) = ciovec(bufs);
+ cvt_wasi(unsafe { libc::__wasi_fd_pwrite(self.fd, ptr, len, offset, &mut read) })?;
+ Ok(read)
+ }
+
+ pub fn read(&self, bufs: &mut [IoVecMut<'_>]) -> io::Result<usize> {
+ let mut read = 0;
+ let (ptr, len) = iovec(bufs);
+ cvt_wasi(unsafe { libc::__wasi_fd_read(self.fd, ptr, len, &mut read) })?;
+ Ok(read)
+ }
+
+ pub fn write(&self, bufs: &[IoVec<'_>]) -> io::Result<usize> {
+ let mut read = 0;
+ let (ptr, len) = ciovec(bufs);
+ cvt_wasi(unsafe { libc::__wasi_fd_write(self.fd, ptr, len, &mut read) })?;
+ Ok(read)
+ }
+
+ pub fn seek(&self, pos: SeekFrom) -> io::Result<u64> {
+ let (whence, offset) = match pos {
+ SeekFrom::Start(pos) => (libc::__WASI_WHENCE_SET, pos as i64),
+ SeekFrom::End(pos) => (libc::__WASI_WHENCE_END, pos),
+ SeekFrom::Current(pos) => (libc::__WASI_WHENCE_CUR, pos),
+ };
+ let mut pos = 0;
+ cvt_wasi(unsafe { libc::__wasi_fd_seek(self.fd, offset, whence, &mut pos) })?;
+ Ok(pos)
+ }
+
+ pub fn tell(&self) -> io::Result<u64> {
+ let mut pos = 0;
+ cvt_wasi(unsafe { libc::__wasi_fd_tell(self.fd, &mut pos) })?;
+ Ok(pos)
+ }
+
+ // FIXME: __wasi_fd_fdstat_get
+
+ pub fn set_flags(&self, flags: FdFlags) -> io::Result<()> {
+ cvt_wasi(unsafe { libc::__wasi_fd_fdstat_set_flags(self.fd, flags) })
+ }
+
+ pub fn set_rights(&self, base: Rights, inheriting: Rights) -> io::Result<()> {
+ cvt_wasi(unsafe { libc::__wasi_fd_fdstat_set_rights(self.fd, base, inheriting) })
+ }
+
+ pub fn sync(&self) -> io::Result<()> {
+ cvt_wasi(unsafe { libc::__wasi_fd_sync(self.fd) })
+ }
+
+ pub fn advise(&self, offset: u64, len: u64, advice: Advice) -> io::Result<()> {
+ cvt_wasi(unsafe { libc::__wasi_fd_advise(self.fd, offset, len, advice as u8) })
+ }
+
+ pub fn allocate(&self, offset: u64, len: u64) -> io::Result<()> {
+ cvt_wasi(unsafe { libc::__wasi_fd_allocate(self.fd, offset, len) })
+ }
+
+ pub fn create_directory(&self, path: &[u8]) -> io::Result<()> {
+ cvt_wasi(unsafe {
+ libc::__wasi_path_create_directory(self.fd, path.as_ptr() as *const c_char, path.len())
+ })
+ }
+
+ pub fn link(
+ &self,
+ old_flags: LookupFlags,
+ old_path: &[u8],
+ new_fd: &WasiFd,
+ new_path: &[u8],
+ ) -> io::Result<()> {
+ cvt_wasi(unsafe {
+ libc::__wasi_path_link(
+ self.fd,
+ old_flags,
+ old_path.as_ptr() as *const c_char,
+ old_path.len(),
+ new_fd.fd,
+ new_path.as_ptr() as *const c_char,
+ new_path.len(),
+ )
+ })
+ }
+
+ pub fn open(
+ &self,
+ dirflags: LookupFlags,
+ path: &[u8],
+ oflags: Oflags,
+ fs_rights_base: Rights,
+ fs_rights_inheriting: Rights,
+ fs_flags: FdFlags,
+ ) -> io::Result<WasiFd> {
+ unsafe {
+ let mut fd = 0;
+ cvt_wasi(libc::__wasi_path_open(
+ self.fd,
+ dirflags,
+ path.as_ptr() as *const c_char,
+ path.len(),
+ oflags,
+ fs_rights_base,
+ fs_rights_inheriting,
+ fs_flags,
+ &mut fd,
+ ))?;
+ Ok(WasiFd::from_raw(fd))
+ }
+ }
+
+ pub fn readdir(&self, buf: &mut [u8], cookie: DirCookie) -> io::Result<usize> {
+ let mut used = 0;
+ cvt_wasi(unsafe {
+ libc::__wasi_fd_readdir(
+ self.fd,
+ buf.as_mut_ptr() as *mut c_void,
+ buf.len(),
+ cookie,
+ &mut used,
+ )
+ })?;
+ Ok(used)
+ }
+
+ pub fn readlink(&self, path: &[u8], buf: &mut [u8]) -> io::Result<usize> {
+ let mut used = 0;
+ cvt_wasi(unsafe {
+ libc::__wasi_path_readlink(
+ self.fd,
+ path.as_ptr() as *const c_char,
+ path.len(),
+ buf.as_mut_ptr() as *mut c_char,
+ buf.len(),
+ &mut used,
+ )
+ })?;
+ Ok(used)
+ }
+
+ pub fn rename(&self, old_path: &[u8], new_fd: &WasiFd, new_path: &[u8]) -> io::Result<()> {
+ cvt_wasi(unsafe {
+ libc::__wasi_path_rename(
+ self.fd,
+ old_path.as_ptr() as *const c_char,
+ old_path.len(),
+ new_fd.fd,
+ new_path.as_ptr() as *const c_char,
+ new_path.len(),
+ )
+ })
+ }
+
+ pub fn filestat_get(&self, buf: *mut libc::__wasi_filestat_t) -> io::Result<()> {
+ cvt_wasi(unsafe { libc::__wasi_fd_filestat_get(self.fd, buf) })
+ }
+
+ pub fn filestat_set_times(
+ &self,
+ atim: Timestamp,
+ mtim: Timestamp,
+ fstflags: FstFlags,
+ ) -> io::Result<()> {
+ cvt_wasi(unsafe { libc::__wasi_fd_filestat_set_times(self.fd, atim, mtim, fstflags) })
+ }
+
+ pub fn filestat_set_size(&self, size: u64) -> io::Result<()> {
+ cvt_wasi(unsafe { libc::__wasi_fd_filestat_set_size(self.fd, size) })
+ }
+
+ pub fn path_filestat_get(
+ &self,
+ flags: LookupFlags,
+ path: &[u8],
+ buf: *mut libc::__wasi_filestat_t,
+ ) -> io::Result<()> {
+ cvt_wasi(unsafe {
+ libc::__wasi_path_filestat_get(
+ self.fd,
+ flags,
+ path.as_ptr() as *const c_char,
+ path.len(),
+ buf,
+ )
+ })
+ }
+
+ pub fn path_filestat_set_times(
+ &self,
+ flags: LookupFlags,
+ path: &[u8],
+ atim: Timestamp,
+ mtim: Timestamp,
+ fstflags: FstFlags,
+ ) -> io::Result<()> {
+ cvt_wasi(unsafe {
+ libc::__wasi_path_filestat_set_times(
+ self.fd,
+ flags,
+ path.as_ptr() as *const c_char,
+ path.len(),
+ atim,
+ mtim,
+ fstflags,
+ )
+ })
+ }
+
+ pub fn symlink(&self, old_path: &[u8], new_path: &[u8]) -> io::Result<()> {
+ cvt_wasi(unsafe {
+ libc::__wasi_path_symlink(
+ old_path.as_ptr() as *const c_char,
+ old_path.len(),
+ self.fd,
+ new_path.as_ptr() as *const c_char,
+ new_path.len(),
+ )
+ })
+ }
+
+ pub fn unlink_file(&self, path: &[u8]) -> io::Result<()> {
+ cvt_wasi(unsafe {
+ libc::__wasi_path_unlink_file(self.fd, path.as_ptr() as *const c_char, path.len())
+ })
+ }
+
+ pub fn remove_directory(&self, path: &[u8]) -> io::Result<()> {
+ cvt_wasi(unsafe {
+ libc::__wasi_path_remove_directory(self.fd, path.as_ptr() as *const c_char, path.len())
+ })
+ }
+
+ pub fn sock_recv(
+ &self,
+ ri_data: &mut [IoVecMut<'_>],
+ ri_flags: RiFlags,
+ ) -> io::Result<(usize, RoFlags)> {
+ let mut ro_datalen = 0;
+ let mut ro_flags = 0;
+ let (ptr, len) = iovec(ri_data);
+ cvt_wasi(unsafe {
+ libc::__wasi_sock_recv(self.fd, ptr, len, ri_flags, &mut ro_datalen, &mut ro_flags)
+ })?;
+ Ok((ro_datalen, ro_flags))
+ }
+
+ pub fn sock_send(&self, si_data: &[IoVec<'_>], si_flags: SiFlags) -> io::Result<usize> {
+ let mut so_datalen = 0;
+ let (ptr, len) = ciovec(si_data);
+ cvt_wasi(unsafe { libc::__wasi_sock_send(self.fd, ptr, len, si_flags, &mut so_datalen) })?;
+ Ok(so_datalen)
+ }
+
+ pub fn sock_shutdown(&self, how: Shutdown) -> io::Result<()> {
+ let how = match how {
+ Shutdown::Read => libc::__WASI_SHUT_RD,
+ Shutdown::Write => libc::__WASI_SHUT_WR,
+ Shutdown::Both => libc::__WASI_SHUT_WR | libc::__WASI_SHUT_RD,
+ };
+ cvt_wasi(unsafe { libc::__wasi_sock_shutdown(self.fd, how) })?;
+ Ok(())
+ }
+}
+
+impl Drop for WasiFd {
+ fn drop(&mut self) {
+ unsafe {
+ // FIXME: can we handle the return code here even though we can't on
+ // unix?
+ libc::__wasi_fd_close(self.fd);
+ }
+ }
+}
diff --git a/src/libstd/sys/wasi/fs.rs b/src/libstd/sys/wasi/fs.rs
new file mode 100644
index 0000000..5895932
--- /dev/null
+++ b/src/libstd/sys/wasi/fs.rs
@@ -0,0 +1,691 @@
+use crate::ffi::{CStr, CString, OsStr, OsString};
+use crate::fmt;
+use crate::io::{self, IoVec, IoVecMut, SeekFrom};
+use crate::iter;
+use crate::mem::{self, ManuallyDrop};
+use crate::os::wasi::ffi::{OsStrExt, OsStringExt};
+use crate::path::{Path, PathBuf};
+use crate::ptr;
+use crate::sync::Arc;
+use crate::sys::fd::{DirCookie, WasiFd};
+use crate::sys::time::SystemTime;
+use crate::sys::unsupported;
+use crate::sys_common::FromInner;
+
+pub use crate::sys_common::fs::copy;
+pub use crate::sys_common::fs::remove_dir_all;
+
+pub struct File {
+ fd: WasiFd,
+}
+
+#[derive(Clone)]
+pub struct FileAttr {
+ meta: libc::__wasi_filestat_t,
+}
+
+pub struct ReadDir {
+ inner: Arc<ReadDirInner>,
+ cookie: Option<DirCookie>,
+ buf: Vec<u8>,
+ offset: usize,
+ cap: usize,
+}
+
+struct ReadDirInner {
+ root: PathBuf,
+ dir: File,
+}
+
+pub struct DirEntry {
+ meta: libc::__wasi_dirent_t,
+ name: Vec<u8>,
+ inner: Arc<ReadDirInner>,
+}
+
+#[derive(Clone, Debug, Default)]
+pub struct OpenOptions {
+ read: bool,
+ write: bool,
+ dirflags: libc::__wasi_lookupflags_t,
+ fdflags: libc::__wasi_fdflags_t,
+ oflags: libc::__wasi_oflags_t,
+ rights_base: Option<libc::__wasi_rights_t>,
+ rights_inheriting: Option<libc::__wasi_rights_t>,
+}
+
+#[derive(Clone, PartialEq, Eq, Debug)]
+pub struct FilePermissions {
+ readonly: bool,
+}
+
+#[derive(PartialEq, Eq, Hash, Debug, Copy, Clone)]
+pub struct FileType {
+ bits: libc::__wasi_filetype_t,
+}
+
+#[derive(Debug)]
+pub struct DirBuilder {}
+
+impl FileAttr {
+ fn zero() -> FileAttr {
+ FileAttr {
+ meta: unsafe { mem::zeroed() },
+ }
+ }
+
+ pub fn size(&self) -> u64 {
+ self.meta.st_size
+ }
+
+ pub fn perm(&self) -> FilePermissions {
+ // not currently implemented in wasi yet
+ FilePermissions { readonly: false }
+ }
+
+ pub fn file_type(&self) -> FileType {
+ FileType {
+ bits: self.meta.st_filetype,
+ }
+ }
+
+ pub fn modified(&self) -> io::Result<SystemTime> {
+ Ok(SystemTime::from_wasi_timestamp(self.meta.st_mtim))
+ }
+
+ pub fn accessed(&self) -> io::Result<SystemTime> {
+ Ok(SystemTime::from_wasi_timestamp(self.meta.st_atim))
+ }
+
+ pub fn created(&self) -> io::Result<SystemTime> {
+ Ok(SystemTime::from_wasi_timestamp(self.meta.st_ctim))
+ }
+
+ pub fn as_wasi(&self) -> &libc::__wasi_filestat_t {
+ &self.meta
+ }
+}
+
+impl FilePermissions {
+ pub fn readonly(&self) -> bool {
+ self.readonly
+ }
+
+ pub fn set_readonly(&mut self, readonly: bool) {
+ self.readonly = readonly;
+ }
+}
+
+impl FileType {
+ pub fn is_dir(&self) -> bool {
+ self.bits == libc::__WASI_FILETYPE_DIRECTORY
+ }
+
+ pub fn is_file(&self) -> bool {
+ self.bits == libc::__WASI_FILETYPE_REGULAR_FILE
+ }
+
+ pub fn is_symlink(&self) -> bool {
+ self.bits == libc::__WASI_FILETYPE_SYMBOLIC_LINK
+ }
+
+ pub fn bits(&self) -> libc::__wasi_filetype_t {
+ self.bits
+ }
+}
+
+impl fmt::Debug for ReadDir {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("ReadDir").finish()
+ }
+}
+
+impl Iterator for ReadDir {
+ type Item = io::Result<DirEntry>;
+
+ fn next(&mut self) -> Option<io::Result<DirEntry>> {
+ loop {
+ // If we've reached the capacity of our buffer then we need to read
+ // some more from the OS, otherwise we pick up at our old offset.
+ let offset = if self.offset == self.cap {
+ let cookie = self.cookie.take()?;
+ match self.inner.dir.fd.readdir(&mut self.buf, cookie) {
+ Ok(bytes) => self.cap = bytes,
+ Err(e) => return Some(Err(e)),
+ }
+ self.offset = 0;
+ self.cookie = Some(cookie);
+
+ // If we didn't actually read anything, this is in theory the
+ // end of the directory.
+ if self.cap == 0 {
+ self.cookie = None;
+ return None;
+ }
+
+ 0
+ } else {
+ self.offset
+ };
+ let data = &self.buf[offset..self.cap];
+
+ // If we're not able to read a directory entry then that means it
+ // must have been truncated at the end of the buffer, so reset our
+ // offset so we can go back and reread into the buffer, picking up
+ // where we last left off.
+ let dirent_size = mem::size_of::<libc::__wasi_dirent_t>();
+ if data.len() < dirent_size {
+ assert!(self.cookie.is_some());
+ assert!(self.buf.len() >= dirent_size);
+ self.offset = self.cap;
+ continue;
+ }
+ let (dirent, data) = data.split_at(dirent_size);
+ let dirent =
+ unsafe { ptr::read_unaligned(dirent.as_ptr() as *const libc::__wasi_dirent_t) };
+
+ // If the file name was truncated, then we need to reinvoke
+ // `readdir` so we truncate our buffer to start over and reread this
+ // descriptor. Note that if our offset is 0 that means the file name
+ // is massive and we need a bigger buffer.
+ if data.len() < dirent.d_namlen as usize {
+ if offset == 0 {
+ let amt_to_add = self.buf.capacity();
+ self.buf.extend(iter::repeat(0).take(amt_to_add));
+ }
+ assert!(self.cookie.is_some());
+ self.offset = self.cap;
+ continue;
+ }
+ self.cookie = Some(dirent.d_next);
+ self.offset = offset + dirent_size + dirent.d_namlen as usize;
+
+ let name = &data[..(dirent.d_namlen as usize)];
+
+ // These names are skipped on all other platforms, so let's skip
+ // them here too
+ if name == b"." || name == b".." {
+ continue;
+ }
+
+ return Some(Ok(DirEntry {
+ meta: dirent,
+ name: name.to_vec(),
+ inner: self.inner.clone(),
+ }));
+ }
+ }
+}
+
+impl DirEntry {
+ pub fn path(&self) -> PathBuf {
+ let name = OsStr::from_bytes(&self.name);
+ self.inner.root.join(name)
+ }
+
+ pub fn file_name(&self) -> OsString {
+ OsString::from_vec(self.name.clone())
+ }
+
+ pub fn metadata(&self) -> io::Result<FileAttr> {
+ metadata_at(
+ &self.inner.dir.fd,
+ 0,
+ OsStr::from_bytes(&self.name).as_ref(),
+ )
+ }
+
+ pub fn file_type(&self) -> io::Result<FileType> {
+ Ok(FileType {
+ bits: self.meta.d_type,
+ })
+ }
+
+ pub fn ino(&self) -> libc::__wasi_inode_t {
+ self.meta.d_ino
+ }
+}
+
+impl OpenOptions {
+ pub fn new() -> OpenOptions {
+ let mut base = OpenOptions::default();
+ base.dirflags = libc::__WASI_LOOKUP_SYMLINK_FOLLOW;
+ return base;
+ }
+
+ pub fn read(&mut self, read: bool) {
+ self.read = read;
+ }
+
+ pub fn write(&mut self, write: bool) {
+ self.write = write;
+ }
+
+ pub fn truncate(&mut self, truncate: bool) {
+ self.oflag(libc::__WASI_O_TRUNC, truncate);
+ }
+
+ pub fn create(&mut self, create: bool) {
+ self.oflag(libc::__WASI_O_CREAT, create);
+ }
+
+ pub fn create_new(&mut self, create_new: bool) {
+ self.oflag(libc::__WASI_O_EXCL, create_new);
+ self.oflag(libc::__WASI_O_CREAT, create_new);
+ }
+
+ pub fn directory(&mut self, directory: bool) {
+ self.oflag(libc::__WASI_O_DIRECTORY, directory);
+ }
+
+ fn oflag(&mut self, bit: libc::__wasi_oflags_t, set: bool) {
+ if set {
+ self.oflags |= bit;
+ } else {
+ self.oflags &= !bit;
+ }
+ }
+
+ pub fn append(&mut self, set: bool) {
+ self.fdflag(libc::__WASI_FDFLAG_APPEND, set);
+ }
+
+ pub fn dsync(&mut self, set: bool) {
+ self.fdflag(libc::__WASI_FDFLAG_DSYNC, set);
+ }
+
+ pub fn nonblock(&mut self, set: bool) {
+ self.fdflag(libc::__WASI_FDFLAG_NONBLOCK, set);
+ }
+
+ pub fn rsync(&mut self, set: bool) {
+ self.fdflag(libc::__WASI_FDFLAG_RSYNC, set);
+ }
+
+ pub fn sync(&mut self, set: bool) {
+ self.fdflag(libc::__WASI_FDFLAG_SYNC, set);
+ }
+
+ fn fdflag(&mut self, bit: libc::__wasi_fdflags_t, set: bool) {
+ if set {
+ self.fdflags |= bit;
+ } else {
+ self.fdflags &= !bit;
+ }
+ }
+
+ pub fn fs_rights_base(&mut self, rights: libc::__wasi_rights_t) {
+ self.rights_base = Some(rights);
+ }
+
+ pub fn fs_rights_inheriting(&mut self, rights: libc::__wasi_rights_t) {
+ self.rights_inheriting = Some(rights);
+ }
+
+ fn rights_base(&self) -> libc::__wasi_rights_t {
+ if let Some(rights) = self.rights_base {
+ return rights;
+ }
+
+ // If rights haven't otherwise been specified try to pick a reasonable
+ // set. This can always be overridden by users via extension traits, and
+ // implementations may give us fewer rights silently than we ask for. So
+ // given that, just look at `read` and `write` and bucket permissions
+ // based on that.
+ let mut base = 0;
+ if self.read {
+ base |= libc::__WASI_RIGHT_FD_READ;
+ base |= libc::__WASI_RIGHT_FD_READDIR;
+ }
+ if self.write {
+ base |= libc::__WASI_RIGHT_FD_WRITE;
+ base |= libc::__WASI_RIGHT_FD_DATASYNC;
+ base |= libc::__WASI_RIGHT_FD_ALLOCATE;
+ base |= libc::__WASI_RIGHT_FD_FILESTAT_SET_SIZE;
+ }
+
+ // FIXME: some of these should probably be read-only or write-only...
+ base |= libc::__WASI_RIGHT_FD_ADVISE;
+ base |= libc::__WASI_RIGHT_FD_FDSTAT_SET_FLAGS;
+ base |= libc::__WASI_RIGHT_FD_FILESTAT_SET_TIMES;
+ base |= libc::__WASI_RIGHT_FD_SEEK;
+ base |= libc::__WASI_RIGHT_FD_SYNC;
+ base |= libc::__WASI_RIGHT_FD_TELL;
+ base |= libc::__WASI_RIGHT_PATH_CREATE_DIRECTORY;
+ base |= libc::__WASI_RIGHT_PATH_CREATE_FILE;
+ base |= libc::__WASI_RIGHT_PATH_FILESTAT_GET;
+ base |= libc::__WASI_RIGHT_PATH_LINK_SOURCE;
+ base |= libc::__WASI_RIGHT_PATH_LINK_TARGET;
+ base |= libc::__WASI_RIGHT_PATH_OPEN;
+ base |= libc::__WASI_RIGHT_PATH_READLINK;
+ base |= libc::__WASI_RIGHT_PATH_REMOVE_DIRECTORY;
+ base |= libc::__WASI_RIGHT_PATH_RENAME_SOURCE;
+ base |= libc::__WASI_RIGHT_PATH_RENAME_TARGET;
+ base |= libc::__WASI_RIGHT_PATH_SYMLINK;
+ base |= libc::__WASI_RIGHT_PATH_UNLINK_FILE;
+ base |= libc::__WASI_RIGHT_POLL_FD_READWRITE;
+
+ return base;
+ }
+
+ fn rights_inheriting(&self) -> libc::__wasi_rights_t {
+ self.rights_inheriting.unwrap_or_else(|| self.rights_base())
+ }
+
+ pub fn lookup_flags(&mut self, flags: libc::__wasi_lookupflags_t) {
+ self.dirflags = flags;
+ }
+}
+
+impl File {
+ pub fn open(path: &Path, opts: &OpenOptions) -> io::Result<File> {
+ let (dir, file) = open_parent(path, libc::__WASI_RIGHT_PATH_OPEN)?;
+ open_at(&dir, &file, opts)
+ }
+
+ pub fn open_at(&self, path: &Path, opts: &OpenOptions) -> io::Result<File> {
+ open_at(&self.fd, path, opts)
+ }
+
+ pub fn file_attr(&self) -> io::Result<FileAttr> {
+ let mut ret = FileAttr::zero();
+ self.fd.filestat_get(&mut ret.meta)?;
+ Ok(ret)
+ }
+
+ pub fn metadata_at(
+ &self,
+ flags: libc::__wasi_lookupflags_t,
+ path: &Path,
+ ) -> io::Result<FileAttr> {
+ metadata_at(&self.fd, flags, path)
+ }
+
+ pub fn fsync(&self) -> io::Result<()> {
+ self.fd.sync()
+ }
+
+ pub fn datasync(&self) -> io::Result<()> {
+ self.fd.datasync()
+ }
+
+ pub fn truncate(&self, size: u64) -> io::Result<()> {
+ self.fd.filestat_set_size(size)
+ }
+
+ pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
+ self.read_vectored(&mut [IoVecMut::new(buf)])
+ }
+
+ pub fn read_vectored(&self, bufs: &mut [IoVecMut<'_>]) -> io::Result<usize> {
+ self.fd.read(bufs)
+ }
+
+ pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
+ self.write_vectored(&[IoVec::new(buf)])
+ }
+
+ pub fn write_vectored(&self, bufs: &[IoVec<'_>]) -> io::Result<usize> {
+ self.fd.write(bufs)
+ }
+
+ pub fn flush(&self) -> io::Result<()> {
+ Ok(())
+ }
+
+ pub fn seek(&self, pos: SeekFrom) -> io::Result<u64> {
+ self.fd.seek(pos)
+ }
+
+ pub fn duplicate(&self) -> io::Result<File> {
+ // https://github.com/CraneStation/wasmtime/blob/master/docs/WASI-rationale.md#why-no-dup
+ unsupported()
+ }
+
+ pub fn set_permissions(&self, _perm: FilePermissions) -> io::Result<()> {
+ // Permissions haven't been fully figured out in wasi yet, so this is
+ // likely temporary
+ unsupported()
+ }
+
+ pub fn fd(&self) -> &WasiFd {
+ &self.fd
+ }
+
+ pub fn into_fd(self) -> WasiFd {
+ self.fd
+ }
+
+ pub fn read_link(&self, file: &Path) -> io::Result<PathBuf> {
+ read_link(&self.fd, file)
+ }
+}
+
+impl FromInner<u32> for File {
+ fn from_inner(fd: u32) -> File {
+ unsafe {
+ File {
+ fd: WasiFd::from_raw(fd),
+ }
+ }
+ }
+}
+
+impl DirBuilder {
+ pub fn new() -> DirBuilder {
+ DirBuilder {}
+ }
+
+ pub fn mkdir(&self, p: &Path) -> io::Result<()> {
+ let (dir, file) = open_parent(p, libc::__WASI_RIGHT_PATH_CREATE_DIRECTORY)?;
+ dir.create_directory(file.as_os_str().as_bytes())
+ }
+}
+
+impl fmt::Debug for File {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("File")
+ .field("fd", &self.fd.as_raw())
+ .finish()
+ }
+}
+
+pub fn readdir(p: &Path) -> io::Result<ReadDir> {
+ let mut opts = OpenOptions::new();
+ opts.directory(true);
+ opts.read(true);
+ let dir = File::open(p, &opts)?;
+ Ok(ReadDir {
+ cookie: Some(0),
+ buf: vec![0; 128],
+ offset: 0,
+ cap: 0,
+ inner: Arc::new(ReadDirInner {
+ dir,
+ root: p.to_path_buf(),
+ }),
+ })
+}
+
+pub fn unlink(p: &Path) -> io::Result<()> {
+ let (dir, file) = open_parent(p, libc::__WASI_RIGHT_PATH_UNLINK_FILE)?;
+ dir.unlink_file(file.as_os_str().as_bytes())
+}
+
+pub fn rename(old: &Path, new: &Path) -> io::Result<()> {
+ let (old, old_file) = open_parent(old, libc::__WASI_RIGHT_PATH_RENAME_SOURCE)?;
+ let (new, new_file) = open_parent(new, libc::__WASI_RIGHT_PATH_RENAME_TARGET)?;
+ old.rename(
+ old_file.as_os_str().as_bytes(),
+ &new,
+ new_file.as_os_str().as_bytes(),
+ )
+}
+
+pub fn set_perm(_p: &Path, _perm: FilePermissions) -> io::Result<()> {
+ // Permissions haven't been fully figured out in wasi yet, so this is
+ // likely temporary
+ unsupported()
+}
+
+pub fn rmdir(p: &Path) -> io::Result<()> {
+ let (dir, file) = open_parent(p, libc::__WASI_RIGHT_PATH_REMOVE_DIRECTORY)?;
+ dir.remove_directory(file.as_os_str().as_bytes())
+}
+
+pub fn readlink(p: &Path) -> io::Result<PathBuf> {
+ let (dir, file) = open_parent(p, libc::__WASI_RIGHT_PATH_READLINK)?;
+ read_link(&dir, &file)
+}
+
+fn read_link(fd: &WasiFd, file: &Path) -> io::Result<PathBuf> {
+ // Try to get a best effort initial capacity for the vector we're going to
+ // fill. Note that if it's not a symlink we don't use a file to avoid
+ // allocating gigabytes if you read_link a huge movie file by accident.
+ // Additionally we add 1 to the initial size so if it doesn't change until
+ // when we call `readlink` the returned length will be less than the
+ // capacity, guaranteeing that we got all the data.
+ let meta = metadata_at(fd, 0, file)?;
+ let initial_size = if meta.file_type().is_symlink() {
+ (meta.size() as usize).saturating_add(1)
+ } else {
+ 1 // this'll fail in just a moment
+ };
+
+ // Now that we have an initial guess of how big to make our buffer, call
+ // `readlink` in a loop until it fails or reports it filled fewer bytes than
+ // we asked for, indicating we got everything.
+ let file = file.as_os_str().as_bytes();
+ let mut destination = vec![0u8; initial_size];
+ loop {
+ let len = fd.readlink(file, &mut destination)?;
+ if len < destination.len() {
+ destination.truncate(len);
+ destination.shrink_to_fit();
+ return Ok(PathBuf::from(OsString::from_vec(destination)));
+ }
+ let amt_to_add = destination.len();
+ destination.extend(iter::repeat(0).take(amt_to_add));
+ }
+}
+
+pub fn symlink(src: &Path, dst: &Path) -> io::Result<()> {
+ let (dst, dst_file) = open_parent(dst, libc::__WASI_RIGHT_PATH_SYMLINK)?;
+ dst.symlink(src.as_os_str().as_bytes(), dst_file.as_os_str().as_bytes())
+}
+
+pub fn link(src: &Path, dst: &Path) -> io::Result<()> {
+ let (src, src_file) = open_parent(src, libc::__WASI_RIGHT_PATH_LINK_SOURCE)?;
+ let (dst, dst_file) = open_parent(dst, libc::__WASI_RIGHT_PATH_LINK_TARGET)?;
+ src.link(
+ libc::__WASI_LOOKUP_SYMLINK_FOLLOW,
+ src_file.as_os_str().as_bytes(),
+ &dst,
+ dst_file.as_os_str().as_bytes(),
+ )
+}
+
+pub fn stat(p: &Path) -> io::Result<FileAttr> {
+ let (dir, file) = open_parent(p, libc::__WASI_RIGHT_PATH_FILESTAT_GET)?;
+ metadata_at(&dir, libc::__WASI_LOOKUP_SYMLINK_FOLLOW, &file)
+}
+
+pub fn lstat(p: &Path) -> io::Result<FileAttr> {
+ let (dir, file) = open_parent(p, libc::__WASI_RIGHT_PATH_FILESTAT_GET)?;
+ metadata_at(&dir, 0, &file)
+}
+
+fn metadata_at(
+ fd: &WasiFd,
+ flags: libc::__wasi_lookupflags_t,
+ path: &Path,
+) -> io::Result<FileAttr> {
+ let mut ret = FileAttr::zero();
+ fd.path_filestat_get(flags, path.as_os_str().as_bytes(), &mut ret.meta)?;
+ Ok(ret)
+}
+
+pub fn canonicalize(_p: &Path) -> io::Result<PathBuf> {
+ // This seems to not be in wasi's API yet, and we may need to end up
+ // emulating it ourselves. For now just return an error.
+ unsupported()
+}
+
+fn open_at(fd: &WasiFd, path: &Path, opts: &OpenOptions) -> io::Result<File> {
+ let fd = fd.open(
+ opts.dirflags,
+ path.as_os_str().as_bytes(),
+ opts.oflags,
+ opts.rights_base(),
+ opts.rights_inheriting(),
+ opts.fdflags,
+ )?;
+ Ok(File { fd })
+}
+
+/// Attempts to open a bare path `p`.
+///
+/// WASI has no fundamental capability to do this. All syscalls and operations
+/// are relative to already-open file descriptors. The C library, however,
+/// manages a map of preopened file descriptors to their path, and then the C
+/// library provides an API to look at this. In other words, when you want to
+/// open a path `p`, you have to find a previously opened file descriptor in a
+/// global table and then see if `p` is relative to that file descriptor.
+///
+/// This function, if successful, will return two items:
+///
+/// * The first is a `ManuallyDrop<WasiFd>`. This represents a preopened file
+/// descriptor which we don't have ownership of, but we can use. You shouldn't
+/// actually drop the `fd`.
+///
+/// * The second is a path that should be a part of `p` and represents a
+/// relative traversal from the file descriptor specified to the desired
+/// location `p`.
+///
+/// If successful you can use the returned file descriptor to perform
+/// file-descriptor-relative operations on the path returned as well. The
+/// `rights` argument indicates what operations are desired on the returned file
+/// descriptor, and if successful the returned file descriptor should have the
+/// appropriate rights for performing `rights` actions.
+///
+/// Note that this can fail if `p` doesn't look like it can be opened relative
+/// to any preopened file descriptor.
+fn open_parent(
+ p: &Path,
+ rights: libc::__wasi_rights_t,
+) -> io::Result<(ManuallyDrop<WasiFd>, PathBuf)> {
+ let p = CString::new(p.as_os_str().as_bytes())?;
+ unsafe {
+ let mut ret = ptr::null();
+ let fd = __wasilibc_find_relpath(p.as_ptr(), rights, 0, &mut ret);
+ if fd == -1 {
+ let msg = format!(
+ "failed to find a preopened file descriptor \
+ through which {:?} could be opened",
+ p
+ );
+ return Err(io::Error::new(io::ErrorKind::Other, msg));
+ }
+ let path = Path::new(OsStr::from_bytes(CStr::from_ptr(ret).to_bytes()));
+
+ // FIXME: right now `path` is a pointer into `p`, the `CString` above.
+ // When we return `p` is deallocated and we can't use it, so we need to
+ // currently separately allocate `path`. If this becomes an issue though
+ // we should probably turn this into a closure-taking interface or take
+ // `&CString` and then pass off `&Path` tied to the same lifetime.
+ let path = path.to_path_buf();
+
+ return Ok((ManuallyDrop::new(WasiFd::from_raw(fd as u32)), path));
+ }
+
+ // FIXME(rust-lang/libc#1314) use the `libc` crate for this when the API
+ // there is published
+ extern "C" {
+ pub fn __wasilibc_find_relpath(
+ path: *const libc::c_char,
+ rights_base: libc::__wasi_rights_t,
+ rights_inheriting: libc::__wasi_rights_t,
+ relative_path: *mut *const libc::c_char,
+ ) -> libc::c_int;
+ }
+}
diff --git a/src/libstd/sys/wasi/io.rs b/src/libstd/sys/wasi/io.rs
new file mode 100644
index 0000000..5f0315d
--- /dev/null
+++ b/src/libstd/sys/wasi/io.rs
@@ -0,0 +1,62 @@
+use crate::marker::PhantomData;
+use crate::slice;
+
+use libc::{__wasi_ciovec_t, __wasi_iovec_t, c_void};
+
+#[repr(transparent)]
+pub struct IoVec<'a> {
+ vec: __wasi_ciovec_t,
+ _p: PhantomData<&'a [u8]>,
+}
+
+impl<'a> IoVec<'a> {
+ #[inline]
+ pub fn new(buf: &'a [u8]) -> IoVec<'a> {
+ IoVec {
+ vec: __wasi_ciovec_t {
+ buf: buf.as_ptr() as *const c_void,
+ buf_len: buf.len(),
+ },
+ _p: PhantomData,
+ }
+ }
+
+ #[inline]
+ pub fn as_slice(&self) -> &[u8] {
+ unsafe {
+ slice::from_raw_parts(self.vec.buf as *const u8, self.vec.buf_len)
+ }
+ }
+}
+
+pub struct IoVecMut<'a> {
+ vec: __wasi_iovec_t,
+ _p: PhantomData<&'a mut [u8]>,
+}
+
+impl<'a> IoVecMut<'a> {
+ #[inline]
+ pub fn new(buf: &'a mut [u8]) -> IoVecMut<'a> {
+ IoVecMut {
+ vec: __wasi_iovec_t {
+ buf: buf.as_mut_ptr() as *mut c_void,
+ buf_len: buf.len()
+ },
+ _p: PhantomData,
+ }
+ }
+
+ #[inline]
+ pub fn as_slice(&self) -> &[u8] {
+ unsafe {
+ slice::from_raw_parts(self.vec.buf as *const u8, self.vec.buf_len)
+ }
+ }
+
+ #[inline]
+ pub fn as_mut_slice(&mut self) -> &mut [u8] {
+ unsafe {
+ slice::from_raw_parts_mut(self.vec.buf as *mut u8, self.vec.buf_len)
+ }
+ }
+}
diff --git a/src/libstd/sys/wasi/mod.rs b/src/libstd/sys/wasi/mod.rs
new file mode 100644
index 0000000..a9bb015
--- /dev/null
+++ b/src/libstd/sys/wasi/mod.rs
@@ -0,0 +1,128 @@
+//! System bindings for the wasm/web platform
+//!
+//! This module contains the facade (aka platform-specific) implementations of
+//! OS level functionality for wasm. Note that this wasm is *not* the emscripten
+//! wasm, so we have no runtime here.
+//!
+//! This is all super highly experimental and not actually intended for
+//! wide/production use yet, it's still all in the experimental category. This
+//! will likely change over time.
+//!
+//! Currently all functions here are basically stubs that immediately return
+//! errors. The hope is that with a portability lint we can turn actually just
+//! remove all this and just omit parts of the standard library if we're
+//! compiling for wasm. That way it's a compile time error for something that's
+//! guaranteed to be a runtime error!
+
+use libc;
+use crate::io::{Error, ErrorKind};
+use crate::mem;
+use crate::os::raw::c_char;
+
+pub mod alloc;
+pub mod args;
+#[cfg(feature = "backtrace")]
+pub mod backtrace;
+#[path = "../wasm/cmath.rs"]
+pub mod cmath;
+#[path = "../wasm/condvar.rs"]
+pub mod condvar;
+pub mod env;
+pub mod fd;
+pub mod fs;
+#[path = "../wasm/memchr.rs"]
+pub mod memchr;
+#[path = "../wasm/mutex.rs"]
+pub mod mutex;
+pub mod net;
+pub mod io;
+pub mod os;
+pub use crate::sys_common::os_str_bytes as os_str;
+pub mod path;
+pub mod pipe;
+pub mod process;
+#[path = "../wasm/rwlock.rs"]
+pub mod rwlock;
+#[path = "../wasm/stack_overflow.rs"]
+pub mod stack_overflow;
+pub mod stdio;
+pub mod thread;
+#[path = "../wasm/thread_local.rs"]
+pub mod thread_local;
+pub mod time;
+pub mod ext;
+
+#[cfg(not(test))]
+pub fn init() {
+}
+
+pub fn unsupported<T>() -> crate::io::Result<T> {
+ Err(unsupported_err())
+}
+
+pub fn unsupported_err() -> Error {
+ Error::new(ErrorKind::Other, "operation not supported on wasm yet")
+}
+
+pub fn decode_error_kind(_code: i32) -> ErrorKind {
+ ErrorKind::Other
+}
+
+// This enum is used as the storage for a bunch of types which can't actually
+// exist.
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
+pub enum Void {}
+
+pub unsafe fn strlen(mut s: *const c_char) -> usize {
+ let mut n = 0;
+ while *s != 0 {
+ n += 1;
+ s = s.offset(1);
+ }
+ return n
+}
+
+pub unsafe fn abort_internal() -> ! {
+ libc::abort()
+}
+
+pub fn hashmap_random_keys() -> (u64, u64) {
+ let mut ret = (0u64, 0u64);
+ unsafe {
+ let base = &mut ret as *mut (u64, u64) as *mut libc::c_void;
+ let len = mem::size_of_val(&ret);
+ cvt_wasi(libc::__wasi_random_get(base, len)).unwrap();
+ }
+ return ret
+}
+
+#[doc(hidden)]
+pub trait IsMinusOne {
+ fn is_minus_one(&self) -> bool;
+}
+
+macro_rules! impl_is_minus_one {
+ ($($t:ident)*) => ($(impl IsMinusOne for $t {
+ fn is_minus_one(&self) -> bool {
+ *self == -1
+ }
+ })*)
+}
+
+impl_is_minus_one! { i8 i16 i32 i64 isize }
+
+pub fn cvt<T: IsMinusOne>(t: T) -> crate::io::Result<T> {
+ if t.is_minus_one() {
+ Err(Error::last_os_error())
+ } else {
+ Ok(t)
+ }
+}
+
+pub fn cvt_wasi(r: u16) -> crate::io::Result<()> {
+ if r != libc::__WASI_ESUCCESS {
+ Err(Error::from_raw_os_error(r as i32))
+ } else {
+ Ok(())
+ }
+}
diff --git a/src/libstd/sys/wasi/net.rs b/src/libstd/sys/wasi/net.rs
new file mode 100644
index 0000000..1579aa4
--- /dev/null
+++ b/src/libstd/sys/wasi/net.rs
@@ -0,0 +1,358 @@
+use crate::fmt;
+use crate::io::{self, IoVec, IoVecMut};
+use crate::net::{SocketAddr, Shutdown, Ipv4Addr, Ipv6Addr};
+use crate::time::Duration;
+use crate::sys::{unsupported, Void};
+use crate::convert::TryFrom;
+
+pub struct TcpStream(Void);
+
+impl TcpStream {
+ pub fn connect(_: io::Result<&SocketAddr>) -> io::Result<TcpStream> {
+ unsupported()
+ }
+
+ pub fn connect_timeout(_: &SocketAddr, _: Duration) -> io::Result<TcpStream> {
+ unsupported()
+ }
+
+ pub fn set_read_timeout(&self, _: Option<Duration>) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn set_write_timeout(&self, _: Option<Duration>) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
+ match self.0 {}
+ }
+
+ pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
+ match self.0 {}
+ }
+
+ pub fn peek(&self, _: &mut [u8]) -> io::Result<usize> {
+ match self.0 {}
+ }
+
+ pub fn read(&self, _: &mut [u8]) -> io::Result<usize> {
+ match self.0 {}
+ }
+
+ pub fn read_vectored(&self, _: &mut [IoVecMut<'_>]) -> io::Result<usize> {
+ match self.0 {}
+ }
+
+ pub fn write(&self, _: &[u8]) -> io::Result<usize> {
+ match self.0 {}
+ }
+
+ pub fn write_vectored(&self, _: &[IoVec<'_>]) -> io::Result<usize> {
+ match self.0 {}
+ }
+
+ pub fn peer_addr(&self) -> io::Result<SocketAddr> {
+ match self.0 {}
+ }
+
+ pub fn socket_addr(&self) -> io::Result<SocketAddr> {
+ match self.0 {}
+ }
+
+ pub fn shutdown(&self, _: Shutdown) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn duplicate(&self) -> io::Result<TcpStream> {
+ match self.0 {}
+ }
+
+ pub fn set_nodelay(&self, _: bool) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn nodelay(&self) -> io::Result<bool> {
+ match self.0 {}
+ }
+
+ pub fn set_ttl(&self, _: u32) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn ttl(&self) -> io::Result<u32> {
+ match self.0 {}
+ }
+
+ pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+ match self.0 {}
+ }
+
+ pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
+ match self.0 {}
+ }
+}
+
+impl fmt::Debug for TcpStream {
+ fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self.0 {}
+ }
+}
+
+pub struct TcpListener(Void);
+
+impl TcpListener {
+ pub fn bind(_: io::Result<&SocketAddr>) -> io::Result<TcpListener> {
+ unsupported()
+ }
+
+ pub fn socket_addr(&self) -> io::Result<SocketAddr> {
+ match self.0 {}
+ }
+
+ pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> {
+ match self.0 {}
+ }
+
+ pub fn duplicate(&self) -> io::Result<TcpListener> {
+ match self.0 {}
+ }
+
+ pub fn set_ttl(&self, _: u32) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn ttl(&self) -> io::Result<u32> {
+ match self.0 {}
+ }
+
+ pub fn set_only_v6(&self, _: bool) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn only_v6(&self) -> io::Result<bool> {
+ match self.0 {}
+ }
+
+ pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+ match self.0 {}
+ }
+
+ pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
+ match self.0 {}
+ }
+}
+
+impl fmt::Debug for TcpListener {
+ fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self.0 {}
+ }
+}
+
+pub struct UdpSocket(Void);
+
+impl UdpSocket {
+ pub fn bind(_: io::Result<&SocketAddr>) -> io::Result<UdpSocket> {
+ unsupported()
+ }
+
+ pub fn peer_addr(&self) -> io::Result<SocketAddr> {
+ match self.0 {}
+ }
+
+ pub fn socket_addr(&self) -> io::Result<SocketAddr> {
+ match self.0 {}
+ }
+
+ pub fn recv_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+ match self.0 {}
+ }
+
+ pub fn peek_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+ match self.0 {}
+ }
+
+ pub fn send_to(&self, _: &[u8], _: &SocketAddr) -> io::Result<usize> {
+ match self.0 {}
+ }
+
+ pub fn duplicate(&self) -> io::Result<UdpSocket> {
+ match self.0 {}
+ }
+
+ pub fn set_read_timeout(&self, _: Option<Duration>) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn set_write_timeout(&self, _: Option<Duration>) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
+ match self.0 {}
+ }
+
+ pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
+ match self.0 {}
+ }
+
+ pub fn set_broadcast(&self, _: bool) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn broadcast(&self) -> io::Result<bool> {
+ match self.0 {}
+ }
+
+ pub fn set_multicast_loop_v4(&self, _: bool) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn multicast_loop_v4(&self) -> io::Result<bool> {
+ match self.0 {}
+ }
+
+ pub fn set_multicast_ttl_v4(&self, _: u32) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn multicast_ttl_v4(&self) -> io::Result<u32> {
+ match self.0 {}
+ }
+
+ pub fn set_multicast_loop_v6(&self, _: bool) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn multicast_loop_v6(&self) -> io::Result<bool> {
+ match self.0 {}
+ }
+
+ pub fn join_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr)
+ -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn join_multicast_v6(&self, _: &Ipv6Addr, _: u32)
+ -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn leave_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr)
+ -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn leave_multicast_v6(&self, _: &Ipv6Addr, _: u32)
+ -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn set_ttl(&self, _: u32) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn ttl(&self) -> io::Result<u32> {
+ match self.0 {}
+ }
+
+ pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+ match self.0 {}
+ }
+
+ pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn recv(&self, _: &mut [u8]) -> io::Result<usize> {
+ match self.0 {}
+ }
+
+ pub fn peek(&self, _: &mut [u8]) -> io::Result<usize> {
+ match self.0 {}
+ }
+
+ pub fn send(&self, _: &[u8]) -> io::Result<usize> {
+ match self.0 {}
+ }
+
+ pub fn connect(&self, _: io::Result<&SocketAddr>) -> io::Result<()> {
+ match self.0 {}
+ }
+}
+
+impl fmt::Debug for UdpSocket {
+ fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self.0 {}
+ }
+}
+
+pub struct LookupHost(Void);
+
+impl LookupHost {
+ pub fn port(&self) -> u16 {
+ match self.0 {}
+ }
+}
+
+impl Iterator for LookupHost {
+ type Item = SocketAddr;
+ fn next(&mut self) -> Option<SocketAddr> {
+ match self.0 {}
+ }
+}
+
+impl<'a> TryFrom<&'a str> for LookupHost {
+ type Error = io::Error;
+
+ fn try_from(_v: &'a str) -> io::Result<LookupHost> {
+ unsupported()
+ }
+}
+
+impl<'a> TryFrom<(&'a str, u16)> for LookupHost {
+ type Error = io::Error;
+
+ fn try_from(_v: (&'a str, u16)) -> io::Result<LookupHost> {
+ unsupported()
+ }
+}
+
+#[allow(nonstandard_style)]
+pub mod netc {
+ pub const AF_INET: u8 = 0;
+ pub const AF_INET6: u8 = 1;
+ pub type sa_family_t = u8;
+
+ #[derive(Copy, Clone)]
+ pub struct in_addr {
+ pub s_addr: u32,
+ }
+
+ #[derive(Copy, Clone)]
+ pub struct sockaddr_in {
+ pub sin_family: sa_family_t,
+ pub sin_port: u16,
+ pub sin_addr: in_addr,
+ }
+
+ #[derive(Copy, Clone)]
+ pub struct in6_addr {
+ pub s6_addr: [u8; 16],
+ }
+
+ #[derive(Copy, Clone)]
+ pub struct sockaddr_in6 {
+ pub sin6_family: sa_family_t,
+ pub sin6_port: u16,
+ pub sin6_addr: in6_addr,
+ pub sin6_flowinfo: u32,
+ pub sin6_scope_id: u32,
+ }
+
+ #[derive(Copy, Clone)]
+ pub struct sockaddr {
+ }
+
+ pub type socklen_t = usize;
+}
diff --git a/src/libstd/sys/wasi/os.rs b/src/libstd/sys/wasi/os.rs
new file mode 100644
index 0000000..822ea02
--- /dev/null
+++ b/src/libstd/sys/wasi/os.rs
@@ -0,0 +1,184 @@
+use crate::any::Any;
+use crate::error::Error as StdError;
+use crate::ffi::{OsString, OsStr, CString, CStr};
+use crate::fmt;
+use crate::io;
+use crate::marker::PhantomData;
+use crate::os::wasi::prelude::*;
+use crate::path::{self, PathBuf};
+use crate::ptr;
+use crate::str;
+use crate::sys::memchr;
+use crate::sys::{cvt, unsupported, Void};
+use crate::vec;
+
+#[cfg(not(target_feature = "atomics"))]
+pub unsafe fn env_lock() -> impl Any {
+ // No need for a lock if we're single-threaded, but this function will need
+ // to get implemented for multi-threaded scenarios
+}
+
+pub fn errno() -> i32 {
+ extern {
+ #[thread_local]
+ static errno: libc::c_int;
+ }
+
+ unsafe { errno as i32 }
+}
+
+pub fn error_string(errno: i32) -> String {
+ extern {
+ fn strerror_r(errnum: libc::c_int, buf: *mut libc::c_char,
+ buflen: libc::size_t) -> libc::c_int;
+ }
+
+ let mut buf = [0 as libc::c_char; 1024];
+
+ let p = buf.as_mut_ptr();
+ unsafe {
+ if strerror_r(errno as libc::c_int, p, buf.len()) < 0 {
+ panic!("strerror_r failure");
+ }
+ str::from_utf8(CStr::from_ptr(p).to_bytes()).unwrap().to_owned()
+ }
+}
+
+pub fn getcwd() -> io::Result<PathBuf> {
+ unsupported()
+}
+
+pub fn chdir(_: &path::Path) -> io::Result<()> {
+ unsupported()
+}
+
+pub struct SplitPaths<'a>(&'a Void);
+
+pub fn split_paths(_unparsed: &OsStr) -> SplitPaths<'_> {
+ panic!("unsupported")
+}
+
+impl<'a> Iterator for SplitPaths<'a> {
+ type Item = PathBuf;
+ fn next(&mut self) -> Option<PathBuf> {
+ match *self.0 {}
+ }
+}
+
+#[derive(Debug)]
+pub struct JoinPathsError;
+
+pub fn join_paths<I, T>(_paths: I) -> Result<OsString, JoinPathsError>
+ where I: Iterator<Item=T>, T: AsRef<OsStr>
+{
+ Err(JoinPathsError)
+}
+
+impl fmt::Display for JoinPathsError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ "not supported on wasm yet".fmt(f)
+ }
+}
+
+impl StdError for JoinPathsError {
+ fn description(&self) -> &str {
+ "not supported on wasm yet"
+ }
+}
+
+pub fn current_exe() -> io::Result<PathBuf> {
+ unsupported()
+}
+
+pub struct Env {
+ iter: vec::IntoIter<(OsString, OsString)>,
+ _dont_send_or_sync_me: PhantomData<*mut ()>,
+}
+
+impl Iterator for Env {
+ type Item = (OsString, OsString);
+ fn next(&mut self) -> Option<(OsString, OsString)> { self.iter.next() }
+ fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
+}
+
+
+pub fn env() -> Env {
+ unsafe {
+ let _guard = env_lock();
+ let mut environ = libc::environ;
+ let mut result = Vec::new();
+ while environ != ptr::null_mut() && *environ != ptr::null_mut() {
+ if let Some(key_value) = parse(CStr::from_ptr(*environ).to_bytes()) {
+ result.push(key_value);
+ }
+ environ = environ.offset(1);
+ }
+ return Env {
+ iter: result.into_iter(),
+ _dont_send_or_sync_me: PhantomData,
+ }
+ }
+
+ // See src/libstd/sys/unix/os.rs, same as that
+ fn parse(input: &[u8]) -> Option<(OsString, OsString)> {
+ if input.is_empty() {
+ return None;
+ }
+ let pos = memchr::memchr(b'=', &input[1..]).map(|p| p + 1);
+ pos.map(|p| (
+ OsStringExt::from_vec(input[..p].to_vec()),
+ OsStringExt::from_vec(input[p+1..].to_vec()),
+ ))
+ }
+}
+
+pub fn getenv(k: &OsStr) -> io::Result<Option<OsString>> {
+ let k = CString::new(k.as_bytes())?;
+ unsafe {
+ let _guard = env_lock();
+ let s = libc::getenv(k.as_ptr()) as *const libc::c_char;
+ let ret = if s.is_null() {
+ None
+ } else {
+ Some(OsStringExt::from_vec(CStr::from_ptr(s).to_bytes().to_vec()))
+ };
+ Ok(ret)
+ }
+}
+
+pub fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> {
+ let k = CString::new(k.as_bytes())?;
+ let v = CString::new(v.as_bytes())?;
+
+ unsafe {
+ let _guard = env_lock();
+ cvt(libc::setenv(k.as_ptr(), v.as_ptr(), 1)).map(|_| ())
+ }
+}
+
+pub fn unsetenv(n: &OsStr) -> io::Result<()> {
+ let nbuf = CString::new(n.as_bytes())?;
+
+ unsafe {
+ let _guard = env_lock();
+ cvt(libc::unsetenv(nbuf.as_ptr())).map(|_| ())
+ }
+}
+
+pub fn temp_dir() -> PathBuf {
+ panic!("no filesystem on wasm")
+}
+
+pub fn home_dir() -> Option<PathBuf> {
+ None
+}
+
+pub fn exit(code: i32) -> ! {
+ unsafe {
+ libc::exit(code)
+ }
+}
+
+pub fn getpid() -> u32 {
+ panic!("unsupported");
+}
diff --git a/src/libstd/sys/wasi/path.rs b/src/libstd/sys/wasi/path.rs
new file mode 100644
index 0000000..7a18395
--- /dev/null
+++ b/src/libstd/sys/wasi/path.rs
@@ -0,0 +1,19 @@
+use crate::path::Prefix;
+use crate::ffi::OsStr;
+
+#[inline]
+pub fn is_sep_byte(b: u8) -> bool {
+ b == b'/'
+}
+
+#[inline]
+pub fn is_verbatim_sep(b: u8) -> bool {
+ b == b'/'
+}
+
+pub fn parse_prefix(_: &OsStr) -> Option<Prefix<'_>> {
+ None
+}
+
+pub const MAIN_SEP_STR: &str = "/";
+pub const MAIN_SEP: char = '/';
diff --git a/src/libstd/sys/wasi/pipe.rs b/src/libstd/sys/wasi/pipe.rs
new file mode 100644
index 0000000..2582b99
--- /dev/null
+++ b/src/libstd/sys/wasi/pipe.rs
@@ -0,0 +1,25 @@
+use crate::io;
+use crate::sys::Void;
+
+pub struct AnonPipe(Void);
+
+impl AnonPipe {
+ pub fn read(&self, _buf: &mut [u8]) -> io::Result<usize> {
+ match self.0 {}
+ }
+
+ pub fn write(&self, _buf: &[u8]) -> io::Result<usize> {
+ match self.0 {}
+ }
+
+ pub fn diverge(&self) -> ! {
+ match self.0 {}
+ }
+}
+
+pub fn read2(p1: AnonPipe,
+ _v1: &mut Vec<u8>,
+ _p2: AnonPipe,
+ _v2: &mut Vec<u8>) -> io::Result<()> {
+ match p1.0 {}
+}
diff --git a/src/libstd/sys/wasi/process.rs b/src/libstd/sys/wasi/process.rs
new file mode 100644
index 0000000..788b829
--- /dev/null
+++ b/src/libstd/sys/wasi/process.rs
@@ -0,0 +1,152 @@
+use crate::ffi::OsStr;
+use crate::fmt;
+use crate::io;
+use crate::sys::fs::File;
+use crate::sys::pipe::AnonPipe;
+use crate::sys::{unsupported, Void};
+use crate::sys_common::process::{CommandEnv, DefaultEnvKey};
+
+////////////////////////////////////////////////////////////////////////////////
+// Command
+////////////////////////////////////////////////////////////////////////////////
+
+pub struct Command {
+ env: CommandEnv<DefaultEnvKey>
+}
+
+// passed back to std::process with the pipes connected to the child, if any
+// were requested
+pub struct StdioPipes {
+ pub stdin: Option<AnonPipe>,
+ pub stdout: Option<AnonPipe>,
+ pub stderr: Option<AnonPipe>,
+}
+
+pub enum Stdio {
+ Inherit,
+ Null,
+ MakePipe,
+}
+
+impl Command {
+ pub fn new(_program: &OsStr) -> Command {
+ Command {
+ env: Default::default()
+ }
+ }
+
+ pub fn arg(&mut self, _arg: &OsStr) {
+ }
+
+ pub fn env_mut(&mut self) -> &mut CommandEnv<DefaultEnvKey> {
+ &mut self.env
+ }
+
+ pub fn cwd(&mut self, _dir: &OsStr) {
+ }
+
+ pub fn stdin(&mut self, _stdin: Stdio) {
+ }
+
+ pub fn stdout(&mut self, _stdout: Stdio) {
+ }
+
+ pub fn stderr(&mut self, _stderr: Stdio) {
+ }
+
+ pub fn spawn(&mut self, _default: Stdio, _needs_stdin: bool)
+ -> io::Result<(Process, StdioPipes)> {
+ unsupported()
+ }
+}
+
+impl From<AnonPipe> for Stdio {
+ fn from(pipe: AnonPipe) -> Stdio {
+ pipe.diverge()
+ }
+}
+
+impl From<File> for Stdio {
+ fn from(_file: File) -> Stdio {
+ panic!("unsupported")
+ }
+}
+
+impl fmt::Debug for Command {
+ fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ Ok(())
+ }
+}
+
+pub struct ExitStatus(Void);
+
+impl ExitStatus {
+ pub fn success(&self) -> bool {
+ match self.0 {}
+ }
+
+ pub fn code(&self) -> Option<i32> {
+ match self.0 {}
+ }
+}
+
+impl Clone for ExitStatus {
+ fn clone(&self) -> ExitStatus {
+ match self.0 {}
+ }
+}
+
+impl Copy for ExitStatus {}
+
+impl PartialEq for ExitStatus {
+ fn eq(&self, _other: &ExitStatus) -> bool {
+ match self.0 {}
+ }
+}
+
+impl Eq for ExitStatus {
+}
+
+impl fmt::Debug for ExitStatus {
+ fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self.0 {}
+ }
+}
+
+impl fmt::Display for ExitStatus {
+ fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self.0 {}
+ }
+}
+
+#[derive(PartialEq, Eq, Clone, Copy, Debug)]
+pub struct ExitCode(bool);
+
+impl ExitCode {
+ pub const SUCCESS: ExitCode = ExitCode(false);
+ pub const FAILURE: ExitCode = ExitCode(true);
+
+ pub fn as_i32(&self) -> i32 {
+ self.0 as i32
+ }
+}
+
+pub struct Process(Void);
+
+impl Process {
+ pub fn id(&self) -> u32 {
+ match self.0 {}
+ }
+
+ pub fn kill(&mut self) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn wait(&mut self) -> io::Result<ExitStatus> {
+ match self.0 {}
+ }
+
+ pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
+ match self.0 {}
+ }
+}
diff --git a/src/libstd/sys/wasi/stdio.rs b/src/libstd/sys/wasi/stdio.rs
new file mode 100644
index 0000000..1929478
--- /dev/null
+++ b/src/libstd/sys/wasi/stdio.rs
@@ -0,0 +1,69 @@
+use crate::io::{self, IoVec, IoVecMut};
+use crate::libc;
+use crate::mem::ManuallyDrop;
+use crate::sys::fd::WasiFd;
+
+pub struct Stdin;
+pub struct Stdout;
+pub struct Stderr;
+
+impl Stdin {
+ pub fn new() -> io::Result<Stdin> {
+ Ok(Stdin)
+ }
+
+ pub fn read(&self, data: &mut [u8]) -> io::Result<usize> {
+ ManuallyDrop::new(unsafe { WasiFd::from_raw(libc::STDIN_FILENO as u32) })
+ .read(&mut [IoVecMut::new(data)])
+ }
+}
+
+impl Stdout {
+ pub fn new() -> io::Result<Stdout> {
+ Ok(Stdout)
+ }
+
+ pub fn write(&self, data: &[u8]) -> io::Result<usize> {
+ ManuallyDrop::new(unsafe { WasiFd::from_raw(libc::STDOUT_FILENO as u32) })
+ .write(&[IoVec::new(data)])
+ }
+
+ pub fn flush(&self) -> io::Result<()> {
+ Ok(())
+ }
+}
+
+impl Stderr {
+ pub fn new() -> io::Result<Stderr> {
+ Ok(Stderr)
+ }
+
+ pub fn write(&self, data: &[u8]) -> io::Result<usize> {
+ ManuallyDrop::new(unsafe { WasiFd::from_raw(libc::STDERR_FILENO as u32) })
+ .write(&[IoVec::new(data)])
+ }
+
+ pub fn flush(&self) -> io::Result<()> {
+ Ok(())
+ }
+}
+
+impl io::Write for Stderr {
+ fn write(&mut self, data: &[u8]) -> io::Result<usize> {
+ (&*self).write(data)
+ }
+
+ fn flush(&mut self) -> io::Result<()> {
+ (&*self).flush()
+ }
+}
+
+pub const STDIN_BUF_SIZE: usize = crate::sys_common::io::DEFAULT_BUF_SIZE;
+
+pub fn is_ebadf(err: &io::Error) -> bool {
+ err.raw_os_error() == Some(libc::__WASI_EBADF as i32)
+}
+
+pub fn panic_output() -> Option<impl io::Write> {
+ Stderr::new().ok()
+}
diff --git a/src/libstd/sys/wasi/thread.rs b/src/libstd/sys/wasi/thread.rs
new file mode 100644
index 0000000..9d3c6ac
--- /dev/null
+++ b/src/libstd/sys/wasi/thread.rs
@@ -0,0 +1,57 @@
+use crate::boxed::FnBox;
+use crate::cmp;
+use crate::ffi::CStr;
+use crate::io;
+use crate::sys::cvt;
+use crate::sys::{unsupported, Void};
+use crate::time::Duration;
+use libc;
+
+pub struct Thread(Void);
+
+pub const DEFAULT_MIN_STACK_SIZE: usize = 4096;
+
+impl Thread {
+ // unsafe: see thread::Builder::spawn_unchecked for safety requirements
+ pub unsafe fn new(_stack: usize, _p: Box<dyn FnBox()>)
+ -> io::Result<Thread>
+ {
+ unsupported()
+ }
+
+ pub fn yield_now() {
+ let ret = unsafe { libc::__wasi_sched_yield() };
+ debug_assert_eq!(ret, 0);
+ }
+
+ pub fn set_name(_name: &CStr) {
+ // nope
+ }
+
+ pub fn sleep(dur: Duration) {
+ let mut secs = dur.as_secs();
+ let mut nsecs = dur.subsec_nanos() as i32;
+
+ unsafe {
+ while secs > 0 || nsecs > 0 {
+ let mut ts = libc::timespec {
+ tv_sec: cmp::min(libc::time_t::max_value() as u64, secs) as libc::time_t,
+ tv_nsec: nsecs,
+ };
+ secs -= ts.tv_sec as u64;
+ cvt(libc::nanosleep(&ts, &mut ts)).unwrap();
+ nsecs = 0;
+ }
+ }
+ }
+
+ pub fn join(self) {
+ match self.0 {}
+ }
+}
+
+pub mod guard {
+ pub type Guard = !;
+ pub unsafe fn current() -> Option<Guard> { None }
+ pub unsafe fn init() -> Option<Guard> { None }
+}
diff --git a/src/libstd/sys/wasi/time.rs b/src/libstd/sys/wasi/time.rs
new file mode 100644
index 0000000..3f14c80
--- /dev/null
+++ b/src/libstd/sys/wasi/time.rs
@@ -0,0 +1,76 @@
+use crate::time::Duration;
+use crate::mem;
+use crate::sys::cvt_wasi;
+use libc;
+
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
+pub struct Instant(Duration);
+
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
+pub struct SystemTime(Duration);
+
+pub const UNIX_EPOCH: SystemTime = SystemTime(Duration::from_secs(0));
+
+fn current_time(clock: u32) -> Duration {
+ unsafe {
+ let mut ts = mem::zeroed();
+ cvt_wasi(libc::__wasi_clock_time_get(
+ clock,
+ 1, // precision... seems ignored though?
+ &mut ts,
+ )).unwrap();
+ Duration::new(
+ (ts / 1_000_000_000) as u64,
+ (ts % 1_000_000_000) as u32,
+ )
+ }
+}
+
+impl Instant {
+ pub fn now() -> Instant {
+ Instant(current_time(libc::__WASI_CLOCK_MONOTONIC))
+ }
+
+ pub const fn zero() -> Instant {
+ Instant(Duration::from_secs(0))
+ }
+
+ pub fn actually_monotonic() -> bool {
+ true
+ }
+
+ pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
+ self.0.checked_sub(other.0)
+ }
+
+ pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
+ Some(Instant(self.0.checked_add(*other)?))
+ }
+
+ pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
+ Some(Instant(self.0.checked_sub(*other)?))
+ }
+}
+
+impl SystemTime {
+ pub fn now() -> SystemTime {
+ SystemTime(current_time(libc::__WASI_CLOCK_REALTIME))
+ }
+
+ pub fn from_wasi_timestamp(ts: libc::__wasi_timestamp_t) -> SystemTime {
+ SystemTime(Duration::from_nanos(ts))
+ }
+
+ pub fn sub_time(&self, other: &SystemTime)
+ -> Result<Duration, Duration> {
+ self.0.checked_sub(other.0).ok_or_else(|| other.0 - self.0)
+ }
+
+ pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
+ Some(SystemTime(self.0.checked_add(*other)?))
+ }
+
+ pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
+ Some(SystemTime(self.0.checked_sub(*other)?))
+ }
+}
diff --git a/src/libstd/sys/wasm/alloc.rs b/src/libstd/sys/wasm/alloc.rs
new file mode 100644
index 0000000..c1af6ec
--- /dev/null
+++ b/src/libstd/sys/wasm/alloc.rs
@@ -0,0 +1,158 @@
+//! This is an implementation of a global allocator on the wasm32 platform when
+//! emscripten is not in use. In that situation there's no actual runtime for us
+//! to lean on for allocation, so instead we provide our own!
+//!
+//! The wasm32 instruction set has two instructions for getting the current
+//! amount of memory and growing the amount of memory. These instructions are the
+//! foundation on which we're able to build an allocator, so we do so! Note that
+//! the instructions are also pretty "global" and this is the "global" allocator
+//! after all!
+//!
+//! The current allocator here is the `dlmalloc` crate which we've got included
+//! in the rust-lang/rust repository as a submodule. The crate is a port of
+//! dlmalloc.c from C to Rust and is basically just so we can have "pure Rust"
+//! for now which is currently technically required (can't link with C yet).
+//!
+//! The crate itself provides a global allocator which on wasm has no
+//! synchronization as there are no threads!
+
+use crate::alloc::{GlobalAlloc, Layout, System};
+
+static mut DLMALLOC: dlmalloc::Dlmalloc = dlmalloc::DLMALLOC_INIT;
+
+#[stable(feature = "alloc_system_type", since = "1.28.0")]
+unsafe impl GlobalAlloc for System {
+ #[inline]
+ unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
+ let _lock = lock::lock();
+ DLMALLOC.malloc(layout.size(), layout.align())
+ }
+
+ #[inline]
+ unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
+ let _lock = lock::lock();
+ DLMALLOC.calloc(layout.size(), layout.align())
+ }
+
+ #[inline]
+ unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
+ let _lock = lock::lock();
+ DLMALLOC.free(ptr, layout.size(), layout.align())
+ }
+
+ #[inline]
+ unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
+ let _lock = lock::lock();
+ DLMALLOC.realloc(ptr, layout.size(), layout.align(), new_size)
+ }
+}
+
+#[cfg(target_feature = "atomics")]
+mod lock {
+ use crate::sync::atomic::{AtomicI32, Ordering::SeqCst};
+
+ static LOCKED: AtomicI32 = AtomicI32::new(0);
+
+ pub struct DropLock;
+
+ pub fn lock() -> DropLock {
+ loop {
+ if LOCKED.swap(1, SeqCst) == 0 {
+ return DropLock
+ }
+ // Ok so here's where things get a little depressing. At this point
+ // in time we need to synchronously acquire a lock, but we're
+ // contending with some other thread. Typically we'd execute some
+ // form of `i32.atomic.wait` like so:
+ //
+ // unsafe {
+ // let r = core::arch::wasm32::i32_atomic_wait(
+ // &LOCKED as *const AtomicI32 as *mut i32,
+ // 1, // expected value
+ // -1, // timeout
+ // );
+ // debug_assert!(r == 0 || r == 1);
+ // }
+ //
+ // Unfortunately though in doing so we would cause issues for the
+ // main thread. The main thread in a web browser *cannot ever
+ // block*, no exceptions. This means that the main thread can't
+ // actually execute the `i32.atomic.wait` instruction.
+ //
+ // As a result if we want to work within the context of browsers we
+ // need to figure out some sort of allocation scheme for the main
+ // thread where when there's contention on the global malloc lock we
+ // do... something.
+ //
+ // Possible ideas include:
+ //
+ // 1. Attempt to acquire the global lock. If it fails, fall back to
+ // memory allocation via `memory.grow`. Later just ... somehow
+ // ... inject this raw page back into the main allocator as it
+ // gets sliced up over time. This strategy has the downside of
+ // forcing allocation of a page to happen whenever the main
+ // thread contents with other threads, which is unfortunate.
+ //
+ // 2. Maintain a form of "two level" allocator scheme where the main
+ // thread has its own allocator. Somehow this allocator would
+ // also be balanced with a global allocator, not only to have
+ // allocations cross between threads but also to ensure that the
+ // two allocators stay "balanced" in terms of free'd memory and
+ // such. This, however, seems significantly complicated.
+ //
+ // Out of a lack of other ideas, the current strategy implemented
+ // here is to simply spin. Typical spin loop algorithms have some
+ // form of "hint" here to the CPU that it's what we're doing to
+ // ensure that the CPU doesn't get too hot, but wasm doesn't have
+ // such an instruction.
+ //
+ // To be clear, spinning here is not a great solution.
+ // Another thread with the lock may take quite a long time to wake
+ // up. For example it could be in `memory.grow` or it could be
+ // evicted from the CPU for a timeslice like 10ms. For these periods
+ // of time our thread will "helpfully" sit here and eat CPU time
+ // until it itself is evicted or the lock holder finishes. This
+ // means we're just burning and wasting CPU time to no one's
+ // benefit.
+ //
+ // Spinning does have the nice properties, though, of being
+ // semantically correct, being fair to all threads for memory
+ // allocation, and being simple enough to implement.
+ //
+ // This will surely (hopefully) be replaced in the future with a
+ // real memory allocator that can handle the restriction of the main
+ // thread.
+ //
+ //
+ // FIXME: We can also possibly add an optimization here to detect
+ // when a thread is the main thread or not and block on all
+ // non-main-thread threads. Currently, however, we have no way
+ // of knowing which wasm thread is on the browser main thread, but
+ // if we could figure out we could at least somewhat mitigate the
+ // cost of this spinning.
+ }
+ }
+
+ impl Drop for DropLock {
+ fn drop(&mut self) {
+ let r = LOCKED.swap(0, SeqCst);
+ debug_assert_eq!(r, 1);
+
+ // Note that due to the above logic we don't actually need to wake
+ // anyone up, but if we did it'd likely look something like this:
+ //
+ // unsafe {
+ // core::arch::wasm32::atomic_notify(
+ // &LOCKED as *const AtomicI32 as *mut i32,
+ // 1, // only one thread
+ // );
+ // }
+ }
+ }
+}
+
+#[cfg(not(target_feature = "atomics"))]
+mod lock {
+ #[inline]
+ pub fn lock() {} // no atomics, no threads, that's easy!
+}
diff --git a/src/libstd/sys/wasm/args.rs b/src/libstd/sys/wasm/args.rs
new file mode 100644
index 0000000..b3c77b8
--- /dev/null
+++ b/src/libstd/sys/wasm/args.rs
@@ -0,0 +1,52 @@
+use crate::ffi::OsString;
+use crate::marker::PhantomData;
+use crate::vec;
+use crate::sys::ArgsSysCall;
+
+pub unsafe fn init(_argc: isize, _argv: *const *const u8) {
+ // On wasm these should always be null, so there's nothing for us to do here
+}
+
+pub unsafe fn cleanup() {
+}
+
+pub fn args() -> Args {
+ let v = ArgsSysCall::perform();
+ Args {
+ iter: v.into_iter(),
+ _dont_send_or_sync_me: PhantomData,
+ }
+}
+
+pub struct Args {
+ iter: vec::IntoIter<OsString>,
+ _dont_send_or_sync_me: PhantomData<*mut ()>,
+}
+
+impl Args {
+ pub fn inner_debug(&self) -> &[OsString] {
+ self.iter.as_slice()
+ }
+}
+
+impl Iterator for Args {
+ type Item = OsString;
+ fn next(&mut self) -> Option<OsString> {
+ self.iter.next()
+ }
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ self.iter.size_hint()
+ }
+}
+
+impl ExactSizeIterator for Args {
+ fn len(&self) -> usize {
+ self.iter.len()
+ }
+}
+
+impl DoubleEndedIterator for Args {
+ fn next_back(&mut self) -> Option<OsString> {
+ self.iter.next_back()
+ }
+}
diff --git a/src/libstd/sys/wasm/backtrace.rs b/src/libstd/sys/wasm/backtrace.rs
new file mode 100644
index 0000000..7d56b29
--- /dev/null
+++ b/src/libstd/sys/wasm/backtrace.rs
@@ -0,0 +1,27 @@
+use crate::io;
+use crate::sys::unsupported;
+use crate::sys_common::backtrace::Frame;
+
+pub struct BacktraceContext;
+
+pub fn unwind_backtrace(_frames: &mut [Frame])
+ -> io::Result<(usize, BacktraceContext)>
+{
+ unsupported()
+}
+
+pub fn resolve_symname<F>(_frame: Frame,
+ _callback: F,
+ _: &BacktraceContext) -> io::Result<()>
+ where F: FnOnce(Option<&str>) -> io::Result<()>
+{
+ unsupported()
+}
+
+pub fn foreach_symbol_fileline<F>(_: Frame,
+ _: F,
+ _: &BacktraceContext) -> io::Result<bool>
+ where F: FnMut(&[u8], u32) -> io::Result<()>
+{
+ unsupported()
+}
diff --git a/src/libstd/sys/wasm/cmath.rs b/src/libstd/sys/wasm/cmath.rs
new file mode 100644
index 0000000..fa77831
--- /dev/null
+++ b/src/libstd/sys/wasm/cmath.rs
@@ -0,0 +1,29 @@
+// These symbols are all defined in `compiler-builtins`
+extern {
+ pub fn acos(n: f64) -> f64;
+ pub fn acosf(n: f32) -> f32;
+ pub fn asin(n: f64) -> f64;
+ pub fn asinf(n: f32) -> f32;
+ pub fn atan(n: f64) -> f64;
+ pub fn atan2(a: f64, b: f64) -> f64;
+ pub fn atan2f(a: f32, b: f32) -> f32;
+ pub fn atanf(n: f32) -> f32;
+ pub fn cbrt(n: f64) -> f64;
+ pub fn cbrtf(n: f32) -> f32;
+ pub fn cosh(n: f64) -> f64;
+ pub fn coshf(n: f32) -> f32;
+ pub fn expm1(n: f64) -> f64;
+ pub fn expm1f(n: f32) -> f32;
+ pub fn fdim(a: f64, b: f64) -> f64;
+ pub fn fdimf(a: f32, b: f32) -> f32;
+ pub fn hypot(x: f64, y: f64) -> f64;
+ pub fn hypotf(x: f32, y: f32) -> f32;
+ pub fn log1p(n: f64) -> f64;
+ pub fn log1pf(n: f32) -> f32;
+ pub fn sinh(n: f64) -> f64;
+ pub fn sinhf(n: f32) -> f32;
+ pub fn tan(n: f64) -> f64;
+ pub fn tanf(n: f32) -> f32;
+ pub fn tanh(n: f64) -> f64;
+ pub fn tanhf(n: f32) -> f32;
+}
diff --git a/src/libstd/sys/wasm/condvar.rs b/src/libstd/sys/wasm/condvar.rs
new file mode 100644
index 0000000..9c7cc3c
--- /dev/null
+++ b/src/libstd/sys/wasm/condvar.rs
@@ -0,0 +1,33 @@
+use crate::sys::mutex::Mutex;
+use crate::time::Duration;
+
+pub struct Condvar { }
+
+impl Condvar {
+ pub const fn new() -> Condvar {
+ Condvar { }
+ }
+
+ #[inline]
+ pub unsafe fn init(&mut self) {}
+
+ #[inline]
+ pub unsafe fn notify_one(&self) {
+ }
+
+ #[inline]
+ pub unsafe fn notify_all(&self) {
+ }
+
+ pub unsafe fn wait(&self, _mutex: &Mutex) {
+ panic!("can't block with web assembly")
+ }
+
+ pub unsafe fn wait_timeout(&self, _mutex: &Mutex, _dur: Duration) -> bool {
+ panic!("can't block with web assembly");
+ }
+
+ #[inline]
+ pub unsafe fn destroy(&self) {
+ }
+}
diff --git a/src/libstd/sys/wasm/condvar_atomics.rs b/src/libstd/sys/wasm/condvar_atomics.rs
new file mode 100644
index 0000000..580d212
--- /dev/null
+++ b/src/libstd/sys/wasm/condvar_atomics.rs
@@ -0,0 +1,94 @@
+use crate::arch::wasm32;
+use crate::cmp;
+use crate::mem;
+use crate::sync::atomic::{AtomicUsize, Ordering::SeqCst};
+use crate::sys::mutex::Mutex;
+use crate::time::Duration;
+
+pub struct Condvar {
+ cnt: AtomicUsize,
+}
+
+// Condition variables are implemented with a simple counter internally that is
+// likely to cause spurious wakeups. Blocking on a condition variable will first
+// read the value of the internal counter, unlock the given mutex, and then
+// block if and only if the counter's value is still the same. Notifying a
+// condition variable will modify the counter (add one for now) and then wake up
+// a thread waiting on the address of the counter.
+//
+// A thread waiting on the condition variable will as a result avoid going to
+// sleep if it's notified after the lock is unlocked but before it fully goes to
+// sleep. A sleeping thread is guaranteed to be woken up at some point as it can
+// only be woken up with a call to `wake`.
+//
+// Note that it's possible for 2 or more threads to be woken up by a call to
+// `notify_one` with this implementation. That can happen where the modification
+// of `cnt` causes any threads in the middle of `wait` to avoid going to sleep,
+// and the subsequent `wake` may wake up a thread that's actually blocking. We
+// consider this a spurious wakeup, though, which all users of condition
+// variables must already be prepared to handle. As a result, this source of
+// spurious wakeups is currently though to be ok, although it may be problematic
+// later on if it causes too many spurious wakeups.
+
+impl Condvar {
+ pub const fn new() -> Condvar {
+ Condvar { cnt: AtomicUsize::new(0) }
+ }
+
+ #[inline]
+ pub unsafe fn init(&mut self) {
+ // nothing to do
+ }
+
+ pub unsafe fn notify_one(&self) {
+ self.cnt.fetch_add(1, SeqCst);
+ wasm32::atomic_notify(self.ptr(), 1);
+ }
+
+ #[inline]
+ pub unsafe fn notify_all(&self) {
+ self.cnt.fetch_add(1, SeqCst);
+ wasm32::atomic_notify(self.ptr(), u32::max_value()); // -1 == "wake everyone"
+ }
+
+ pub unsafe fn wait(&self, mutex: &Mutex) {
+ // "atomically block and unlock" implemented by loading our current
+ // counter's value, unlocking the mutex, and blocking if the counter
+ // still has the same value.
+ //
+ // Notifications happen by incrementing the counter and then waking a
+ // thread. Incrementing the counter after we unlock the mutex will
+ // prevent us from sleeping and otherwise the call to `wake` will
+ // wake us up once we're asleep.
+ let ticket = self.cnt.load(SeqCst) as i32;
+ mutex.unlock();
+ let val = wasm32::i32_atomic_wait(self.ptr(), ticket, -1);
+ // 0 == woken, 1 == not equal to `ticket`, 2 == timeout (shouldn't happen)
+ debug_assert!(val == 0 || val == 1);
+ mutex.lock();
+ }
+
+ pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
+ let ticket = self.cnt.load(SeqCst) as i32;
+ mutex.unlock();
+ let nanos = dur.as_nanos();
+ let nanos = cmp::min(i64::max_value() as u128, nanos);
+
+ // If the return value is 2 then a timeout happened, so we return
+ // `false` as we weren't actually notified.
+ let ret = wasm32::i32_atomic_wait(self.ptr(), ticket, nanos as i64) != 2;
+ mutex.lock();
+ return ret
+ }
+
+ #[inline]
+ pub unsafe fn destroy(&self) {
+ // nothing to do
+ }
+
+ #[inline]
+ fn ptr(&self) -> *mut i32 {
+ assert_eq!(mem::size_of::<usize>(), mem::size_of::<i32>());
+ &self.cnt as *const AtomicUsize as *mut i32
+ }
+}
diff --git a/src/libstd/sys/wasm/env.rs b/src/libstd/sys/wasm/env.rs
new file mode 100644
index 0000000..730e356
--- /dev/null
+++ b/src/libstd/sys/wasm/env.rs
@@ -0,0 +1,9 @@
+pub mod os {
+ pub const FAMILY: &str = "";
+ pub const OS: &str = "";
+ pub const DLL_PREFIX: &str = "";
+ pub const DLL_SUFFIX: &str = ".wasm";
+ pub const DLL_EXTENSION: &str = "wasm";
+ pub const EXE_SUFFIX: &str = ".wasm";
+ pub const EXE_EXTENSION: &str = "wasm";
+}
diff --git a/src/libstd/sys/wasm/fs.rs b/src/libstd/sys/wasm/fs.rs
new file mode 100644
index 0000000..68c8e93
--- /dev/null
+++ b/src/libstd/sys/wasm/fs.rs
@@ -0,0 +1,294 @@
+use crate::ffi::OsString;
+use crate::fmt;
+use crate::hash::{Hash, Hasher};
+use crate::io::{self, SeekFrom};
+use crate::path::{Path, PathBuf};
+use crate::sys::time::SystemTime;
+use crate::sys::{unsupported, Void};
+
+pub struct File(Void);
+
+pub struct FileAttr(Void);
+
+pub struct ReadDir(Void);
+
+pub struct DirEntry(Void);
+
+#[derive(Clone, Debug)]
+pub struct OpenOptions { }
+
+pub struct FilePermissions(Void);
+
+pub struct FileType(Void);
+
+#[derive(Debug)]
+pub struct DirBuilder { }
+
+impl FileAttr {
+ pub fn size(&self) -> u64 {
+ match self.0 {}
+ }
+
+ pub fn perm(&self) -> FilePermissions {
+ match self.0 {}
+ }
+
+ pub fn file_type(&self) -> FileType {
+ match self.0 {}
+ }
+
+ pub fn modified(&self) -> io::Result<SystemTime> {
+ match self.0 {}
+ }
+
+ pub fn accessed(&self) -> io::Result<SystemTime> {
+ match self.0 {}
+ }
+
+ pub fn created(&self) -> io::Result<SystemTime> {
+ match self.0 {}
+ }
+}
+
+impl Clone for FileAttr {
+ fn clone(&self) -> FileAttr {
+ match self.0 {}
+ }
+}
+
+impl FilePermissions {
+ pub fn readonly(&self) -> bool {
+ match self.0 {}
+ }
+
+ pub fn set_readonly(&mut self, _readonly: bool) {
+ match self.0 {}
+ }
+}
+
+impl Clone for FilePermissions {
+ fn clone(&self) -> FilePermissions {
+ match self.0 {}
+ }
+}
+
+impl PartialEq for FilePermissions {
+ fn eq(&self, _other: &FilePermissions) -> bool {
+ match self.0 {}
+ }
+}
+
+impl Eq for FilePermissions {
+}
+
+impl fmt::Debug for FilePermissions {
+ fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self.0 {}
+ }
+}
+
+impl FileType {
+ pub fn is_dir(&self) -> bool {
+ match self.0 {}
+ }
+
+ pub fn is_file(&self) -> bool {
+ match self.0 {}
+ }
+
+ pub fn is_symlink(&self) -> bool {
+ match self.0 {}
+ }
+}
+
+impl Clone for FileType {
+ fn clone(&self) -> FileType {
+ match self.0 {}
+ }
+}
+
+impl Copy for FileType {}
+
+impl PartialEq for FileType {
+ fn eq(&self, _other: &FileType) -> bool {
+ match self.0 {}
+ }
+}
+
+impl Eq for FileType {
+}
+
+impl Hash for FileType {
+ fn hash<H: Hasher>(&self, _h: &mut H) {
+ match self.0 {}
+ }
+}
+
+impl fmt::Debug for FileType {
+ fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self.0 {}
+ }
+}
+
+impl fmt::Debug for ReadDir {
+ fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self.0 {}
+ }
+}
+
+impl Iterator for ReadDir {
+ type Item = io::Result<DirEntry>;
+
+ fn next(&mut self) -> Option<io::Result<DirEntry>> {
+ match self.0 {}
+ }
+}
+
+impl DirEntry {
+ pub fn path(&self) -> PathBuf {
+ match self.0 {}
+ }
+
+ pub fn file_name(&self) -> OsString {
+ match self.0 {}
+ }
+
+ pub fn metadata(&self) -> io::Result<FileAttr> {
+ match self.0 {}
+ }
+
+ pub fn file_type(&self) -> io::Result<FileType> {
+ match self.0 {}
+ }
+}
+
+impl OpenOptions {
+ pub fn new() -> OpenOptions {
+ OpenOptions { }
+ }
+
+ pub fn read(&mut self, _read: bool) { }
+ pub fn write(&mut self, _write: bool) { }
+ pub fn append(&mut self, _append: bool) { }
+ pub fn truncate(&mut self, _truncate: bool) { }
+ pub fn create(&mut self, _create: bool) { }
+ pub fn create_new(&mut self, _create_new: bool) { }
+}
+
+impl File {
+ pub fn open(_path: &Path, _opts: &OpenOptions) -> io::Result<File> {
+ unsupported()
+ }
+
+ pub fn file_attr(&self) -> io::Result<FileAttr> {
+ match self.0 {}
+ }
+
+ pub fn fsync(&self) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn datasync(&self) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn truncate(&self, _size: u64) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn read(&self, _buf: &mut [u8]) -> io::Result<usize> {
+ match self.0 {}
+ }
+
+ pub fn write(&self, _buf: &[u8]) -> io::Result<usize> {
+ match self.0 {}
+ }
+
+ pub fn flush(&self) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn seek(&self, _pos: SeekFrom) -> io::Result<u64> {
+ match self.0 {}
+ }
+
+ pub fn duplicate(&self) -> io::Result<File> {
+ match self.0 {}
+ }
+
+ pub fn set_permissions(&self, _perm: FilePermissions) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn diverge(&self) -> ! {
+ match self.0 {}
+ }
+}
+
+impl DirBuilder {
+ pub fn new() -> DirBuilder {
+ DirBuilder { }
+ }
+
+ pub fn mkdir(&self, _p: &Path) -> io::Result<()> {
+ unsupported()
+ }
+}
+
+impl fmt::Debug for File {
+ fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self.0 {}
+ }
+}
+
+pub fn readdir(_p: &Path) -> io::Result<ReadDir> {
+ unsupported()
+}
+
+pub fn unlink(_p: &Path) -> io::Result<()> {
+ unsupported()
+}
+
+pub fn rename(_old: &Path, _new: &Path) -> io::Result<()> {
+ unsupported()
+}
+
+pub fn set_perm(_p: &Path, perm: FilePermissions) -> io::Result<()> {
+ match perm.0 {}
+}
+
+pub fn rmdir(_p: &Path) -> io::Result<()> {
+ unsupported()
+}
+
+pub fn remove_dir_all(_path: &Path) -> io::Result<()> {
+ unsupported()
+}
+
+pub fn readlink(_p: &Path) -> io::Result<PathBuf> {
+ unsupported()
+}
+
+pub fn symlink(_src: &Path, _dst: &Path) -> io::Result<()> {
+ unsupported()
+}
+
+pub fn link(_src: &Path, _dst: &Path) -> io::Result<()> {
+ unsupported()
+}
+
+pub fn stat(_p: &Path) -> io::Result<FileAttr> {
+ unsupported()
+}
+
+pub fn lstat(_p: &Path) -> io::Result<FileAttr> {
+ unsupported()
+}
+
+pub fn canonicalize(_p: &Path) -> io::Result<PathBuf> {
+ unsupported()
+}
+
+pub fn copy(_from: &Path, _to: &Path) -> io::Result<u64> {
+ unsupported()
+}
diff --git a/src/libstd/sys/wasm/io.rs b/src/libstd/sys/wasm/io.rs
new file mode 100644
index 0000000..8b02d3f
--- /dev/null
+++ b/src/libstd/sys/wasm/io.rs
@@ -0,0 +1,32 @@
+pub struct IoVec<'a>(&'a [u8]);
+
+impl<'a> IoVec<'a> {
+ #[inline]
+ pub fn new(buf: &'a [u8]) -> IoVec<'a> {
+ IoVec(buf)
+ }
+
+ #[inline]
+ pub fn as_slice(&self) -> &[u8] {
+ self.0
+ }
+}
+
+pub struct IoVecMut<'a>(&'a mut [u8]);
+
+impl<'a> IoVecMut<'a> {
+ #[inline]
+ pub fn new(buf: &'a mut [u8]) -> IoVecMut<'a> {
+ IoVecMut(buf)
+ }
+
+ #[inline]
+ pub fn as_slice(&self) -> &[u8] {
+ self.0
+ }
+
+ #[inline]
+ pub fn as_mut_slice(&mut self) -> &mut [u8] {
+ self.0
+ }
+}
diff --git a/src/libstd/sys/wasm/memchr.rs b/src/libstd/sys/wasm/memchr.rs
new file mode 100644
index 0000000..9967482
--- /dev/null
+++ b/src/libstd/sys/wasm/memchr.rs
@@ -0,0 +1 @@
+pub use core::slice::memchr::{memchr, memrchr};
diff --git a/src/libstd/sys/wasm/mod.rs b/src/libstd/sys/wasm/mod.rs
new file mode 100644
index 0000000..670d07d
--- /dev/null
+++ b/src/libstd/sys/wasm/mod.rs
@@ -0,0 +1,320 @@
+//! System bindings for the wasm/web platform
+//!
+//! This module contains the facade (aka platform-specific) implementations of
+//! OS level functionality for wasm. Note that this wasm is *not* the emscripten
+//! wasm, so we have no runtime here.
+//!
+//! This is all super highly experimental and not actually intended for
+//! wide/production use yet, it's still all in the experimental category. This
+//! will likely change over time.
+//!
+//! Currently all functions here are basically stubs that immediately return
+//! errors. The hope is that with a portability lint we can turn actually just
+//! remove all this and just omit parts of the standard library if we're
+//! compiling for wasm. That way it's a compile time error for something that's
+//! guaranteed to be a runtime error!
+
+use crate::os::raw::c_char;
+use crate::ptr;
+use crate::sys::os_str::Buf;
+use crate::sys_common::{AsInner, FromInner};
+use crate::ffi::{OsString, OsStr};
+use crate::time::Duration;
+
+pub mod alloc;
+pub mod args;
+#[cfg(feature = "backtrace")]
+pub mod backtrace;
+pub mod cmath;
+pub mod env;
+pub mod fs;
+pub mod io;
+pub mod memchr;
+pub mod net;
+pub mod os;
+pub mod path;
+pub mod pipe;
+pub mod process;
+pub mod stack_overflow;
+pub mod thread;
+pub mod time;
+pub mod stdio;
+
+pub use crate::sys_common::os_str_bytes as os_str;
+
+cfg_if! {
+ if #[cfg(target_feature = "atomics")] {
+ #[path = "condvar_atomics.rs"]
+ pub mod condvar;
+ #[path = "mutex_atomics.rs"]
+ pub mod mutex;
+ #[path = "rwlock_atomics.rs"]
+ pub mod rwlock;
+ #[path = "thread_local_atomics.rs"]
+ pub mod thread_local;
+ } else {
+ pub mod condvar;
+ pub mod mutex;
+ pub mod rwlock;
+ pub mod thread_local;
+ }
+}
+
+#[cfg(not(test))]
+pub fn init() {
+}
+
+pub fn unsupported<T>() -> crate::io::Result<T> {
+ Err(unsupported_err())
+}
+
+pub fn unsupported_err() -> crate::io::Error {
+ crate::io::Error::new(crate::io::ErrorKind::Other,
+ "operation not supported on wasm yet")
+}
+
+pub fn decode_error_kind(_code: i32) -> crate::io::ErrorKind {
+ crate::io::ErrorKind::Other
+}
+
+// This enum is used as the storage for a bunch of types which can't actually
+// exist.
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
+pub enum Void {}
+
+pub unsafe fn strlen(mut s: *const c_char) -> usize {
+ let mut n = 0;
+ while *s != 0 {
+ n += 1;
+ s = s.offset(1);
+ }
+ return n
+}
+
+pub unsafe fn abort_internal() -> ! {
+ ExitSysCall::perform(1)
+}
+
+// We don't have randomness yet, but I totally used a random number generator to
+// generate these numbers.
+//
+// More seriously though this is just for DOS protection in hash maps. It's ok
+// if we don't do that on wasm just yet.
+pub fn hashmap_random_keys() -> (u64, u64) {
+ (1, 2)
+}
+
+// Implement a minimal set of system calls to enable basic IO
+pub enum SysCallIndex {
+ Read = 0,
+ Write = 1,
+ Exit = 2,
+ Args = 3,
+ GetEnv = 4,
+ SetEnv = 5,
+ Time = 6,
+}
+
+#[repr(C)]
+pub struct ReadSysCall {
+ fd: usize,
+ ptr: *mut u8,
+ len: usize,
+ result: usize,
+}
+
+impl ReadSysCall {
+ pub fn perform(fd: usize, buffer: &mut [u8]) -> usize {
+ let mut call_record = ReadSysCall {
+ fd,
+ len: buffer.len(),
+ ptr: buffer.as_mut_ptr(),
+ result: 0
+ };
+ if unsafe { syscall(SysCallIndex::Read, &mut call_record) } {
+ call_record.result
+ } else {
+ 0
+ }
+ }
+}
+
+#[repr(C)]
+pub struct WriteSysCall {
+ fd: usize,
+ ptr: *const u8,
+ len: usize,
+}
+
+impl WriteSysCall {
+ pub fn perform(fd: usize, buffer: &[u8]) {
+ let mut call_record = WriteSysCall {
+ fd,
+ len: buffer.len(),
+ ptr: buffer.as_ptr()
+ };
+ unsafe { syscall(SysCallIndex::Write, &mut call_record); }
+ }
+}
+
+#[repr(C)]
+pub struct ExitSysCall {
+ code: usize,
+}
+
+impl ExitSysCall {
+ pub fn perform(code: usize) -> ! {
+ let mut call_record = ExitSysCall {
+ code
+ };
+ unsafe {
+ syscall(SysCallIndex::Exit, &mut call_record);
+ crate::intrinsics::abort();
+ }
+ }
+}
+
+fn receive_buffer<E, F: FnMut(&mut [u8]) -> Result<usize, E>>(estimate: usize, mut f: F)
+ -> Result<Vec<u8>, E>
+{
+ let mut buffer = vec![0; estimate];
+ loop {
+ let result = f(&mut buffer)?;
+ if result <= buffer.len() {
+ buffer.truncate(result);
+ break;
+ }
+ buffer.resize(result, 0);
+ }
+ Ok(buffer)
+}
+
+#[repr(C)]
+pub struct ArgsSysCall {
+ ptr: *mut u8,
+ len: usize,
+ result: usize
+}
+
+impl ArgsSysCall {
+ pub fn perform() -> Vec<OsString> {
+ receive_buffer(1024, |buffer| -> Result<usize, !> {
+ let mut call_record = ArgsSysCall {
+ len: buffer.len(),
+ ptr: buffer.as_mut_ptr(),
+ result: 0
+ };
+ if unsafe { syscall(SysCallIndex::Args, &mut call_record) } {
+ Ok(call_record.result)
+ } else {
+ Ok(0)
+ }
+ })
+ .unwrap()
+ .split(|b| *b == 0)
+ .map(|s| FromInner::from_inner(Buf { inner: s.to_owned() }))
+ .collect()
+ }
+}
+
+#[repr(C)]
+pub struct GetEnvSysCall {
+ key_ptr: *const u8,
+ key_len: usize,
+ value_ptr: *mut u8,
+ value_len: usize,
+ result: usize
+}
+
+impl GetEnvSysCall {
+ pub fn perform(key: &OsStr) -> Option<OsString> {
+ let key_buf = &AsInner::as_inner(key).inner;
+ receive_buffer(64, |buffer| {
+ let mut call_record = GetEnvSysCall {
+ key_len: key_buf.len(),
+ key_ptr: key_buf.as_ptr(),
+ value_len: buffer.len(),
+ value_ptr: buffer.as_mut_ptr(),
+ result: !0usize
+ };
+ if unsafe { syscall(SysCallIndex::GetEnv, &mut call_record) } {
+ if call_record.result == !0usize {
+ Err(())
+ } else {
+ Ok(call_record.result)
+ }
+ } else {
+ Err(())
+ }
+ }).ok().map(|s| {
+ FromInner::from_inner(Buf { inner: s })
+ })
+ }
+}
+
+#[repr(C)]
+pub struct SetEnvSysCall {
+ key_ptr: *const u8,
+ key_len: usize,
+ value_ptr: *const u8,
+ value_len: usize
+}
+
+impl SetEnvSysCall {
+ pub fn perform(key: &OsStr, value: Option<&OsStr>) {
+ let key_buf = &AsInner::as_inner(key).inner;
+ let value_buf = value.map(|v| &AsInner::as_inner(v).inner);
+ let mut call_record = SetEnvSysCall {
+ key_len: key_buf.len(),
+ key_ptr: key_buf.as_ptr(),
+ value_len: value_buf.map(|v| v.len()).unwrap_or(!0usize),
+ value_ptr: value_buf.map(|v| v.as_ptr()).unwrap_or(ptr::null())
+ };
+ unsafe { syscall(SysCallIndex::SetEnv, &mut call_record); }
+ }
+}
+
+pub enum TimeClock {
+ Monotonic = 0,
+ System = 1,
+}
+
+#[repr(C)]
+pub struct TimeSysCall {
+ clock: usize,
+ secs_hi: usize,
+ secs_lo: usize,
+ nanos: usize
+}
+
+impl TimeSysCall {
+ pub fn perform(clock: TimeClock) -> Duration {
+ let mut call_record = TimeSysCall {
+ clock: clock as usize,
+ secs_hi: 0,
+ secs_lo: 0,
+ nanos: 0
+ };
+ if unsafe { syscall(SysCallIndex::Time, &mut call_record) } {
+ Duration::new(
+ ((call_record.secs_hi as u64) << 32) | (call_record.secs_lo as u64),
+ call_record.nanos as u32
+ )
+ } else {
+ panic!("Time system call is not implemented by WebAssembly host");
+ }
+ }
+}
+
+unsafe fn syscall<T>(index: SysCallIndex, data: &mut T) -> bool {
+ #[cfg(feature = "wasm_syscall")]
+ extern {
+ #[no_mangle]
+ fn rust_wasm_syscall(index: usize, data: *mut Void) -> usize;
+ }
+
+ #[cfg(not(feature = "wasm_syscall"))]
+ unsafe fn rust_wasm_syscall(_index: usize, _data: *mut Void) -> usize { 0 }
+
+ rust_wasm_syscall(index as usize, data as *mut T as *mut Void) != 0
+}
diff --git a/src/libstd/sys/wasm/mutex.rs b/src/libstd/sys/wasm/mutex.rs
new file mode 100644
index 0000000..9d713e9
--- /dev/null
+++ b/src/libstd/sys/wasm/mutex.rs
@@ -0,0 +1,69 @@
+use crate::cell::UnsafeCell;
+
+pub struct Mutex {
+ locked: UnsafeCell<bool>,
+}
+
+unsafe impl Send for Mutex {}
+unsafe impl Sync for Mutex {} // no threads on wasm
+
+impl Mutex {
+ pub const fn new() -> Mutex {
+ Mutex { locked: UnsafeCell::new(false) }
+ }
+
+ #[inline]
+ pub unsafe fn init(&mut self) {
+ }
+
+ #[inline]
+ pub unsafe fn lock(&self) {
+ let locked = self.locked.get();
+ assert!(!*locked, "cannot recursively acquire mutex");
+ *locked = true;
+ }
+
+ #[inline]
+ pub unsafe fn unlock(&self) {
+ *self.locked.get() = false;
+ }
+
+ #[inline]
+ pub unsafe fn try_lock(&self) -> bool {
+ let locked = self.locked.get();
+ if *locked {
+ false
+ } else {
+ *locked = true;
+ true
+ }
+ }
+
+ #[inline]
+ pub unsafe fn destroy(&self) {
+ }
+}
+
+// All empty stubs because wasm has no threads yet, so lock acquisition always
+// succeeds.
+pub struct ReentrantMutex {
+}
+
+impl ReentrantMutex {
+ pub unsafe fn uninitialized() -> ReentrantMutex {
+ ReentrantMutex { }
+ }
+
+ pub unsafe fn init(&mut self) {}
+
+ pub unsafe fn lock(&self) {}
+
+ #[inline]
+ pub unsafe fn try_lock(&self) -> bool {
+ true
+ }
+
+ pub unsafe fn unlock(&self) {}
+
+ pub unsafe fn destroy(&self) {}
+}
diff --git a/src/libstd/sys/wasm/mutex_atomics.rs b/src/libstd/sys/wasm/mutex_atomics.rs
new file mode 100644
index 0000000..0e4f3d8
--- /dev/null
+++ b/src/libstd/sys/wasm/mutex_atomics.rs
@@ -0,0 +1,150 @@
+use crate::arch::wasm32;
+use crate::cell::UnsafeCell;
+use crate::mem;
+use crate::sync::atomic::{AtomicUsize, AtomicU32, Ordering::SeqCst};
+use crate::sys::thread;
+
+pub struct Mutex {
+ locked: AtomicUsize,
+}
+
+// Mutexes have a pretty simple implementation where they contain an `i32`
+// internally that is 0 when unlocked and 1 when the mutex is locked.
+// Acquisition has a fast path where it attempts to cmpxchg the 0 to a 1, and
+// if it fails it then waits for a notification. Releasing a lock is then done
+// by swapping in 0 and then notifying any waiters, if present.
+
+impl Mutex {
+ pub const fn new() -> Mutex {
+ Mutex { locked: AtomicUsize::new(0) }
+ }
+
+ #[inline]
+ pub unsafe fn init(&mut self) {
+ // nothing to do
+ }
+
+ pub unsafe fn lock(&self) {
+ while !self.try_lock() {
+ let val = wasm32::i32_atomic_wait(
+ self.ptr(),
+ 1, // we expect our mutex is locked
+ -1, // wait infinitely
+ );
+ // we should have either woke up (0) or got a not-equal due to a
+ // race (1). We should never time out (2)
+ debug_assert!(val == 0 || val == 1);
+ }
+ }
+
+ pub unsafe fn unlock(&self) {
+ let prev = self.locked.swap(0, SeqCst);
+ debug_assert_eq!(prev, 1);
+ wasm32::atomic_notify(self.ptr(), 1); // wake up one waiter, if any
+ }
+
+ #[inline]
+ pub unsafe fn try_lock(&self) -> bool {
+ self.locked.compare_exchange(0, 1, SeqCst, SeqCst).is_ok()
+ }
+
+ #[inline]
+ pub unsafe fn destroy(&self) {
+ // nothing to do
+ }
+
+ #[inline]
+ fn ptr(&self) -> *mut i32 {
+ assert_eq!(mem::size_of::<usize>(), mem::size_of::<i32>());
+ &self.locked as *const AtomicUsize as *mut isize as *mut i32
+ }
+}
+
+pub struct ReentrantMutex {
+ owner: AtomicU32,
+ recursions: UnsafeCell<u32>,
+}
+
+unsafe impl Send for ReentrantMutex {}
+unsafe impl Sync for ReentrantMutex {}
+
+// Reentrant mutexes are similarly implemented to mutexs above except that
+// instead of "1" meaning unlocked we use the id of a thread to represent
+// whether it has locked a mutex. That way we have an atomic counter which
+// always holds the id of the thread that currently holds the lock (or 0 if the
+// lock is unlocked).
+//
+// Once a thread acquires a lock recursively, which it detects by looking at
+// the value that's already there, it will update a local `recursions` counter
+// in a nonatomic fashion (as we hold the lock). The lock is then fully
+// released when this recursion counter reaches 0.
+
+impl ReentrantMutex {
+ pub unsafe fn uninitialized() -> ReentrantMutex {
+ ReentrantMutex {
+ owner: AtomicU32::new(0),
+ recursions: UnsafeCell::new(0),
+ }
+ }
+
+ pub unsafe fn init(&mut self) {
+ // nothing to do...
+ }
+
+ pub unsafe fn lock(&self) {
+ let me = thread::my_id();
+ while let Err(owner) = self._try_lock(me) {
+ let val = wasm32::i32_atomic_wait(self.ptr(), owner as i32, -1);
+ debug_assert!(val == 0 || val == 1);
+ }
+ }
+
+ #[inline]
+ pub unsafe fn try_lock(&self) -> bool {
+ self._try_lock(thread::my_id()).is_ok()
+ }
+
+ #[inline]
+ unsafe fn _try_lock(&self, id: u32) -> Result<(), u32> {
+ let id = id.checked_add(1).unwrap(); // make sure `id` isn't 0
+ match self.owner.compare_exchange(0, id, SeqCst, SeqCst) {
+ // we transitioned from unlocked to locked
+ Ok(_) => {
+ debug_assert_eq!(*self.recursions.get(), 0);
+ Ok(())
+ }
+
+ // we currently own this lock, so let's update our count and return
+ // true.
+ Err(n) if n == id => {
+ *self.recursions.get() += 1;
+ Ok(())
+ }
+
+ // Someone else owns the lock, let our caller take care of it
+ Err(other) => Err(other),
+ }
+ }
+
+ pub unsafe fn unlock(&self) {
+ // If we didn't ever recursively lock the lock then we fully unlock the
+ // mutex and wake up a waiter, if any. Otherwise we decrement our
+ // recursive counter and let some one else take care of the zero.
+ match *self.recursions.get() {
+ 0 => {
+ self.owner.swap(0, SeqCst);
+ wasm32::atomic_notify(self.ptr() as *mut i32, 1); // wake up one waiter, if any
+ }
+ ref mut n => *n -= 1,
+ }
+ }
+
+ pub unsafe fn destroy(&self) {
+ // nothing to do...
+ }
+
+ #[inline]
+ fn ptr(&self) -> *mut i32 {
+ &self.owner as *const AtomicU32 as *mut i32
+ }
+}
diff --git a/src/libstd/sys/wasm/net.rs b/src/libstd/sys/wasm/net.rs
new file mode 100644
index 0000000..38552ea
--- /dev/null
+++ b/src/libstd/sys/wasm/net.rs
@@ -0,0 +1,358 @@
+use crate::fmt;
+use crate::io::{self, IoVec, IoVecMut};
+use crate::net::{SocketAddr, Shutdown, Ipv4Addr, Ipv6Addr};
+use crate::time::Duration;
+use crate::sys::{unsupported, Void};
+use crate::convert::TryFrom;
+
+pub struct TcpStream(Void);
+
+impl TcpStream {
+ pub fn connect(_: io::Result<&SocketAddr>) -> io::Result<TcpStream> {
+ unsupported()
+ }
+
+ pub fn connect_timeout(_: &SocketAddr, _: Duration) -> io::Result<TcpStream> {
+ unsupported()
+ }
+
+ pub fn set_read_timeout(&self, _: Option<Duration>) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn set_write_timeout(&self, _: Option<Duration>) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
+ match self.0 {}
+ }
+
+ pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
+ match self.0 {}
+ }
+
+ pub fn peek(&self, _: &mut [u8]) -> io::Result<usize> {
+ match self.0 {}
+ }
+
+ pub fn read(&self, _: &mut [u8]) -> io::Result<usize> {
+ match self.0 {}
+ }
+
+ pub fn read_vectored(&self, _: &mut [IoVecMut<'_>]) -> io::Result<usize> {
+ match self.0 {}
+ }
+
+ pub fn write(&self, _: &[u8]) -> io::Result<usize> {
+ match self.0 {}
+ }
+
+ pub fn write_vectored(&self, _: &[IoVec<'_>]) -> io::Result<usize> {
+ match self.0 {}
+ }
+
+ pub fn peer_addr(&self) -> io::Result<SocketAddr> {
+ match self.0 {}
+ }
+
+ pub fn socket_addr(&self) -> io::Result<SocketAddr> {
+ match self.0 {}
+ }
+
+ pub fn shutdown(&self, _: Shutdown) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn duplicate(&self) -> io::Result<TcpStream> {
+ match self.0 {}
+ }
+
+ pub fn set_nodelay(&self, _: bool) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn nodelay(&self) -> io::Result<bool> {
+ match self.0 {}
+ }
+
+ pub fn set_ttl(&self, _: u32) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn ttl(&self) -> io::Result<u32> {
+ match self.0 {}
+ }
+
+ pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+ match self.0 {}
+ }
+
+ pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
+ match self.0 {}
+ }
+}
+
+impl fmt::Debug for TcpStream {
+ fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self.0 {}
+ }
+}
+
+pub struct TcpListener(Void);
+
+impl TcpListener {
+ pub fn bind(_: io::Result<&SocketAddr>) -> io::Result<TcpListener> {
+ unsupported()
+ }
+
+ pub fn socket_addr(&self) -> io::Result<SocketAddr> {
+ match self.0 {}
+ }
+
+ pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> {
+ match self.0 {}
+ }
+
+ pub fn duplicate(&self) -> io::Result<TcpListener> {
+ match self.0 {}
+ }
+
+ pub fn set_ttl(&self, _: u32) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn ttl(&self) -> io::Result<u32> {
+ match self.0 {}
+ }
+
+ pub fn set_only_v6(&self, _: bool) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn only_v6(&self) -> io::Result<bool> {
+ match self.0 {}
+ }
+
+ pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+ match self.0 {}
+ }
+
+ pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
+ match self.0 {}
+ }
+}
+
+impl fmt::Debug for TcpListener {
+ fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self.0 {}
+ }
+}
+
+pub struct UdpSocket(Void);
+
+impl UdpSocket {
+ pub fn bind(_: io::Result<&SocketAddr>) -> io::Result<UdpSocket> {
+ unsupported()
+ }
+
+ pub fn peer_addr(&self) -> io::Result<SocketAddr> {
+ match self.0 {}
+ }
+
+ pub fn socket_addr(&self) -> io::Result<SocketAddr> {
+ match self.0 {}
+ }
+
+ pub fn recv_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+ match self.0 {}
+ }
+
+ pub fn peek_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+ match self.0 {}
+ }
+
+ pub fn send_to(&self, _: &[u8], _: &SocketAddr) -> io::Result<usize> {
+ match self.0 {}
+ }
+
+ pub fn duplicate(&self) -> io::Result<UdpSocket> {
+ match self.0 {}
+ }
+
+ pub fn set_read_timeout(&self, _: Option<Duration>) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn set_write_timeout(&self, _: Option<Duration>) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
+ match self.0 {}
+ }
+
+ pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
+ match self.0 {}
+ }
+
+ pub fn set_broadcast(&self, _: bool) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn broadcast(&self) -> io::Result<bool> {
+ match self.0 {}
+ }
+
+ pub fn set_multicast_loop_v4(&self, _: bool) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn multicast_loop_v4(&self) -> io::Result<bool> {
+ match self.0 {}
+ }
+
+ pub fn set_multicast_ttl_v4(&self, _: u32) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn multicast_ttl_v4(&self) -> io::Result<u32> {
+ match self.0 {}
+ }
+
+ pub fn set_multicast_loop_v6(&self, _: bool) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn multicast_loop_v6(&self) -> io::Result<bool> {
+ match self.0 {}
+ }
+
+ pub fn join_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr)
+ -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn join_multicast_v6(&self, _: &Ipv6Addr, _: u32)
+ -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn leave_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr)
+ -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn leave_multicast_v6(&self, _: &Ipv6Addr, _: u32)
+ -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn set_ttl(&self, _: u32) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn ttl(&self) -> io::Result<u32> {
+ match self.0 {}
+ }
+
+ pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+ match self.0 {}
+ }
+
+ pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn recv(&self, _: &mut [u8]) -> io::Result<usize> {
+ match self.0 {}
+ }
+
+ pub fn peek(&self, _: &mut [u8]) -> io::Result<usize> {
+ match self.0 {}
+ }
+
+ pub fn send(&self, _: &[u8]) -> io::Result<usize> {
+ match self.0 {}
+ }
+
+ pub fn connect(&self, _: io::Result<&SocketAddr>) -> io::Result<()> {
+ match self.0 {}
+ }
+}
+
+impl fmt::Debug for UdpSocket {
+ fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self.0 {}
+ }
+}
+
+pub struct LookupHost(Void);
+
+impl LookupHost {
+ pub fn port(&self) -> u16 {
+ match self.0 {}
+ }
+}
+
+impl Iterator for LookupHost {
+ type Item = SocketAddr;
+ fn next(&mut self) -> Option<SocketAddr> {
+ match self.0 {}
+ }
+}
+
+impl TryFrom<&str> for LookupHost {
+ type Error = io::Error;
+
+ fn try_from(_v: &str) -> io::Result<LookupHost> {
+ unsupported()
+ }
+}
+
+impl<'a> TryFrom<(&'a str, u16)> for LookupHost {
+ type Error = io::Error;
+
+ fn try_from(_v: (&'a str, u16)) -> io::Result<LookupHost> {
+ unsupported()
+ }
+}
+
+#[allow(nonstandard_style)]
+pub mod netc {
+ pub const AF_INET: u8 = 0;
+ pub const AF_INET6: u8 = 1;
+ pub type sa_family_t = u8;
+
+ #[derive(Copy, Clone)]
+ pub struct in_addr {
+ pub s_addr: u32,
+ }
+
+ #[derive(Copy, Clone)]
+ pub struct sockaddr_in {
+ pub sin_family: sa_family_t,
+ pub sin_port: u16,
+ pub sin_addr: in_addr,
+ }
+
+ #[derive(Copy, Clone)]
+ pub struct in6_addr {
+ pub s6_addr: [u8; 16],
+ }
+
+ #[derive(Copy, Clone)]
+ pub struct sockaddr_in6 {
+ pub sin6_family: sa_family_t,
+ pub sin6_port: u16,
+ pub sin6_addr: in6_addr,
+ pub sin6_flowinfo: u32,
+ pub sin6_scope_id: u32,
+ }
+
+ #[derive(Copy, Clone)]
+ pub struct sockaddr {
+ }
+
+ pub type socklen_t = usize;
+}
diff --git a/src/libstd/sys/wasm/os.rs b/src/libstd/sys/wasm/os.rs
new file mode 100644
index 0000000..5d21999
--- /dev/null
+++ b/src/libstd/sys/wasm/os.rs
@@ -0,0 +1,102 @@
+use crate::error::Error as StdError;
+use crate::ffi::{OsString, OsStr};
+use crate::fmt;
+use crate::io;
+use crate::path::{self, PathBuf};
+use crate::str;
+use crate::sys::{unsupported, Void, ExitSysCall, GetEnvSysCall, SetEnvSysCall};
+
+pub fn errno() -> i32 {
+ 0
+}
+
+pub fn error_string(_errno: i32) -> String {
+ "operation successful".to_string()
+}
+
+pub fn getcwd() -> io::Result<PathBuf> {
+ unsupported()
+}
+
+pub fn chdir(_: &path::Path) -> io::Result<()> {
+ unsupported()
+}
+
+pub struct SplitPaths<'a>(&'a Void);
+
+pub fn split_paths(_unparsed: &OsStr) -> SplitPaths<'_> {
+ panic!("unsupported")
+}
+
+impl<'a> Iterator for SplitPaths<'a> {
+ type Item = PathBuf;
+ fn next(&mut self) -> Option<PathBuf> {
+ match *self.0 {}
+ }
+}
+
+#[derive(Debug)]
+pub struct JoinPathsError;
+
+pub fn join_paths<I, T>(_paths: I) -> Result<OsString, JoinPathsError>
+ where I: Iterator<Item=T>, T: AsRef<OsStr>
+{
+ Err(JoinPathsError)
+}
+
+impl fmt::Display for JoinPathsError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ "not supported on wasm yet".fmt(f)
+ }
+}
+
+impl StdError for JoinPathsError {
+ fn description(&self) -> &str {
+ "not supported on wasm yet"
+ }
+}
+
+pub fn current_exe() -> io::Result<PathBuf> {
+ unsupported()
+}
+
+pub struct Env(Void);
+
+impl Iterator for Env {
+ type Item = (OsString, OsString);
+ fn next(&mut self) -> Option<(OsString, OsString)> {
+ match self.0 {}
+ }
+}
+
+pub fn env() -> Env {
+ panic!("not supported on web assembly")
+}
+
+pub fn getenv(k: &OsStr) -> io::Result<Option<OsString>> {
+ Ok(GetEnvSysCall::perform(k))
+}
+
+pub fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> {
+ Ok(SetEnvSysCall::perform(k, Some(v)))
+}
+
+pub fn unsetenv(k: &OsStr) -> io::Result<()> {
+ Ok(SetEnvSysCall::perform(k, None))
+}
+
+pub fn temp_dir() -> PathBuf {
+ panic!("no filesystem on wasm")
+}
+
+pub fn home_dir() -> Option<PathBuf> {
+ None
+}
+
+pub fn exit(_code: i32) -> ! {
+ ExitSysCall::perform(_code as isize as usize)
+}
+
+pub fn getpid() -> u32 {
+ panic!("no pids on wasm")
+}
diff --git a/src/libstd/sys/wasm/path.rs b/src/libstd/sys/wasm/path.rs
new file mode 100644
index 0000000..7a18395
--- /dev/null
+++ b/src/libstd/sys/wasm/path.rs
@@ -0,0 +1,19 @@
+use crate::path::Prefix;
+use crate::ffi::OsStr;
+
+#[inline]
+pub fn is_sep_byte(b: u8) -> bool {
+ b == b'/'
+}
+
+#[inline]
+pub fn is_verbatim_sep(b: u8) -> bool {
+ b == b'/'
+}
+
+pub fn parse_prefix(_: &OsStr) -> Option<Prefix<'_>> {
+ None
+}
+
+pub const MAIN_SEP_STR: &str = "/";
+pub const MAIN_SEP: char = '/';
diff --git a/src/libstd/sys/wasm/pipe.rs b/src/libstd/sys/wasm/pipe.rs
new file mode 100644
index 0000000..2582b99
--- /dev/null
+++ b/src/libstd/sys/wasm/pipe.rs
@@ -0,0 +1,25 @@
+use crate::io;
+use crate::sys::Void;
+
+pub struct AnonPipe(Void);
+
+impl AnonPipe {
+ pub fn read(&self, _buf: &mut [u8]) -> io::Result<usize> {
+ match self.0 {}
+ }
+
+ pub fn write(&self, _buf: &[u8]) -> io::Result<usize> {
+ match self.0 {}
+ }
+
+ pub fn diverge(&self) -> ! {
+ match self.0 {}
+ }
+}
+
+pub fn read2(p1: AnonPipe,
+ _v1: &mut Vec<u8>,
+ _p2: AnonPipe,
+ _v2: &mut Vec<u8>) -> io::Result<()> {
+ match p1.0 {}
+}
diff --git a/src/libstd/sys/wasm/process.rs b/src/libstd/sys/wasm/process.rs
new file mode 100644
index 0000000..a02e009
--- /dev/null
+++ b/src/libstd/sys/wasm/process.rs
@@ -0,0 +1,152 @@
+use crate::ffi::OsStr;
+use crate::fmt;
+use crate::io;
+use crate::sys::fs::File;
+use crate::sys::pipe::AnonPipe;
+use crate::sys::{unsupported, Void};
+use crate::sys_common::process::{CommandEnv, DefaultEnvKey};
+
+////////////////////////////////////////////////////////////////////////////////
+// Command
+////////////////////////////////////////////////////////////////////////////////
+
+pub struct Command {
+ env: CommandEnv<DefaultEnvKey>
+}
+
+// passed back to std::process with the pipes connected to the child, if any
+// were requested
+pub struct StdioPipes {
+ pub stdin: Option<AnonPipe>,
+ pub stdout: Option<AnonPipe>,
+ pub stderr: Option<AnonPipe>,
+}
+
+pub enum Stdio {
+ Inherit,
+ Null,
+ MakePipe,
+}
+
+impl Command {
+ pub fn new(_program: &OsStr) -> Command {
+ Command {
+ env: Default::default()
+ }
+ }
+
+ pub fn arg(&mut self, _arg: &OsStr) {
+ }
+
+ pub fn env_mut(&mut self) -> &mut CommandEnv<DefaultEnvKey> {
+ &mut self.env
+ }
+
+ pub fn cwd(&mut self, _dir: &OsStr) {
+ }
+
+ pub fn stdin(&mut self, _stdin: Stdio) {
+ }
+
+ pub fn stdout(&mut self, _stdout: Stdio) {
+ }
+
+ pub fn stderr(&mut self, _stderr: Stdio) {
+ }
+
+ pub fn spawn(&mut self, _default: Stdio, _needs_stdin: bool)
+ -> io::Result<(Process, StdioPipes)> {
+ unsupported()
+ }
+}
+
+impl From<AnonPipe> for Stdio {
+ fn from(pipe: AnonPipe) -> Stdio {
+ pipe.diverge()
+ }
+}
+
+impl From<File> for Stdio {
+ fn from(file: File) -> Stdio {
+ file.diverge()
+ }
+}
+
+impl fmt::Debug for Command {
+ fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ Ok(())
+ }
+}
+
+pub struct ExitStatus(Void);
+
+impl ExitStatus {
+ pub fn success(&self) -> bool {
+ match self.0 {}
+ }
+
+ pub fn code(&self) -> Option<i32> {
+ match self.0 {}
+ }
+}
+
+impl Clone for ExitStatus {
+ fn clone(&self) -> ExitStatus {
+ match self.0 {}
+ }
+}
+
+impl Copy for ExitStatus {}
+
+impl PartialEq for ExitStatus {
+ fn eq(&self, _other: &ExitStatus) -> bool {
+ match self.0 {}
+ }
+}
+
+impl Eq for ExitStatus {
+}
+
+impl fmt::Debug for ExitStatus {
+ fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self.0 {}
+ }
+}
+
+impl fmt::Display for ExitStatus {
+ fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self.0 {}
+ }
+}
+
+#[derive(PartialEq, Eq, Clone, Copy, Debug)]
+pub struct ExitCode(bool);
+
+impl ExitCode {
+ pub const SUCCESS: ExitCode = ExitCode(false);
+ pub const FAILURE: ExitCode = ExitCode(true);
+
+ pub fn as_i32(&self) -> i32 {
+ self.0 as i32
+ }
+}
+
+pub struct Process(Void);
+
+impl Process {
+ pub fn id(&self) -> u32 {
+ match self.0 {}
+ }
+
+ pub fn kill(&mut self) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn wait(&mut self) -> io::Result<ExitStatus> {
+ match self.0 {}
+ }
+
+ pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
+ match self.0 {}
+ }
+}
diff --git a/src/libstd/sys/wasm/rwlock.rs b/src/libstd/sys/wasm/rwlock.rs
new file mode 100644
index 0000000..a2b07c7
--- /dev/null
+++ b/src/libstd/sys/wasm/rwlock.rs
@@ -0,0 +1,72 @@
+use crate::cell::UnsafeCell;
+
+pub struct RWLock {
+ mode: UnsafeCell<isize>,
+}
+
+unsafe impl Send for RWLock {}
+unsafe impl Sync for RWLock {} // no threads on wasm
+
+impl RWLock {
+ pub const fn new() -> RWLock {
+ RWLock {
+ mode: UnsafeCell::new(0),
+ }
+ }
+
+ #[inline]
+ pub unsafe fn read(&self) {
+ let mode = self.mode.get();
+ if *mode >= 0 {
+ *mode += 1;
+ } else {
+ rtabort!("rwlock locked for writing");
+ }
+ }
+
+ #[inline]
+ pub unsafe fn try_read(&self) -> bool {
+ let mode = self.mode.get();
+ if *mode >= 0 {
+ *mode += 1;
+ true
+ } else {
+ false
+ }
+ }
+
+ #[inline]
+ pub unsafe fn write(&self) {
+ let mode = self.mode.get();
+ if *mode == 0 {
+ *mode = -1;
+ } else {
+ rtabort!("rwlock locked for reading")
+ }
+ }
+
+ #[inline]
+ pub unsafe fn try_write(&self) -> bool {
+ let mode = self.mode.get();
+ if *mode == 0 {
+ *mode = -1;
+ true
+ } else {
+ false
+ }
+ }
+
+ #[inline]
+ pub unsafe fn read_unlock(&self) {
+ *self.mode.get() -= 1;
+ }
+
+ #[inline]
+ pub unsafe fn write_unlock(&self) {
+ *self.mode.get() += 1;
+ }
+
+ #[inline]
+ pub unsafe fn destroy(&self) {
+ }
+}
diff --git a/src/libstd/sys/wasm/rwlock_atomics.rs b/src/libstd/sys/wasm/rwlock_atomics.rs
new file mode 100644
index 0000000..c705568
--- /dev/null
+++ b/src/libstd/sys/wasm/rwlock_atomics.rs
@@ -0,0 +1,151 @@
+use crate::cell::UnsafeCell;
+use crate::sys::mutex::Mutex;
+use crate::sys::condvar::Condvar;
+
+pub struct RWLock {
+ lock: Mutex,
+ cond: Condvar,
+ state: UnsafeCell<State>,
+}
+
+enum State {
+ Unlocked,
+ Reading(usize),
+ Writing,
+}
+
+unsafe impl Send for RWLock {}
+unsafe impl Sync for RWLock {}
+
+// This rwlock implementation is a relatively simple implementation which has a
+// condition variable for readers/writers as well as a mutex protecting the
+// internal state of the lock. A current downside of the implementation is that
+// unlocking the lock will notify *all* waiters rather than just readers or just
+// writers. This can cause lots of "thundering stampede" problems. While
+// hopefully correct this implementation is very likely to want to be changed in
+// the future.
+
+impl RWLock {
+ pub const fn new() -> RWLock {
+ RWLock {
+ lock: Mutex::new(),
+ cond: Condvar::new(),
+ state: UnsafeCell::new(State::Unlocked),
+ }
+ }
+
+ #[inline]
+ pub unsafe fn read(&self) {
+ self.lock.lock();
+ while !(*self.state.get()).inc_readers() {
+ self.cond.wait(&self.lock);
+ }
+ self.lock.unlock();
+ }
+
+ #[inline]
+ pub unsafe fn try_read(&self) -> bool {
+ self.lock.lock();
+ let ok = (*self.state.get()).inc_readers();
+ self.lock.unlock();
+ return ok
+ }
+
+ #[inline]
+ pub unsafe fn write(&self) {
+ self.lock.lock();
+ while !(*self.state.get()).inc_writers() {
+ self.cond.wait(&self.lock);
+ }
+ self.lock.unlock();
+ }
+
+ #[inline]
+ pub unsafe fn try_write(&self) -> bool {
+ self.lock.lock();
+ let ok = (*self.state.get()).inc_writers();
+ self.lock.unlock();
+ return ok
+ }
+
+ #[inline]
+ pub unsafe fn read_unlock(&self) {
+ self.lock.lock();
+ let notify = (*self.state.get()).dec_readers();
+ self.lock.unlock();
+ if notify {
+ // FIXME: should only wake up one of these some of the time
+ self.cond.notify_all();
+ }
+ }
+
+ #[inline]
+ pub unsafe fn write_unlock(&self) {
+ self.lock.lock();
+ (*self.state.get()).dec_writers();
+ self.lock.unlock();
+ // FIXME: should only wake up one of these some of the time
+ self.cond.notify_all();
+ }
+
+ #[inline]
+ pub unsafe fn destroy(&self) {
+ self.lock.destroy();
+ self.cond.destroy();
+ }
+}
+
+impl State {
+ fn inc_readers(&mut self) -> bool {
+ match *self {
+ State::Unlocked => {
+ *self = State::Reading(1);
+ true
+ }
+ State::Reading(ref mut cnt) => {
+ *cnt += 1;
+ true
+ }
+ State::Writing => false
+ }
+ }
+
+ fn inc_writers(&mut self) -> bool {
+ match *self {
+ State::Unlocked => {
+ *self = State::Writing;
+ true
+ }
+ State::Reading(_) |
+ State::Writing => false
+ }
+ }
+
+ fn dec_readers(&mut self) -> bool {
+ let zero = match *self {
+ State::Reading(ref mut cnt) => {
+ *cnt -= 1;
+ *cnt == 0
+ }
+ State::Unlocked |
+ State::Writing => invalid(),
+ };
+ if zero {
+ *self = State::Unlocked;
+ }
+ zero
+ }
+
+ fn dec_writers(&mut self) {
+ match *self {
+ State::Writing => {}
+ State::Unlocked |
+ State::Reading(_) => invalid(),
+ }
+ *self = State::Unlocked;
+ }
+}
+
+fn invalid() -> ! {
+ panic!("inconsistent rwlock");
+}
diff --git a/src/libstd/sys/wasm/stack_overflow.rs b/src/libstd/sys/wasm/stack_overflow.rs
new file mode 100644
index 0000000..c0e7c82
--- /dev/null
+++ b/src/libstd/sys/wasm/stack_overflow.rs
@@ -0,0 +1,13 @@
+pub struct Handler;
+
+impl Handler {
+ pub unsafe fn new() -> Handler {
+ Handler
+ }
+}
+
+pub unsafe fn init() {
+}
+
+pub unsafe fn cleanup() {
+}
diff --git a/src/libstd/sys/wasm/stdio.rs b/src/libstd/sys/wasm/stdio.rs
new file mode 100644
index 0000000..b8899a9
--- /dev/null
+++ b/src/libstd/sys/wasm/stdio.rs
@@ -0,0 +1,66 @@
+use crate::io;
+use crate::sys::{ReadSysCall, WriteSysCall};
+
+pub struct Stdin;
+pub struct Stdout;
+pub struct Stderr;
+
+impl Stdin {
+ pub fn new() -> io::Result<Stdin> {
+ Ok(Stdin)
+ }
+}
+
+impl io::Read for Stdin {
+ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+ Ok(ReadSysCall::perform(0, buf))
+ }
+}
+
+impl Stdout {
+ pub fn new() -> io::Result<Stdout> {
+ Ok(Stdout)
+ }
+}
+
+impl io::Write for Stdout {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ WriteSysCall::perform(1, buf);
+ Ok(buf.len())
+ }
+
+ fn flush(&mut self) -> io::Result<()> {
+ Ok(())
+ }
+}
+
+impl Stderr {
+ pub fn new() -> io::Result<Stderr> {
+ Ok(Stderr)
+ }
+}
+
+impl io::Write for Stderr {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ WriteSysCall::perform(2, buf);
+ Ok(buf.len())
+ }
+
+ fn flush(&mut self) -> io::Result<()> {
+ Ok(())
+ }
+}
+
+pub const STDIN_BUF_SIZE: usize = 0;
+
+pub fn is_ebadf(_err: &io::Error) -> bool {
+ true
+}
+
+pub fn panic_output() -> Option<impl io::Write> {
+ if cfg!(feature = "wasm_syscall") {
+ Stderr::new().ok()
+ } else {
+ None
+ }
+}
diff --git a/src/libstd/sys/wasm/thread.rs b/src/libstd/sys/wasm/thread.rs
new file mode 100644
index 0000000..a65c413
--- /dev/null
+++ b/src/libstd/sys/wasm/thread.rs
@@ -0,0 +1,107 @@
+use crate::boxed::FnBox;
+use crate::ffi::CStr;
+use crate::io;
+use crate::sys::{unsupported, Void};
+use crate::time::Duration;
+
+pub struct Thread(Void);
+
+pub const DEFAULT_MIN_STACK_SIZE: usize = 4096;
+
+impl Thread {
+ // unsafe: see thread::Builder::spawn_unchecked for safety requirements
+ pub unsafe fn new(_stack: usize, _p: Box<dyn FnBox()>)
+ -> io::Result<Thread>
+ {
+ unsupported()
+ }
+
+ pub fn yield_now() {
+ // do nothing
+ }
+
+ pub fn set_name(_name: &CStr) {
+ // nope
+ }
+
+ #[cfg(not(target_feature = "atomics"))]
+ pub fn sleep(_dur: Duration) {
+ panic!("can't sleep");
+ }
+
+ #[cfg(target_feature = "atomics")]
+ pub fn sleep(dur: Duration) {
+ use crate::arch::wasm32;
+ use crate::cmp;
+
+ // Use an atomic wait to block the current thread artificially with a
+ // timeout listed. Note that we should never be notified (return value
+ // of 0) or our comparison should never fail (return value of 1) so we
+ // should always only resume execution through a timeout (return value
+ // 2).
+ let mut nanos = dur.as_nanos();
+ while nanos > 0 {
+ let amt = cmp::min(i64::max_value() as u128, nanos);
+ let mut x = 0;
+ let val = unsafe { wasm32::i32_atomic_wait(&mut x, 0, amt as i64) };
+ debug_assert_eq!(val, 2);
+ nanos -= amt;
+ }
+ }
+
+ pub fn join(self) {
+ match self.0 {}
+ }
+}
+
+pub mod guard {
+ pub type Guard = !;
+ pub unsafe fn current() -> Option<Guard> { None }
+ pub unsafe fn init() -> Option<Guard> { None }
+}
+
+cfg_if! {
+ if #[cfg(all(target_feature = "atomics", feature = "wasm-bindgen-threads"))] {
+ #[link(wasm_import_module = "__wbindgen_thread_xform__")]
+ extern {
+ fn __wbindgen_current_id() -> u32;
+ fn __wbindgen_tcb_get() -> u32;
+ fn __wbindgen_tcb_set(ptr: u32);
+ }
+ pub fn my_id() -> u32 {
+ unsafe { __wbindgen_current_id() }
+ }
+
+ // These are currently only ever used in `thread_local_atomics.rs`, if
+ // you'd like to use them be sure to update that and make sure everyone
+ // agrees what's what.
+ pub fn tcb_get() -> *mut u8 {
+ use crate::mem;
+ assert_eq!(mem::size_of::<*mut u8>(), mem::size_of::<u32>());
+ unsafe { __wbindgen_tcb_get() as *mut u8 }
+ }
+
+ pub fn tcb_set(ptr: *mut u8) {
+ unsafe { __wbindgen_tcb_set(ptr as u32); }
+ }
+
+ // FIXME: still need something for hooking exiting a thread to free
+ // data...
+
+ } else if #[cfg(target_feature = "atomics")] {
+ pub fn my_id() -> u32 {
+ panic!("thread ids not implemented on wasm with atomics yet")
+ }
+
+ pub fn tcb_get() -> *mut u8 {
+ panic!("thread local data not implemented on wasm with atomics yet")
+ }
+
+ pub fn tcb_set(_ptr: *mut u8) {
+ panic!("thread local data not implemented on wasm with atomics yet")
+ }
+ } else {
+ // stubbed out because no functions actually access these intrinsics
+ // unless atomics are enabled
+ }
+}
diff --git a/src/libstd/sys/wasm/thread_local.rs b/src/libstd/sys/wasm/thread_local.rs
new file mode 100644
index 0000000..29e9854
--- /dev/null
+++ b/src/libstd/sys/wasm/thread_local.rs
@@ -0,0 +1,40 @@
+use crate::boxed::Box;
+use crate::ptr;
+
+pub type Key = usize;
+
+struct Allocated {
+ value: *mut u8,
+ dtor: Option<unsafe extern fn(*mut u8)>,
+}
+
+#[inline]
+pub unsafe fn create(dtor: Option<unsafe extern fn(*mut u8)>) -> Key {
+ Box::into_raw(Box::new(Allocated {
+ value: ptr::null_mut(),
+ dtor,
+ })) as usize
+}
+
+#[inline]
+pub unsafe fn set(key: Key, value: *mut u8) {
+ (*(key as *mut Allocated)).value = value;
+}
+
+#[inline]
+pub unsafe fn get(key: Key) -> *mut u8 {
+ (*(key as *mut Allocated)).value
+}
+
+#[inline]
+pub unsafe fn destroy(key: Key) {
+ let key = Box::from_raw(key as *mut Allocated);
+ if let Some(f) = key.dtor {
+ f(key.value);
+ }
+}
+
+#[inline]
+pub fn requires_synchronized_create() -> bool {
+ false
+}
diff --git a/src/libstd/sys/wasm/thread_local_atomics.rs b/src/libstd/sys/wasm/thread_local_atomics.rs
new file mode 100644
index 0000000..b408ad0
--- /dev/null
+++ b/src/libstd/sys/wasm/thread_local_atomics.rs
@@ -0,0 +1,61 @@
+use crate::sys::thread;
+use crate::sync::atomic::{AtomicUsize, Ordering::SeqCst};
+
+const MAX_KEYS: usize = 128;
+static NEXT_KEY: AtomicUsize = AtomicUsize::new(0);
+
+struct ThreadControlBlock {
+ keys: [*mut u8; MAX_KEYS],
+}
+
+impl ThreadControlBlock {
+ fn new() -> ThreadControlBlock {
+ ThreadControlBlock {
+ keys: [0 as *mut u8; MAX_KEYS],
+ }
+ }
+
+ fn get() -> *mut ThreadControlBlock {
+ let ptr = thread::tcb_get();
+ if !ptr.is_null() {
+ return ptr as *mut ThreadControlBlock
+ }
+ let tcb = Box::into_raw(Box::new(ThreadControlBlock::new()));
+ thread::tcb_set(tcb as *mut u8);
+ tcb
+ }
+}
+
+pub type Key = usize;
+
+pub unsafe fn create(dtor: Option<unsafe extern fn(*mut u8)>) -> Key {
+ drop(dtor); // FIXME: need to figure out how to hook thread exit to run this
+ let key = NEXT_KEY.fetch_add(1, SeqCst);
+ if key >= MAX_KEYS {
+ NEXT_KEY.store(MAX_KEYS, SeqCst);
+ panic!("cannot allocate space for more TLS keys");
+ }
+ // offset by 1 so we never hand out 0. This is currently required by
+ // `sys_common/thread_local.rs` where it can't cope with keys of value 0
+ // because it messes up the atomic management.
+ return key + 1
+}
+
+pub unsafe fn set(key: Key, value: *mut u8) {
+ (*ThreadControlBlock::get()).keys[key - 1] = value;
+}
+
+pub unsafe fn get(key: Key) -> *mut u8 {
+ (*ThreadControlBlock::get()).keys[key - 1]
+}
+
+pub unsafe fn destroy(_key: Key) {
+ // FIXME: should implement this somehow, this isn't typically called but it
+ // can be called if two threads race to initialize a TLS slot and one ends
+ // up not being needed.
+}
+
+#[inline]
+pub fn requires_synchronized_create() -> bool {
+ false
+}
diff --git a/src/libstd/sys/wasm/time.rs b/src/libstd/sys/wasm/time.rs
new file mode 100644
index 0000000..3f71461
--- /dev/null
+++ b/src/libstd/sys/wasm/time.rs
@@ -0,0 +1,55 @@
+use crate::time::Duration;
+use crate::sys::{TimeSysCall, TimeClock};
+
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
+pub struct Instant(Duration);
+
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
+pub struct SystemTime(Duration);
+
+pub const UNIX_EPOCH: SystemTime = SystemTime(Duration::from_secs(0));
+
+impl Instant {
+ pub fn now() -> Instant {
+ Instant(TimeSysCall::perform(TimeClock::Monotonic))
+ }
+
+ pub const fn zero() -> Instant {
+ Instant(Duration::from_secs(0))
+ }
+
+ pub fn actually_monotonic() -> bool {
+ false
+ }
+
+ pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
+ self.0.checked_sub(other.0)
+ }
+
+ pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
+ Some(Instant(self.0.checked_add(*other)?))
+ }
+
+ pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
+ Some(Instant(self.0.checked_sub(*other)?))
+ }
+}
+
+impl SystemTime {
+ pub fn now() -> SystemTime {
+ SystemTime(TimeSysCall::perform(TimeClock::System))
+ }
+
+ pub fn sub_time(&self, other: &SystemTime)
+ -> Result<Duration, Duration> {
+ self.0.checked_sub(other.0).ok_or_else(|| other.0 - self.0)
+ }
+
+ pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
+ Some(SystemTime(self.0.checked_add(*other)?))
+ }
+
+ pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
+ Some(SystemTime(self.0.checked_sub(*other)?))
+ }
+}
diff --git a/src/libstd/sys/windows/alloc.rs b/src/libstd/sys/windows/alloc.rs
new file mode 100644
index 0000000..a33c401
--- /dev/null
+++ b/src/libstd/sys/windows/alloc.rs
@@ -0,0 +1,67 @@
+use crate::alloc::{GlobalAlloc, Layout, System};
+use crate::sys::c;
+use crate::sys_common::alloc::{MIN_ALIGN, realloc_fallback};
+
+#[repr(C)]
+struct Header(*mut u8);
+
+unsafe fn get_header<'a>(ptr: *mut u8) -> &'a mut Header {
+ &mut *(ptr as *mut Header).offset(-1)
+}
+
+unsafe fn align_ptr(ptr: *mut u8, align: usize) -> *mut u8 {
+ let aligned = ptr.add(align - (ptr as usize & (align - 1)));
+ *get_header(aligned) = Header(ptr);
+ aligned
+}
+
+#[inline]
+unsafe fn allocate_with_flags(layout: Layout, flags: c::DWORD) -> *mut u8 {
+ if layout.align() <= MIN_ALIGN {
+ return c::HeapAlloc(c::GetProcessHeap(), flags, layout.size()) as *mut u8
+ }
+
+ let size = layout.size() + layout.align();
+ let ptr = c::HeapAlloc(c::GetProcessHeap(), flags, size);
+ if ptr.is_null() {
+ ptr as *mut u8
+ } else {
+ align_ptr(ptr as *mut u8, layout.align())
+ }
+}
+
+#[stable(feature = "alloc_system_type", since = "1.28.0")]
+unsafe impl GlobalAlloc for System {
+ #[inline]
+ unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
+ allocate_with_flags(layout, 0)
+ }
+
+ #[inline]
+ unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
+ allocate_with_flags(layout, c::HEAP_ZERO_MEMORY)
+ }
+
+ #[inline]
+ unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
+ if layout.align() <= MIN_ALIGN {
+ let err = c::HeapFree(c::GetProcessHeap(), 0, ptr as c::LPVOID);
+ debug_assert!(err != 0, "Failed to free heap memory: {}",
+ c::GetLastError());
+ } else {
+ let header = get_header(ptr);
+ let err = c::HeapFree(c::GetProcessHeap(), 0, header.0 as c::LPVOID);
+ debug_assert!(err != 0, "Failed to free heap memory: {}",
+ c::GetLastError());
+ }
+ }
+
+ #[inline]
+ unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
+ if layout.align() <= MIN_ALIGN {
+ c::HeapReAlloc(c::GetProcessHeap(), 0, ptr as c::LPVOID, new_size) as *mut u8
+ } else {
+ realloc_fallback(self, ptr, layout, new_size)
+ }
+ }
+}
diff --git a/src/libstd/sys/windows/args.rs b/src/libstd/sys/windows/args.rs
new file mode 100644
index 0000000..b04bb48
--- /dev/null
+++ b/src/libstd/sys/windows/args.rs
@@ -0,0 +1,258 @@
+#![allow(dead_code)] // runtime init functions not used during testing
+
+use crate::os::windows::prelude::*;
+use crate::sys::windows::os::current_exe;
+use crate::sys::c;
+use crate::ffi::OsString;
+use crate::fmt;
+use crate::vec;
+use crate::slice;
+use crate::path::PathBuf;
+
+use core::iter;
+
+pub unsafe fn init(_argc: isize, _argv: *const *const u8) { }
+
+pub unsafe fn cleanup() { }
+
+pub fn args() -> Args {
+ unsafe {
+ let lp_cmd_line = c::GetCommandLineW();
+ let parsed_args_list = parse_lp_cmd_line(
+ lp_cmd_line as *const u16,
+ || current_exe().map(PathBuf::into_os_string).unwrap_or_else(|_| OsString::new()));
+
+ Args { parsed_args_list: parsed_args_list.into_iter() }
+ }
+}
+
+/// Implements the Windows command-line argument parsing algorithm.
+///
+/// Microsoft's documentation for the Windows CLI argument format can be found at
+/// <https://docs.microsoft.com/en-us/previous-versions//17w5ykft(v=vs.85)>.
+///
+/// Windows includes a function to do this in shell32.dll,
+/// but linking with that DLL causes the process to be registered as a GUI application.
+/// GUI applications add a bunch of overhead, even if no windows are drawn. See
+/// <https://randomascii.wordpress.com/2018/12/03/a-not-called-function-can-cause-a-5x-slowdown/>.
+///
+/// This function was tested for equivalence to the shell32.dll implementation in
+/// Windows 10 Pro v1803, using an exhaustive test suite available at
+/// <https://gist.github.com/notriddle/dde431930c392e428055b2dc22e638f5> or
+/// <https://paste.gg/p/anonymous/47d6ed5f5bd549168b1c69c799825223>.
+unsafe fn parse_lp_cmd_line<F: Fn() -> OsString>(lp_cmd_line: *const u16, exe_name: F)
+ -> Vec<OsString> {
+ const BACKSLASH: u16 = '\\' as u16;
+ const QUOTE: u16 = '"' as u16;
+ const TAB: u16 = '\t' as u16;
+ const SPACE: u16 = ' ' as u16;
+ let mut ret_val = Vec::new();
+ if lp_cmd_line.is_null() || *lp_cmd_line == 0 {
+ ret_val.push(exe_name());
+ return ret_val;
+ }
+ let mut cmd_line = {
+ let mut end = 0;
+ while *lp_cmd_line.offset(end) != 0 {
+ end += 1;
+ }
+ slice::from_raw_parts(lp_cmd_line, end as usize)
+ };
+ // The executable name at the beginning is special.
+ cmd_line = match cmd_line[0] {
+ // The executable name ends at the next quote mark,
+ // no matter what.
+ QUOTE => {
+ let args = {
+ let mut cut = cmd_line[1..].splitn(2, |&c| c == QUOTE);
+ if let Some(exe) = cut.next() {
+ ret_val.push(OsString::from_wide(exe));
+ }
+ cut.next()
+ };
+ if let Some(args) = args {
+ args
+ } else {
+ return ret_val;
+ }
+ }
+ // Implement quirk: when they say whitespace here,
+ // they include the entire ASCII control plane:
+ // "However, if lpCmdLine starts with any amount of whitespace, CommandLineToArgvW
+ // will consider the first argument to be an empty string. Excess whitespace at the
+ // end of lpCmdLine is ignored."
+ 0..=SPACE => {
+ ret_val.push(OsString::new());
+ &cmd_line[1..]
+ },
+ // The executable name ends at the next whitespace,
+ // no matter what.
+ _ => {
+ let args = {
+ let mut cut = cmd_line.splitn(2, |&c| c > 0 && c <= SPACE);
+ if let Some(exe) = cut.next() {
+ ret_val.push(OsString::from_wide(exe));
+ }
+ cut.next()
+ };
+ if let Some(args) = args {
+ args
+ } else {
+ return ret_val;
+ }
+ }
+ };
+ let mut cur = Vec::new();
+ let mut in_quotes = false;
+ let mut was_in_quotes = false;
+ let mut backslash_count: usize = 0;
+ for &c in cmd_line {
+ match c {
+ // backslash
+ BACKSLASH => {
+ backslash_count += 1;
+ was_in_quotes = false;
+ },
+ QUOTE if backslash_count % 2 == 0 => {
+ cur.extend(iter::repeat(b'\\' as u16).take(backslash_count / 2));
+ backslash_count = 0;
+ if was_in_quotes {
+ cur.push('"' as u16);
+ was_in_quotes = false;
+ } else {
+ was_in_quotes = in_quotes;
+ in_quotes = !in_quotes;
+ }
+ }
+ QUOTE if backslash_count % 2 != 0 => {
+ cur.extend(iter::repeat(b'\\' as u16).take(backslash_count / 2));
+ backslash_count = 0;
+ was_in_quotes = false;
+ cur.push(b'"' as u16);
+ }
+ SPACE | TAB if !in_quotes => {
+ cur.extend(iter::repeat(b'\\' as u16).take(backslash_count));
+ if !cur.is_empty() || was_in_quotes {
+ ret_val.push(OsString::from_wide(&cur[..]));
+ cur.truncate(0);
+ }
+ backslash_count = 0;
+ was_in_quotes = false;
+ }
+ _ => {
+ cur.extend(iter::repeat(b'\\' as u16).take(backslash_count));
+ backslash_count = 0;
+ was_in_quotes = false;
+ cur.push(c);
+ }
+ }
+ }
+ cur.extend(iter::repeat(b'\\' as u16).take(backslash_count));
+ // include empty quoted strings at the end of the arguments list
+ if !cur.is_empty() || was_in_quotes || in_quotes {
+ ret_val.push(OsString::from_wide(&cur[..]));
+ }
+ ret_val
+}
+
+pub struct Args {
+ parsed_args_list: vec::IntoIter<OsString>,
+}
+
+pub struct ArgsInnerDebug<'a> {
+ args: &'a Args,
+}
+
+impl<'a> fmt::Debug for ArgsInnerDebug<'a> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ self.args.parsed_args_list.as_slice().fmt(f)
+ }
+}
+
+impl Args {
+ pub fn inner_debug(&self) -> ArgsInnerDebug<'_> {
+ ArgsInnerDebug {
+ args: self
+ }
+ }
+}
+
+impl Iterator for Args {
+ type Item = OsString;
+ fn next(&mut self) -> Option<OsString> { self.parsed_args_list.next() }
+ fn size_hint(&self) -> (usize, Option<usize>) { self.parsed_args_list.size_hint() }
+}
+
+impl DoubleEndedIterator for Args {
+ fn next_back(&mut self) -> Option<OsString> { self.parsed_args_list.next_back() }
+}
+
+impl ExactSizeIterator for Args {
+ fn len(&self) -> usize { self.parsed_args_list.len() }
+}
+
+#[cfg(test)]
+mod tests {
+ use crate::sys::windows::args::*;
+ use crate::ffi::OsString;
+
+ fn chk(string: &str, parts: &[&str]) {
+ let mut wide: Vec<u16> = OsString::from(string).encode_wide().collect();
+ wide.push(0);
+ let parsed = unsafe {
+ parse_lp_cmd_line(wide.as_ptr() as *const u16, || OsString::from("TEST.EXE"))
+ };
+ let expected: Vec<OsString> = parts.iter().map(|k| OsString::from(k)).collect();
+ assert_eq!(parsed.as_slice(), expected.as_slice());
+ }
+
+ #[test]
+ fn empty() {
+ chk("", &["TEST.EXE"]);
+ chk("\0", &["TEST.EXE"]);
+ }
+
+ #[test]
+ fn single_words() {
+ chk("EXE one_word", &["EXE", "one_word"]);
+ chk("EXE a", &["EXE", "a"]);
+ chk("EXE 😅", &["EXE", "😅"]);
+ chk("EXE 😅🤦", &["EXE", "😅🤦"]);
+ }
+
+ #[test]
+ fn official_examples() {
+ chk(r#"EXE "abc" d e"#, &["EXE", "abc", "d", "e"]);
+ chk(r#"EXE a\\\b d"e f"g h"#, &["EXE", r#"a\\\b"#, "de fg", "h"]);
+ chk(r#"EXE a\\\"b c d"#, &["EXE", r#"a\"b"#, "c", "d"]);
+ chk(r#"EXE a\\\\"b c" d e"#, &["EXE", r#"a\\b c"#, "d", "e"]);
+ }
+
+ #[test]
+ fn whitespace_behavior() {
+ chk(r#" test"#, &["", "test"]);
+ chk(r#" test"#, &["", "test"]);
+ chk(r#" test test2"#, &["", "test", "test2"]);
+ chk(r#" test test2"#, &["", "test", "test2"]);
+ chk(r#"test test2 "#, &["test", "test2"]);
+ chk(r#"test test2 "#, &["test", "test2"]);
+ chk(r#"test "#, &["test"]);
+ }
+
+ #[test]
+ fn genius_quotes() {
+ chk(r#"EXE "" """#, &["EXE", "", ""]);
+ chk(r#"EXE "" """"#, &["EXE", "", "\""]);
+ chk(
+ r#"EXE "this is """all""" in the same argument""#,
+ &["EXE", "this is \"all\" in the same argument"]
+ );
+ chk(r#"EXE "a"""#, &["EXE", "a\""]);
+ chk(r#"EXE "a"" a"#, &["EXE", "a\"", "a"]);
+ // quotes cannot be escaped in command names
+ chk(r#""EXE" check"#, &["EXE", "check"]);
+ chk(r#""EXE check""#, &["EXE check"]);
+ chk(r#""EXE """for""" check"#, &["EXE ", r#"for""#, "check"]);
+ chk(r#""EXE \"for\" check"#, &[r#"EXE \"#, r#"for""#, "check"]);
+ }
+}
diff --git a/src/libstd/sys/windows/backtrace/backtrace_gnu.rs b/src/libstd/sys/windows/backtrace/backtrace_gnu.rs
new file mode 100644
index 0000000..7ac1f81
--- /dev/null
+++ b/src/libstd/sys/windows/backtrace/backtrace_gnu.rs
@@ -0,0 +1,53 @@
+use crate::io;
+use crate::sys::c;
+use crate::path::PathBuf;
+use crate::fs::{OpenOptions, File};
+use crate::sys::ext::fs::OpenOptionsExt;
+use crate::sys::handle::Handle;
+
+use libc::c_char;
+use super::super::{fill_utf16_buf, os2path, to_u16s, wide_char_to_multi_byte};
+
+fn query_full_process_image_name() -> io::Result<PathBuf> {
+ unsafe {
+ let process_handle = Handle::new(c::OpenProcess(c::PROCESS_QUERY_INFORMATION,
+ c::FALSE,
+ c::GetCurrentProcessId()));
+ fill_utf16_buf(|buf, mut sz| {
+ if c::QueryFullProcessImageNameW(process_handle.raw(), 0, buf, &mut sz) == 0 {
+ 0
+ } else {
+ sz
+ }
+ }, os2path)
+ }
+}
+
+fn lock_and_get_executable_filename() -> io::Result<(PathBuf, File)> {
+ // We query the current image name, open the file without FILE_SHARE_DELETE so it
+ // can't be moved and then get the current image name again. If the names are the
+ // same than we have successfully locked the file
+ let image_name1 = query_full_process_image_name()?;
+ let file = OpenOptions::new()
+ .read(true)
+ .share_mode(c::FILE_SHARE_READ | c::FILE_SHARE_WRITE)
+ .open(&image_name1)?;
+ let image_name2 = query_full_process_image_name()?;
+
+ if image_name1 != image_name2 {
+ return Err(io::Error::new(io::ErrorKind::Other,
+ "executable moved while trying to lock it"));
+ }
+
+ Ok((image_name1, file))
+}
+
+// Get the executable filename for libbacktrace
+// This returns the path in the ANSI code page and a File which should remain open
+// for as long as the path should remain valid
+pub fn get_executable_filename() -> io::Result<(Vec<c_char>, File)> {
+ let (executable, file) = lock_and_get_executable_filename()?;
+ let u16_executable = to_u16s(executable.into_os_string())?;
+ Ok((wide_char_to_multi_byte(c::CP_ACP, c::WC_NO_BEST_FIT_CHARS,
+ &u16_executable, true)?, file))
+}
diff --git a/src/libstd/sys/windows/backtrace/mod.rs b/src/libstd/sys/windows/backtrace/mod.rs
new file mode 100644
index 0000000..c5b0cc8
--- /dev/null
+++ b/src/libstd/sys/windows/backtrace/mod.rs
@@ -0,0 +1,355 @@
+//! As always, windows has something very different than unix, we mainly want
+//! to avoid having to depend too much on libunwind for windows.
+//!
+//! If you google around, you'll find a fair bit of references to built-in
+//! functions to get backtraces on windows. It turns out that most of these are
+//! in an external library called dbghelp. I was unable to find this library
+//! via `-ldbghelp`, but it is apparently normal to do the `dlopen` equivalent
+//! of it.
+//!
+//! You'll also find that there's a function called CaptureStackBackTrace
+//! mentioned frequently (which is also easy to use), but sadly I didn't have a
+//! copy of that function in my mingw install (maybe it was broken?). Instead,
+//! this takes the route of using StackWalk64 in order to walk the stack.
+
+#![allow(deprecated)] // dynamic_lib
+
+use crate::io;
+use crate::mem;
+use crate::ptr;
+use crate::sys::c;
+use crate::sys::dynamic_lib::DynamicLibrary;
+use crate::sys_common::backtrace::Frame;
+
+use libc::c_void;
+
+macro_rules! sym {
+ ($lib:expr, $e:expr, $t:ident) => (
+ $lib.symbol($e).map(|f| unsafe {
+ $crate::mem::transmute::<usize, $t>(f)
+ })
+ )
+}
+
+mod printing;
+
+#[cfg(target_env = "gnu")]
+#[path = "backtrace_gnu.rs"]
+pub mod gnu;
+
+pub use self::printing::{foreach_symbol_fileline, resolve_symname};
+use self::printing::{load_printing_fns_64, load_printing_fns_ex};
+
+pub fn unwind_backtrace(frames: &mut [Frame]) -> io::Result<(usize, BacktraceContext)> {
+ let dbghelp = DynamicLibrary::open("dbghelp.dll")?;
+
+ // Fetch the symbols necessary from dbghelp.dll
+ let SymInitialize = sym!(dbghelp, "SymInitialize", SymInitializeFn)?;
+ let SymCleanup = sym!(dbghelp, "SymCleanup", SymCleanupFn)?;
+
+ // StackWalkEx might not be present and we'll fall back to StackWalk64
+ let sw_var = match sym!(dbghelp, "StackWalkEx", StackWalkExFn) {
+ Ok(StackWalkEx) => {
+ StackWalkVariant::StackWalkEx(StackWalkEx, load_printing_fns_ex(&dbghelp)?)
+ }
+ Err(e) => match sym!(dbghelp, "StackWalk64", StackWalk64Fn) {
+ Ok(StackWalk64) => {
+ StackWalkVariant::StackWalk64(StackWalk64, load_printing_fns_64(&dbghelp)?)
+ }
+ Err(..) => return Err(e),
+ },
+ };
+
+ // Allocate necessary structures for doing the stack walk
+ let process = unsafe { c::GetCurrentProcess() };
+
+ let backtrace_context = BacktraceContext {
+ handle: process,
+ SymCleanup,
+ StackWalkVariant: sw_var,
+ dbghelp,
+ };
+
+ // Initialize this process's symbols
+ let ret = unsafe { SymInitialize(process, ptr::null_mut(), c::TRUE) };
+ if ret != c::TRUE {
+ return Ok((0, backtrace_context));
+ }
+
+ // 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;
+ while i < frames.len()
+ && StackWalk.walk(image, process, thread, &mut frame, &mut context) == c::TRUE
+ {
+ let addr = frame.get_addr();
+ frames[i] = Frame {
+ symbol_addr: addr,
+ exact_position: addr,
+ inline_context: frame.get_inline_context(),
+ };
+
+ i += 1
+ }
+ Ok(i)
+}
+
+type SymInitializeFn = unsafe extern "system" fn(c::HANDLE, *mut c_void, c::BOOL) -> c::BOOL;
+type SymCleanupFn = unsafe extern "system" fn(c::HANDLE) -> c::BOOL;
+
+type StackWalkExFn = unsafe extern "system" fn(
+ c::DWORD,
+ c::HANDLE,
+ c::HANDLE,
+ *mut c::STACKFRAME_EX,
+ *mut c::CONTEXT,
+ *mut c_void,
+ *mut c_void,
+ *mut c_void,
+ *mut c_void,
+ c::DWORD,
+) -> c::BOOL;
+
+type StackWalk64Fn = unsafe extern "system" fn(
+ c::DWORD,
+ c::HANDLE,
+ c::HANDLE,
+ *mut c::STACKFRAME64,
+ *mut c::CONTEXT,
+ *mut c_void,
+ *mut c_void,
+ *mut c_void,
+ *mut c_void,
+) -> c::BOOL;
+
+trait StackWalker {
+ type Item: StackFrame;
+
+ fn walk(
+ &self,
+ _: c::DWORD,
+ _: c::HANDLE,
+ _: c::HANDLE,
+ _: &mut Self::Item,
+ _: &mut c::CONTEXT
+ ) -> c::BOOL;
+}
+
+impl StackWalker for StackWalkExFn {
+ type Item = c::STACKFRAME_EX;
+ fn walk(
+ &self,
+ image: c::DWORD,
+ process: c::HANDLE,
+ thread: c::HANDLE,
+ frame: &mut Self::Item,
+ context: &mut c::CONTEXT,
+ ) -> c::BOOL {
+ unsafe {
+ self(
+ image,
+ process,
+ thread,
+ frame,
+ context,
+ ptr::null_mut(),
+ ptr::null_mut(),
+ ptr::null_mut(),
+ ptr::null_mut(),
+ 0,
+ )
+ }
+ }
+}
+
+impl StackWalker for StackWalk64Fn {
+ type Item = c::STACKFRAME64;
+ fn walk(
+ &self,
+ image: c::DWORD,
+ process: c::HANDLE,
+ thread: c::HANDLE,
+ frame: &mut Self::Item,
+ context: &mut c::CONTEXT,
+ ) -> c::BOOL {
+ unsafe {
+ self(
+ image,
+ process,
+ thread,
+ frame,
+ context,
+ ptr::null_mut(),
+ ptr::null_mut(),
+ ptr::null_mut(),
+ ptr::null_mut(),
+ )
+ }
+ }
+}
+
+trait StackFrame {
+ fn new() -> Self;
+ fn init(&mut self, ctx: &c::CONTEXT) -> c::DWORD;
+ fn get_addr(&self) -> *const u8;
+ fn get_inline_context(&self) -> u32;
+}
+
+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 = "arm")]
+ 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.R11 as u64;
+ self.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat;
+ c::IMAGE_FILE_MACHINE_ARMNT
+ }
+
+ #[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
+ }
+
+ fn get_inline_context(&self) -> u32 {
+ self.InlineFrameContext
+ }
+}
+
+impl StackFrame for c::STACKFRAME64 {
+ fn new() -> c::STACKFRAME64 {
+ unsafe { mem::zeroed() }
+ }
+
+ #[cfg(target_arch = "x86")]
+ fn init(&mut self, ctx: &c::CONTEXT) -> c::DWORD {
+ self.AddrPC.Offset = ctx.Eip as u64;
+ self.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat;
+ self.AddrStack.Offset = ctx.Esp as u64;
+ self.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat;
+ self.AddrFrame.Offset = ctx.Ebp as u64;
+ self.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat;
+ c::IMAGE_FILE_MACHINE_I386
+ }
+
+ #[cfg(target_arch = "x86_64")]
+ fn init(&mut self, ctx: &c::CONTEXT) -> c::DWORD {
+ self.AddrPC.Offset = ctx.Rip as u64;
+ self.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat;
+ self.AddrStack.Offset = ctx.Rsp as u64;
+ self.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat;
+ self.AddrFrame.Offset = ctx.Rbp as u64;
+ self.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat;
+ c::IMAGE_FILE_MACHINE_AMD64
+ }
+
+ #[cfg(target_arch = "arm")]
+ 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.R11 as u64;
+ self.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat;
+ c::IMAGE_FILE_MACHINE_ARMNT
+ }
+
+ #[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
+ }
+
+ fn get_inline_context(&self) -> u32 {
+ 0
+ }
+}
+
+enum StackWalkVariant {
+ StackWalkEx(StackWalkExFn, printing::PrintingFnsEx),
+ StackWalk64(StackWalk64Fn, printing::PrintingFns64),
+}
+
+pub struct BacktraceContext {
+ handle: c::HANDLE,
+ SymCleanup: SymCleanupFn,
+ // Only used in printing for msvc and not gnu
+ // The gnu version is effectively a ZST dummy.
+ #[allow(dead_code)]
+ StackWalkVariant: StackWalkVariant,
+ // keeping DynamycLibrary loaded until its functions no longer needed
+ #[allow(dead_code)]
+ dbghelp: DynamicLibrary,
+}
+
+impl Drop for BacktraceContext {
+ fn drop(&mut self) {
+ unsafe {
+ (self.SymCleanup)(self.handle);
+ }
+ }
+}
diff --git a/src/libstd/sys/windows/backtrace/printing/mod.rs b/src/libstd/sys/windows/backtrace/printing/mod.rs
new file mode 100644
index 0000000..9497d51
--- /dev/null
+++ b/src/libstd/sys/windows/backtrace/printing/mod.rs
@@ -0,0 +1,24 @@
+#[cfg(target_env = "msvc")]
+#[path = "msvc.rs"]
+mod printing;
+
+#[cfg(target_env = "gnu")]
+mod printing {
+ pub use crate::sys_common::gnu::libbacktrace::{foreach_symbol_fileline, resolve_symname};
+
+ // dummy functions to mirror those present in msvc version.
+ use crate::sys::dynamic_lib::DynamicLibrary;
+ use crate::io;
+ pub struct PrintingFnsEx {}
+ pub struct PrintingFns64 {}
+ pub fn load_printing_fns_ex(_: &DynamicLibrary) -> io::Result<PrintingFnsEx> {
+ Ok(PrintingFnsEx{})
+ }
+ pub fn load_printing_fns_64(_: &DynamicLibrary) -> io::Result<PrintingFns64> {
+ Ok(PrintingFns64{})
+ }
+}
+
+pub use self::printing::{foreach_symbol_fileline, resolve_symname};
+pub use self::printing::{load_printing_fns_ex, load_printing_fns_64,
+ PrintingFnsEx, PrintingFns64};
diff --git a/src/libstd/sys/windows/backtrace/printing/msvc.rs b/src/libstd/sys/windows/backtrace/printing/msvc.rs
new file mode 100644
index 0000000..13a1512
--- /dev/null
+++ b/src/libstd/sys/windows/backtrace/printing/msvc.rs
@@ -0,0 +1,208 @@
+use crate::ffi::CStr;
+use crate::io;
+use crate::mem;
+use crate::sys::backtrace::BacktraceContext;
+use crate::sys::backtrace::StackWalkVariant;
+use crate::sys::c;
+use crate::sys::dynamic_lib::DynamicLibrary;
+use crate::sys_common::backtrace::Frame;
+
+use libc::{c_char, c_ulong};
+
+// Structs holding printing functions and loaders for them
+// Two versions depending on whether dbghelp.dll has StackWalkEx or not
+// (the former being in newer Windows versions, the older being in Win7 and before)
+pub struct PrintingFnsEx {
+ resolve_symname: SymFromInlineContextFn,
+ sym_get_line: SymGetLineFromInlineContextFn,
+}
+pub struct PrintingFns64 {
+ resolve_symname: SymFromAddrFn,
+ sym_get_line: SymGetLineFromAddr64Fn,
+}
+
+pub fn load_printing_fns_ex(dbghelp: &DynamicLibrary) -> io::Result<PrintingFnsEx> {
+ Ok(PrintingFnsEx {
+ resolve_symname: sym!(dbghelp, "SymFromInlineContext", SymFromInlineContextFn)?,
+ sym_get_line: sym!(
+ dbghelp,
+ "SymGetLineFromInlineContext",
+ SymGetLineFromInlineContextFn
+ )?,
+ })
+}
+pub fn load_printing_fns_64(dbghelp: &DynamicLibrary) -> io::Result<PrintingFns64> {
+ Ok(PrintingFns64 {
+ resolve_symname: sym!(dbghelp, "SymFromAddr", SymFromAddrFn)?,
+ sym_get_line: sym!(dbghelp, "SymGetLineFromAddr64", SymGetLineFromAddr64Fn)?,
+ })
+}
+
+type SymFromAddrFn =
+ unsafe extern "system" fn(c::HANDLE, u64, *mut u64, *mut c::SYMBOL_INFO) -> c::BOOL;
+type SymFromInlineContextFn =
+ unsafe extern "system" fn(c::HANDLE, u64, c::ULONG, *mut u64, *mut c::SYMBOL_INFO) -> c::BOOL;
+
+type SymGetLineFromAddr64Fn =
+ unsafe extern "system" fn(c::HANDLE, u64, *mut u32, *mut c::IMAGEHLP_LINE64) -> c::BOOL;
+type SymGetLineFromInlineContextFn = unsafe extern "system" fn(
+ c::HANDLE,
+ u64,
+ c::ULONG,
+ u64,
+ *mut c::DWORD,
+ *mut c::IMAGEHLP_LINE64,
+) -> c::BOOL;
+
+/// Converts a pointer to symbol to its string value.
+pub fn resolve_symname<F>(frame: Frame, callback: F, context: &BacktraceContext) -> io::Result<()>
+where
+ F: FnOnce(Option<&str>) -> io::Result<()>,
+{
+ match context.StackWalkVariant {
+ StackWalkVariant::StackWalkEx(_, ref fns) => resolve_symname_internal(
+ |process: c::HANDLE,
+ symbol_address: u64,
+ inline_context: c::ULONG,
+ info: *mut c::SYMBOL_INFO| unsafe {
+ let mut displacement = 0u64;
+ (fns.resolve_symname)(
+ process,
+ symbol_address,
+ inline_context,
+ &mut displacement,
+ info,
+ )
+ },
+ frame,
+ callback,
+ context,
+ ),
+ StackWalkVariant::StackWalk64(_, ref fns) => resolve_symname_internal(
+ |process: c::HANDLE,
+ symbol_address: u64,
+ _inline_context: c::ULONG,
+ info: *mut c::SYMBOL_INFO| unsafe {
+ let mut displacement = 0u64;
+ (fns.resolve_symname)(process, symbol_address, &mut displacement, info)
+ },
+ frame,
+ callback,
+ context,
+ ),
+ }
+}
+
+fn resolve_symname_internal<F, R>(
+ mut symbol_resolver: R,
+ frame: Frame,
+ callback: F,
+ context: &BacktraceContext,
+) -> io::Result<()>
+where
+ F: FnOnce(Option<&str>) -> io::Result<()>,
+ R: FnMut(c::HANDLE, u64, c::ULONG, *mut c::SYMBOL_INFO) -> c::BOOL,
+{
+ unsafe {
+ let mut info: c::SYMBOL_INFO = mem::zeroed();
+ info.MaxNameLen = c::MAX_SYM_NAME as c_ulong;
+ // the struct size in C. the value is different to
+ // `size_of::<SYMBOL_INFO>() - MAX_SYM_NAME + 1` (== 81)
+ // due to struct alignment.
+ info.SizeOfStruct = 88;
+
+ let ret = symbol_resolver(
+ context.handle,
+ frame.symbol_addr as u64,
+ frame.inline_context,
+ &mut info,
+ );
+ let valid_range = if ret == c::TRUE && frame.symbol_addr as usize >= info.Address as usize {
+ if info.Size != 0 {
+ (frame.symbol_addr as usize) < info.Address as usize + info.Size as usize
+ } else {
+ true
+ }
+ } else {
+ false
+ };
+ let symname = if valid_range {
+ let ptr = info.Name.as_ptr() as *const c_char;
+ CStr::from_ptr(ptr).to_str().ok()
+ } else {
+ None
+ };
+ callback(symname)
+ }
+}
+
+pub fn foreach_symbol_fileline<F>(
+ frame: Frame,
+ callback: F,
+ context: &BacktraceContext,
+) -> io::Result<bool>
+where
+ F: FnMut(&[u8], u32) -> io::Result<()>,
+{
+ match context.StackWalkVariant {
+ StackWalkVariant::StackWalkEx(_, ref fns) => foreach_symbol_fileline_iternal(
+ |process: c::HANDLE,
+ frame_address: u64,
+ inline_context: c::ULONG,
+ line: *mut c::IMAGEHLP_LINE64| unsafe {
+ let mut displacement = 0u32;
+ (fns.sym_get_line)(
+ process,
+ frame_address,
+ inline_context,
+ 0,
+ &mut displacement,
+ line,
+ )
+ },
+ frame,
+ callback,
+ context,
+ ),
+ StackWalkVariant::StackWalk64(_, ref fns) => foreach_symbol_fileline_iternal(
+ |process: c::HANDLE,
+ frame_address: u64,
+ _inline_context: c::ULONG,
+ line: *mut c::IMAGEHLP_LINE64| unsafe {
+ let mut displacement = 0u32;
+ (fns.sym_get_line)(process, frame_address, &mut displacement, line)
+ },
+ frame,
+ callback,
+ context,
+ ),
+ }
+}
+
+fn foreach_symbol_fileline_iternal<F, G>(
+ mut line_getter: G,
+ frame: Frame,
+ mut callback: F,
+ context: &BacktraceContext,
+) -> io::Result<bool>
+where
+ F: FnMut(&[u8], u32) -> io::Result<()>,
+ G: FnMut(c::HANDLE, u64, c::ULONG, *mut c::IMAGEHLP_LINE64) -> c::BOOL,
+{
+ unsafe {
+ let mut line: c::IMAGEHLP_LINE64 = mem::zeroed();
+ line.SizeOfStruct = mem::size_of::<c::IMAGEHLP_LINE64>() as u32;
+
+ let ret = line_getter(
+ context.handle,
+ frame.exact_position as u64,
+ frame.inline_context,
+ &mut line,
+ );
+ if ret == c::TRUE {
+ let name = CStr::from_ptr(line.Filename).to_bytes();
+ callback(name, line.LineNumber as u32)?;
+ }
+ Ok(false)
+ }
+}
diff --git a/src/libstd/sys/windows/c.rs b/src/libstd/sys/windows/c.rs
new file mode 100644
index 0000000..518eccf
--- /dev/null
+++ b/src/libstd/sys/windows/c.rs
@@ -0,0 +1,1394 @@
+//! C definitions used by libnative that don't belong in liblibc
+
+#![allow(nonstandard_style)]
+#![cfg_attr(test, allow(dead_code))]
+#![unstable(issue = "0", feature = "windows_c")]
+
+use crate::os::raw::{c_int, c_uint, c_ulong, c_long, c_longlong, c_ushort, c_char};
+#[cfg(target_arch = "x86_64")]
+use crate::os::raw::c_ulonglong;
+use crate::ptr;
+
+use libc::{wchar_t, size_t, c_void};
+
+pub use self::FILE_INFO_BY_HANDLE_CLASS::*;
+pub use self::EXCEPTION_DISPOSITION::*;
+
+pub type DWORD = c_ulong;
+pub type HANDLE = LPVOID;
+pub type HINSTANCE = HANDLE;
+pub type HMODULE = HINSTANCE;
+pub type HRESULT = LONG;
+pub type BOOL = c_int;
+pub type BYTE = u8;
+pub type BOOLEAN = BYTE;
+pub type GROUP = c_uint;
+pub type LARGE_INTEGER = c_longlong;
+pub type LONG = c_long;
+pub type UINT = c_uint;
+pub type WCHAR = u16;
+pub type USHORT = c_ushort;
+pub type SIZE_T = usize;
+pub type WORD = u16;
+pub type CHAR = c_char;
+pub type ULONG_PTR = usize;
+pub type ULONG = c_ulong;
+#[cfg(target_arch = "x86_64")]
+pub type ULONGLONG = u64;
+#[cfg(target_arch = "x86_64")]
+pub type DWORDLONG = ULONGLONG;
+
+pub type LPBOOL = *mut BOOL;
+pub type LPBYTE = *mut BYTE;
+pub type LPBY_HANDLE_FILE_INFORMATION = *mut BY_HANDLE_FILE_INFORMATION;
+pub type LPCSTR = *const CHAR;
+pub type LPCVOID = *const c_void;
+pub type LPCWSTR = *const WCHAR;
+pub type LPDWORD = *mut DWORD;
+pub type LPHANDLE = *mut HANDLE;
+pub type LPOVERLAPPED = *mut OVERLAPPED;
+pub type LPPROCESS_INFORMATION = *mut PROCESS_INFORMATION;
+pub type LPSECURITY_ATTRIBUTES = *mut SECURITY_ATTRIBUTES;
+pub type LPSTARTUPINFO = *mut STARTUPINFO;
+pub type LPVOID = *mut c_void;
+pub type LPWCH = *mut WCHAR;
+pub type LPWIN32_FIND_DATAW = *mut WIN32_FIND_DATAW;
+pub type LPWSADATA = *mut WSADATA;
+pub type LPWSAPROTOCOL_INFO = *mut WSAPROTOCOL_INFO;
+pub type LPSTR = *mut CHAR;
+pub type LPWSTR = *mut WCHAR;
+pub type LPFILETIME = *mut FILETIME;
+pub type LPWSABUF = *mut WSABUF;
+pub type LPWSAOVERLAPPED = *mut c_void;
+pub type LPWSAOVERLAPPED_COMPLETION_ROUTINE = *mut c_void;
+
+pub type PCONDITION_VARIABLE = *mut CONDITION_VARIABLE;
+pub type PLARGE_INTEGER = *mut c_longlong;
+pub type PSRWLOCK = *mut SRWLOCK;
+
+pub type SOCKET = crate::os::windows::raw::SOCKET;
+pub type socklen_t = c_int;
+pub type ADDRESS_FAMILY = USHORT;
+
+pub const TRUE: BOOL = 1;
+pub const FALSE: BOOL = 0;
+
+pub const FILE_ATTRIBUTE_READONLY: DWORD = 0x1;
+pub const FILE_ATTRIBUTE_DIRECTORY: DWORD = 0x10;
+pub const FILE_ATTRIBUTE_REPARSE_POINT: DWORD = 0x400;
+
+pub const FILE_SHARE_DELETE: DWORD = 0x4;
+pub const FILE_SHARE_READ: DWORD = 0x1;
+pub const FILE_SHARE_WRITE: DWORD = 0x2;
+
+pub const CREATE_ALWAYS: DWORD = 2;
+pub const CREATE_NEW: DWORD = 1;
+pub const OPEN_ALWAYS: DWORD = 4;
+pub const OPEN_EXISTING: DWORD = 3;
+pub const TRUNCATE_EXISTING: DWORD = 5;
+
+pub const FILE_WRITE_DATA: DWORD = 0x00000002;
+pub const FILE_APPEND_DATA: DWORD = 0x00000004;
+pub const FILE_WRITE_EA: DWORD = 0x00000010;
+pub const FILE_WRITE_ATTRIBUTES: DWORD = 0x00000100;
+pub const READ_CONTROL: DWORD = 0x00020000;
+pub const SYNCHRONIZE: DWORD = 0x00100000;
+pub const GENERIC_READ: DWORD = 0x80000000;
+pub const GENERIC_WRITE: DWORD = 0x40000000;
+pub const STANDARD_RIGHTS_WRITE: DWORD = READ_CONTROL;
+pub const FILE_GENERIC_WRITE: DWORD = STANDARD_RIGHTS_WRITE | FILE_WRITE_DATA |
+ FILE_WRITE_ATTRIBUTES |
+ FILE_WRITE_EA |
+ FILE_APPEND_DATA |
+ SYNCHRONIZE;
+
+pub const FILE_FLAG_OPEN_REPARSE_POINT: DWORD = 0x00200000;
+pub const FILE_FLAG_BACKUP_SEMANTICS: DWORD = 0x02000000;
+pub const SECURITY_SQOS_PRESENT: DWORD = 0x00100000;
+
+pub const FIONBIO: c_ulong = 0x8004667e;
+
+#[cfg(target_arch = "arm")]
+const ARM_MAX_BREAKPOINTS: usize = 8;
+#[cfg(target_arch = "arm")]
+const ARM_MAX_WATCHPOINTS: usize = 1;
+
+#[repr(C)]
+#[derive(Copy)]
+pub struct WIN32_FIND_DATAW {
+ pub dwFileAttributes: DWORD,
+ pub ftCreationTime: FILETIME,
+ pub ftLastAccessTime: FILETIME,
+ pub ftLastWriteTime: FILETIME,
+ pub nFileSizeHigh: DWORD,
+ pub nFileSizeLow: DWORD,
+ pub dwReserved0: DWORD,
+ pub dwReserved1: DWORD,
+ pub cFileName: [wchar_t; 260], // #define MAX_PATH 260
+ pub cAlternateFileName: [wchar_t; 14],
+}
+impl Clone for WIN32_FIND_DATAW {
+ fn clone(&self) -> Self { *self }
+}
+
+pub const WSA_FLAG_OVERLAPPED: DWORD = 0x01;
+
+pub const WSADESCRIPTION_LEN: usize = 256;
+pub const WSASYS_STATUS_LEN: usize = 128;
+pub const WSAPROTOCOL_LEN: DWORD = 255;
+pub const INVALID_SOCKET: SOCKET = !0;
+
+pub const WSAEACCES: c_int = 10013;
+pub const WSAEINVAL: c_int = 10022;
+pub const WSAEWOULDBLOCK: c_int = 10035;
+pub const WSAEADDRINUSE: c_int = 10048;
+pub const WSAEADDRNOTAVAIL: c_int = 10049;
+pub const WSAECONNABORTED: c_int = 10053;
+pub const WSAECONNRESET: c_int = 10054;
+pub const WSAENOTCONN: c_int = 10057;
+pub const WSAESHUTDOWN: c_int = 10058;
+pub const WSAETIMEDOUT: c_int = 10060;
+pub const WSAECONNREFUSED: c_int = 10061;
+
+pub const MAX_PROTOCOL_CHAIN: DWORD = 7;
+
+pub const TOKEN_READ: DWORD = 0x20008;
+pub const MAXIMUM_REPARSE_DATA_BUFFER_SIZE: usize = 16 * 1024;
+pub const FSCTL_GET_REPARSE_POINT: DWORD = 0x900a8;
+pub const IO_REPARSE_TAG_SYMLINK: DWORD = 0xa000000c;
+pub const IO_REPARSE_TAG_MOUNT_POINT: DWORD = 0xa0000003;
+pub const SYMLINK_FLAG_RELATIVE: DWORD = 0x00000001;
+pub const FSCTL_SET_REPARSE_POINT: DWORD = 0x900a4;
+
+pub const SYMBOLIC_LINK_FLAG_DIRECTORY: DWORD = 0x1;
+pub const SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE: DWORD = 0x2;
+
+// Note that these are not actually HANDLEs, just values to pass to GetStdHandle
+pub const STD_INPUT_HANDLE: DWORD = -10i32 as DWORD;
+pub const STD_OUTPUT_HANDLE: DWORD = -11i32 as DWORD;
+pub const STD_ERROR_HANDLE: DWORD = -12i32 as DWORD;
+
+pub const HANDLE_FLAG_INHERIT: DWORD = 0x00000001;
+
+pub const PROGRESS_CONTINUE: DWORD = 0;
+
+pub const ERROR_FILE_NOT_FOUND: DWORD = 2;
+pub const ERROR_PATH_NOT_FOUND: DWORD = 3;
+pub const ERROR_ACCESS_DENIED: DWORD = 5;
+pub const ERROR_INVALID_HANDLE: DWORD = 6;
+pub const ERROR_NO_MORE_FILES: DWORD = 18;
+pub const ERROR_HANDLE_EOF: DWORD = 38;
+pub const ERROR_FILE_EXISTS: DWORD = 80;
+pub const ERROR_INVALID_PARAMETER: DWORD = 87;
+pub const ERROR_BROKEN_PIPE: DWORD = 109;
+pub const ERROR_CALL_NOT_IMPLEMENTED: DWORD = 120;
+pub const ERROR_INSUFFICIENT_BUFFER: DWORD = 122;
+pub const ERROR_ALREADY_EXISTS: DWORD = 183;
+pub const ERROR_NO_DATA: DWORD = 232;
+pub const ERROR_ENVVAR_NOT_FOUND: DWORD = 203;
+pub const ERROR_OPERATION_ABORTED: DWORD = 995;
+pub const ERROR_IO_PENDING: DWORD = 997;
+pub const ERROR_TIMEOUT: DWORD = 0x5B4;
+
+pub const E_NOTIMPL: HRESULT = 0x80004001u32 as HRESULT;
+
+pub const INVALID_HANDLE_VALUE: HANDLE = !0 as HANDLE;
+
+pub const FACILITY_NT_BIT: DWORD = 0x1000_0000;
+
+pub const FORMAT_MESSAGE_FROM_SYSTEM: DWORD = 0x00001000;
+pub const FORMAT_MESSAGE_FROM_HMODULE: DWORD = 0x00000800;
+pub const FORMAT_MESSAGE_IGNORE_INSERTS: DWORD = 0x00000200;
+
+pub const TLS_OUT_OF_INDEXES: DWORD = 0xFFFFFFFF;
+
+pub const DLL_THREAD_DETACH: DWORD = 3;
+pub const DLL_PROCESS_DETACH: DWORD = 0;
+
+pub const INFINITE: DWORD = !0;
+
+pub const DUPLICATE_SAME_ACCESS: DWORD = 0x00000002;
+
+pub const CONDITION_VARIABLE_INIT: CONDITION_VARIABLE = CONDITION_VARIABLE {
+ ptr: ptr::null_mut(),
+};
+pub const SRWLOCK_INIT: SRWLOCK = SRWLOCK { ptr: ptr::null_mut() };
+
+pub const DETACHED_PROCESS: DWORD = 0x00000008;
+pub const CREATE_NEW_PROCESS_GROUP: DWORD = 0x00000200;
+pub const CREATE_UNICODE_ENVIRONMENT: DWORD = 0x00000400;
+pub const STARTF_USESTDHANDLES: DWORD = 0x00000100;
+
+pub const AF_INET: c_int = 2;
+pub const AF_INET6: c_int = 23;
+pub const SD_BOTH: c_int = 2;
+pub const SD_RECEIVE: c_int = 0;
+pub const SD_SEND: c_int = 1;
+pub const SOCK_DGRAM: c_int = 2;
+pub const SOCK_STREAM: c_int = 1;
+pub const SOL_SOCKET: c_int = 0xffff;
+pub const SO_RCVTIMEO: c_int = 0x1006;
+pub const SO_SNDTIMEO: c_int = 0x1005;
+pub const SO_REUSEADDR: c_int = 0x0004;
+pub const IPPROTO_IP: c_int = 0;
+pub const IPPROTO_TCP: c_int = 6;
+pub const IPPROTO_IPV6: c_int = 41;
+pub const TCP_NODELAY: c_int = 0x0001;
+pub const IP_TTL: c_int = 4;
+pub const IPV6_V6ONLY: c_int = 27;
+pub const SO_ERROR: c_int = 0x1007;
+pub const SO_BROADCAST: c_int = 0x0020;
+pub const IP_MULTICAST_LOOP: c_int = 11;
+pub const IPV6_MULTICAST_LOOP: c_int = 11;
+pub const IP_MULTICAST_TTL: c_int = 10;
+pub const IP_ADD_MEMBERSHIP: c_int = 12;
+pub const IP_DROP_MEMBERSHIP: c_int = 13;
+pub const IPV6_ADD_MEMBERSHIP: c_int = 12;
+pub const IPV6_DROP_MEMBERSHIP: c_int = 13;
+pub const MSG_PEEK: c_int = 0x2;
+
+#[repr(C)]
+pub struct ip_mreq {
+ pub imr_multiaddr: in_addr,
+ pub imr_interface: in_addr,
+}
+
+#[repr(C)]
+pub struct ipv6_mreq {
+ pub ipv6mr_multiaddr: in6_addr,
+ pub ipv6mr_interface: c_uint,
+}
+
+pub const VOLUME_NAME_DOS: DWORD = 0x0;
+pub const MOVEFILE_REPLACE_EXISTING: DWORD = 1;
+
+pub const FILE_BEGIN: DWORD = 0;
+pub const FILE_CURRENT: DWORD = 1;
+pub const FILE_END: DWORD = 2;
+
+pub const WAIT_OBJECT_0: DWORD = 0x00000000;
+pub const WAIT_TIMEOUT: DWORD = 258;
+pub const WAIT_FAILED: DWORD = 0xFFFFFFFF;
+
+#[cfg(target_env = "msvc")]
+#[cfg(feature = "backtrace")]
+pub const MAX_SYM_NAME: usize = 2000;
+#[cfg(target_arch = "x86")]
+#[cfg(feature = "backtrace")]
+pub const IMAGE_FILE_MACHINE_I386: DWORD = 0x014c;
+#[cfg(target_arch = "x86_64")]
+#[cfg(feature = "backtrace")]
+pub const IMAGE_FILE_MACHINE_AMD64: DWORD = 0x8664;
+#[cfg(target_arch = "aarch64")]
+#[cfg(feature = "backtrace")]
+pub const IMAGE_FILE_MACHINE_ARM64: DWORD = 0xAA64;
+#[cfg(target_arch = "arm")]
+#[cfg(feature = "backtrace")]
+pub const IMAGE_FILE_MACHINE_ARMNT: DWORD = 0x01c4;
+
+pub const EXCEPTION_CONTINUE_SEARCH: LONG = 0;
+pub const EXCEPTION_STACK_OVERFLOW: DWORD = 0xc00000fd;
+pub const EXCEPTION_MAXIMUM_PARAMETERS: usize = 15;
+
+pub const PIPE_ACCESS_INBOUND: DWORD = 0x00000001;
+pub const PIPE_ACCESS_OUTBOUND: DWORD = 0x00000002;
+pub const FILE_FLAG_FIRST_PIPE_INSTANCE: DWORD = 0x00080000;
+pub const FILE_FLAG_OVERLAPPED: DWORD = 0x40000000;
+pub const PIPE_WAIT: DWORD = 0x00000000;
+pub const PIPE_TYPE_BYTE: DWORD = 0x00000000;
+pub const PIPE_REJECT_REMOTE_CLIENTS: DWORD = 0x00000008;
+pub const PIPE_READMODE_BYTE: DWORD = 0x00000000;
+
+pub const FD_SETSIZE: usize = 64;
+
+pub const STACK_SIZE_PARAM_IS_A_RESERVATION: DWORD = 0x00010000;
+
+pub const HEAP_ZERO_MEMORY: DWORD = 0x00000008;
+
+#[repr(C)]
+#[cfg(not(target_pointer_width = "64"))]
+pub struct WSADATA {
+ pub wVersion: WORD,
+ pub wHighVersion: WORD,
+ pub szDescription: [u8; WSADESCRIPTION_LEN + 1],
+ pub szSystemStatus: [u8; WSASYS_STATUS_LEN + 1],
+ pub iMaxSockets: u16,
+ pub iMaxUdpDg: u16,
+ pub lpVendorInfo: *mut u8,
+}
+#[repr(C)]
+#[cfg(target_pointer_width = "64")]
+pub struct WSADATA {
+ pub wVersion: WORD,
+ pub wHighVersion: WORD,
+ pub iMaxSockets: u16,
+ pub iMaxUdpDg: u16,
+ pub lpVendorInfo: *mut u8,
+ pub szDescription: [u8; WSADESCRIPTION_LEN + 1],
+ pub szSystemStatus: [u8; WSASYS_STATUS_LEN + 1],
+}
+
+#[repr(C)]
+pub struct WSABUF {
+ pub len: ULONG,
+ pub buf: *mut CHAR,
+}
+
+#[repr(C)]
+pub struct WSAPROTOCOL_INFO {
+ pub dwServiceFlags1: DWORD,
+ pub dwServiceFlags2: DWORD,
+ pub dwServiceFlags3: DWORD,
+ pub dwServiceFlags4: DWORD,
+ pub dwProviderFlags: DWORD,
+ pub ProviderId: GUID,
+ pub dwCatalogEntryId: DWORD,
+ pub ProtocolChain: WSAPROTOCOLCHAIN,
+ pub iVersion: c_int,
+ pub iAddressFamily: c_int,
+ pub iMaxSockAddr: c_int,
+ pub iMinSockAddr: c_int,
+ pub iSocketType: c_int,
+ pub iProtocol: c_int,
+ pub iProtocolMaxOffset: c_int,
+ pub iNetworkByteOrder: c_int,
+ pub iSecurityScheme: c_int,
+ pub dwMessageSize: DWORD,
+ pub dwProviderReserved: DWORD,
+ pub szProtocol: [u16; (WSAPROTOCOL_LEN as usize) + 1],
+}
+
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct WIN32_FILE_ATTRIBUTE_DATA {
+ pub dwFileAttributes: DWORD,
+ pub ftCreationTime: FILETIME,
+ pub ftLastAccessTime: FILETIME,
+ pub ftLastWriteTime: FILETIME,
+ pub nFileSizeHigh: DWORD,
+ pub nFileSizeLow: DWORD,
+}
+
+#[repr(C)]
+pub struct BY_HANDLE_FILE_INFORMATION {
+ pub dwFileAttributes: DWORD,
+ pub ftCreationTime: FILETIME,
+ pub ftLastAccessTime: FILETIME,
+ pub ftLastWriteTime: FILETIME,
+ pub dwVolumeSerialNumber: DWORD,
+ pub nFileSizeHigh: DWORD,
+ pub nFileSizeLow: DWORD,
+ pub nNumberOfLinks: DWORD,
+ pub nFileIndexHigh: DWORD,
+ pub nFileIndexLow: DWORD,
+}
+
+#[repr(C)]
+#[allow(dead_code)] // we only use some variants
+pub enum FILE_INFO_BY_HANDLE_CLASS {
+ FileBasicInfo = 0,
+ FileStandardInfo = 1,
+ FileNameInfo = 2,
+ FileRenameInfo = 3,
+ FileDispositionInfo = 4,
+ FileAllocationInfo = 5,
+ FileEndOfFileInfo = 6,
+ FileStreamInfo = 7,
+ FileCompressionInfo = 8,
+ FileAttributeTagInfo = 9,
+ FileIdBothDirectoryInfo = 10, // 0xA
+ FileIdBothDirectoryRestartInfo = 11, // 0xB
+ FileIoPriorityHintInfo = 12, // 0xC
+ FileRemoteProtocolInfo = 13, // 0xD
+ FileFullDirectoryInfo = 14, // 0xE
+ FileFullDirectoryRestartInfo = 15, // 0xF
+ FileStorageInfo = 16, // 0x10
+ FileAlignmentInfo = 17, // 0x11
+ FileIdInfo = 18, // 0x12
+ FileIdExtdDirectoryInfo = 19, // 0x13
+ FileIdExtdDirectoryRestartInfo = 20, // 0x14
+ MaximumFileInfoByHandlesClass
+}
+
+#[repr(C)]
+pub struct FILE_BASIC_INFO {
+ pub CreationTime: LARGE_INTEGER,
+ pub LastAccessTime: LARGE_INTEGER,
+ pub LastWriteTime: LARGE_INTEGER,
+ pub ChangeTime: LARGE_INTEGER,
+ pub FileAttributes: DWORD,
+}
+
+#[repr(C)]
+pub struct FILE_END_OF_FILE_INFO {
+ pub EndOfFile: LARGE_INTEGER,
+}
+
+#[repr(C)]
+pub struct REPARSE_DATA_BUFFER {
+ pub ReparseTag: c_uint,
+ pub ReparseDataLength: c_ushort,
+ pub Reserved: c_ushort,
+ pub rest: (),
+}
+
+#[repr(C)]
+pub struct SYMBOLIC_LINK_REPARSE_BUFFER {
+ pub SubstituteNameOffset: c_ushort,
+ pub SubstituteNameLength: c_ushort,
+ pub PrintNameOffset: c_ushort,
+ pub PrintNameLength: c_ushort,
+ pub Flags: c_ulong,
+ pub PathBuffer: WCHAR,
+}
+
+#[repr(C)]
+pub struct MOUNT_POINT_REPARSE_BUFFER {
+ pub SubstituteNameOffset: c_ushort,
+ pub SubstituteNameLength: c_ushort,
+ pub PrintNameOffset: c_ushort,
+ pub PrintNameLength: c_ushort,
+ pub PathBuffer: WCHAR,
+}
+
+pub type LPPROGRESS_ROUTINE = crate::option::Option<unsafe extern "system" fn(
+ TotalFileSize: LARGE_INTEGER,
+ TotalBytesTransferred: LARGE_INTEGER,
+ StreamSize: LARGE_INTEGER,
+ StreamBytesTransferred: LARGE_INTEGER,
+ dwStreamNumber: DWORD,
+ dwCallbackReason: DWORD,
+ hSourceFile: HANDLE,
+ hDestinationFile: HANDLE,
+ lpData: LPVOID,
+) -> DWORD>;
+
+#[repr(C)]
+pub struct CONDITION_VARIABLE { pub ptr: LPVOID }
+#[repr(C)]
+pub struct SRWLOCK { pub ptr: LPVOID }
+#[repr(C)]
+pub struct CRITICAL_SECTION {
+ CriticalSectionDebug: LPVOID,
+ LockCount: LONG,
+ RecursionCount: LONG,
+ OwningThread: HANDLE,
+ LockSemaphore: HANDLE,
+ SpinCount: ULONG_PTR
+}
+
+#[repr(C)]
+pub struct REPARSE_MOUNTPOINT_DATA_BUFFER {
+ pub ReparseTag: DWORD,
+ pub ReparseDataLength: DWORD,
+ pub Reserved: WORD,
+ pub ReparseTargetLength: WORD,
+ pub ReparseTargetMaximumLength: WORD,
+ pub Reserved1: WORD,
+ pub ReparseTarget: WCHAR,
+}
+
+#[repr(C)]
+pub struct EXCEPTION_RECORD {
+ pub ExceptionCode: DWORD,
+ pub ExceptionFlags: DWORD,
+ pub ExceptionRecord: *mut EXCEPTION_RECORD,
+ pub ExceptionAddress: LPVOID,
+ pub NumberParameters: DWORD,
+ pub ExceptionInformation: [LPVOID; EXCEPTION_MAXIMUM_PARAMETERS]
+}
+
+#[repr(C)]
+pub struct EXCEPTION_POINTERS {
+ pub ExceptionRecord: *mut EXCEPTION_RECORD,
+ pub ContextRecord: *mut CONTEXT,
+}
+
+pub type PVECTORED_EXCEPTION_HANDLER = extern "system"
+ fn(ExceptionInfo: *mut EXCEPTION_POINTERS) -> LONG;
+
+#[repr(C)]
+pub struct GUID {
+ pub Data1: DWORD,
+ pub Data2: WORD,
+ pub Data3: WORD,
+ pub Data4: [BYTE; 8],
+}
+
+#[repr(C)]
+pub struct WSAPROTOCOLCHAIN {
+ pub ChainLen: c_int,
+ pub ChainEntries: [DWORD; MAX_PROTOCOL_CHAIN as usize],
+}
+
+#[repr(C)]
+pub struct SECURITY_ATTRIBUTES {
+ pub nLength: DWORD,
+ pub lpSecurityDescriptor: LPVOID,
+ pub bInheritHandle: BOOL,
+}
+
+#[repr(C)]
+pub struct PROCESS_INFORMATION {
+ pub hProcess: HANDLE,
+ pub hThread: HANDLE,
+ pub dwProcessId: DWORD,
+ pub dwThreadId: DWORD,
+}
+
+#[repr(C)]
+pub struct STARTUPINFO {
+ pub cb: DWORD,
+ pub lpReserved: LPWSTR,
+ pub lpDesktop: LPWSTR,
+ pub lpTitle: LPWSTR,
+ pub dwX: DWORD,
+ pub dwY: DWORD,
+ pub dwXSize: DWORD,
+ pub dwYSize: DWORD,
+ pub dwXCountChars: DWORD,
+ pub dwYCountCharts: DWORD,
+ pub dwFillAttribute: DWORD,
+ pub dwFlags: DWORD,
+ pub wShowWindow: WORD,
+ pub cbReserved2: WORD,
+ pub lpReserved2: LPBYTE,
+ pub hStdInput: HANDLE,
+ pub hStdOutput: HANDLE,
+ pub hStdError: HANDLE,
+}
+
+#[repr(C)]
+pub struct SOCKADDR {
+ pub sa_family: ADDRESS_FAMILY,
+ pub sa_data: [CHAR; 14],
+}
+
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct FILETIME {
+ pub dwLowDateTime: DWORD,
+ pub dwHighDateTime: DWORD,
+}
+
+#[repr(C)]
+pub struct OVERLAPPED {
+ pub Internal: *mut c_ulong,
+ pub InternalHigh: *mut c_ulong,
+ pub Offset: DWORD,
+ pub OffsetHigh: DWORD,
+ pub hEvent: HANDLE,
+}
+
+#[repr(C)]
+#[cfg(target_env = "msvc")]
+#[cfg(feature = "backtrace")]
+pub struct SYMBOL_INFO {
+ pub SizeOfStruct: c_ulong,
+ pub TypeIndex: c_ulong,
+ pub Reserved: [u64; 2],
+ pub Index: c_ulong,
+ pub Size: c_ulong,
+ pub ModBase: u64,
+ pub Flags: c_ulong,
+ pub Value: u64,
+ pub Address: u64,
+ pub Register: c_ulong,
+ pub Scope: c_ulong,
+ pub Tag: c_ulong,
+ pub NameLen: c_ulong,
+ pub MaxNameLen: c_ulong,
+ // note that windows has this as 1, but it basically just means that
+ // the name is inline at the end of the struct. For us, we just bump
+ // the struct size up to MAX_SYM_NAME.
+ pub Name: [c_char; MAX_SYM_NAME],
+}
+
+#[repr(C)]
+#[cfg(target_env = "msvc")]
+#[cfg(feature = "backtrace")]
+pub struct IMAGEHLP_LINE64 {
+ pub SizeOfStruct: u32,
+ pub Key: *const c_void,
+ pub LineNumber: u32,
+ pub Filename: *const c_char,
+ pub Address: u64,
+}
+
+#[repr(C)]
+#[allow(dead_code)] // we only use some variants
+pub enum ADDRESS_MODE {
+ AddrMode1616,
+ AddrMode1632,
+ AddrModeReal,
+ AddrModeFlat,
+}
+
+#[repr(C)]
+#[cfg(feature = "backtrace")]
+pub struct ADDRESS64 {
+ pub Offset: u64,
+ pub Segment: u16,
+ pub Mode: ADDRESS_MODE,
+}
+
+#[repr(C)]
+#[cfg(feature = "backtrace")]
+pub struct STACKFRAME_EX {
+ pub AddrPC: ADDRESS64,
+ pub AddrReturn: ADDRESS64,
+ pub AddrFrame: ADDRESS64,
+ pub AddrStack: ADDRESS64,
+ pub AddrBStore: ADDRESS64,
+ pub FuncTableEntry: *mut c_void,
+ pub Params: [u64; 4],
+ pub Far: BOOL,
+ pub Virtual: BOOL,
+ pub Reserved: [u64; 3],
+ pub KdHelp: KDHELP64,
+ pub StackFrameSize: DWORD,
+ pub InlineFrameContext: DWORD,
+}
+
+#[repr(C)]
+#[cfg(feature = "backtrace")]
+pub struct STACKFRAME64 {
+ pub AddrPC: ADDRESS64,
+ pub AddrReturn: ADDRESS64,
+ pub AddrFrame: ADDRESS64,
+ pub AddrStack: ADDRESS64,
+ pub AddrBStore: ADDRESS64,
+ pub FuncTableEntry: *mut c_void,
+ pub Params: [u64; 4],
+ pub Far: BOOL,
+ pub Virtual: BOOL,
+ pub Reserved: [u64; 3],
+ pub KdHelp: KDHELP64,
+}
+
+#[repr(C)]
+#[cfg(feature = "backtrace")]
+pub struct KDHELP64 {
+ pub Thread: u64,
+ pub ThCallbackStack: DWORD,
+ pub ThCallbackBStore: DWORD,
+ pub NextCallback: DWORD,
+ pub FramePointer: DWORD,
+ pub KiCallUserMode: u64,
+ pub KeUserCallbackDispatcher: u64,
+ pub SystemRangeStart: u64,
+ pub KiUserExceptionDispatcher: u64,
+ pub StackBase: u64,
+ pub StackLimit: u64,
+ pub Reserved: [u64; 5],
+}
+
+#[cfg(target_arch = "x86")]
+#[repr(C)]
+pub struct CONTEXT {
+ pub ContextFlags: DWORD,
+ pub Dr0: DWORD,
+ pub Dr1: DWORD,
+ pub Dr2: DWORD,
+ pub Dr3: DWORD,
+ pub Dr6: DWORD,
+ pub Dr7: DWORD,
+ pub FloatSave: FLOATING_SAVE_AREA,
+ pub SegGs: DWORD,
+ pub SegFs: DWORD,
+ pub SegEs: DWORD,
+ pub SegDs: DWORD,
+ pub Edi: DWORD,
+ pub Esi: DWORD,
+ pub Ebx: DWORD,
+ pub Edx: DWORD,
+ pub Ecx: DWORD,
+ pub Eax: DWORD,
+ pub Ebp: DWORD,
+ pub Eip: DWORD,
+ pub SegCs: DWORD,
+ pub EFlags: DWORD,
+ pub Esp: DWORD,
+ pub SegSs: DWORD,
+ pub ExtendedRegisters: [u8; 512],
+}
+
+#[cfg(target_arch = "x86")]
+#[repr(C)]
+pub struct FLOATING_SAVE_AREA {
+ pub ControlWord: DWORD,
+ pub StatusWord: DWORD,
+ pub TagWord: DWORD,
+ pub ErrorOffset: DWORD,
+ pub ErrorSelector: DWORD,
+ pub DataOffset: DWORD,
+ pub DataSelector: DWORD,
+ pub RegisterArea: [u8; 80],
+ pub Cr0NpxState: DWORD,
+}
+
+#[cfg(target_arch = "x86_64")]
+#[repr(C, align(16))]
+pub struct CONTEXT {
+ pub P1Home: DWORDLONG,
+ pub P2Home: DWORDLONG,
+ pub P3Home: DWORDLONG,
+ pub P4Home: DWORDLONG,
+ pub P5Home: DWORDLONG,
+ pub P6Home: DWORDLONG,
+
+ pub ContextFlags: DWORD,
+ pub MxCsr: DWORD,
+
+ pub SegCs: WORD,
+ pub SegDs: WORD,
+ pub SegEs: WORD,
+ pub SegFs: WORD,
+ pub SegGs: WORD,
+ pub SegSs: WORD,
+ pub EFlags: DWORD,
+
+ pub Dr0: DWORDLONG,
+ pub Dr1: DWORDLONG,
+ pub Dr2: DWORDLONG,
+ pub Dr3: DWORDLONG,
+ pub Dr6: DWORDLONG,
+ pub Dr7: DWORDLONG,
+
+ pub Rax: DWORDLONG,
+ pub Rcx: DWORDLONG,
+ pub Rdx: DWORDLONG,
+ pub Rbx: DWORDLONG,
+ pub Rsp: DWORDLONG,
+ pub Rbp: DWORDLONG,
+ pub Rsi: DWORDLONG,
+ pub Rdi: DWORDLONG,
+ pub R8: DWORDLONG,
+ pub R9: DWORDLONG,
+ pub R10: DWORDLONG,
+ pub R11: DWORDLONG,
+ pub R12: DWORDLONG,
+ pub R13: DWORDLONG,
+ pub R14: DWORDLONG,
+ pub R15: DWORDLONG,
+
+ pub Rip: DWORDLONG,
+
+ pub FltSave: FLOATING_SAVE_AREA,
+
+ pub VectorRegister: [M128A; 26],
+ pub VectorControl: DWORDLONG,
+
+ pub DebugControl: DWORDLONG,
+ pub LastBranchToRip: DWORDLONG,
+ pub LastBranchFromRip: DWORDLONG,
+ pub LastExceptionToRip: DWORDLONG,
+ pub LastExceptionFromRip: DWORDLONG,
+}
+
+#[cfg(target_arch = "x86_64")]
+#[repr(C, align(16))]
+pub struct M128A {
+ pub Low: c_ulonglong,
+ pub High: c_longlong
+}
+
+#[cfg(target_arch = "x86_64")]
+#[repr(C, align(16))]
+pub struct FLOATING_SAVE_AREA {
+ _Dummy: [u8; 512] // FIXME: Fill this out
+}
+
+#[cfg(target_arch = "arm")]
+#[repr(C)]
+pub struct CONTEXT {
+ pub ContextFlags: ULONG,
+ pub R0: ULONG,
+ pub R1: ULONG,
+ pub R2: ULONG,
+ pub R3: ULONG,
+ pub R4: ULONG,
+ pub R5: ULONG,
+ pub R6: ULONG,
+ pub R7: ULONG,
+ pub R8: ULONG,
+ pub R9: ULONG,
+ pub R10: ULONG,
+ pub R11: ULONG,
+ pub R12: ULONG,
+ pub Sp: ULONG,
+ pub Lr: ULONG,
+ pub Pc: ULONG,
+ pub Cpsr: ULONG,
+ pub Fpscr: ULONG,
+ pub Padding: ULONG,
+ pub D: [u64; 32],
+ pub Bvr: [ULONG; ARM_MAX_BREAKPOINTS],
+ pub Bcr: [ULONG; ARM_MAX_BREAKPOINTS],
+ pub Wvr: [ULONG; ARM_MAX_WATCHPOINTS],
+ pub Wcr: [ULONG; ARM_MAX_WATCHPOINTS],
+ pub Padding2: [ULONG; 2]
+}
+
+// FIXME(#43348): This structure is used for backtrace only, and a fake
+// definition is provided here only to allow rustdoc to pass type-check. This
+// will not appear in the final documentation. This should be also defined for
+// other architectures supported by Windows such as ARM, and for historical
+// interest, maybe MIPS and PowerPC as well.
+#[cfg(all(rustdoc, not(any(target_arch = "x86_64", target_arch = "x86",
+ target_arch = "aarch64", target_arch = "arm"))))]
+pub enum CONTEXT {}
+
+#[cfg(target_arch = "aarch64")]
+pub const ARM64_MAX_BREAKPOINTS: usize = 8;
+
+#[cfg(target_arch = "aarch64")]
+pub const ARM64_MAX_WATCHPOINTS: usize = 2;
+
+#[cfg(target_arch = "aarch64")]
+#[repr(C)]
+pub struct ARM64_NT_NEON128 {
+ pub D: [f64; 2],
+}
+
+#[cfg(target_arch = "aarch64")]
+#[repr(C, align(16))]
+pub struct CONTEXT {
+ pub ContextFlags: DWORD,
+ pub Cpsr: DWORD,
+ pub X0: u64,
+ pub X1: u64,
+ pub X2: u64,
+ pub X3: u64,
+ pub X4: u64,
+ pub X5: u64,
+ pub X6: u64,
+ pub X7: u64,
+ pub X8: u64,
+ pub X9: u64,
+ pub X10: u64,
+ pub X11: u64,
+ pub X12: u64,
+ pub X13: u64,
+ pub X14: u64,
+ pub X15: u64,
+ pub X16: u64,
+ pub X17: u64,
+ pub X18: u64,
+ pub X19: u64,
+ pub X20: u64,
+ pub X21: u64,
+ pub X22: u64,
+ pub X23: u64,
+ pub X24: u64,
+ pub X25: u64,
+ pub X26: u64,
+ pub X27: u64,
+ pub X28: u64,
+ pub Fp: u64,
+ pub Lr: u64,
+ pub Sp: u64,
+ pub Pc: u64,
+ pub V: [ARM64_NT_NEON128; 32],
+ pub Fpcr: DWORD,
+ pub Fpsr: DWORD,
+ pub Bcr: [DWORD; ARM64_MAX_BREAKPOINTS],
+ pub Bvr: [DWORD; ARM64_MAX_BREAKPOINTS],
+ pub Wcr: [DWORD; ARM64_MAX_WATCHPOINTS],
+ pub Wvr: [DWORD; ARM64_MAX_WATCHPOINTS],
+}
+
+#[repr(C)]
+pub struct SOCKADDR_STORAGE_LH {
+ pub ss_family: ADDRESS_FAMILY,
+ pub __ss_pad1: [CHAR; 6],
+ pub __ss_align: i64,
+ pub __ss_pad2: [CHAR; 112],
+}
+
+#[repr(C)]
+pub struct ADDRINFOA {
+ pub ai_flags: c_int,
+ pub ai_family: c_int,
+ pub ai_socktype: c_int,
+ pub ai_protocol: c_int,
+ pub ai_addrlen: size_t,
+ pub ai_canonname: *mut c_char,
+ pub ai_addr: *mut SOCKADDR,
+ pub ai_next: *mut ADDRINFOA,
+}
+
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct sockaddr_in {
+ pub sin_family: ADDRESS_FAMILY,
+ pub sin_port: USHORT,
+ pub sin_addr: in_addr,
+ pub sin_zero: [CHAR; 8],
+}
+
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct sockaddr_in6 {
+ pub sin6_family: ADDRESS_FAMILY,
+ pub sin6_port: USHORT,
+ pub sin6_flowinfo: c_ulong,
+ pub sin6_addr: in6_addr,
+ pub sin6_scope_id: c_ulong,
+}
+
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct in_addr {
+ pub s_addr: u32,
+}
+
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct in6_addr {
+ pub s6_addr: [u8; 16],
+}
+
+#[repr(C)]
+#[derive(Copy, Clone)]
+#[allow(dead_code)] // we only use some variants
+pub enum EXCEPTION_DISPOSITION {
+ ExceptionContinueExecution,
+ ExceptionContinueSearch,
+ ExceptionNestedException,
+ ExceptionCollidedUnwind
+}
+
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct CONSOLE_READCONSOLE_CONTROL {
+ pub nLength: ULONG,
+ pub nInitialChars: ULONG,
+ pub dwCtrlWakeupMask: ULONG,
+ pub dwControlKeyState: ULONG,
+}
+pub type PCONSOLE_READCONSOLE_CONTROL = *mut CONSOLE_READCONSOLE_CONTROL;
+
+#[repr(C)]
+#[derive(Copy)]
+pub struct fd_set {
+ pub fd_count: c_uint,
+ pub fd_array: [SOCKET; FD_SETSIZE],
+}
+
+impl Clone for fd_set {
+ fn clone(&self) -> fd_set {
+ *self
+ }
+}
+
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct timeval {
+ pub tv_sec: c_long,
+ pub tv_usec: c_long,
+}
+
+extern "system" {
+ pub fn WSAStartup(wVersionRequested: WORD,
+ lpWSAData: LPWSADATA) -> c_int;
+ pub fn WSACleanup() -> c_int;
+ pub fn WSAGetLastError() -> c_int;
+ pub fn WSADuplicateSocketW(s: SOCKET,
+ dwProcessId: DWORD,
+ lpProtocolInfo: LPWSAPROTOCOL_INFO)
+ -> c_int;
+ pub fn WSASend(s: SOCKET,
+ lpBuffers: LPWSABUF,
+ dwBufferCount: DWORD,
+ lpNumberOfBytesSent: LPDWORD,
+ dwFlags: DWORD,
+ lpOverlapped: LPWSAOVERLAPPED,
+ lpCompletionRoutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE)
+ -> c_int;
+ pub fn WSARecv(s: SOCKET,
+ lpBuffers: LPWSABUF,
+ dwBufferCount: DWORD,
+ lpNumberOfBytesRecvd: LPDWORD,
+ lpFlags: LPDWORD,
+ lpOverlapped: LPWSAOVERLAPPED,
+ lpCompletionRoutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE)
+ -> c_int;
+ pub fn GetCurrentProcessId() -> DWORD;
+ pub fn WSASocketW(af: c_int,
+ kind: c_int,
+ protocol: c_int,
+ lpProtocolInfo: LPWSAPROTOCOL_INFO,
+ g: GROUP,
+ dwFlags: DWORD) -> SOCKET;
+ pub fn ioctlsocket(s: SOCKET, cmd: c_long, argp: *mut c_ulong) -> c_int;
+ pub fn InitializeCriticalSection(CriticalSection: *mut CRITICAL_SECTION);
+ pub fn EnterCriticalSection(CriticalSection: *mut CRITICAL_SECTION);
+ pub fn TryEnterCriticalSection(CriticalSection: *mut CRITICAL_SECTION) -> BOOLEAN;
+ pub fn LeaveCriticalSection(CriticalSection: *mut CRITICAL_SECTION);
+ pub fn DeleteCriticalSection(CriticalSection: *mut CRITICAL_SECTION);
+
+ pub fn ReadConsoleW(hConsoleInput: HANDLE,
+ lpBuffer: LPVOID,
+ nNumberOfCharsToRead: DWORD,
+ lpNumberOfCharsRead: LPDWORD,
+ pInputControl: PCONSOLE_READCONSOLE_CONTROL) -> BOOL;
+
+ pub fn WriteConsoleW(hConsoleOutput: HANDLE,
+ lpBuffer: LPCVOID,
+ nNumberOfCharsToWrite: DWORD,
+ lpNumberOfCharsWritten: LPDWORD,
+ lpReserved: LPVOID) -> BOOL;
+
+ pub fn GetConsoleMode(hConsoleHandle: HANDLE,
+ lpMode: LPDWORD) -> BOOL;
+ pub fn RemoveDirectoryW(lpPathName: LPCWSTR) -> BOOL;
+ pub fn SetFileAttributesW(lpFileName: LPCWSTR,
+ dwFileAttributes: DWORD) -> BOOL;
+ pub fn GetFileInformationByHandle(hFile: HANDLE,
+ lpFileInformation: LPBY_HANDLE_FILE_INFORMATION)
+ -> BOOL;
+
+ pub fn SetLastError(dwErrCode: DWORD);
+ pub fn GetCommandLineW() -> *mut LPCWSTR;
+ pub fn GetTempPathW(nBufferLength: DWORD,
+ lpBuffer: LPCWSTR) -> DWORD;
+ pub fn OpenProcessToken(ProcessHandle: HANDLE,
+ DesiredAccess: DWORD,
+ TokenHandle: *mut HANDLE) -> BOOL;
+ pub fn GetCurrentProcess() -> HANDLE;
+ pub fn GetCurrentThread() -> HANDLE;
+ pub fn GetStdHandle(which: DWORD) -> HANDLE;
+ pub fn ExitProcess(uExitCode: c_uint) -> !;
+ pub fn DeviceIoControl(hDevice: HANDLE,
+ dwIoControlCode: DWORD,
+ lpInBuffer: LPVOID,
+ nInBufferSize: DWORD,
+ lpOutBuffer: LPVOID,
+ nOutBufferSize: DWORD,
+ lpBytesReturned: LPDWORD,
+ lpOverlapped: LPOVERLAPPED) -> BOOL;
+ pub fn CreateThread(lpThreadAttributes: LPSECURITY_ATTRIBUTES,
+ dwStackSize: SIZE_T,
+ lpStartAddress: extern "system" fn(*mut c_void)
+ -> DWORD,
+ lpParameter: LPVOID,
+ dwCreationFlags: DWORD,
+ lpThreadId: LPDWORD) -> HANDLE;
+ pub fn WaitForSingleObject(hHandle: HANDLE,
+ dwMilliseconds: DWORD) -> DWORD;
+ pub fn SwitchToThread() -> BOOL;
+ pub fn Sleep(dwMilliseconds: DWORD);
+ pub fn GetProcessId(handle: HANDLE) -> DWORD;
+ pub fn GetUserProfileDirectoryW(hToken: HANDLE,
+ lpProfileDir: LPWSTR,
+ lpcchSize: *mut DWORD) -> BOOL;
+ pub fn SetHandleInformation(hObject: HANDLE,
+ dwMask: DWORD,
+ dwFlags: DWORD) -> BOOL;
+ pub fn CopyFileExW(lpExistingFileName: LPCWSTR,
+ lpNewFileName: LPCWSTR,
+ lpProgressRoutine: LPPROGRESS_ROUTINE,
+ lpData: LPVOID,
+ pbCancel: LPBOOL,
+ dwCopyFlags: DWORD) -> BOOL;
+ pub fn AddVectoredExceptionHandler(FirstHandler: ULONG,
+ VectoredHandler: PVECTORED_EXCEPTION_HANDLER)
+ -> LPVOID;
+ pub fn FormatMessageW(flags: DWORD,
+ lpSrc: LPVOID,
+ msgId: DWORD,
+ langId: DWORD,
+ buf: LPWSTR,
+ nsize: DWORD,
+ args: *const c_void)
+ -> DWORD;
+ pub fn TlsAlloc() -> DWORD;
+ pub fn TlsGetValue(dwTlsIndex: DWORD) -> LPVOID;
+ pub fn TlsSetValue(dwTlsIndex: DWORD, lpTlsvalue: LPVOID) -> BOOL;
+ pub fn GetLastError() -> DWORD;
+ pub fn QueryPerformanceFrequency(lpFrequency: *mut LARGE_INTEGER) -> BOOL;
+ pub fn QueryPerformanceCounter(lpPerformanceCount: *mut LARGE_INTEGER)
+ -> BOOL;
+ pub fn GetExitCodeProcess(hProcess: HANDLE, lpExitCode: LPDWORD) -> BOOL;
+ pub fn TerminateProcess(hProcess: HANDLE, uExitCode: UINT) -> BOOL;
+ pub fn CreateProcessW(lpApplicationName: LPCWSTR,
+ lpCommandLine: LPWSTR,
+ lpProcessAttributes: LPSECURITY_ATTRIBUTES,
+ lpThreadAttributes: LPSECURITY_ATTRIBUTES,
+ bInheritHandles: BOOL,
+ dwCreationFlags: DWORD,
+ lpEnvironment: LPVOID,
+ lpCurrentDirectory: LPCWSTR,
+ lpStartupInfo: LPSTARTUPINFO,
+ lpProcessInformation: LPPROCESS_INFORMATION)
+ -> BOOL;
+ pub fn GetEnvironmentVariableW(n: LPCWSTR, v: LPWSTR, nsize: DWORD) -> DWORD;
+ pub fn SetEnvironmentVariableW(n: LPCWSTR, v: LPCWSTR) -> BOOL;
+ pub fn GetEnvironmentStringsW() -> LPWCH;
+ pub fn FreeEnvironmentStringsW(env_ptr: LPWCH) -> BOOL;
+ pub fn GetModuleFileNameW(hModule: HMODULE,
+ lpFilename: LPWSTR,
+ nSize: DWORD)
+ -> DWORD;
+ pub fn CreateDirectoryW(lpPathName: LPCWSTR,
+ lpSecurityAttributes: LPSECURITY_ATTRIBUTES)
+ -> BOOL;
+ pub fn DeleteFileW(lpPathName: LPCWSTR) -> BOOL;
+ pub fn GetCurrentDirectoryW(nBufferLength: DWORD, lpBuffer: LPWSTR) -> DWORD;
+ pub fn SetCurrentDirectoryW(lpPathName: LPCWSTR) -> BOOL;
+ pub fn WideCharToMultiByte(CodePage: UINT,
+ dwFlags: DWORD,
+ lpWideCharStr: LPCWSTR,
+ cchWideChar: c_int,
+ lpMultiByteStr: LPSTR,
+ cbMultiByte: c_int,
+ lpDefaultChar: LPCSTR,
+ lpUsedDefaultChar: LPBOOL) -> c_int;
+
+ pub fn closesocket(socket: SOCKET) -> c_int;
+ pub fn recv(socket: SOCKET, buf: *mut c_void, len: c_int,
+ flags: c_int) -> c_int;
+ pub fn send(socket: SOCKET, buf: *const c_void, len: c_int,
+ flags: c_int) -> c_int;
+ pub fn recvfrom(socket: SOCKET,
+ buf: *mut c_void,
+ len: c_int,
+ flags: c_int,
+ addr: *mut SOCKADDR,
+ addrlen: *mut c_int)
+ -> c_int;
+ pub fn sendto(socket: SOCKET,
+ buf: *const c_void,
+ len: c_int,
+ flags: c_int,
+ addr: *const SOCKADDR,
+ addrlen: c_int)
+ -> c_int;
+ pub fn shutdown(socket: SOCKET, how: c_int) -> c_int;
+ pub fn accept(socket: SOCKET,
+ address: *mut SOCKADDR,
+ address_len: *mut c_int)
+ -> SOCKET;
+ pub fn DuplicateHandle(hSourceProcessHandle: HANDLE,
+ hSourceHandle: HANDLE,
+ hTargetProcessHandle: HANDLE,
+ lpTargetHandle: LPHANDLE,
+ dwDesiredAccess: DWORD,
+ bInheritHandle: BOOL,
+ dwOptions: DWORD)
+ -> BOOL;
+ pub fn ReadFile(hFile: HANDLE,
+ lpBuffer: LPVOID,
+ nNumberOfBytesToRead: DWORD,
+ lpNumberOfBytesRead: LPDWORD,
+ lpOverlapped: LPOVERLAPPED)
+ -> BOOL;
+ pub fn WriteFile(hFile: HANDLE,
+ lpBuffer: LPVOID,
+ nNumberOfBytesToWrite: DWORD,
+ lpNumberOfBytesWritten: LPDWORD,
+ lpOverlapped: LPOVERLAPPED)
+ -> BOOL;
+ pub fn CloseHandle(hObject: HANDLE) -> BOOL;
+ pub fn CreateHardLinkW(lpSymlinkFileName: LPCWSTR,
+ lpTargetFileName: LPCWSTR,
+ lpSecurityAttributes: LPSECURITY_ATTRIBUTES)
+ -> BOOL;
+ pub fn MoveFileExW(lpExistingFileName: LPCWSTR,
+ lpNewFileName: LPCWSTR,
+ dwFlags: DWORD)
+ -> BOOL;
+ pub fn SetFilePointerEx(hFile: HANDLE,
+ liDistanceToMove: LARGE_INTEGER,
+ lpNewFilePointer: PLARGE_INTEGER,
+ dwMoveMethod: DWORD)
+ -> BOOL;
+ pub fn FlushFileBuffers(hFile: HANDLE) -> BOOL;
+ pub fn CreateFileW(lpFileName: LPCWSTR,
+ dwDesiredAccess: DWORD,
+ dwShareMode: DWORD,
+ lpSecurityAttributes: LPSECURITY_ATTRIBUTES,
+ dwCreationDisposition: DWORD,
+ dwFlagsAndAttributes: DWORD,
+ hTemplateFile: HANDLE)
+ -> HANDLE;
+
+ pub fn FindFirstFileW(fileName: LPCWSTR,
+ findFileData: LPWIN32_FIND_DATAW)
+ -> HANDLE;
+ pub fn FindNextFileW(findFile: HANDLE, findFileData: LPWIN32_FIND_DATAW)
+ -> BOOL;
+ pub fn FindClose(findFile: HANDLE) -> BOOL;
+ #[cfg(feature = "backtrace")]
+ pub fn RtlCaptureContext(ctx: *mut CONTEXT);
+ pub fn getsockopt(s: SOCKET,
+ level: c_int,
+ optname: c_int,
+ optval: *mut c_char,
+ optlen: *mut c_int)
+ -> c_int;
+ pub fn setsockopt(s: SOCKET,
+ level: c_int,
+ optname: c_int,
+ optval: *const c_void,
+ optlen: c_int)
+ -> c_int;
+ pub fn getsockname(socket: SOCKET,
+ address: *mut SOCKADDR,
+ address_len: *mut c_int)
+ -> c_int;
+ pub fn getpeername(socket: SOCKET,
+ address: *mut SOCKADDR,
+ address_len: *mut c_int)
+ -> c_int;
+ pub fn bind(socket: SOCKET, address: *const SOCKADDR,
+ address_len: socklen_t) -> c_int;
+ pub fn listen(socket: SOCKET, backlog: c_int) -> c_int;
+ pub fn connect(socket: SOCKET, address: *const SOCKADDR, len: c_int)
+ -> c_int;
+ pub fn getaddrinfo(node: *const c_char, service: *const c_char,
+ hints: *const ADDRINFOA,
+ res: *mut *mut ADDRINFOA) -> c_int;
+ pub fn freeaddrinfo(res: *mut ADDRINFOA);
+
+ #[cfg(feature = "backtrace")]
+ pub fn LoadLibraryW(name: LPCWSTR) -> HMODULE;
+ #[cfg(feature = "backtrace")]
+ pub fn FreeLibrary(handle: HMODULE) -> BOOL;
+ pub fn GetProcAddress(handle: HMODULE,
+ name: LPCSTR) -> *mut c_void;
+ pub fn GetModuleHandleW(lpModuleName: LPCWSTR) -> HMODULE;
+
+ pub fn GetSystemTimeAsFileTime(lpSystemTimeAsFileTime: LPFILETIME);
+
+ pub fn CreateEventW(lpEventAttributes: LPSECURITY_ATTRIBUTES,
+ bManualReset: BOOL,
+ bInitialState: BOOL,
+ lpName: LPCWSTR) -> HANDLE;
+ pub fn WaitForMultipleObjects(nCount: DWORD,
+ lpHandles: *const HANDLE,
+ bWaitAll: BOOL,
+ dwMilliseconds: DWORD) -> DWORD;
+ pub fn CreateNamedPipeW(lpName: LPCWSTR,
+ dwOpenMode: DWORD,
+ dwPipeMode: DWORD,
+ nMaxInstances: DWORD,
+ nOutBufferSize: DWORD,
+ nInBufferSize: DWORD,
+ nDefaultTimeOut: DWORD,
+ lpSecurityAttributes: LPSECURITY_ATTRIBUTES)
+ -> HANDLE;
+ pub fn CancelIo(handle: HANDLE) -> BOOL;
+ pub fn GetOverlappedResult(hFile: HANDLE,
+ lpOverlapped: LPOVERLAPPED,
+ lpNumberOfBytesTransferred: LPDWORD,
+ bWait: BOOL) -> BOOL;
+ pub fn select(nfds: c_int,
+ readfds: *mut fd_set,
+ writefds: *mut fd_set,
+ exceptfds: *mut fd_set,
+ timeout: *const timeval) -> c_int;
+
+ #[link_name = "SystemFunction036"]
+ pub fn RtlGenRandom(RandomBuffer: *mut u8, RandomBufferLength: ULONG) -> BOOLEAN;
+
+ pub fn GetProcessHeap() -> HANDLE;
+ pub fn HeapAlloc(hHeap: HANDLE, dwFlags: DWORD, dwBytes: SIZE_T) -> LPVOID;
+ pub fn HeapReAlloc(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID, dwBytes: SIZE_T) -> LPVOID;
+ pub fn HeapFree(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID) -> BOOL;
+}
+
+// Functions that aren't available on every version of Windows that we support,
+// but we still use them and just provide some form of a fallback implementation.
+compat_fn! {
+ kernel32:
+
+ pub fn CreateSymbolicLinkW(_lpSymlinkFileName: LPCWSTR,
+ _lpTargetFileName: LPCWSTR,
+ _dwFlags: DWORD) -> BOOLEAN {
+ SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); 0
+ }
+ pub fn GetFinalPathNameByHandleW(_hFile: HANDLE,
+ _lpszFilePath: LPCWSTR,
+ _cchFilePath: DWORD,
+ _dwFlags: DWORD) -> DWORD {
+ SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); 0
+ }
+ pub fn SetThreadStackGuarantee(_size: *mut c_ulong) -> BOOL {
+ SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); 0
+ }
+ pub fn SetThreadDescription(hThread: HANDLE,
+ lpThreadDescription: LPCWSTR) -> HRESULT {
+ SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); E_NOTIMPL
+ }
+ pub fn SetFileInformationByHandle(_hFile: HANDLE,
+ _FileInformationClass: FILE_INFO_BY_HANDLE_CLASS,
+ _lpFileInformation: LPVOID,
+ _dwBufferSize: DWORD) -> BOOL {
+ SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); 0
+ }
+ pub fn SleepConditionVariableSRW(ConditionVariable: PCONDITION_VARIABLE,
+ SRWLock: PSRWLOCK,
+ dwMilliseconds: DWORD,
+ Flags: ULONG) -> BOOL {
+ panic!("condition variables not available")
+ }
+ pub fn WakeConditionVariable(ConditionVariable: PCONDITION_VARIABLE)
+ -> () {
+ panic!("condition variables not available")
+ }
+ pub fn WakeAllConditionVariable(ConditionVariable: PCONDITION_VARIABLE)
+ -> () {
+ panic!("condition variables not available")
+ }
+ pub fn AcquireSRWLockExclusive(SRWLock: PSRWLOCK) -> () {
+ panic!("rwlocks not available")
+ }
+ pub fn AcquireSRWLockShared(SRWLock: PSRWLOCK) -> () {
+ panic!("rwlocks not available")
+ }
+ pub fn ReleaseSRWLockExclusive(SRWLock: PSRWLOCK) -> () {
+ panic!("rwlocks not available")
+ }
+ pub fn ReleaseSRWLockShared(SRWLock: PSRWLOCK) -> () {
+ panic!("rwlocks not available")
+ }
+ pub fn TryAcquireSRWLockExclusive(SRWLock: PSRWLOCK) -> BOOLEAN {
+ panic!("rwlocks not available")
+ }
+ pub fn TryAcquireSRWLockShared(SRWLock: PSRWLOCK) -> BOOLEAN {
+ panic!("rwlocks not available")
+ }
+}
+
+#[cfg(all(target_env = "gnu", feature = "backtrace"))]
+mod gnu {
+ use super::*;
+
+ pub const PROCESS_QUERY_INFORMATION: DWORD = 0x0400;
+
+ pub const CP_ACP: UINT = 0;
+
+ pub const WC_NO_BEST_FIT_CHARS: DWORD = 0x00000400;
+
+ extern "system" {
+ pub fn OpenProcess(dwDesiredAccess: DWORD,
+ bInheritHandle: BOOL,
+ dwProcessId: DWORD) -> HANDLE;
+ }
+
+ compat_fn! {
+ kernel32:
+
+ pub fn QueryFullProcessImageNameW(_hProcess: HANDLE,
+ _dwFlags: DWORD,
+ _lpExeName: LPWSTR,
+ _lpdwSize: LPDWORD) -> BOOL {
+ SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); 0
+ }
+ }
+}
+
+#[cfg(all(target_env = "gnu", feature = "backtrace"))]
+pub use self::gnu::*;
diff --git a/src/libstd/sys/windows/cmath.rs b/src/libstd/sys/windows/cmath.rs
new file mode 100644
index 0000000..e744cb2
--- /dev/null
+++ b/src/libstd/sys/windows/cmath.rs
@@ -0,0 +1,93 @@
+#![cfg(not(test))]
+
+use libc::{c_float, c_double};
+
+#[link_name = "m"]
+extern {
+ pub fn acos(n: c_double) -> c_double;
+ pub fn asin(n: c_double) -> c_double;
+ pub fn atan(n: c_double) -> c_double;
+ pub fn atan2(a: c_double, b: c_double) -> c_double;
+ pub fn cbrt(n: c_double) -> c_double;
+ pub fn cbrtf(n: c_float) -> c_float;
+ pub fn cosh(n: c_double) -> c_double;
+ pub fn expm1(n: c_double) -> c_double;
+ pub fn expm1f(n: c_float) -> c_float;
+ pub fn fdim(a: c_double, b: c_double) -> c_double;
+ pub fn fdimf(a: c_float, b: c_float) -> c_float;
+ #[cfg_attr(target_env = "msvc", link_name = "_hypot")]
+ pub fn hypot(x: c_double, y: c_double) -> c_double;
+ #[cfg_attr(target_env = "msvc", link_name = "_hypotf")]
+ pub fn hypotf(x: c_float, y: c_float) -> c_float;
+ pub fn log1p(n: c_double) -> c_double;
+ pub fn log1pf(n: c_float) -> c_float;
+ pub fn sinh(n: c_double) -> c_double;
+ pub fn tan(n: c_double) -> c_double;
+ pub fn tanh(n: c_double) -> c_double;
+}
+
+pub use self::shims::*;
+
+#[cfg(not(target_env = "msvc"))]
+mod shims {
+ use libc::c_float;
+
+ extern {
+ pub fn acosf(n: c_float) -> c_float;
+ pub fn asinf(n: c_float) -> c_float;
+ pub fn atan2f(a: c_float, b: c_float) -> c_float;
+ pub fn atanf(n: c_float) -> c_float;
+ pub fn coshf(n: c_float) -> c_float;
+ pub fn sinhf(n: c_float) -> c_float;
+ pub fn tanf(n: c_float) -> c_float;
+ pub fn tanhf(n: c_float) -> c_float;
+ }
+}
+
+// On MSVC these functions aren't defined, so we just define shims which promote
+// everything fo f64, perform the calculation, and then demote back to f32.
+// While not precisely correct should be "correct enough" for now.
+#[cfg(target_env = "msvc")]
+mod shims {
+ use libc::c_float;
+
+ #[inline]
+ pub unsafe fn acosf(n: c_float) -> c_float {
+ f64::acos(n as f64) as c_float
+ }
+
+ #[inline]
+ pub unsafe fn asinf(n: c_float) -> c_float {
+ f64::asin(n as f64) as c_float
+ }
+
+ #[inline]
+ pub unsafe fn atan2f(n: c_float, b: c_float) -> c_float {
+ f64::atan2(n as f64, b as f64) as c_float
+ }
+
+ #[inline]
+ pub unsafe fn atanf(n: c_float) -> c_float {
+ f64::atan(n as f64) as c_float
+ }
+
+ #[inline]
+ pub unsafe fn coshf(n: c_float) -> c_float {
+ f64::cosh(n as f64) as c_float
+ }
+
+ #[inline]
+ pub unsafe fn sinhf(n: c_float) -> c_float {
+ f64::sinh(n as f64) as c_float
+ }
+
+ #[inline]
+ pub unsafe fn tanf(n: c_float) -> c_float {
+ f64::tan(n as f64) as c_float
+ }
+
+ #[inline]
+ pub unsafe fn tanhf(n: c_float) -> c_float {
+ f64::tanh(n as f64) as c_float
+ }
+}
diff --git a/src/libstd/sys/windows/compat.rs b/src/libstd/sys/windows/compat.rs
new file mode 100644
index 0000000..748c161
--- /dev/null
+++ b/src/libstd/sys/windows/compat.rs
@@ -0,0 +1,71 @@
+//! A "compatibility layer" for spanning XP and Windows 7
+//!
+//! The standard library currently binds many functions that are not available
+//! on Windows XP, but we would also like to support building executables that
+//! run on XP. To do this we specify all non-XP APIs as having a fallback
+//! implementation to do something reasonable.
+//!
+//! This dynamic runtime detection of whether a function is available is
+//! implemented with `GetModuleHandle` and `GetProcAddress` paired with a
+//! static-per-function which caches the result of the first check. In this
+//! manner we pay a semi-large one-time cost up front for detecting whether a
+//! function is available but afterwards it's just a load and a jump.
+
+use crate::ffi::CString;
+use crate::sync::atomic::{AtomicUsize, Ordering};
+use crate::sys::c;
+
+pub fn lookup(module: &str, symbol: &str) -> Option<usize> {
+ let mut module: Vec<u16> = module.encode_utf16().collect();
+ module.push(0);
+ let symbol = CString::new(symbol).unwrap();
+ unsafe {
+ let handle = c::GetModuleHandleW(module.as_ptr());
+ match c::GetProcAddress(handle, symbol.as_ptr()) as usize {
+ 0 => None,
+ n => Some(n),
+ }
+ }
+}
+
+pub fn store_func(ptr: &AtomicUsize, module: &str, symbol: &str,
+ fallback: usize) -> usize {
+ let value = lookup(module, symbol).unwrap_or(fallback);
+ ptr.store(value, Ordering::SeqCst);
+ value
+}
+
+macro_rules! compat_fn {
+ ($module:ident: $(
+ pub fn $symbol:ident($($argname:ident: $argtype:ty),*)
+ -> $rettype:ty {
+ $($body:expr);*
+ }
+ )*) => ($(
+ #[allow(unused_variables)]
+ pub unsafe fn $symbol($($argname: $argtype),*) -> $rettype {
+ use crate::sync::atomic::{AtomicUsize, Ordering};
+ use crate::mem;
+ type F = unsafe extern "system" fn($($argtype),*) -> $rettype;
+
+ static PTR: AtomicUsize = AtomicUsize::new(0);
+
+ fn load() -> usize {
+ crate::sys::compat::store_func(&PTR,
+ stringify!($module),
+ stringify!($symbol),
+ fallback as usize)
+ }
+ unsafe extern "system" fn fallback($($argname: $argtype),*)
+ -> $rettype {
+ $($body);*
+ }
+
+ let addr = match PTR.load(Ordering::SeqCst) {
+ 0 => load(),
+ n => n,
+ };
+ mem::transmute::<usize, F>(addr)($($argname),*)
+ }
+ )*)
+}
diff --git a/src/libstd/sys/windows/condvar.rs b/src/libstd/sys/windows/condvar.rs
new file mode 100644
index 0000000..62835ea
--- /dev/null
+++ b/src/libstd/sys/windows/condvar.rs
@@ -0,0 +1,55 @@
+use crate::cell::UnsafeCell;
+use crate::sys::c;
+use crate::sys::mutex::{self, Mutex};
+use crate::sys::os;
+use crate::time::Duration;
+
+pub struct Condvar { inner: UnsafeCell<c::CONDITION_VARIABLE> }
+
+unsafe impl Send for Condvar {}
+unsafe impl Sync for Condvar {}
+
+impl Condvar {
+ pub const fn new() -> Condvar {
+ Condvar { inner: UnsafeCell::new(c::CONDITION_VARIABLE_INIT) }
+ }
+
+ #[inline]
+ pub unsafe fn init(&mut self) {}
+
+ #[inline]
+ pub unsafe fn wait(&self, mutex: &Mutex) {
+ let r = c::SleepConditionVariableSRW(self.inner.get(),
+ mutex::raw(mutex),
+ c::INFINITE,
+ 0);
+ debug_assert!(r != 0);
+ }
+
+ pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
+ let r = c::SleepConditionVariableSRW(self.inner.get(),
+ mutex::raw(mutex),
+ super::dur2timeout(dur),
+ 0);
+ if r == 0 {
+ debug_assert_eq!(os::errno() as usize, c::ERROR_TIMEOUT as usize);
+ false
+ } else {
+ true
+ }
+ }
+
+ #[inline]
+ pub unsafe fn notify_one(&self) {
+ c::WakeConditionVariable(self.inner.get())
+ }
+
+ #[inline]
+ pub unsafe fn notify_all(&self) {
+ c::WakeAllConditionVariable(self.inner.get())
+ }
+
+ pub unsafe fn destroy(&self) {
+ // ...
+ }
+}
diff --git a/src/libstd/sys/windows/dynamic_lib.rs b/src/libstd/sys/windows/dynamic_lib.rs
new file mode 100644
index 0000000..b9d5105
--- /dev/null
+++ b/src/libstd/sys/windows/dynamic_lib.rs
@@ -0,0 +1,44 @@
+use crate::os::windows::prelude::*;
+
+use crate::ffi::{CString, OsStr};
+use crate::io;
+use crate::sys::c;
+
+pub struct DynamicLibrary {
+ handle: c::HMODULE,
+}
+
+impl DynamicLibrary {
+ pub fn open(filename: &str) -> io::Result<DynamicLibrary> {
+ let filename = OsStr::new(filename)
+ .encode_wide()
+ .chain(Some(0))
+ .collect::<Vec<_>>();
+ let result = unsafe {
+ c::LoadLibraryW(filename.as_ptr())
+ };
+ if result.is_null() {
+ Err(io::Error::last_os_error())
+ } else {
+ Ok(DynamicLibrary { handle: result })
+ }
+ }
+
+ pub fn symbol(&self, symbol: &str) -> io::Result<usize> {
+ let symbol = CString::new(symbol)?;
+ unsafe {
+ match c::GetProcAddress(self.handle, symbol.as_ptr()) as usize {
+ 0 => Err(io::Error::last_os_error()),
+ n => Ok(n),
+ }
+ }
+ }
+}
+
+impl Drop for DynamicLibrary {
+ fn drop(&mut self) {
+ unsafe {
+ c::FreeLibrary(self.handle);
+ }
+ }
+}
diff --git a/src/libstd/sys/windows/env.rs b/src/libstd/sys/windows/env.rs
new file mode 100644
index 0000000..f0a99d6
--- /dev/null
+++ b/src/libstd/sys/windows/env.rs
@@ -0,0 +1,9 @@
+pub mod os {
+ pub const FAMILY: &str = "windows";
+ pub const OS: &str = "windows";
+ pub const DLL_PREFIX: &str = "";
+ pub const DLL_SUFFIX: &str = ".dll";
+ pub const DLL_EXTENSION: &str = "dll";
+ pub const EXE_SUFFIX: &str = ".exe";
+ pub const EXE_EXTENSION: &str = "exe";
+}
diff --git a/src/libstd/sys/windows/ext/ffi.rs b/src/libstd/sys/windows/ext/ffi.rs
new file mode 100644
index 0000000..1381825
--- /dev/null
+++ b/src/libstd/sys/windows/ext/ffi.rs
@@ -0,0 +1,142 @@
+//! Windows-specific extensions to the primitives in the `std::ffi` module.
+//!
+//! # Overview
+//!
+//! For historical reasons, the Windows API uses a form of potentially
+//! ill-formed UTF-16 encoding for strings. Specifically, the 16-bit
+//! code units in Windows strings may contain [isolated surrogate code
+//! points which are not paired together][ill-formed-utf-16]. The
+//! Unicode standard requires that surrogate code points (those in the
+//! range U+D800 to U+DFFF) always be *paired*, because in the UTF-16
+//! encoding a *surrogate code unit pair* is used to encode a single
+//! character. For compatibility with code that does not enforce
+//! these pairings, Windows does not enforce them, either.
+//!
+//! While it is not always possible to convert such a string losslessly into
+//! a valid UTF-16 string (or even UTF-8), it is often desirable to be
+//! able to round-trip such a string from and to Windows APIs
+//! losslessly. For example, some Rust code may be "bridging" some
+//! Windows APIs together, just passing `WCHAR` strings among those
+//! APIs without ever really looking into the strings.
+//!
+//! If Rust code *does* need to look into those strings, it can
+//! convert them to valid UTF-8, possibly lossily, by substituting
+//! invalid sequences with [`U+FFFD REPLACEMENT CHARACTER`][U+FFFD], as is
+//! conventionally done in other Rust APIs that deal with string
+//! encodings.
+//!
+//! # `OsStringExt` and `OsStrExt`
+//!
+//! [`OsString`] is the Rust wrapper for owned strings in the
+//! preferred representation of the operating system. On Windows,
+//! this struct gets augmented with an implementation of the
+//! [`OsStringExt`] trait, which has a [`from_wide`] method. This
+//! lets you create an [`OsString`] from a `&[u16]` slice; presumably
+//! you get such a slice out of a `WCHAR` Windows API.
+//!
+//! Similarly, [`OsStr`] is the Rust wrapper for borrowed strings from
+//! preferred representation of the operating system. On Windows, the
+//! [`OsStrExt`] trait provides the [`encode_wide`] method, which
+//! outputs an [`EncodeWide`] iterator. You can [`collect`] this
+//! iterator, for example, to obtain a `Vec<u16>`; you can later get a
+//! pointer to this vector's contents and feed it to Windows APIs.
+//!
+//! These traits, along with [`OsString`] and [`OsStr`], work in
+//! conjunction so that it is possible to **round-trip** strings from
+//! Windows and back, with no loss of data, even if the strings are
+//! ill-formed UTF-16.
+//!
+//! [ill-formed-utf-16]: https://simonsapin.github.io/wtf-8/#ill-formed-utf-16
+//! [`OsString`]: ../../../ffi/struct.OsString.html
+//! [`OsStr`]: ../../../ffi/struct.OsStr.html
+//! [`OsStringExt`]: trait.OsStringExt.html
+//! [`OsStrExt`]: trait.OsStrExt.html
+//! [`EncodeWide`]: struct.EncodeWide.html
+//! [`from_wide`]: trait.OsStringExt.html#tymethod.from_wide
+//! [`encode_wide`]: trait.OsStrExt.html#tymethod.encode_wide
+//! [`collect`]: ../../../iter/trait.Iterator.html#method.collect
+//! [U+FFFD]: ../../../char/constant.REPLACEMENT_CHARACTER.html
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+use crate::ffi::{OsString, OsStr};
+use crate::sys::os_str::Buf;
+use crate::sys_common::wtf8::Wtf8Buf;
+use crate::sys_common::{FromInner, AsInner};
+
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use crate::sys_common::wtf8::EncodeWide;
+
+/// Windows-specific extensions to [`OsString`].
+///
+/// [`OsString`]: ../../../../std/ffi/struct.OsString.html
+#[stable(feature = "rust1", since = "1.0.0")]
+pub trait OsStringExt {
+ /// Creates an `OsString` from a potentially ill-formed UTF-16 slice of
+ /// 16-bit code units.
+ ///
+ /// This is lossless: calling [`encode_wide`] on the resulting string
+ /// will always return the original code units.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ffi::OsString;
+ /// use std::os::windows::prelude::*;
+ ///
+ /// // UTF-16 encoding for "Unicode".
+ /// let source = [0x0055, 0x006E, 0x0069, 0x0063, 0x006F, 0x0064, 0x0065];
+ ///
+ /// let string = OsString::from_wide(&source[..]);
+ /// ```
+ ///
+ /// [`encode_wide`]: ./trait.OsStrExt.html#tymethod.encode_wide
+ #[stable(feature = "rust1", since = "1.0.0")]
+ fn from_wide(wide: &[u16]) -> Self;
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl OsStringExt for OsString {
+ fn from_wide(wide: &[u16]) -> OsString {
+ FromInner::from_inner(Buf { inner: Wtf8Buf::from_wide(wide) })
+ }
+}
+
+/// Windows-specific extensions to [`OsStr`].
+///
+/// [`OsStr`]: ../../../../std/ffi/struct.OsStr.html
+#[stable(feature = "rust1", since = "1.0.0")]
+pub trait OsStrExt {
+ /// Re-encodes an `OsStr` as a wide character sequence, i.e., potentially
+ /// ill-formed UTF-16.
+ ///
+ /// This is lossless: calling [`OsString::from_wide`] and then
+ /// `encode_wide` on the result will yield the original code units.
+ /// Note that the encoding does not add a final null terminator.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ffi::OsString;
+ /// use std::os::windows::prelude::*;
+ ///
+ /// // UTF-16 encoding for "Unicode".
+ /// let source = [0x0055, 0x006E, 0x0069, 0x0063, 0x006F, 0x0064, 0x0065];
+ ///
+ /// let string = OsString::from_wide(&source[..]);
+ ///
+ /// let result: Vec<u16> = string.encode_wide().collect();
+ /// assert_eq!(&source[..], &result[..]);
+ /// ```
+ ///
+ /// [`OsString::from_wide`]: ./trait.OsStringExt.html#tymethod.from_wide
+ #[stable(feature = "rust1", since = "1.0.0")]
+ fn encode_wide(&self) -> EncodeWide<'_>;
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl OsStrExt for OsStr {
+ fn encode_wide(&self) -> EncodeWide<'_> {
+ self.as_inner().inner.encode_wide()
+ }
+}
diff --git a/src/libstd/sys/windows/ext/fs.rs b/src/libstd/sys/windows/ext/fs.rs
new file mode 100644
index 0000000..268a14f
--- /dev/null
+++ b/src/libstd/sys/windows/ext/fs.rs
@@ -0,0 +1,512 @@
+//! Windows-specific extensions for the primitives in the `std::fs` module.
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+use crate::fs::{self, OpenOptions, Metadata};
+use crate::io;
+use crate::path::Path;
+use crate::sys;
+use crate::sys_common::{AsInnerMut, AsInner};
+
+/// Windows-specific extensions to [`File`].
+///
+/// [`File`]: ../../../fs/struct.File.html
+#[stable(feature = "file_offset", since = "1.15.0")]
+pub trait FileExt {
+ /// Seeks to a given position and reads a number of bytes.
+ ///
+ /// Returns the number of bytes read.
+ ///
+ /// The offset is relative to the start of the file and thus independent
+ /// from the current cursor. The current cursor **is** affected by this
+ /// function, it is set to the end of the read.
+ ///
+ /// Reading beyond the end of the file will always return with a length of
+ /// 0\.
+ ///
+ /// Note that similar to `File::read`, it is not an error to return with a
+ /// short read. When returning from such a short read, the file pointer is
+ /// still updated.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::io;
+ /// use std::fs::File;
+ /// use std::os::windows::prelude::*;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let mut file = File::open("foo.txt")?;
+ /// let mut buffer = [0; 10];
+ ///
+ /// // Read 10 bytes, starting 72 bytes from the
+ /// // start of the file.
+ /// file.seek_read(&mut buffer[..], 72)?;
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "file_offset", since = "1.15.0")]
+ fn seek_read(&self, buf: &mut [u8], offset: u64) -> io::Result<usize>;
+
+ /// Seeks to a given position and writes a number of bytes.
+ ///
+ /// Returns the number of bytes written.
+ ///
+ /// The offset is relative to the start of the file and thus independent
+ /// from the current cursor. The current cursor **is** affected by this
+ /// function, it is set to the end of the write.
+ ///
+ /// When writing beyond the end of the file, the file is appropriately
+ /// extended and the intermediate bytes are left uninitialized.
+ ///
+ /// Note that similar to `File::write`, it is not an error to return a
+ /// short write. When returning from such a short write, the file pointer
+ /// is still updated.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs::File;
+ /// use std::os::windows::prelude::*;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let mut buffer = File::create("foo.txt")?;
+ ///
+ /// // Write a byte string starting 72 bytes from
+ /// // the start of the file.
+ /// buffer.seek_write(b"some bytes", 72)?;
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "file_offset", since = "1.15.0")]
+ fn seek_write(&self, buf: &[u8], offset: u64) -> io::Result<usize>;
+}
+
+#[stable(feature = "file_offset", since = "1.15.0")]
+impl FileExt for fs::File {
+ fn seek_read(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
+ self.as_inner().read_at(buf, offset)
+ }
+
+ fn seek_write(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
+ self.as_inner().write_at(buf, offset)
+ }
+}
+
+/// Windows-specific extensions to [`fs::OpenOptions`].
+///
+/// [`fs::OpenOptions`]: ../../../../std/fs/struct.OpenOptions.html
+#[stable(feature = "open_options_ext", since = "1.10.0")]
+pub trait OpenOptionsExt {
+ /// Overrides the `dwDesiredAccess` argument to the call to [`CreateFile`]
+ /// with the specified value.
+ ///
+ /// This will override the `read`, `write`, and `append` flags on the
+ /// `OpenOptions` structure. This method provides fine-grained control over
+ /// the permissions to read, write and append data, attributes (like hidden
+ /// and system), and extended attributes.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs::OpenOptions;
+ /// use std::os::windows::prelude::*;
+ ///
+ /// // Open without read and write permission, for example if you only need
+ /// // to call `stat` on the file
+ /// let file = OpenOptions::new().access_mode(0).open("foo.txt");
+ /// ```
+ ///
+ /// [`CreateFile`]: https://msdn.microsoft.com/en-us/library/windows/desktop/aa363858.aspx
+ #[stable(feature = "open_options_ext", since = "1.10.0")]
+ fn access_mode(&mut self, access: u32) -> &mut Self;
+
+ /// Overrides the `dwShareMode` argument to the call to [`CreateFile`] with
+ /// the specified value.
+ ///
+ /// By default `share_mode` is set to
+ /// `FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE`. This allows
+ /// other processes to read, write, and delete/rename the same file
+ /// while it is open. Removing any of the flags will prevent other
+ /// processes from performing the corresponding operation until the file
+ /// handle is closed.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs::OpenOptions;
+ /// use std::os::windows::prelude::*;
+ ///
+ /// // Do not allow others to read or modify this file while we have it open
+ /// // for writing.
+ /// let file = OpenOptions::new()
+ /// .write(true)
+ /// .share_mode(0)
+ /// .open("foo.txt");
+ /// ```
+ ///
+ /// [`CreateFile`]: https://msdn.microsoft.com/en-us/library/windows/desktop/aa363858.aspx
+ #[stable(feature = "open_options_ext", since = "1.10.0")]
+ fn share_mode(&mut self, val: u32) -> &mut Self;
+
+ /// Sets extra flags for the `dwFileFlags` argument to the call to
+ /// [`CreateFile2`] to the specified value (or combines it with
+ /// `attributes` and `security_qos_flags` to set the `dwFlagsAndAttributes`
+ /// for [`CreateFile`]).
+ ///
+ /// Custom flags can only set flags, not remove flags set by Rust's options.
+ /// This option overwrites any previously set custom flags.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # #[cfg(for_demonstration_only)]
+ /// extern crate winapi;
+ /// # mod winapi { pub const FILE_FLAG_DELETE_ON_CLOSE: u32 = 0x04000000; }
+ ///
+ /// use std::fs::OpenOptions;
+ /// use std::os::windows::prelude::*;
+ ///
+ /// let file = OpenOptions::new()
+ /// .create(true)
+ /// .write(true)
+ /// .custom_flags(winapi::FILE_FLAG_DELETE_ON_CLOSE)
+ /// .open("foo.txt");
+ /// ```
+ ///
+ /// [`CreateFile`]: https://msdn.microsoft.com/en-us/library/windows/desktop/aa363858.aspx
+ /// [`CreateFile2`]: https://msdn.microsoft.com/en-us/library/windows/desktop/hh449422.aspx
+ #[stable(feature = "open_options_ext", since = "1.10.0")]
+ fn custom_flags(&mut self, flags: u32) -> &mut Self;
+
+ /// Sets the `dwFileAttributes` argument to the call to [`CreateFile2`] to
+ /// the specified value (or combines it with `custom_flags` and
+ /// `security_qos_flags` to set the `dwFlagsAndAttributes` for
+ /// [`CreateFile`]).
+ ///
+ /// If a _new_ file is created because it does not yet exist and
+ /// `.create(true)` or `.create_new(true)` are specified, the new file is
+ /// given the attributes declared with `.attributes()`.
+ ///
+ /// If an _existing_ file is opened with `.create(true).truncate(true)`, its
+ /// existing attributes are preserved and combined with the ones declared
+ /// with `.attributes()`.
+ ///
+ /// In all other cases the attributes get ignored.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # #[cfg(for_demonstration_only)]
+ /// extern crate winapi;
+ /// # mod winapi { pub const FILE_ATTRIBUTE_HIDDEN: u32 = 2; }
+ ///
+ /// use std::fs::OpenOptions;
+ /// use std::os::windows::prelude::*;
+ ///
+ /// let file = OpenOptions::new()
+ /// .write(true)
+ /// .create(true)
+ /// .attributes(winapi::FILE_ATTRIBUTE_HIDDEN)
+ /// .open("foo.txt");
+ /// ```
+ ///
+ /// [`CreateFile`]: https://msdn.microsoft.com/en-us/library/windows/desktop/aa363858.aspx
+ /// [`CreateFile2`]: https://msdn.microsoft.com/en-us/library/windows/desktop/hh449422.aspx
+ #[stable(feature = "open_options_ext", since = "1.10.0")]
+ fn attributes(&mut self, val: u32) -> &mut Self;
+
+ /// Sets the `dwSecurityQosFlags` argument to the call to [`CreateFile2`] to
+ /// the specified value (or combines it with `custom_flags` and `attributes`
+ /// to set the `dwFlagsAndAttributes` for [`CreateFile`]).
+ ///
+ /// By default `security_qos_flags` is not set. It should be specified when
+ /// opening a named pipe, to control to which degree a server process can
+ /// act on behalf of a client process (security impersonation level).
+ ///
+ /// When `security_qos_flags` is not set a malicious program can gain the
+ /// elevated privileges of a privileged Rust process when it allows opening
+ /// user-specified paths, by tricking it into opening a named pipe. So
+ /// arguably `security_qos_flags` should also be set when opening arbitrary
+ /// paths. However the bits can then conflict with other flags, specifically
+ /// `FILE_FLAG_OPEN_NO_RECALL`.
+ ///
+ /// For information about possible values, see [Impersonation Levels] on the
+ /// Windows Dev Center site. The `SECURITY_SQOS_PRESENT` flag is set
+ /// automatically when using this method.
+
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # #[cfg(for_demonstration_only)]
+ /// extern crate winapi;
+ /// # mod winapi { pub const SECURITY_IDENTIFICATION: u32 = 0; }
+ /// use std::fs::OpenOptions;
+ /// use std::os::windows::prelude::*;
+ ///
+ /// let file = OpenOptions::new()
+ /// .write(true)
+ /// .create(true)
+ ///
+ /// // Sets the flag value to `SecurityIdentification`.
+ /// .security_qos_flags(winapi::SECURITY_IDENTIFICATION)
+ ///
+ /// .open(r"\\.\pipe\MyPipe");
+ /// ```
+ ///
+ /// [`CreateFile`]: https://msdn.microsoft.com/en-us/library/windows/desktop/aa363858.aspx
+ /// [`CreateFile2`]: https://msdn.microsoft.com/en-us/library/windows/desktop/hh449422.aspx
+ /// [Impersonation Levels]:
+ /// https://msdn.microsoft.com/en-us/library/windows/desktop/aa379572.aspx
+ #[stable(feature = "open_options_ext", since = "1.10.0")]
+ fn security_qos_flags(&mut self, flags: u32) -> &mut OpenOptions;
+}
+
+#[stable(feature = "open_options_ext", since = "1.10.0")]
+impl OpenOptionsExt for OpenOptions {
+ fn access_mode(&mut self, access: u32) -> &mut OpenOptions {
+ self.as_inner_mut().access_mode(access); self
+ }
+
+ fn share_mode(&mut self, share: u32) -> &mut OpenOptions {
+ self.as_inner_mut().share_mode(share); self
+ }
+
+ fn custom_flags(&mut self, flags: u32) -> &mut OpenOptions {
+ self.as_inner_mut().custom_flags(flags); self
+ }
+
+ fn attributes(&mut self, attributes: u32) -> &mut OpenOptions {
+ self.as_inner_mut().attributes(attributes); self
+ }
+
+ fn security_qos_flags(&mut self, flags: u32) -> &mut OpenOptions {
+ self.as_inner_mut().security_qos_flags(flags); self
+ }
+}
+
+/// Windows-specific extensions to [`fs::Metadata`].
+///
+/// The data members that this trait exposes correspond to the members
+/// of the [`BY_HANDLE_FILE_INFORMATION`] structure.
+///
+/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html
+/// [`BY_HANDLE_FILE_INFORMATION`]:
+/// https://msdn.microsoft.com/en-us/library/windows/desktop/aa363788.aspx
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+pub trait MetadataExt {
+ /// Returns the value of the `dwFileAttributes` field of this metadata.
+ ///
+ /// This field contains the file system attribute information for a file
+ /// or directory. For possible values and their descriptions, see
+ /// [File Attribute Constants] in the Windows Dev Center.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::io;
+ /// use std::fs;
+ /// use std::os::windows::prelude::*;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let metadata = fs::metadata("foo.txt")?;
+ /// let attributes = metadata.file_attributes();
+ /// Ok(())
+ /// }
+ /// ```
+ ///
+ /// [File Attribute Constants]:
+ /// https://msdn.microsoft.com/en-us/library/windows/desktop/gg258117.aspx
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn file_attributes(&self) -> u32;
+
+ /// Returns the value of the `ftCreationTime` field of this metadata.
+ ///
+ /// The returned 64-bit value is equivalent to a [`FILETIME`] struct,
+ /// which represents the number of 100-nanosecond intervals since
+ /// January 1, 1601 (UTC). The struct is automatically
+ /// converted to a `u64` value, as that is the recommended way
+ /// to use it.
+ ///
+ /// If the underlying filesystem does not support creation time, the
+ /// returned value is 0.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::io;
+ /// use std::fs;
+ /// use std::os::windows::prelude::*;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let metadata = fs::metadata("foo.txt")?;
+ /// let creation_time = metadata.creation_time();
+ /// Ok(())
+ /// }
+ /// ```
+ ///
+ /// [`FILETIME`]: https://msdn.microsoft.com/en-us/library/windows/desktop/ms724284.aspx
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn creation_time(&self) -> u64;
+
+ /// Returns the value of the `ftLastAccessTime` field of this metadata.
+ ///
+ /// The returned 64-bit value is equivalent to a [`FILETIME`] struct,
+ /// which represents the number of 100-nanosecond intervals since
+ /// January 1, 1601 (UTC). The struct is automatically
+ /// converted to a `u64` value, as that is the recommended way
+ /// to use it.
+ ///
+ /// For a file, the value specifies the last time that a file was read
+ /// from or written to. For a directory, the value specifies when
+ /// the directory was created. For both files and directories, the
+ /// specified date is correct, but the time of day is always set to
+ /// midnight.
+ ///
+ /// If the underlying filesystem does not support last access time, the
+ /// returned value is 0.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::io;
+ /// use std::fs;
+ /// use std::os::windows::prelude::*;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let metadata = fs::metadata("foo.txt")?;
+ /// let last_access_time = metadata.last_access_time();
+ /// Ok(())
+ /// }
+ /// ```
+ ///
+ /// [`FILETIME`]: https://msdn.microsoft.com/en-us/library/windows/desktop/ms724284.aspx
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn last_access_time(&self) -> u64;
+
+ /// Returns the value of the `ftLastWriteTime` field of this metadata.
+ ///
+ /// The returned 64-bit value is equivalent to a [`FILETIME`] struct,
+ /// which represents the number of 100-nanosecond intervals since
+ /// January 1, 1601 (UTC). The struct is automatically
+ /// converted to a `u64` value, as that is the recommended way
+ /// to use it.
+ ///
+ /// For a file, the value specifies the last time that a file was written
+ /// to. For a directory, the structure specifies when the directory was
+ /// created.
+ ///
+ /// If the underlying filesystem does not support the last write time,
+ /// the returned value is 0.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::io;
+ /// use std::fs;
+ /// use std::os::windows::prelude::*;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let metadata = fs::metadata("foo.txt")?;
+ /// let last_write_time = metadata.last_write_time();
+ /// Ok(())
+ /// }
+ /// ```
+ ///
+ /// [`FILETIME`]: https://msdn.microsoft.com/en-us/library/windows/desktop/ms724284.aspx
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn last_write_time(&self) -> u64;
+
+ /// Returns the value of the `nFileSize{High,Low}` fields of this
+ /// metadata.
+ ///
+ /// The returned value does not have meaning for directories.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::io;
+ /// use std::fs;
+ /// use std::os::windows::prelude::*;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let metadata = fs::metadata("foo.txt")?;
+ /// let file_size = metadata.file_size();
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn file_size(&self) -> u64;
+}
+
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+impl MetadataExt for Metadata {
+ fn file_attributes(&self) -> u32 { self.as_inner().attrs() }
+ fn creation_time(&self) -> u64 { self.as_inner().created_u64() }
+ fn last_access_time(&self) -> u64 { self.as_inner().accessed_u64() }
+ fn last_write_time(&self) -> u64 { self.as_inner().modified_u64() }
+ fn file_size(&self) -> u64 { self.as_inner().size() }
+}
+
+/// Windows-specific extensions to [`FileType`].
+///
+/// On Windows, a symbolic link knows whether it is a file or directory.
+///
+/// [`FileType`]: ../../../../std/fs/struct.FileType.html
+#[unstable(feature = "windows_file_type_ext", issue = "0")]
+pub trait FileTypeExt {
+ /// Returns `true` if this file type is a symbolic link that is also a directory.
+ #[unstable(feature = "windows_file_type_ext", issue = "0")]
+ fn is_symlink_dir(&self) -> bool;
+ /// Returns `true` if this file type is a symbolic link that is also a file.
+ #[unstable(feature = "windows_file_type_ext", issue = "0")]
+ fn is_symlink_file(&self) -> bool;
+}
+
+#[unstable(feature = "windows_file_type_ext", issue = "0")]
+impl FileTypeExt for fs::FileType {
+ fn is_symlink_dir(&self) -> bool { self.as_inner().is_symlink_dir() }
+ fn is_symlink_file(&self) -> bool { self.as_inner().is_symlink_file() }
+}
+
+/// Creates a new file symbolic link on the filesystem.
+///
+/// The `dst` path will be a file symbolic link pointing to the `src`
+/// path.
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::os::windows::fs;
+///
+/// fn main() -> std::io::Result<()> {
+/// fs::symlink_file("a.txt", "b.txt")?;
+/// Ok(())
+/// }
+/// ```
+#[stable(feature = "symlink", since = "1.1.0")]
+pub fn symlink_file<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q)
+ -> io::Result<()> {
+ sys::fs::symlink_inner(src.as_ref(), dst.as_ref(), false)
+}
+
+/// Creates a new directory symlink on the filesystem.
+///
+/// The `dst` path will be a directory symbolic link pointing to the `src`
+/// path.
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::os::windows::fs;
+///
+/// fn main() -> std::io::Result<()> {
+/// fs::symlink_dir("a", "b")?;
+/// Ok(())
+/// }
+/// ```
+#[stable(feature = "symlink", since = "1.1.0")]
+pub fn symlink_dir<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q)
+ -> io::Result<()> {
+ sys::fs::symlink_inner(src.as_ref(), dst.as_ref(), true)
+}
diff --git a/src/libstd/sys/windows/ext/io.rs b/src/libstd/sys/windows/ext/io.rs
new file mode 100644
index 0000000..ec47c2e
--- /dev/null
+++ b/src/libstd/sys/windows/ext/io.rs
@@ -0,0 +1,220 @@
+#![stable(feature = "rust1", since = "1.0.0")]
+
+use crate::fs;
+use crate::os::windows::raw;
+use crate::net;
+use crate::sys_common::{self, AsInner, FromInner, IntoInner};
+use crate::sys;
+use crate::sys::c;
+use crate::io;
+
+/// Raw HANDLEs.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub type RawHandle = raw::HANDLE;
+
+/// Raw SOCKETs.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub type RawSocket = raw::SOCKET;
+
+/// Extracts raw handles.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub trait AsRawHandle {
+ /// Extracts the raw handle, without taking any ownership.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ fn as_raw_handle(&self) -> RawHandle;
+}
+
+/// Construct I/O objects from raw handles.
+#[stable(feature = "from_raw_os", since = "1.1.0")]
+pub trait FromRawHandle {
+ /// Constructs a new I/O object from the specified raw handle.
+ ///
+ /// This function will **consume ownership** of the handle given,
+ /// passing responsibility for closing the handle to the returned
+ /// object.
+ ///
+ /// This function is also unsafe as the primitives currently returned
+ /// have the contract that they are the sole owner of the file
+ /// descriptor they are wrapping. Usage of this function could
+ /// accidentally allow violating this contract which can cause memory
+ /// unsafety in code that relies on it being true.
+ #[stable(feature = "from_raw_os", since = "1.1.0")]
+ unsafe fn from_raw_handle(handle: RawHandle) -> Self;
+}
+
+/// A trait to express the ability to consume an object and acquire ownership of
+/// its raw `HANDLE`.
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+pub trait IntoRawHandle {
+ /// Consumes this object, returning the raw underlying handle.
+ ///
+ /// This function **transfers ownership** of the underlying handle to the
+ /// caller. Callers are then the unique owners of the handle and must close
+ /// it once it's no longer needed.
+ #[stable(feature = "into_raw_os", since = "1.4.0")]
+ fn into_raw_handle(self) -> RawHandle;
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRawHandle for fs::File {
+ fn as_raw_handle(&self) -> RawHandle {
+ self.as_inner().handle().raw() as RawHandle
+ }
+}
+
+#[stable(feature = "asraw_stdio", since = "1.21.0")]
+impl AsRawHandle for io::Stdin {
+ fn as_raw_handle(&self) -> RawHandle {
+ unsafe { c::GetStdHandle(c::STD_INPUT_HANDLE) as RawHandle }
+ }
+}
+
+#[stable(feature = "asraw_stdio", since = "1.21.0")]
+impl AsRawHandle for io::Stdout {
+ fn as_raw_handle(&self) -> RawHandle {
+ unsafe { c::GetStdHandle(c::STD_OUTPUT_HANDLE) as RawHandle }
+ }
+}
+
+#[stable(feature = "asraw_stdio", since = "1.21.0")]
+impl AsRawHandle for io::Stderr {
+ fn as_raw_handle(&self) -> RawHandle {
+ unsafe { c::GetStdHandle(c::STD_ERROR_HANDLE) as RawHandle }
+ }
+}
+
+#[stable(feature = "asraw_stdio_locks", since = "1.35.0")]
+impl<'a> AsRawHandle for io::StdinLock<'a> {
+ fn as_raw_handle(&self) -> RawHandle {
+ unsafe { c::GetStdHandle(c::STD_INPUT_HANDLE) as RawHandle }
+ }
+}
+
+#[stable(feature = "asraw_stdio_locks", since = "1.35.0")]
+impl<'a> AsRawHandle for io::StdoutLock<'a> {
+ fn as_raw_handle(&self) -> RawHandle {
+ unsafe { c::GetStdHandle(c::STD_OUTPUT_HANDLE) as RawHandle }
+ }
+}
+
+#[stable(feature = "asraw_stdio_locks", since = "1.35.0")]
+impl<'a> AsRawHandle for io::StderrLock<'a> {
+ fn as_raw_handle(&self) -> RawHandle {
+ unsafe { c::GetStdHandle(c::STD_ERROR_HANDLE) as RawHandle }
+ }
+}
+
+#[stable(feature = "from_raw_os", since = "1.1.0")]
+impl FromRawHandle for fs::File {
+ unsafe fn from_raw_handle(handle: RawHandle) -> fs::File {
+ let handle = handle as c::HANDLE;
+ fs::File::from_inner(sys::fs::File::from_inner(handle))
+ }
+}
+
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+impl IntoRawHandle for fs::File {
+ fn into_raw_handle(self) -> RawHandle {
+ self.into_inner().into_handle().into_raw() as *mut _
+ }
+}
+
+/// Extracts raw sockets.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub trait AsRawSocket {
+ /// Extracts the underlying raw socket from this object.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ fn as_raw_socket(&self) -> RawSocket;
+}
+
+/// Creates I/O objects from raw sockets.
+#[stable(feature = "from_raw_os", since = "1.1.0")]
+pub trait FromRawSocket {
+ /// Creates a new I/O object from the given raw socket.
+ ///
+ /// This function will **consume ownership** of the socket provided and
+ /// it will be closed when the returned object goes out of scope.
+ ///
+ /// This function is also unsafe as the primitives currently returned
+ /// have the contract that they are the sole owner of the file
+ /// descriptor they are wrapping. Usage of this function could
+ /// accidentally allow violating this contract which can cause memory
+ /// unsafety in code that relies on it being true.
+ #[stable(feature = "from_raw_os", since = "1.1.0")]
+ unsafe fn from_raw_socket(sock: RawSocket) -> Self;
+}
+
+/// A trait to express the ability to consume an object and acquire ownership of
+/// its raw `SOCKET`.
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+pub trait IntoRawSocket {
+ /// Consumes this object, returning the raw underlying socket.
+ ///
+ /// This function **transfers ownership** of the underlying socket to the
+ /// caller. Callers are then the unique owners of the socket and must close
+ /// it once it's no longer needed.
+ #[stable(feature = "into_raw_os", since = "1.4.0")]
+ fn into_raw_socket(self) -> RawSocket;
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRawSocket for net::TcpStream {
+ fn as_raw_socket(&self) -> RawSocket {
+ *self.as_inner().socket().as_inner()
+ }
+}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRawSocket for net::TcpListener {
+ fn as_raw_socket(&self) -> RawSocket {
+ *self.as_inner().socket().as_inner()
+ }
+}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRawSocket for net::UdpSocket {
+ fn as_raw_socket(&self) -> RawSocket {
+ *self.as_inner().socket().as_inner()
+ }
+}
+
+#[stable(feature = "from_raw_os", since = "1.1.0")]
+impl FromRawSocket for net::TcpStream {
+ unsafe fn from_raw_socket(sock: RawSocket) -> net::TcpStream {
+ let sock = sys::net::Socket::from_inner(sock);
+ net::TcpStream::from_inner(sys_common::net::TcpStream::from_inner(sock))
+ }
+}
+#[stable(feature = "from_raw_os", since = "1.1.0")]
+impl FromRawSocket for net::TcpListener {
+ unsafe fn from_raw_socket(sock: RawSocket) -> net::TcpListener {
+ let sock = sys::net::Socket::from_inner(sock);
+ net::TcpListener::from_inner(sys_common::net::TcpListener::from_inner(sock))
+ }
+}
+#[stable(feature = "from_raw_os", since = "1.1.0")]
+impl FromRawSocket for net::UdpSocket {
+ unsafe fn from_raw_socket(sock: RawSocket) -> net::UdpSocket {
+ let sock = sys::net::Socket::from_inner(sock);
+ net::UdpSocket::from_inner(sys_common::net::UdpSocket::from_inner(sock))
+ }
+}
+
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+impl IntoRawSocket for net::TcpStream {
+ fn into_raw_socket(self) -> RawSocket {
+ self.into_inner().into_socket().into_inner()
+ }
+}
+
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+impl IntoRawSocket for net::TcpListener {
+ fn into_raw_socket(self) -> RawSocket {
+ self.into_inner().into_socket().into_inner()
+ }
+}
+
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+impl IntoRawSocket for net::UdpSocket {
+ fn into_raw_socket(self) -> RawSocket {
+ self.into_inner().into_socket().into_inner()
+ }
+}
diff --git a/src/libstd/sys/windows/ext/mod.rs b/src/libstd/sys/windows/ext/mod.rs
new file mode 100644
index 0000000..0a6d435
--- /dev/null
+++ b/src/libstd/sys/windows/ext/mod.rs
@@ -0,0 +1,35 @@
+//! Platform-specific extensions to `std` for Windows.
+//!
+//! Provides access to platform-level information for Windows, and exposes
+//! Windows-specific idioms that would otherwise be inappropriate as part
+//! the core `std` library. These extensions allow developers to use
+//! `std` types and idioms with Windows in a way that the normal
+//! platform-agnostic idioms would not normally support.
+
+#![stable(feature = "rust1", since = "1.0.0")]
+#![doc(cfg(windows))]
+#![allow(missing_docs)]
+
+pub mod ffi;
+pub mod fs;
+pub mod io;
+pub mod raw;
+pub mod process;
+pub mod thread;
+
+/// A prelude for conveniently writing platform-specific code.
+///
+/// Includes all extension traits, and some important type definitions.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub mod prelude {
+ #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
+ pub use super::io::{RawSocket, RawHandle, AsRawSocket, AsRawHandle};
+ #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
+ pub use super::io::{FromRawSocket, FromRawHandle, IntoRawSocket, IntoRawHandle};
+ #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
+ pub use super::ffi::{OsStrExt, OsStringExt};
+ #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
+ pub use super::fs::{OpenOptionsExt, MetadataExt};
+ #[doc(no_inline)] #[stable(feature = "file_offset", since = "1.15.0")]
+ pub use super::fs::FileExt;
+}
diff --git a/src/libstd/sys/windows/ext/process.rs b/src/libstd/sys/windows/ext/process.rs
new file mode 100644
index 0000000..b2e6cde
--- /dev/null
+++ b/src/libstd/sys/windows/ext/process.rs
@@ -0,0 +1,113 @@
+//! Extensions to `std::process` for Windows.
+
+#![stable(feature = "process_extensions", since = "1.2.0")]
+
+use crate::os::windows::io::{FromRawHandle, RawHandle, AsRawHandle, IntoRawHandle};
+use crate::process;
+use crate::sys;
+use crate::sys_common::{AsInnerMut, AsInner, FromInner, IntoInner};
+
+#[stable(feature = "process_extensions", since = "1.2.0")]
+impl FromRawHandle for process::Stdio {
+ unsafe fn from_raw_handle(handle: RawHandle) -> process::Stdio {
+ let handle = sys::handle::Handle::new(handle as *mut _);
+ let io = sys::process::Stdio::Handle(handle);
+ process::Stdio::from_inner(io)
+ }
+}
+
+#[stable(feature = "process_extensions", since = "1.2.0")]
+impl AsRawHandle for process::Child {
+ fn as_raw_handle(&self) -> RawHandle {
+ self.as_inner().handle().raw() as *mut _
+ }
+}
+
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+impl IntoRawHandle for process::Child {
+ fn into_raw_handle(self) -> RawHandle {
+ self.into_inner().into_handle().into_raw() as *mut _
+ }
+}
+
+#[stable(feature = "process_extensions", since = "1.2.0")]
+impl AsRawHandle for process::ChildStdin {
+ fn as_raw_handle(&self) -> RawHandle {
+ self.as_inner().handle().raw() as *mut _
+ }
+}
+
+#[stable(feature = "process_extensions", since = "1.2.0")]
+impl AsRawHandle for process::ChildStdout {
+ fn as_raw_handle(&self) -> RawHandle {
+ self.as_inner().handle().raw() as *mut _
+ }
+}
+
+#[stable(feature = "process_extensions", since = "1.2.0")]
+impl AsRawHandle for process::ChildStderr {
+ fn as_raw_handle(&self) -> RawHandle {
+ self.as_inner().handle().raw() as *mut _
+ }
+}
+
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+impl IntoRawHandle for process::ChildStdin {
+ fn into_raw_handle(self) -> RawHandle {
+ self.into_inner().into_handle().into_raw() as *mut _
+ }
+}
+
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+impl IntoRawHandle for process::ChildStdout {
+ fn into_raw_handle(self) -> RawHandle {
+ self.into_inner().into_handle().into_raw() as *mut _
+ }
+}
+
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+impl IntoRawHandle for process::ChildStderr {
+ fn into_raw_handle(self) -> RawHandle {
+ self.into_inner().into_handle().into_raw() as *mut _
+ }
+}
+
+/// Windows-specific extensions to [`process::ExitStatus`].
+///
+/// [`process::ExitStatus`]: ../../../../std/process/struct.ExitStatus.html
+#[stable(feature = "exit_status_from", since = "1.12.0")]
+pub trait ExitStatusExt {
+ /// Creates a new `ExitStatus` from the raw underlying `u32` return value of
+ /// a process.
+ #[stable(feature = "exit_status_from", since = "1.12.0")]
+ fn from_raw(raw: u32) -> Self;
+}
+
+#[stable(feature = "exit_status_from", since = "1.12.0")]
+impl ExitStatusExt for process::ExitStatus {
+ fn from_raw(raw: u32) -> Self {
+ process::ExitStatus::from_inner(From::from(raw))
+ }
+}
+
+/// Windows-specific extensions to the [`process::Command`] builder.
+///
+/// [`process::Command`]: ../../../../std/process/struct.Command.html
+#[stable(feature = "windows_process_extensions", since = "1.16.0")]
+pub trait CommandExt {
+ /// Sets the [process creation flags][1] to be passed to `CreateProcess`.
+ ///
+ /// These will always be ORed with `CREATE_UNICODE_ENVIRONMENT`.
+ ///
+ /// [1]: https://msdn.microsoft.com/en-us/library/windows/desktop/ms684863(v=vs.85).aspx
+ #[stable(feature = "windows_process_extensions", since = "1.16.0")]
+ fn creation_flags(&mut self, flags: u32) -> &mut process::Command;
+}
+
+#[stable(feature = "windows_process_extensions", since = "1.16.0")]
+impl CommandExt for process::Command {
+ fn creation_flags(&mut self, flags: u32) -> &mut process::Command {
+ self.as_inner_mut().creation_flags(flags);
+ self
+ }
+}
diff --git a/src/libstd/sys/windows/ext/raw.rs b/src/libstd/sys/windows/ext/raw.rs
new file mode 100644
index 0000000..d2bab27
--- /dev/null
+++ b/src/libstd/sys/windows/ext/raw.rs
@@ -0,0 +1,11 @@
+//! Windows-specific primitives
+
+#![stable(feature = "raw_ext", since = "1.1.0")]
+
+use crate::os::raw::c_void;
+
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type HANDLE = *mut c_void;
+#[cfg(target_pointer_width = "32")]
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type SOCKET = u32;
+#[cfg(target_pointer_width = "64")]
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type SOCKET = u64;
diff --git a/src/libstd/sys/windows/ext/thread.rs b/src/libstd/sys/windows/ext/thread.rs
new file mode 100644
index 0000000..fdc7e7f
--- /dev/null
+++ b/src/libstd/sys/windows/ext/thread.rs
@@ -0,0 +1,21 @@
+//! Extensions to `std::thread` for Windows.
+
+#![stable(feature = "thread_extensions", since = "1.9.0")]
+
+use crate::os::windows::io::{RawHandle, AsRawHandle, IntoRawHandle};
+use crate::thread;
+use crate::sys_common::{AsInner, IntoInner};
+
+#[stable(feature = "thread_extensions", since = "1.9.0")]
+impl<T> AsRawHandle for thread::JoinHandle<T> {
+ fn as_raw_handle(&self) -> RawHandle {
+ self.as_inner().handle().raw() as *mut _
+ }
+}
+
+#[stable(feature = "thread_extensions", since = "1.9.0")]
+impl<T> IntoRawHandle for thread::JoinHandle<T> {
+ fn into_raw_handle(self) -> RawHandle {
+ self.into_inner().into_handle().into_raw() as *mut _
+ }
+}
diff --git a/src/libstd/sys/windows/fast_thread_local.rs b/src/libstd/sys/windows/fast_thread_local.rs
new file mode 100644
index 0000000..0ccc67e
--- /dev/null
+++ b/src/libstd/sys/windows/fast_thread_local.rs
@@ -0,0 +1,8 @@
+#![unstable(feature = "thread_local_internals", issue = "0")]
+#![cfg(target_thread_local)]
+
+pub use crate::sys_common::thread_local::register_dtor_fallback as register_dtor;
+
+pub fn requires_move_before_drop() -> bool {
+ false
+}
diff --git a/src/libstd/sys/windows/fs.rs b/src/libstd/sys/windows/fs.rs
new file mode 100644
index 0000000..4ebbb07
--- /dev/null
+++ b/src/libstd/sys/windows/fs.rs
@@ -0,0 +1,797 @@
+use crate::os::windows::prelude::*;
+
+use crate::ffi::OsString;
+use crate::fmt;
+use crate::io::{self, Error, SeekFrom};
+use crate::mem;
+use crate::path::{Path, PathBuf};
+use crate::ptr;
+use crate::slice;
+use crate::sync::Arc;
+use crate::sys::handle::Handle;
+use crate::sys::time::SystemTime;
+use crate::sys::{c, cvt};
+use crate::sys_common::FromInner;
+
+use super::to_u16s;
+
+pub struct File { handle: Handle }
+
+#[derive(Clone)]
+pub struct FileAttr {
+ attributes: c::DWORD,
+ creation_time: c::FILETIME,
+ last_access_time: c::FILETIME,
+ last_write_time: c::FILETIME,
+ file_size: u64,
+ reparse_tag: c::DWORD,
+}
+
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
+pub struct FileType {
+ attributes: c::DWORD,
+ reparse_tag: c::DWORD,
+}
+
+pub struct ReadDir {
+ handle: FindNextFileHandle,
+ root: Arc<PathBuf>,
+ first: Option<c::WIN32_FIND_DATAW>,
+}
+
+struct FindNextFileHandle(c::HANDLE);
+
+unsafe impl Send for FindNextFileHandle {}
+unsafe impl Sync for FindNextFileHandle {}
+
+pub struct DirEntry {
+ root: Arc<PathBuf>,
+ data: c::WIN32_FIND_DATAW,
+}
+
+#[derive(Clone, Debug)]
+pub struct OpenOptions {
+ // generic
+ read: bool,
+ write: bool,
+ append: bool,
+ truncate: bool,
+ create: bool,
+ create_new: bool,
+ // system-specific
+ custom_flags: u32,
+ access_mode: Option<c::DWORD>,
+ attributes: c::DWORD,
+ share_mode: c::DWORD,
+ security_qos_flags: c::DWORD,
+ security_attributes: usize, // FIXME: should be a reference
+}
+
+#[derive(Clone, PartialEq, Eq, Debug)]
+pub struct FilePermissions { attrs: c::DWORD }
+
+#[derive(Debug)]
+pub struct DirBuilder;
+
+impl fmt::Debug for ReadDir {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ // This will only be called from std::fs::ReadDir, which will add a "ReadDir()" frame.
+ // Thus the result will be e g 'ReadDir("C:\")'
+ fmt::Debug::fmt(&*self.root, f)
+ }
+}
+
+impl Iterator for ReadDir {
+ type Item = io::Result<DirEntry>;
+ fn next(&mut self) -> Option<io::Result<DirEntry>> {
+ if let Some(first) = self.first.take() {
+ if let Some(e) = DirEntry::new(&self.root, &first) {
+ return Some(Ok(e));
+ }
+ }
+ unsafe {
+ let mut wfd = mem::zeroed();
+ loop {
+ if c::FindNextFileW(self.handle.0, &mut wfd) == 0 {
+ if c::GetLastError() == c::ERROR_NO_MORE_FILES {
+ return None
+ } else {
+ return Some(Err(Error::last_os_error()))
+ }
+ }
+ if let Some(e) = DirEntry::new(&self.root, &wfd) {
+ return Some(Ok(e))
+ }
+ }
+ }
+ }
+}
+
+impl Drop for FindNextFileHandle {
+ fn drop(&mut self) {
+ let r = unsafe { c::FindClose(self.0) };
+ debug_assert!(r != 0);
+ }
+}
+
+impl DirEntry {
+ fn new(root: &Arc<PathBuf>, wfd: &c::WIN32_FIND_DATAW) -> Option<DirEntry> {
+ match &wfd.cFileName[0..3] {
+ // check for '.' and '..'
+ &[46, 0, ..] |
+ &[46, 46, 0, ..] => return None,
+ _ => {}
+ }
+
+ Some(DirEntry {
+ root: root.clone(),
+ data: *wfd,
+ })
+ }
+
+ pub fn path(&self) -> PathBuf {
+ self.root.join(&self.file_name())
+ }
+
+ pub fn file_name(&self) -> OsString {
+ let filename = super::truncate_utf16_at_nul(&self.data.cFileName);
+ OsString::from_wide(filename)
+ }
+
+ pub fn file_type(&self) -> io::Result<FileType> {
+ Ok(FileType::new(self.data.dwFileAttributes,
+ /* reparse_tag = */ self.data.dwReserved0))
+ }
+
+ pub fn metadata(&self) -> io::Result<FileAttr> {
+ Ok(FileAttr {
+ attributes: self.data.dwFileAttributes,
+ creation_time: self.data.ftCreationTime,
+ last_access_time: self.data.ftLastAccessTime,
+ last_write_time: self.data.ftLastWriteTime,
+ file_size: ((self.data.nFileSizeHigh as u64) << 32) | (self.data.nFileSizeLow as u64),
+ reparse_tag: if self.data.dwFileAttributes & c::FILE_ATTRIBUTE_REPARSE_POINT != 0 {
+ // reserved unless this is a reparse point
+ self.data.dwReserved0
+ } else {
+ 0
+ },
+ })
+ }
+}
+
+impl OpenOptions {
+ pub fn new() -> OpenOptions {
+ OpenOptions {
+ // generic
+ read: false,
+ write: false,
+ append: false,
+ truncate: false,
+ create: false,
+ create_new: false,
+ // system-specific
+ custom_flags: 0,
+ access_mode: None,
+ share_mode: c::FILE_SHARE_READ | c::FILE_SHARE_WRITE | c::FILE_SHARE_DELETE,
+ attributes: 0,
+ security_qos_flags: 0,
+ security_attributes: 0,
+ }
+ }
+
+ pub fn read(&mut self, read: bool) { self.read = read; }
+ pub fn write(&mut self, write: bool) { self.write = write; }
+ pub fn append(&mut self, append: bool) { self.append = append; }
+ pub fn truncate(&mut self, truncate: bool) { self.truncate = truncate; }
+ pub fn create(&mut self, create: bool) { self.create = create; }
+ pub fn create_new(&mut self, create_new: bool) { self.create_new = create_new; }
+
+ pub fn custom_flags(&mut self, flags: u32) { self.custom_flags = flags; }
+ pub fn access_mode(&mut self, access_mode: u32) { self.access_mode = Some(access_mode); }
+ pub fn share_mode(&mut self, share_mode: u32) { self.share_mode = share_mode; }
+ pub fn attributes(&mut self, attrs: u32) { self.attributes = attrs; }
+ pub fn security_qos_flags(&mut self, flags: u32) {
+ // We have to set `SECURITY_SQOS_PRESENT` here, because one of the valid flags we can
+ // receive is `SECURITY_ANONYMOUS = 0x0`, which we can't check for later on.
+ self.security_qos_flags = flags | c::SECURITY_SQOS_PRESENT;
+ }
+ pub fn security_attributes(&mut self, attrs: c::LPSECURITY_ATTRIBUTES) {
+ self.security_attributes = attrs as usize;
+ }
+
+ fn get_access_mode(&self) -> io::Result<c::DWORD> {
+ const ERROR_INVALID_PARAMETER: i32 = 87;
+
+ match (self.read, self.write, self.append, self.access_mode) {
+ (.., Some(mode)) => Ok(mode),
+ (true, false, false, None) => Ok(c::GENERIC_READ),
+ (false, true, false, None) => Ok(c::GENERIC_WRITE),
+ (true, true, false, None) => Ok(c::GENERIC_READ | c::GENERIC_WRITE),
+ (false, _, true, None) => Ok(c::FILE_GENERIC_WRITE & !c::FILE_WRITE_DATA),
+ (true, _, true, None) => Ok(c::GENERIC_READ |
+ (c::FILE_GENERIC_WRITE & !c::FILE_WRITE_DATA)),
+ (false, false, false, None) => Err(Error::from_raw_os_error(ERROR_INVALID_PARAMETER)),
+ }
+ }
+
+ fn get_creation_mode(&self) -> io::Result<c::DWORD> {
+ const ERROR_INVALID_PARAMETER: i32 = 87;
+
+ match (self.write, self.append) {
+ (true, false) => {}
+ (false, false) =>
+ if self.truncate || self.create || self.create_new {
+ return Err(Error::from_raw_os_error(ERROR_INVALID_PARAMETER));
+ },
+ (_, true) =>
+ if self.truncate && !self.create_new {
+ return Err(Error::from_raw_os_error(ERROR_INVALID_PARAMETER));
+ },
+ }
+
+ Ok(match (self.create, self.truncate, self.create_new) {
+ (false, false, false) => c::OPEN_EXISTING,
+ (true, false, false) => c::OPEN_ALWAYS,
+ (false, true, false) => c::TRUNCATE_EXISTING,
+ (true, true, false) => c::CREATE_ALWAYS,
+ (_, _, true) => c::CREATE_NEW,
+ })
+ }
+
+ fn get_flags_and_attributes(&self) -> c::DWORD {
+ self.custom_flags |
+ self.attributes |
+ self.security_qos_flags |
+ if self.create_new { c::FILE_FLAG_OPEN_REPARSE_POINT } else { 0 }
+ }
+}
+
+impl File {
+ pub fn open(path: &Path, opts: &OpenOptions) -> io::Result<File> {
+ let path = to_u16s(path)?;
+ let handle = unsafe {
+ c::CreateFileW(path.as_ptr(),
+ opts.get_access_mode()?,
+ opts.share_mode,
+ opts.security_attributes as *mut _,
+ opts.get_creation_mode()?,
+ opts.get_flags_and_attributes(),
+ ptr::null_mut())
+ };
+ if handle == c::INVALID_HANDLE_VALUE {
+ Err(Error::last_os_error())
+ } else {
+ Ok(File { handle: Handle::new(handle) })
+ }
+ }
+
+ pub fn fsync(&self) -> io::Result<()> {
+ cvt(unsafe { c::FlushFileBuffers(self.handle.raw()) })?;
+ Ok(())
+ }
+
+ pub fn datasync(&self) -> io::Result<()> { self.fsync() }
+
+ pub fn truncate(&self, size: u64) -> io::Result<()> {
+ let mut info = c::FILE_END_OF_FILE_INFO {
+ EndOfFile: size as c::LARGE_INTEGER,
+ };
+ let size = mem::size_of_val(&info);
+ cvt(unsafe {
+ c::SetFileInformationByHandle(self.handle.raw(),
+ c::FileEndOfFileInfo,
+ &mut info as *mut _ as *mut _,
+ size as c::DWORD)
+ })?;
+ Ok(())
+ }
+
+ pub fn file_attr(&self) -> io::Result<FileAttr> {
+ unsafe {
+ let mut info: c::BY_HANDLE_FILE_INFORMATION = mem::zeroed();
+ cvt(c::GetFileInformationByHandle(self.handle.raw(),
+ &mut info))?;
+ let mut attr = FileAttr {
+ attributes: info.dwFileAttributes,
+ creation_time: info.ftCreationTime,
+ last_access_time: info.ftLastAccessTime,
+ last_write_time: info.ftLastWriteTime,
+ file_size: ((info.nFileSizeHigh as u64) << 32) | (info.nFileSizeLow as u64),
+ reparse_tag: 0,
+ };
+ if attr.is_reparse_point() {
+ let mut b = [0; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
+ if let Ok((_, buf)) = self.reparse_point(&mut b) {
+ attr.reparse_tag = buf.ReparseTag;
+ }
+ }
+ Ok(attr)
+ }
+ }
+
+ pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
+ self.handle.read(buf)
+ }
+
+ pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
+ self.handle.read_at(buf, offset)
+ }
+
+ pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
+ self.handle.write(buf)
+ }
+
+ pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
+ self.handle.write_at(buf, offset)
+ }
+
+ pub fn flush(&self) -> io::Result<()> { Ok(()) }
+
+ pub fn seek(&self, pos: SeekFrom) -> io::Result<u64> {
+ let (whence, pos) = match pos {
+ // Casting to `i64` is fine, `SetFilePointerEx` reinterprets this
+ // integer as `u64`.
+ SeekFrom::Start(n) => (c::FILE_BEGIN, n as i64),
+ SeekFrom::End(n) => (c::FILE_END, n),
+ SeekFrom::Current(n) => (c::FILE_CURRENT, n),
+ };
+ let pos = pos as c::LARGE_INTEGER;
+ let mut newpos = 0;
+ cvt(unsafe {
+ c::SetFilePointerEx(self.handle.raw(), pos,
+ &mut newpos, whence)
+ })?;
+ Ok(newpos as u64)
+ }
+
+ pub fn duplicate(&self) -> io::Result<File> {
+ Ok(File {
+ handle: self.handle.duplicate(0, true, c::DUPLICATE_SAME_ACCESS)?,
+ })
+ }
+
+ pub fn handle(&self) -> &Handle { &self.handle }
+
+ pub fn into_handle(self) -> Handle { self.handle }
+
+ fn reparse_point<'a>(&self,
+ space: &'a mut [u8; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE])
+ -> io::Result<(c::DWORD, &'a c::REPARSE_DATA_BUFFER)> {
+ unsafe {
+ let mut bytes = 0;
+ cvt({
+ c::DeviceIoControl(self.handle.raw(),
+ c::FSCTL_GET_REPARSE_POINT,
+ ptr::null_mut(),
+ 0,
+ space.as_mut_ptr() as *mut _,
+ space.len() as c::DWORD,
+ &mut bytes,
+ ptr::null_mut())
+ })?;
+ Ok((bytes, &*(space.as_ptr() as *const c::REPARSE_DATA_BUFFER)))
+ }
+ }
+
+ fn readlink(&self) -> io::Result<PathBuf> {
+ let mut space = [0u8; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
+ let (_bytes, buf) = self.reparse_point(&mut space)?;
+ unsafe {
+ let (path_buffer, subst_off, subst_len, relative) = match buf.ReparseTag {
+ c::IO_REPARSE_TAG_SYMLINK => {
+ let info: *const c::SYMBOLIC_LINK_REPARSE_BUFFER =
+ &buf.rest as *const _ as *const _;
+ (&(*info).PathBuffer as *const _ as *const u16,
+ (*info).SubstituteNameOffset / 2,
+ (*info).SubstituteNameLength / 2,
+ (*info).Flags & c::SYMLINK_FLAG_RELATIVE != 0)
+ },
+ c::IO_REPARSE_TAG_MOUNT_POINT => {
+ let info: *const c::MOUNT_POINT_REPARSE_BUFFER =
+ &buf.rest as *const _ as *const _;
+ (&(*info).PathBuffer as *const _ as *const u16,
+ (*info).SubstituteNameOffset / 2,
+ (*info).SubstituteNameLength / 2,
+ false)
+ },
+ _ => return Err(io::Error::new(io::ErrorKind::Other,
+ "Unsupported reparse point type"))
+ };
+ let subst_ptr = path_buffer.offset(subst_off as isize);
+ let mut subst = slice::from_raw_parts(subst_ptr, subst_len as usize);
+ // Absolute paths start with an NT internal namespace prefix `\??\`
+ // We should not let it leak through.
+ if !relative && subst.starts_with(&[92u16, 63u16, 63u16, 92u16]) {
+ subst = &subst[4..];
+ }
+ Ok(PathBuf::from(OsString::from_wide(subst)))
+ }
+ }
+
+ pub fn set_permissions(&self, perm: FilePermissions) -> io::Result<()> {
+ let mut info = c::FILE_BASIC_INFO {
+ CreationTime: 0,
+ LastAccessTime: 0,
+ LastWriteTime: 0,
+ ChangeTime: 0,
+ FileAttributes: perm.attrs,
+ };
+ let size = mem::size_of_val(&info);
+ cvt(unsafe {
+ c::SetFileInformationByHandle(self.handle.raw(),
+ c::FileBasicInfo,
+ &mut info as *mut _ as *mut _,
+ size as c::DWORD)
+ })?;
+ Ok(())
+ }
+}
+
+impl FromInner<c::HANDLE> for File {
+ fn from_inner(handle: c::HANDLE) -> File {
+ File { handle: Handle::new(handle) }
+ }
+}
+
+impl fmt::Debug for File {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ // FIXME(#24570): add more info here (e.g., mode)
+ let mut b = f.debug_struct("File");
+ b.field("handle", &self.handle.raw());
+ if let Ok(path) = get_path(&self) {
+ b.field("path", &path);
+ }
+ b.finish()
+ }
+}
+
+impl FileAttr {
+ pub fn size(&self) -> u64 {
+ self.file_size
+ }
+
+ pub fn perm(&self) -> FilePermissions {
+ FilePermissions { attrs: self.attributes }
+ }
+
+ pub fn attrs(&self) -> u32 { self.attributes as u32 }
+
+ pub fn file_type(&self) -> FileType {
+ FileType::new(self.attributes, self.reparse_tag)
+ }
+
+ pub fn modified(&self) -> io::Result<SystemTime> {
+ Ok(SystemTime::from(self.last_write_time))
+ }
+
+ pub fn accessed(&self) -> io::Result<SystemTime> {
+ Ok(SystemTime::from(self.last_access_time))
+ }
+
+ pub fn created(&self) -> io::Result<SystemTime> {
+ Ok(SystemTime::from(self.creation_time))
+ }
+
+ pub fn modified_u64(&self) -> u64 {
+ to_u64(&self.last_write_time)
+ }
+
+ pub fn accessed_u64(&self) -> u64 {
+ to_u64(&self.last_access_time)
+ }
+
+ pub fn created_u64(&self) -> u64 {
+ to_u64(&self.creation_time)
+ }
+
+ fn is_reparse_point(&self) -> bool {
+ self.attributes & c::FILE_ATTRIBUTE_REPARSE_POINT != 0
+ }
+}
+
+fn to_u64(ft: &c::FILETIME) -> u64 {
+ (ft.dwLowDateTime as u64) | ((ft.dwHighDateTime as u64) << 32)
+}
+
+impl FilePermissions {
+ pub fn readonly(&self) -> bool {
+ self.attrs & c::FILE_ATTRIBUTE_READONLY != 0
+ }
+
+ pub fn set_readonly(&mut self, readonly: bool) {
+ if readonly {
+ self.attrs |= c::FILE_ATTRIBUTE_READONLY;
+ } else {
+ self.attrs &= !c::FILE_ATTRIBUTE_READONLY;
+ }
+ }
+}
+
+impl FileType {
+ fn new(attrs: c::DWORD, reparse_tag: c::DWORD) -> FileType {
+ FileType {
+ attributes: attrs,
+ reparse_tag: reparse_tag,
+ }
+ }
+ pub fn is_dir(&self) -> bool {
+ !self.is_symlink() && self.is_directory()
+ }
+ pub fn is_file(&self) -> bool {
+ !self.is_symlink() && !self.is_directory()
+ }
+ pub fn is_symlink(&self) -> bool {
+ self.is_reparse_point() && self.is_reparse_tag_name_surrogate()
+ }
+ pub fn is_symlink_dir(&self) -> bool {
+ self.is_symlink() && self.is_directory()
+ }
+ pub fn is_symlink_file(&self) -> bool {
+ self.is_symlink() && !self.is_directory()
+ }
+ fn is_directory(&self) -> bool {
+ self.attributes & c::FILE_ATTRIBUTE_DIRECTORY != 0
+ }
+ fn is_reparse_point(&self) -> bool {
+ self.attributes & c::FILE_ATTRIBUTE_REPARSE_POINT != 0
+ }
+ fn is_reparse_tag_name_surrogate(&self) -> bool {
+ self.reparse_tag & 0x20000000 != 0
+ }
+}
+
+impl DirBuilder {
+ pub fn new() -> DirBuilder { DirBuilder }
+
+ pub fn mkdir(&self, p: &Path) -> io::Result<()> {
+ let p = to_u16s(p)?;
+ cvt(unsafe {
+ c::CreateDirectoryW(p.as_ptr(), ptr::null_mut())
+ })?;
+ Ok(())
+ }
+}
+
+pub fn readdir(p: &Path) -> io::Result<ReadDir> {
+ let root = p.to_path_buf();
+ let star = p.join("*");
+ let path = to_u16s(&star)?;
+
+ unsafe {
+ let mut wfd = mem::zeroed();
+ let find_handle = c::FindFirstFileW(path.as_ptr(), &mut wfd);
+ if find_handle != c::INVALID_HANDLE_VALUE {
+ Ok(ReadDir {
+ handle: FindNextFileHandle(find_handle),
+ root: Arc::new(root),
+ first: Some(wfd),
+ })
+ } else {
+ Err(Error::last_os_error())
+ }
+ }
+}
+
+pub fn unlink(p: &Path) -> io::Result<()> {
+ let p_u16s = to_u16s(p)?;
+ cvt(unsafe { c::DeleteFileW(p_u16s.as_ptr()) })?;
+ Ok(())
+}
+
+pub fn rename(old: &Path, new: &Path) -> io::Result<()> {
+ let old = to_u16s(old)?;
+ let new = to_u16s(new)?;
+ cvt(unsafe {
+ c::MoveFileExW(old.as_ptr(), new.as_ptr(), c::MOVEFILE_REPLACE_EXISTING)
+ })?;
+ Ok(())
+}
+
+pub fn rmdir(p: &Path) -> io::Result<()> {
+ let p = to_u16s(p)?;
+ cvt(unsafe { c::RemoveDirectoryW(p.as_ptr()) })?;
+ Ok(())
+}
+
+pub fn remove_dir_all(path: &Path) -> io::Result<()> {
+ let filetype = lstat(path)?.file_type();
+ if filetype.is_symlink() {
+ // On Windows symlinks to files and directories are removed differently.
+ // rmdir only deletes dir symlinks and junctions, not file symlinks.
+ rmdir(path)
+ } else {
+ remove_dir_all_recursive(path)
+ }
+}
+
+fn remove_dir_all_recursive(path: &Path) -> io::Result<()> {
+ for child in readdir(path)? {
+ let child = child?;
+ let child_type = child.file_type()?;
+ if child_type.is_dir() {
+ remove_dir_all_recursive(&child.path())?;
+ } else if child_type.is_symlink_dir() {
+ rmdir(&child.path())?;
+ } else {
+ unlink(&child.path())?;
+ }
+ }
+ rmdir(path)
+}
+
+pub fn readlink(path: &Path) -> io::Result<PathBuf> {
+ // Open the link with no access mode, instead of generic read.
+ // By default FILE_LIST_DIRECTORY is denied for the junction "C:\Documents and Settings", so
+ // this is needed for a common case.
+ let mut opts = OpenOptions::new();
+ opts.access_mode(0);
+ opts.custom_flags(c::FILE_FLAG_OPEN_REPARSE_POINT |
+ c::FILE_FLAG_BACKUP_SEMANTICS);
+ let file = File::open(&path, &opts)?;
+ file.readlink()
+}
+
+pub fn symlink(src: &Path, dst: &Path) -> io::Result<()> {
+ symlink_inner(src, dst, false)
+}
+
+pub fn symlink_inner(src: &Path, dst: &Path, dir: bool) -> io::Result<()> {
+ let src = to_u16s(src)?;
+ let dst = to_u16s(dst)?;
+ let flags = if dir { c::SYMBOLIC_LINK_FLAG_DIRECTORY } else { 0 };
+ // Formerly, symlink creation required the SeCreateSymbolicLink privilege. For the Windows 10
+ // Creators Update, Microsoft loosened this to allow unprivileged symlink creation if the
+ // computer is in Developer Mode, but SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE must be
+ // added to dwFlags to opt into this behaviour.
+ let result = cvt(unsafe {
+ c::CreateSymbolicLinkW(dst.as_ptr(), src.as_ptr(),
+ flags | c::SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE) as c::BOOL
+ });
+ if let Err(err) = result {
+ if err.raw_os_error() == Some(c::ERROR_INVALID_PARAMETER as i32) {
+ // Older Windows objects to SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE,
+ // so if we encounter ERROR_INVALID_PARAMETER, retry without that flag.
+ cvt(unsafe {
+ c::CreateSymbolicLinkW(dst.as_ptr(), src.as_ptr(), flags) as c::BOOL
+ })?;
+ } else {
+ return Err(err);
+ }
+ }
+ Ok(())
+}
+
+pub fn link(src: &Path, dst: &Path) -> io::Result<()> {
+ let src = to_u16s(src)?;
+ let dst = to_u16s(dst)?;
+ cvt(unsafe {
+ c::CreateHardLinkW(dst.as_ptr(), src.as_ptr(), ptr::null_mut())
+ })?;
+ Ok(())
+}
+
+pub fn stat(path: &Path) -> io::Result<FileAttr> {
+ let mut opts = OpenOptions::new();
+ // No read or write permissions are necessary
+ opts.access_mode(0);
+ // This flag is so we can open directories too
+ opts.custom_flags(c::FILE_FLAG_BACKUP_SEMANTICS);
+ let file = File::open(path, &opts)?;
+ file.file_attr()
+}
+
+pub fn lstat(path: &Path) -> io::Result<FileAttr> {
+ let mut opts = OpenOptions::new();
+ // No read or write permissions are necessary
+ opts.access_mode(0);
+ opts.custom_flags(c::FILE_FLAG_BACKUP_SEMANTICS | c::FILE_FLAG_OPEN_REPARSE_POINT);
+ let file = File::open(path, &opts)?;
+ file.file_attr()
+}
+
+pub fn set_perm(p: &Path, perm: FilePermissions) -> io::Result<()> {
+ let p = to_u16s(p)?;
+ unsafe {
+ cvt(c::SetFileAttributesW(p.as_ptr(), perm.attrs))?;
+ Ok(())
+ }
+}
+
+fn get_path(f: &File) -> io::Result<PathBuf> {
+ super::fill_utf16_buf(|buf, sz| unsafe {
+ c::GetFinalPathNameByHandleW(f.handle.raw(), buf, sz,
+ c::VOLUME_NAME_DOS)
+ }, |buf| {
+ PathBuf::from(OsString::from_wide(buf))
+ })
+}
+
+pub fn canonicalize(p: &Path) -> io::Result<PathBuf> {
+ let mut opts = OpenOptions::new();
+ // No read or write permissions are necessary
+ opts.access_mode(0);
+ // This flag is so we can open directories too
+ opts.custom_flags(c::FILE_FLAG_BACKUP_SEMANTICS);
+ let f = File::open(p, &opts)?;
+ get_path(&f)
+}
+
+pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
+ unsafe extern "system" fn callback(
+ _TotalFileSize: c::LARGE_INTEGER,
+ _TotalBytesTransferred: c::LARGE_INTEGER,
+ _StreamSize: c::LARGE_INTEGER,
+ StreamBytesTransferred: c::LARGE_INTEGER,
+ dwStreamNumber: c::DWORD,
+ _dwCallbackReason: c::DWORD,
+ _hSourceFile: c::HANDLE,
+ _hDestinationFile: c::HANDLE,
+ lpData: c::LPVOID,
+ ) -> c::DWORD {
+ if dwStreamNumber == 1 {*(lpData as *mut i64) = StreamBytesTransferred;}
+ c::PROGRESS_CONTINUE
+ }
+ let pfrom = to_u16s(from)?;
+ let pto = to_u16s(to)?;
+ let mut size = 0i64;
+ cvt(unsafe {
+ c::CopyFileExW(pfrom.as_ptr(), pto.as_ptr(), Some(callback),
+ &mut size as *mut _ as *mut _, ptr::null_mut(), 0)
+ })?;
+ Ok(size as u64)
+}
+
+#[allow(dead_code)]
+pub fn symlink_junction<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()> {
+ symlink_junction_inner(src.as_ref(), dst.as_ref())
+}
+
+// Creating a directory junction on windows involves dealing with reparse
+// points and the DeviceIoControl function, and this code is a skeleton of
+// what can be found here:
+//
+// http://www.flexhex.com/docs/articles/hard-links.phtml
+#[allow(dead_code)]
+fn symlink_junction_inner(target: &Path, junction: &Path) -> io::Result<()> {
+ let d = DirBuilder::new();
+ d.mkdir(&junction)?;
+
+ let mut opts = OpenOptions::new();
+ opts.write(true);
+ opts.custom_flags(c::FILE_FLAG_OPEN_REPARSE_POINT |
+ c::FILE_FLAG_BACKUP_SEMANTICS);
+ let f = File::open(junction, &opts)?;
+ let h = f.handle().raw();
+
+ unsafe {
+ let mut data = [0u8; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
+ let db = data.as_mut_ptr()
+ as *mut c::REPARSE_MOUNTPOINT_DATA_BUFFER;
+ let buf = &mut (*db).ReparseTarget as *mut c::WCHAR;
+ let mut i = 0;
+ // FIXME: this conversion is very hacky
+ let v = br"\??\";
+ let v = v.iter().map(|x| *x as u16);
+ for c in v.chain(target.as_os_str().encode_wide()) {
+ *buf.offset(i) = c;
+ i += 1;
+ }
+ *buf.offset(i) = 0;
+ i += 1;
+ (*db).ReparseTag = c::IO_REPARSE_TAG_MOUNT_POINT;
+ (*db).ReparseTargetMaximumLength = (i * 2) as c::WORD;
+ (*db).ReparseTargetLength = ((i - 1) * 2) as c::WORD;
+ (*db).ReparseDataLength =
+ (*db).ReparseTargetLength as c::DWORD + 12;
+
+ let mut ret = 0;
+ cvt(c::DeviceIoControl(h as *mut _,
+ c::FSCTL_SET_REPARSE_POINT,
+ data.as_ptr() as *mut _,
+ (*db).ReparseDataLength + 8,
+ ptr::null_mut(), 0,
+ &mut ret,
+ ptr::null_mut())).map(|_| ())
+ }
+}
diff --git a/src/libstd/sys/windows/handle.rs b/src/libstd/sys/windows/handle.rs
new file mode 100644
index 0000000..0254908
--- /dev/null
+++ b/src/libstd/sys/windows/handle.rs
@@ -0,0 +1,202 @@
+#![unstable(issue = "0", feature = "windows_handle")]
+
+use crate::cmp;
+use crate::io::{self, ErrorKind, Read};
+use crate::mem;
+use crate::ops::Deref;
+use crate::ptr;
+use crate::sys::c;
+use crate::sys::cvt;
+
+/// An owned container for `HANDLE` object, closing them on Drop.
+///
+/// All methods are inherited through a `Deref` impl to `RawHandle`
+pub struct Handle(RawHandle);
+
+/// A wrapper type for `HANDLE` objects to give them proper Send/Sync inference
+/// as well as Rust-y methods.
+///
+/// This does **not** drop the handle when it goes out of scope, use `Handle`
+/// instead for that.
+#[derive(Copy, Clone)]
+pub struct RawHandle(c::HANDLE);
+
+unsafe impl Send for RawHandle {}
+unsafe impl Sync for RawHandle {}
+
+impl Handle {
+ pub fn new(handle: c::HANDLE) -> Handle {
+ Handle(RawHandle::new(handle))
+ }
+
+ pub fn new_event(manual: bool, init: bool) -> io::Result<Handle> {
+ unsafe {
+ let event = c::CreateEventW(ptr::null_mut(),
+ manual as c::BOOL,
+ init as c::BOOL,
+ ptr::null());
+ if event.is_null() {
+ Err(io::Error::last_os_error())
+ } else {
+ Ok(Handle::new(event))
+ }
+ }
+ }
+
+ pub fn into_raw(self) -> c::HANDLE {
+ let ret = self.raw();
+ mem::forget(self);
+ return ret;
+ }
+}
+
+impl Deref for Handle {
+ type Target = RawHandle;
+ fn deref(&self) -> &RawHandle { &self.0 }
+}
+
+impl Drop for Handle {
+ fn drop(&mut self) {
+ unsafe { let _ = c::CloseHandle(self.raw()); }
+ }
+}
+
+impl RawHandle {
+ pub fn new(handle: c::HANDLE) -> RawHandle {
+ RawHandle(handle)
+ }
+
+ pub fn raw(&self) -> c::HANDLE { self.0 }
+
+ pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
+ let mut read = 0;
+ let len = cmp::min(buf.len(), <c::DWORD>::max_value() as usize) as c::DWORD;
+ let res = cvt(unsafe {
+ c::ReadFile(self.0, buf.as_mut_ptr() as c::LPVOID,
+ len, &mut read, ptr::null_mut())
+ });
+
+ match res {
+ Ok(_) => Ok(read as usize),
+
+ // The special treatment of BrokenPipe is to deal with Windows
+ // pipe semantics, which yields this error when *reading* from
+ // a pipe after the other end has closed; we interpret that as
+ // EOF on the pipe.
+ Err(ref e) if e.kind() == ErrorKind::BrokenPipe => Ok(0),
+
+ Err(e) => Err(e)
+ }
+ }
+
+ pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
+ let mut read = 0;
+ let len = cmp::min(buf.len(), <c::DWORD>::max_value() as usize) as c::DWORD;
+ let res = unsafe {
+ let mut overlapped: c::OVERLAPPED = mem::zeroed();
+ overlapped.Offset = offset as u32;
+ overlapped.OffsetHigh = (offset >> 32) as u32;
+ cvt(c::ReadFile(self.0, buf.as_mut_ptr() as c::LPVOID,
+ len, &mut read, &mut overlapped))
+ };
+ match res {
+ Ok(_) => Ok(read as usize),
+ Err(ref e) if e.raw_os_error() == Some(c::ERROR_HANDLE_EOF as i32) => Ok(0),
+ Err(e) => Err(e),
+ }
+ }
+
+ pub unsafe fn read_overlapped(&self,
+ buf: &mut [u8],
+ overlapped: *mut c::OVERLAPPED)
+ -> io::Result<Option<usize>> {
+ let len = cmp::min(buf.len(), <c::DWORD>::max_value() as usize) as c::DWORD;
+ let mut amt = 0;
+ let res = cvt({
+ c::ReadFile(self.0, buf.as_ptr() as c::LPVOID,
+ len, &mut amt, overlapped)
+ });
+ match res {
+ Ok(_) => Ok(Some(amt as usize)),
+ Err(e) => {
+ if e.raw_os_error() == Some(c::ERROR_IO_PENDING as i32) {
+ Ok(None)
+ } else if e.raw_os_error() == Some(c::ERROR_BROKEN_PIPE as i32) {
+ Ok(Some(0))
+ } else {
+ Err(e)
+ }
+ }
+ }
+ }
+
+ pub fn overlapped_result(&self,
+ overlapped: *mut c::OVERLAPPED,
+ wait: bool) -> io::Result<usize> {
+ unsafe {
+ let mut bytes = 0;
+ let wait = if wait {c::TRUE} else {c::FALSE};
+ let res = cvt({
+ c::GetOverlappedResult(self.raw(), overlapped, &mut bytes, wait)
+ });
+ match res {
+ Ok(_) => Ok(bytes as usize),
+ Err(e) => {
+ if e.raw_os_error() == Some(c::ERROR_HANDLE_EOF as i32) ||
+ e.raw_os_error() == Some(c::ERROR_BROKEN_PIPE as i32) {
+ Ok(0)
+ } else {
+ Err(e)
+ }
+ }
+ }
+ }
+ }
+
+ pub fn cancel_io(&self) -> io::Result<()> {
+ unsafe {
+ cvt(c::CancelIo(self.raw())).map(|_| ())
+ }
+ }
+
+ pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
+ let mut amt = 0;
+ let len = cmp::min(buf.len(), <c::DWORD>::max_value() as usize) as c::DWORD;
+ cvt(unsafe {
+ c::WriteFile(self.0, buf.as_ptr() as c::LPVOID,
+ len, &mut amt, ptr::null_mut())
+ })?;
+ Ok(amt as usize)
+ }
+
+ pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
+ let mut written = 0;
+ let len = cmp::min(buf.len(), <c::DWORD>::max_value() as usize) as c::DWORD;
+ unsafe {
+ let mut overlapped: c::OVERLAPPED = mem::zeroed();
+ overlapped.Offset = offset as u32;
+ overlapped.OffsetHigh = (offset >> 32) as u32;
+ cvt(c::WriteFile(self.0, buf.as_ptr() as c::LPVOID,
+ len, &mut written, &mut overlapped))?;
+ }
+ Ok(written as usize)
+ }
+
+ pub fn duplicate(&self, access: c::DWORD, inherit: bool,
+ options: c::DWORD) -> io::Result<Handle> {
+ let mut ret = 0 as c::HANDLE;
+ cvt(unsafe {
+ let cur_proc = c::GetCurrentProcess();
+ c::DuplicateHandle(cur_proc, self.0, cur_proc, &mut ret,
+ access, inherit as c::BOOL,
+ options)
+ })?;
+ Ok(Handle::new(ret))
+ }
+}
+
+impl<'a> Read for &'a RawHandle {
+ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+ (**self).read(buf)
+ }
+}
diff --git a/src/libstd/sys/windows/io.rs b/src/libstd/sys/windows/io.rs
new file mode 100644
index 0000000..54dd271
--- /dev/null
+++ b/src/libstd/sys/windows/io.rs
@@ -0,0 +1,63 @@
+use crate::marker::PhantomData;
+use crate::slice;
+use crate::sys::c;
+
+#[repr(transparent)]
+pub struct IoVec<'a> {
+ vec: c::WSABUF,
+ _p: PhantomData<&'a [u8]>,
+}
+
+impl<'a> IoVec<'a> {
+ #[inline]
+ pub fn new(buf: &'a [u8]) -> IoVec<'a> {
+ assert!(buf.len() <= c::ULONG::max_value() as usize);
+ IoVec {
+ vec: c::WSABUF {
+ len: buf.len() as c::ULONG,
+ buf: buf.as_ptr() as *mut u8 as *mut c::CHAR,
+ },
+ _p: PhantomData,
+ }
+ }
+
+ #[inline]
+ pub fn as_slice(&self) -> &[u8] {
+ unsafe {
+ slice::from_raw_parts(self.vec.buf as *mut u8, self.vec.len as usize)
+ }
+ }
+}
+
+pub struct IoVecMut<'a> {
+ vec: c::WSABUF,
+ _p: PhantomData<&'a mut [u8]>,
+}
+
+impl<'a> IoVecMut<'a> {
+ #[inline]
+ pub fn new(buf: &'a mut [u8]) -> IoVecMut<'a> {
+ assert!(buf.len() <= c::ULONG::max_value() as usize);
+ IoVecMut {
+ vec: c::WSABUF {
+ len: buf.len() as c::ULONG,
+ buf: buf.as_mut_ptr() as *mut c::CHAR,
+ },
+ _p: PhantomData,
+ }
+ }
+
+ #[inline]
+ pub fn as_slice(&self) -> &[u8] {
+ unsafe {
+ slice::from_raw_parts(self.vec.buf as *mut u8, self.vec.len as usize)
+ }
+ }
+
+ #[inline]
+ pub fn as_mut_slice(&mut self) -> &mut [u8] {
+ unsafe {
+ slice::from_raw_parts_mut(self.vec.buf as *mut u8, self.vec.len as usize)
+ }
+ }
+}
diff --git a/src/libstd/sys/windows/memchr.rs b/src/libstd/sys/windows/memchr.rs
new file mode 100644
index 0000000..b9e5bcc
--- /dev/null
+++ b/src/libstd/sys/windows/memchr.rs
@@ -0,0 +1,5 @@
+// Original implementation taken from rust-memchr.
+// Copyright 2015 Andrew Gallant, bluss and Nicolas Koch
+
+// Fallback memchr is fastest on Windows.
+pub use core::slice::memchr::{memchr, memrchr};
diff --git a/src/libstd/sys/windows/mod.rs b/src/libstd/sys/windows/mod.rs
new file mode 100644
index 0000000..1425254
--- /dev/null
+++ b/src/libstd/sys/windows/mod.rs
@@ -0,0 +1,269 @@
+#![allow(missing_docs, nonstandard_style)]
+
+use crate::ptr;
+use crate::ffi::{OsStr, OsString};
+use crate::io::ErrorKind;
+use crate::os::windows::ffi::{OsStrExt, OsStringExt};
+use crate::path::PathBuf;
+use crate::time::Duration;
+
+pub use libc::strlen;
+pub use self::rand::hashmap_random_keys;
+
+#[macro_use] pub mod compat;
+
+pub mod alloc;
+pub mod args;
+#[cfg(feature = "backtrace")]
+pub mod backtrace;
+pub mod c;
+pub mod cmath;
+pub mod condvar;
+#[cfg(feature = "backtrace")]
+pub mod dynamic_lib;
+pub mod env;
+pub mod ext;
+pub mod fast_thread_local;
+pub mod fs;
+pub mod handle;
+pub mod io;
+pub mod memchr;
+pub mod mutex;
+pub mod net;
+pub mod os;
+pub mod os_str;
+pub mod path;
+pub mod pipe;
+pub mod process;
+pub mod rand;
+pub mod rwlock;
+pub mod stack_overflow;
+pub mod thread;
+pub mod thread_local;
+pub mod time;
+pub mod stdio;
+
+#[cfg(not(test))]
+pub fn init() {
+}
+
+pub fn decode_error_kind(errno: i32) -> ErrorKind {
+ match errno as c::DWORD {
+ c::ERROR_ACCESS_DENIED => return ErrorKind::PermissionDenied,
+ c::ERROR_ALREADY_EXISTS => return ErrorKind::AlreadyExists,
+ c::ERROR_FILE_EXISTS => return ErrorKind::AlreadyExists,
+ c::ERROR_BROKEN_PIPE => return ErrorKind::BrokenPipe,
+ c::ERROR_FILE_NOT_FOUND => return ErrorKind::NotFound,
+ c::ERROR_PATH_NOT_FOUND => return ErrorKind::NotFound,
+ c::ERROR_NO_DATA => return ErrorKind::BrokenPipe,
+ c::ERROR_OPERATION_ABORTED => return ErrorKind::TimedOut,
+ _ => {}
+ }
+
+ match errno {
+ c::WSAEACCES => ErrorKind::PermissionDenied,
+ c::WSAEADDRINUSE => ErrorKind::AddrInUse,
+ c::WSAEADDRNOTAVAIL => ErrorKind::AddrNotAvailable,
+ c::WSAECONNABORTED => ErrorKind::ConnectionAborted,
+ c::WSAECONNREFUSED => ErrorKind::ConnectionRefused,
+ c::WSAECONNRESET => ErrorKind::ConnectionReset,
+ c::WSAEINVAL => ErrorKind::InvalidInput,
+ c::WSAENOTCONN => ErrorKind::NotConnected,
+ c::WSAEWOULDBLOCK => ErrorKind::WouldBlock,
+ c::WSAETIMEDOUT => ErrorKind::TimedOut,
+
+ _ => ErrorKind::Other,
+ }
+}
+
+pub fn to_u16s<S: AsRef<OsStr>>(s: S) -> crate::io::Result<Vec<u16>> {
+ fn inner(s: &OsStr) -> crate::io::Result<Vec<u16>> {
+ let mut maybe_result: Vec<u16> = s.encode_wide().collect();
+ if maybe_result.iter().any(|&u| u == 0) {
+ return Err(crate::io::Error::new(ErrorKind::InvalidInput,
+ "strings passed to WinAPI cannot contain NULs"));
+ }
+ maybe_result.push(0);
+ Ok(maybe_result)
+ }
+ inner(s.as_ref())
+}
+
+// Many Windows APIs follow a pattern of where we hand a buffer and then they
+// will report back to us how large the buffer should be or how many bytes
+// currently reside in the buffer. This function is an abstraction over these
+// functions by making them easier to call.
+//
+// The first callback, `f1`, is yielded a (pointer, len) pair which can be
+// passed to a syscall. The `ptr` is valid for `len` items (u16 in this case).
+// The closure is expected to return what the syscall returns which will be
+// interpreted by this function to determine if the syscall needs to be invoked
+// again (with more buffer space).
+//
+// Once the syscall has completed (errors bail out early) the second closure is
+// yielded the data which has been read from the syscall. The return value
+// from this closure is then the return value of the function.
+fn fill_utf16_buf<F1, F2, T>(mut f1: F1, f2: F2) -> crate::io::Result<T>
+ where F1: FnMut(*mut u16, c::DWORD) -> c::DWORD,
+ F2: FnOnce(&[u16]) -> T
+{
+ // Start off with a stack buf but then spill over to the heap if we end up
+ // needing more space.
+ let mut stack_buf = [0u16; 512];
+ let mut heap_buf = Vec::new();
+ unsafe {
+ let mut n = stack_buf.len();
+ loop {
+ let buf = if n <= stack_buf.len() {
+ &mut stack_buf[..]
+ } else {
+ let extra = n - heap_buf.len();
+ heap_buf.reserve(extra);
+ heap_buf.set_len(n);
+ &mut heap_buf[..]
+ };
+
+ // This function is typically called on windows API functions which
+ // will return the correct length of the string, but these functions
+ // also return the `0` on error. In some cases, however, the
+ // returned "correct length" may actually be 0!
+ //
+ // To handle this case we call `SetLastError` to reset it to 0 and
+ // then check it again if we get the "0 error value". If the "last
+ // error" is still 0 then we interpret it as a 0 length buffer and
+ // not an actual error.
+ c::SetLastError(0);
+ let k = match f1(buf.as_mut_ptr(), n as c::DWORD) {
+ 0 if c::GetLastError() == 0 => 0,
+ 0 => return Err(crate::io::Error::last_os_error()),
+ n => n,
+ } as usize;
+ if k == n && c::GetLastError() == c::ERROR_INSUFFICIENT_BUFFER {
+ n *= 2;
+ } else if k >= n {
+ n = k;
+ } else {
+ return Ok(f2(&buf[..k]))
+ }
+ }
+ }
+}
+
+fn os2path(s: &[u16]) -> PathBuf {
+ PathBuf::from(OsString::from_wide(s))
+}
+
+#[allow(dead_code)] // Only used in backtrace::gnu::get_executable_filename()
+fn wide_char_to_multi_byte(code_page: u32,
+ flags: u32,
+ s: &[u16],
+ no_default_char: bool)
+ -> crate::io::Result<Vec<i8>> {
+ unsafe {
+ let mut size = c::WideCharToMultiByte(code_page,
+ flags,
+ s.as_ptr(),
+ s.len() as i32,
+ ptr::null_mut(),
+ 0,
+ ptr::null(),
+ ptr::null_mut());
+ if size == 0 {
+ return Err(crate::io::Error::last_os_error());
+ }
+
+ let mut buf = Vec::with_capacity(size as usize);
+ buf.set_len(size as usize);
+
+ let mut used_default_char = c::FALSE;
+ size = c::WideCharToMultiByte(code_page,
+ flags,
+ s.as_ptr(),
+ s.len() as i32,
+ buf.as_mut_ptr(),
+ buf.len() as i32,
+ ptr::null(),
+ if no_default_char { &mut used_default_char }
+ else { ptr::null_mut() });
+ if size == 0 {
+ return Err(crate::io::Error::last_os_error());
+ }
+ if no_default_char && used_default_char == c::TRUE {
+ return Err(crate::io::Error::new(crate::io::ErrorKind::InvalidData,
+ "string cannot be converted to requested code page"));
+ }
+
+ buf.set_len(size as usize);
+
+ Ok(buf)
+ }
+}
+
+pub fn truncate_utf16_at_nul<'a>(v: &'a [u16]) -> &'a [u16] {
+ match v.iter().position(|c| *c == 0) {
+ // don't include the 0
+ Some(i) => &v[..i],
+ None => v
+ }
+}
+
+pub trait IsZero {
+ fn is_zero(&self) -> bool;
+}
+
+macro_rules! impl_is_zero {
+ ($($t:ident)*) => ($(impl IsZero for $t {
+ fn is_zero(&self) -> bool {
+ *self == 0
+ }
+ })*)
+}
+
+impl_is_zero! { i8 i16 i32 i64 isize u8 u16 u32 u64 usize }
+
+pub fn cvt<I: IsZero>(i: I) -> crate::io::Result<I> {
+ if i.is_zero() {
+ Err(crate::io::Error::last_os_error())
+ } else {
+ Ok(i)
+ }
+}
+
+pub fn dur2timeout(dur: Duration) -> c::DWORD {
+ // Note that a duration is a (u64, u32) (seconds, nanoseconds) pair, and the
+ // timeouts in windows APIs are typically u32 milliseconds. To translate, we
+ // have two pieces to take care of:
+ //
+ // * Nanosecond precision is rounded up
+ // * Greater than u32::MAX milliseconds (50 days) is rounded up to INFINITE
+ // (never time out).
+ dur.as_secs().checked_mul(1000).and_then(|ms| {
+ ms.checked_add((dur.subsec_nanos() as u64) / 1_000_000)
+ }).and_then(|ms| {
+ ms.checked_add(if dur.subsec_nanos() % 1_000_000 > 0 {1} else {0})
+ }).map(|ms| {
+ if ms > <c::DWORD>::max_value() as u64 {
+ c::INFINITE
+ } else {
+ ms as c::DWORD
+ }
+ }).unwrap_or(c::INFINITE)
+}
+
+// On Windows, use the processor-specific __fastfail mechanism. In Windows 8
+// and later, this will terminate the process immediately without running any
+// in-process exception handlers. In earlier versions of Windows, this
+// sequence of instructions will be treated as an access violation,
+// terminating the process but without necessarily bypassing all exception
+// handlers.
+//
+// https://msdn.microsoft.com/en-us/library/dn774154.aspx
+#[allow(unreachable_code)]
+pub unsafe fn abort_internal() -> ! {
+ #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+ {
+ asm!("int $$0x29" :: "{ecx}"(7) ::: volatile); // 7 is FAST_FAIL_FATAL_APP_EXIT
+ crate::intrinsics::unreachable();
+ }
+ crate::intrinsics::abort();
+}
diff --git a/src/libstd/sys/windows/mutex.rs b/src/libstd/sys/windows/mutex.rs
new file mode 100644
index 0000000..37cbdce
--- /dev/null
+++ b/src/libstd/sys/windows/mutex.rs
@@ -0,0 +1,180 @@
+//! System Mutexes
+//!
+//! The Windows implementation of mutexes is a little odd and it may not be
+//! immediately obvious what's going on. The primary oddness is that SRWLock is
+//! used instead of CriticalSection, and this is done because:
+//!
+//! 1. SRWLock is several times faster than CriticalSection according to
+//! benchmarks performed on both Windows 8 and Windows 7.
+//!
+//! 2. CriticalSection allows recursive locking while SRWLock deadlocks. The
+//! Unix implementation deadlocks so consistency is preferred. See #19962 for
+//! more details.
+//!
+//! 3. While CriticalSection is fair and SRWLock is not, the current Rust policy
+//! is that there are no guarantees of fairness.
+//!
+//! The downside of this approach, however, is that SRWLock is not available on
+//! Windows XP, so we continue to have a fallback implementation where
+//! CriticalSection is used and we keep track of who's holding the mutex to
+//! detect recursive locks.
+
+use crate::cell::UnsafeCell;
+use crate::mem::{self, MaybeUninit};
+use crate::sync::atomic::{AtomicUsize, Ordering};
+use crate::sys::c;
+use crate::sys::compat;
+
+pub struct Mutex {
+ lock: AtomicUsize,
+ held: UnsafeCell<bool>,
+}
+
+unsafe impl Send for Mutex {}
+unsafe impl Sync for Mutex {}
+
+#[derive(Clone, Copy)]
+enum Kind {
+ SRWLock = 1,
+ CriticalSection = 2,
+}
+
+#[inline]
+pub unsafe fn raw(m: &Mutex) -> c::PSRWLOCK {
+ debug_assert!(mem::size_of::<c::SRWLOCK>() <= mem::size_of_val(&m.lock));
+ &m.lock as *const _ as *mut _
+}
+
+impl Mutex {
+ pub const fn new() -> Mutex {
+ Mutex {
+ // This works because SRWLOCK_INIT is 0 (wrapped in a struct), so we are also properly
+ // initializing an SRWLOCK here.
+ lock: AtomicUsize::new(0),
+ held: UnsafeCell::new(false),
+ }
+ }
+ #[inline]
+ pub unsafe fn init(&mut self) {}
+ pub unsafe fn lock(&self) {
+ match kind() {
+ Kind::SRWLock => c::AcquireSRWLockExclusive(raw(self)),
+ Kind::CriticalSection => {
+ let re = self.remutex();
+ (*re).lock();
+ if !self.flag_locked() {
+ (*re).unlock();
+ panic!("cannot recursively lock a mutex");
+ }
+ }
+ }
+ }
+ pub unsafe fn try_lock(&self) -> bool {
+ match kind() {
+ Kind::SRWLock => c::TryAcquireSRWLockExclusive(raw(self)) != 0,
+ Kind::CriticalSection => {
+ let re = self.remutex();
+ if !(*re).try_lock() {
+ false
+ } else if self.flag_locked() {
+ true
+ } else {
+ (*re).unlock();
+ false
+ }
+ }
+ }
+ }
+ pub unsafe fn unlock(&self) {
+ *self.held.get() = false;
+ match kind() {
+ Kind::SRWLock => c::ReleaseSRWLockExclusive(raw(self)),
+ Kind::CriticalSection => (*self.remutex()).unlock(),
+ }
+ }
+ pub unsafe fn destroy(&self) {
+ match kind() {
+ Kind::SRWLock => {}
+ Kind::CriticalSection => {
+ match self.lock.load(Ordering::SeqCst) {
+ 0 => {}
+ n => { Box::from_raw(n as *mut ReentrantMutex).destroy(); }
+ }
+ }
+ }
+ }
+
+ unsafe fn remutex(&self) -> *mut ReentrantMutex {
+ match self.lock.load(Ordering::SeqCst) {
+ 0 => {}
+ n => return n as *mut _,
+ }
+ let mut re = box ReentrantMutex::uninitialized();
+ re.init();
+ let re = Box::into_raw(re);
+ match self.lock.compare_and_swap(0, re as usize, Ordering::SeqCst) {
+ 0 => re,
+ n => { Box::from_raw(re).destroy(); n as *mut _ }
+ }
+ }
+
+ unsafe fn flag_locked(&self) -> bool {
+ if *self.held.get() {
+ false
+ } else {
+ *self.held.get() = true;
+ true
+ }
+
+ }
+}
+
+fn kind() -> Kind {
+ static KIND: AtomicUsize = AtomicUsize::new(0);
+
+ let val = KIND.load(Ordering::SeqCst);
+ if val == Kind::SRWLock as usize {
+ return Kind::SRWLock
+ } else if val == Kind::CriticalSection as usize {
+ return Kind::CriticalSection
+ }
+
+ let ret = match compat::lookup("kernel32", "AcquireSRWLockExclusive") {
+ None => Kind::CriticalSection,
+ Some(..) => Kind::SRWLock,
+ };
+ KIND.store(ret as usize, Ordering::SeqCst);
+ return ret;
+}
+
+pub struct ReentrantMutex { inner: UnsafeCell<MaybeUninit<c::CRITICAL_SECTION>> }
+
+unsafe impl Send for ReentrantMutex {}
+unsafe impl Sync for ReentrantMutex {}
+
+impl ReentrantMutex {
+ pub fn uninitialized() -> ReentrantMutex {
+ ReentrantMutex { inner: UnsafeCell::new(MaybeUninit::uninit()) }
+ }
+
+ pub unsafe fn init(&mut self) {
+ c::InitializeCriticalSection((&mut *self.inner.get()).as_mut_ptr());
+ }
+
+ pub unsafe fn lock(&self) {
+ c::EnterCriticalSection((&mut *self.inner.get()).as_mut_ptr());
+ }
+
+ #[inline]
+ pub unsafe fn try_lock(&self) -> bool {
+ c::TryEnterCriticalSection((&mut *self.inner.get()).as_mut_ptr()) != 0
+ }
+
+ pub unsafe fn unlock(&self) {
+ c::LeaveCriticalSection((&mut *self.inner.get()).as_mut_ptr());
+ }
+
+ pub unsafe fn destroy(&self) {
+ c::DeleteCriticalSection((&mut *self.inner.get()).as_mut_ptr());
+ }
+}
diff --git a/src/libstd/sys/windows/net.rs b/src/libstd/sys/windows/net.rs
new file mode 100644
index 0000000..1231fd5
--- /dev/null
+++ b/src/libstd/sys/windows/net.rs
@@ -0,0 +1,388 @@
+#![unstable(issue = "0", feature = "windows_net")]
+
+use crate::cmp;
+use crate::io::{self, Read, IoVec, IoVecMut};
+use crate::mem;
+use crate::net::{SocketAddr, Shutdown};
+use crate::ptr;
+use crate::sync::Once;
+use crate::sys::c;
+use crate::sys;
+use crate::sys_common::{self, AsInner, FromInner, IntoInner};
+use crate::sys_common::net;
+use crate::time::Duration;
+
+use libc::{c_int, c_void, c_ulong, c_long};
+
+pub type wrlen_t = i32;
+
+pub mod netc {
+ pub use crate::sys::c::*;
+ pub use crate::sys::c::SOCKADDR as sockaddr;
+ pub use crate::sys::c::SOCKADDR_STORAGE_LH as sockaddr_storage;
+ pub use crate::sys::c::ADDRINFOA as addrinfo;
+ pub use crate::sys::c::ADDRESS_FAMILY as sa_family_t;
+}
+
+pub struct Socket(c::SOCKET);
+
+/// Checks whether the Windows socket interface has been started already, and
+/// if not, starts it.
+pub fn init() {
+ static START: Once = Once::new();
+
+ START.call_once(|| unsafe {
+ let mut data: c::WSADATA = mem::zeroed();
+ let ret = c::WSAStartup(0x202, // version 2.2
+ &mut data);
+ assert_eq!(ret, 0);
+
+ let _ = sys_common::at_exit(|| { c::WSACleanup(); });
+ });
+}
+
+/// Returns the last error from the Windows socket interface.
+fn last_error() -> io::Error {
+ io::Error::from_raw_os_error(unsafe { c::WSAGetLastError() })
+}
+
+#[doc(hidden)]
+pub trait IsMinusOne {
+ fn is_minus_one(&self) -> bool;
+}
+
+macro_rules! impl_is_minus_one {
+ ($($t:ident)*) => ($(impl IsMinusOne for $t {
+ fn is_minus_one(&self) -> bool {
+ *self == -1
+ }
+ })*)
+}
+
+impl_is_minus_one! { i8 i16 i32 i64 isize }
+
+/// Checks if the signed integer is the Windows constant `SOCKET_ERROR` (-1)
+/// and if so, returns the last error from the Windows socket interface. This
+/// function must be called before another call to the socket API is made.
+pub fn cvt<T: IsMinusOne>(t: T) -> io::Result<T> {
+ if t.is_minus_one() {
+ Err(last_error())
+ } else {
+ Ok(t)
+ }
+}
+
+/// A variant of `cvt` for `getaddrinfo` which return 0 for a success.
+pub fn cvt_gai(err: c_int) -> io::Result<()> {
+ if err == 0 {
+ Ok(())
+ } else {
+ Err(last_error())
+ }
+}
+
+/// Just to provide the same interface as sys/unix/net.rs
+pub fn cvt_r<T, F>(mut f: F) -> io::Result<T>
+ where T: IsMinusOne,
+ F: FnMut() -> T
+{
+ cvt(f())
+}
+
+impl Socket {
+ pub fn new(addr: &SocketAddr, ty: c_int) -> io::Result<Socket> {
+ let fam = match *addr {
+ SocketAddr::V4(..) => c::AF_INET,
+ SocketAddr::V6(..) => c::AF_INET6,
+ };
+ let socket = unsafe {
+ match c::WSASocketW(fam, ty, 0, ptr::null_mut(), 0,
+ c::WSA_FLAG_OVERLAPPED) {
+ c::INVALID_SOCKET => Err(last_error()),
+ n => Ok(Socket(n)),
+ }
+ }?;
+ socket.set_no_inherit()?;
+ Ok(socket)
+ }
+
+ pub fn connect_timeout(&self, addr: &SocketAddr, timeout: Duration) -> io::Result<()> {
+ self.set_nonblocking(true)?;
+ let r = unsafe {
+ let (addrp, len) = addr.into_inner();
+ cvt(c::connect(self.0, addrp, len))
+ };
+ self.set_nonblocking(false)?;
+
+ match r {
+ Ok(_) => return Ok(()),
+ Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {}
+ Err(e) => return Err(e),
+ }
+
+ if timeout.as_secs() == 0 && timeout.subsec_nanos() == 0 {
+ return Err(io::Error::new(io::ErrorKind::InvalidInput,
+ "cannot set a 0 duration timeout"));
+ }
+
+ let mut timeout = c::timeval {
+ tv_sec: timeout.as_secs() as c_long,
+ tv_usec: (timeout.subsec_nanos() / 1000) as c_long,
+ };
+ if timeout.tv_sec == 0 && timeout.tv_usec == 0 {
+ timeout.tv_usec = 1;
+ }
+
+ let fds = unsafe {
+ let mut fds = mem::zeroed::<c::fd_set>();
+ fds.fd_count = 1;
+ fds.fd_array[0] = self.0;
+ fds
+ };
+
+ let mut writefds = fds;
+ let mut errorfds = fds;
+
+ let n = unsafe {
+ cvt(c::select(1, ptr::null_mut(), &mut writefds, &mut errorfds, &timeout))?
+ };
+
+ match n {
+ 0 => Err(io::Error::new(io::ErrorKind::TimedOut, "connection timed out")),
+ _ => {
+ if writefds.fd_count != 1 {
+ if let Some(e) = self.take_error()? {
+ return Err(e);
+ }
+ }
+ Ok(())
+ }
+ }
+ }
+
+ pub fn accept(&self, storage: *mut c::SOCKADDR,
+ len: *mut c_int) -> io::Result<Socket> {
+ let socket = unsafe {
+ match c::accept(self.0, storage, len) {
+ c::INVALID_SOCKET => Err(last_error()),
+ n => Ok(Socket(n)),
+ }
+ }?;
+ socket.set_no_inherit()?;
+ Ok(socket)
+ }
+
+ pub fn duplicate(&self) -> io::Result<Socket> {
+ let socket = unsafe {
+ let mut info: c::WSAPROTOCOL_INFO = mem::zeroed();
+ cvt(c::WSADuplicateSocketW(self.0,
+ c::GetCurrentProcessId(),
+ &mut info))?;
+ match c::WSASocketW(info.iAddressFamily,
+ info.iSocketType,
+ info.iProtocol,
+ &mut info, 0,
+ c::WSA_FLAG_OVERLAPPED) {
+ c::INVALID_SOCKET => Err(last_error()),
+ n => Ok(Socket(n)),
+ }
+ }?;
+ socket.set_no_inherit()?;
+ Ok(socket)
+ }
+
+ fn recv_with_flags(&self, buf: &mut [u8], flags: c_int) -> io::Result<usize> {
+ // On unix when a socket is shut down all further reads return 0, so we
+ // do the same on windows to map a shut down socket to returning EOF.
+ let len = cmp::min(buf.len(), i32::max_value() as usize) as i32;
+ unsafe {
+ match c::recv(self.0, buf.as_mut_ptr() as *mut c_void, len, flags) {
+ -1 if c::WSAGetLastError() == c::WSAESHUTDOWN => Ok(0),
+ -1 => Err(last_error()),
+ n => Ok(n as usize)
+ }
+ }
+ }
+
+ pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
+ self.recv_with_flags(buf, 0)
+ }
+
+ pub fn read_vectored(&self, bufs: &mut [IoVecMut<'_>]) -> io::Result<usize> {
+ // On unix when a socket is shut down all further reads return 0, so we
+ // do the same on windows to map a shut down socket to returning EOF.
+ let len = cmp::min(bufs.len(), c::DWORD::max_value() as usize) as c::DWORD;
+ let mut nread = 0;
+ let mut flags = 0;
+ unsafe {
+ let ret = c::WSARecv(
+ self.0,
+ bufs.as_mut_ptr() as *mut c::WSABUF,
+ len,
+ &mut nread,
+ &mut flags,
+ ptr::null_mut(),
+ ptr::null_mut(),
+ );
+ match ret {
+ 0 => Ok(nread as usize),
+ _ if c::WSAGetLastError() == c::WSAESHUTDOWN => Ok(0),
+ _ => Err(last_error()),
+ }
+ }
+ }
+
+ pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
+ self.recv_with_flags(buf, c::MSG_PEEK)
+ }
+
+ fn recv_from_with_flags(&self, buf: &mut [u8], flags: c_int)
+ -> io::Result<(usize, SocketAddr)> {
+ let mut storage: c::SOCKADDR_STORAGE_LH = unsafe { mem::zeroed() };
+ let mut addrlen = mem::size_of_val(&storage) as c::socklen_t;
+ let len = cmp::min(buf.len(), <wrlen_t>::max_value() as usize) as wrlen_t;
+
+ // On unix when a socket is shut down all further reads return 0, so we
+ // do the same on windows to map a shut down socket to returning EOF.
+ unsafe {
+ match c::recvfrom(self.0,
+ buf.as_mut_ptr() as *mut c_void,
+ len,
+ flags,
+ &mut storage as *mut _ as *mut _,
+ &mut addrlen) {
+ -1 if c::WSAGetLastError() == c::WSAESHUTDOWN => {
+ Ok((0, net::sockaddr_to_addr(&storage, addrlen as usize)?))
+ },
+ -1 => Err(last_error()),
+ n => Ok((n as usize, net::sockaddr_to_addr(&storage, addrlen as usize)?)),
+ }
+ }
+ }
+
+ pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+ self.recv_from_with_flags(buf, 0)
+ }
+
+ pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+ self.recv_from_with_flags(buf, c::MSG_PEEK)
+ }
+
+ pub fn write_vectored(&self, bufs: &[IoVec<'_>]) -> io::Result<usize> {
+ let len = cmp::min(bufs.len(), c::DWORD::max_value() as usize) as c::DWORD;
+ let mut nwritten = 0;
+ unsafe {
+ cvt(c::WSASend(
+ self.0,
+ bufs.as_ptr() as *const c::WSABUF as *mut c::WSABUF,
+ len,
+ &mut nwritten,
+ 0,
+ ptr::null_mut(),
+ ptr::null_mut(),
+ ))?;
+ }
+ Ok(nwritten as usize)
+ }
+
+ pub fn set_timeout(&self, dur: Option<Duration>,
+ kind: c_int) -> io::Result<()> {
+ let timeout = match dur {
+ Some(dur) => {
+ let timeout = sys::dur2timeout(dur);
+ if timeout == 0 {
+ return Err(io::Error::new(io::ErrorKind::InvalidInput,
+ "cannot set a 0 duration timeout"));
+ }
+ timeout
+ }
+ None => 0
+ };
+ net::setsockopt(self, c::SOL_SOCKET, kind, timeout)
+ }
+
+ pub fn timeout(&self, kind: c_int) -> io::Result<Option<Duration>> {
+ let raw: c::DWORD = net::getsockopt(self, c::SOL_SOCKET, kind)?;
+ if raw == 0 {
+ Ok(None)
+ } else {
+ let secs = raw / 1000;
+ let nsec = (raw % 1000) * 1000000;
+ Ok(Some(Duration::new(secs as u64, nsec as u32)))
+ }
+ }
+
+ fn set_no_inherit(&self) -> io::Result<()> {
+ sys::cvt(unsafe {
+ c::SetHandleInformation(self.0 as c::HANDLE,
+ c::HANDLE_FLAG_INHERIT, 0)
+ }).map(|_| ())
+ }
+
+ pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
+ let how = match how {
+ Shutdown::Write => c::SD_SEND,
+ Shutdown::Read => c::SD_RECEIVE,
+ Shutdown::Both => c::SD_BOTH,
+ };
+ cvt(unsafe { c::shutdown(self.0, how) })?;
+ Ok(())
+ }
+
+ pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
+ let mut nonblocking = nonblocking as c_ulong;
+ let r = unsafe { c::ioctlsocket(self.0, c::FIONBIO as c_int, &mut nonblocking) };
+ if r == 0 {
+ Ok(())
+ } else {
+ Err(io::Error::last_os_error())
+ }
+ }
+
+ pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> {
+ net::setsockopt(self, c::IPPROTO_TCP, c::TCP_NODELAY, nodelay as c::BYTE)
+ }
+
+ pub fn nodelay(&self) -> io::Result<bool> {
+ let raw: c::BYTE = net::getsockopt(self, c::IPPROTO_TCP, c::TCP_NODELAY)?;
+ Ok(raw != 0)
+ }
+
+ pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+ let raw: c_int = net::getsockopt(self, c::SOL_SOCKET, c::SO_ERROR)?;
+ if raw == 0 {
+ Ok(None)
+ } else {
+ Ok(Some(io::Error::from_raw_os_error(raw as i32)))
+ }
+ }
+}
+
+#[unstable(reason = "not public", issue = "0", feature = "fd_read")]
+impl<'a> Read for &'a Socket {
+ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+ (**self).read(buf)
+ }
+}
+
+impl Drop for Socket {
+ fn drop(&mut self) {
+ let _ = unsafe { c::closesocket(self.0) };
+ }
+}
+
+impl AsInner<c::SOCKET> for Socket {
+ fn as_inner(&self) -> &c::SOCKET { &self.0 }
+}
+
+impl FromInner<c::SOCKET> for Socket {
+ fn from_inner(sock: c::SOCKET) -> Socket { Socket(sock) }
+}
+
+impl IntoInner<c::SOCKET> for Socket {
+ fn into_inner(self) -> c::SOCKET {
+ let ret = self.0;
+ mem::forget(self);
+ ret
+ }
+}
diff --git a/src/libstd/sys/windows/os.rs b/src/libstd/sys/windows/os.rs
new file mode 100644
index 0000000..4e50b55
--- /dev/null
+++ b/src/libstd/sys/windows/os.rs
@@ -0,0 +1,327 @@
+//! Implementation of `std::os` functionality for Windows.
+
+#![allow(nonstandard_style)]
+
+use crate::os::windows::prelude::*;
+
+use crate::error::Error as StdError;
+use crate::ffi::{OsString, OsStr};
+use crate::fmt;
+use crate::io;
+use crate::os::windows::ffi::EncodeWide;
+use crate::path::{self, PathBuf};
+use crate::ptr;
+use crate::slice;
+use crate::sys::{c, cvt};
+use crate::sys::handle::Handle;
+
+use super::to_u16s;
+
+pub fn errno() -> i32 {
+ unsafe { c::GetLastError() as i32 }
+}
+
+/// Gets a detailed string description for the given error number.
+pub fn error_string(mut errnum: i32) -> String {
+ // This value is calculated from the macro
+ // MAKELANGID(LANG_SYSTEM_DEFAULT, SUBLANG_SYS_DEFAULT)
+ let langId = 0x0800 as c::DWORD;
+
+ let mut buf = [0 as c::WCHAR; 2048];
+
+ unsafe {
+ let mut module = ptr::null_mut();
+ let mut flags = 0;
+
+ // NTSTATUS errors may be encoded as HRESULT, which may returned from
+ // GetLastError. For more information about Windows error codes, see
+ // `[MS-ERREF]`: https://msdn.microsoft.com/en-us/library/cc231198.aspx
+ if (errnum & c::FACILITY_NT_BIT as i32) != 0 {
+ // format according to https://support.microsoft.com/en-us/help/259693
+ const NTDLL_DLL: &[u16] = &['N' as _, 'T' as _, 'D' as _, 'L' as _, 'L' as _,
+ '.' as _, 'D' as _, 'L' as _, 'L' as _, 0];
+ module = c::GetModuleHandleW(NTDLL_DLL.as_ptr());
+
+ if module != ptr::null_mut() {
+ errnum ^= c::FACILITY_NT_BIT as i32;
+ flags = c::FORMAT_MESSAGE_FROM_HMODULE;
+ }
+ }
+
+ let res = c::FormatMessageW(flags | c::FORMAT_MESSAGE_FROM_SYSTEM |
+ c::FORMAT_MESSAGE_IGNORE_INSERTS,
+ module,
+ errnum as c::DWORD,
+ langId,
+ buf.as_mut_ptr(),
+ buf.len() as c::DWORD,
+ ptr::null()) as usize;
+ if res == 0 {
+ // Sometimes FormatMessageW can fail e.g., system doesn't like langId,
+ let fm_err = errno();
+ return format!("OS Error {} (FormatMessageW() returned error {})",
+ errnum, fm_err);
+ }
+
+ match String::from_utf16(&buf[..res]) {
+ Ok(mut msg) => {
+ // Trim trailing CRLF inserted by FormatMessageW
+ let len = msg.trim_end().len();
+ msg.truncate(len);
+ msg
+ },
+ Err(..) => format!("OS Error {} (FormatMessageW() returned \
+ invalid UTF-16)", errnum),
+ }
+ }
+}
+
+pub struct Env {
+ base: c::LPWCH,
+ cur: c::LPWCH,
+}
+
+impl Iterator for Env {
+ type Item = (OsString, OsString);
+
+ fn next(&mut self) -> Option<(OsString, OsString)> {
+ loop {
+ unsafe {
+ if *self.cur == 0 { return None }
+ let p = &*self.cur as *const u16;
+ let mut len = 0;
+ while *p.offset(len) != 0 {
+ len += 1;
+ }
+ let s = slice::from_raw_parts(p, len as usize);
+ self.cur = self.cur.offset(len + 1);
+
+ // Windows allows environment variables to start with an equals
+ // symbol (in any other position, this is the separator between
+ // variable name and value). Since`s` has at least length 1 at
+ // this point (because the empty string terminates the array of
+ // environment variables), we can safely slice.
+ let pos = match s[1..].iter().position(|&u| u == b'=' as u16).map(|p| p + 1) {
+ Some(p) => p,
+ None => continue,
+ };
+ return Some((
+ OsStringExt::from_wide(&s[..pos]),
+ OsStringExt::from_wide(&s[pos+1..]),
+ ))
+ }
+ }
+ }
+}
+
+impl Drop for Env {
+ fn drop(&mut self) {
+ unsafe { c::FreeEnvironmentStringsW(self.base); }
+ }
+}
+
+pub fn env() -> Env {
+ unsafe {
+ let ch = c::GetEnvironmentStringsW();
+ if ch as usize == 0 {
+ panic!("failure getting env string from OS: {}",
+ io::Error::last_os_error());
+ }
+ Env { base: ch, cur: ch }
+ }
+}
+
+pub struct SplitPaths<'a> {
+ data: EncodeWide<'a>,
+ must_yield: bool,
+}
+
+pub fn split_paths(unparsed: &OsStr) -> SplitPaths<'_> {
+ SplitPaths {
+ data: unparsed.encode_wide(),
+ must_yield: true,
+ }
+}
+
+impl<'a> Iterator for SplitPaths<'a> {
+ type Item = PathBuf;
+ fn next(&mut self) -> Option<PathBuf> {
+ // On Windows, the PATH environment variable is semicolon separated.
+ // Double quotes are used as a way of introducing literal semicolons
+ // (since c:\some;dir is a valid Windows path). Double quotes are not
+ // themselves permitted in path names, so there is no way to escape a
+ // double quote. Quoted regions can appear in arbitrary locations, so
+ //
+ // c:\foo;c:\som"e;di"r;c:\bar
+ //
+ // Should parse as [c:\foo, c:\some;dir, c:\bar].
+ //
+ // (The above is based on testing; there is no clear reference available
+ // for the grammar.)
+
+
+ let must_yield = self.must_yield;
+ self.must_yield = false;
+
+ let mut in_progress = Vec::new();
+ let mut in_quote = false;
+ for b in self.data.by_ref() {
+ if b == '"' as u16 {
+ in_quote = !in_quote;
+ } else if b == ';' as u16 && !in_quote {
+ self.must_yield = true;
+ break
+ } else {
+ in_progress.push(b)
+ }
+ }
+
+ if !must_yield && in_progress.is_empty() {
+ None
+ } else {
+ Some(super::os2path(&in_progress))
+ }
+ }
+}
+
+#[derive(Debug)]
+pub struct JoinPathsError;
+
+pub fn join_paths<I, T>(paths: I) -> Result<OsString, JoinPathsError>
+ where I: Iterator<Item=T>, T: AsRef<OsStr>
+{
+ let mut joined = Vec::new();
+ let sep = b';' as u16;
+
+ for (i, path) in paths.enumerate() {
+ let path = path.as_ref();
+ if i > 0 { joined.push(sep) }
+ let v = path.encode_wide().collect::<Vec<u16>>();
+ if v.contains(&(b'"' as u16)) {
+ return Err(JoinPathsError)
+ } else if v.contains(&sep) {
+ joined.push(b'"' as u16);
+ joined.extend_from_slice(&v[..]);
+ joined.push(b'"' as u16);
+ } else {
+ joined.extend_from_slice(&v[..]);
+ }
+ }
+
+ Ok(OsStringExt::from_wide(&joined[..]))
+}
+
+impl fmt::Display for JoinPathsError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ "path segment contains `\"`".fmt(f)
+ }
+}
+
+impl StdError for JoinPathsError {
+ fn description(&self) -> &str { "failed to join paths" }
+}
+
+pub fn current_exe() -> io::Result<PathBuf> {
+ super::fill_utf16_buf(|buf, sz| unsafe {
+ c::GetModuleFileNameW(ptr::null_mut(), buf, sz)
+ }, super::os2path)
+}
+
+pub fn getcwd() -> io::Result<PathBuf> {
+ super::fill_utf16_buf(|buf, sz| unsafe {
+ c::GetCurrentDirectoryW(sz, buf)
+ }, super::os2path)
+}
+
+pub fn chdir(p: &path::Path) -> io::Result<()> {
+ let p: &OsStr = p.as_ref();
+ let mut p = p.encode_wide().collect::<Vec<_>>();
+ p.push(0);
+
+ cvt(unsafe {
+ c::SetCurrentDirectoryW(p.as_ptr())
+ }).map(|_| ())
+}
+
+pub fn getenv(k: &OsStr) -> io::Result<Option<OsString>> {
+ let k = to_u16s(k)?;
+ let res = super::fill_utf16_buf(|buf, sz| unsafe {
+ c::GetEnvironmentVariableW(k.as_ptr(), buf, sz)
+ }, |buf| {
+ OsStringExt::from_wide(buf)
+ });
+ match res {
+ Ok(value) => Ok(Some(value)),
+ Err(e) => {
+ if e.raw_os_error() == Some(c::ERROR_ENVVAR_NOT_FOUND as i32) {
+ Ok(None)
+ } else {
+ Err(e)
+ }
+ }
+ }
+}
+
+pub fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> {
+ let k = to_u16s(k)?;
+ let v = to_u16s(v)?;
+
+ cvt(unsafe {
+ c::SetEnvironmentVariableW(k.as_ptr(), v.as_ptr())
+ }).map(|_| ())
+}
+
+pub fn unsetenv(n: &OsStr) -> io::Result<()> {
+ let v = to_u16s(n)?;
+ cvt(unsafe {
+ c::SetEnvironmentVariableW(v.as_ptr(), ptr::null())
+ }).map(|_| ())
+}
+
+pub fn temp_dir() -> PathBuf {
+ super::fill_utf16_buf(|buf, sz| unsafe {
+ c::GetTempPathW(sz, buf)
+ }, super::os2path).unwrap()
+}
+
+pub fn home_dir() -> Option<PathBuf> {
+ crate::env::var_os("HOME").or_else(|| {
+ crate::env::var_os("USERPROFILE")
+ }).map(PathBuf::from).or_else(|| unsafe {
+ let me = c::GetCurrentProcess();
+ let mut token = ptr::null_mut();
+ if c::OpenProcessToken(me, c::TOKEN_READ, &mut token) == 0 {
+ return None
+ }
+ let _handle = Handle::new(token);
+ super::fill_utf16_buf(|buf, mut sz| {
+ match c::GetUserProfileDirectoryW(token, buf, &mut sz) {
+ 0 if c::GetLastError() != c::ERROR_INSUFFICIENT_BUFFER => 0,
+ 0 => sz,
+ _ => sz - 1, // sz includes the null terminator
+ }
+ }, super::os2path).ok()
+ })
+}
+
+pub fn exit(code: i32) -> ! {
+ unsafe { c::ExitProcess(code as c::UINT) }
+}
+
+pub fn getpid() -> u32 {
+ unsafe { c::GetCurrentProcessId() as u32 }
+}
+
+#[cfg(test)]
+mod tests {
+ use crate::io::Error;
+ use crate::sys::c;
+
+ // tests `error_string` above
+ #[test]
+ fn ntstatus_error() {
+ const STATUS_UNSUCCESSFUL: u32 = 0xc000_0001;
+ assert!(!Error::from_raw_os_error((STATUS_UNSUCCESSFUL | c::FACILITY_NT_BIT) as _)
+ .to_string().contains("FormatMessageW() returned error"));
+ }
+}
diff --git a/src/libstd/sys/windows/os_str.rs b/src/libstd/sys/windows/os_str.rs
new file mode 100644
index 0000000..c7a82e0
--- /dev/null
+++ b/src/libstd/sys/windows/os_str.rs
@@ -0,0 +1,172 @@
+/// The underlying OsString/OsStr implementation on Windows is a
+/// wrapper around the "WTF-8" encoding; see the `wtf8` module for more.
+
+use crate::borrow::Cow;
+use crate::fmt;
+use crate::sys_common::wtf8::{Wtf8, Wtf8Buf};
+use crate::mem;
+use crate::rc::Rc;
+use crate::sync::Arc;
+use crate::sys_common::{AsInner, IntoInner, FromInner};
+
+#[derive(Clone, Hash)]
+pub struct Buf {
+ pub inner: Wtf8Buf
+}
+
+impl IntoInner<Wtf8Buf> for Buf {
+ fn into_inner(self) -> Wtf8Buf {
+ self.inner
+ }
+}
+
+impl FromInner<Wtf8Buf> for Buf {
+ fn from_inner(inner: Wtf8Buf) -> Self {
+ Buf { inner }
+ }
+}
+
+impl AsInner<Wtf8> for Buf {
+ fn as_inner(&self) -> &Wtf8 {
+ &self.inner
+ }
+}
+
+impl fmt::Debug for Buf {
+ fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt::Debug::fmt(self.as_slice(), formatter)
+ }
+}
+
+impl fmt::Display for Buf {
+ fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt::Display::fmt(self.as_slice(), formatter)
+ }
+}
+
+pub struct Slice {
+ pub inner: Wtf8
+}
+
+impl fmt::Debug for Slice {
+ fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt::Debug::fmt(&self.inner, formatter)
+ }
+}
+
+impl fmt::Display for Slice {
+ fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt::Display::fmt(&self.inner, formatter)
+ }
+}
+
+impl Buf {
+ pub fn with_capacity(capacity: usize) -> Buf {
+ Buf {
+ inner: Wtf8Buf::with_capacity(capacity)
+ }
+ }
+
+ pub fn clear(&mut self) {
+ self.inner.clear()
+ }
+
+ pub fn capacity(&self) -> usize {
+ self.inner.capacity()
+ }
+
+ pub fn from_string(s: String) -> Buf {
+ Buf { inner: Wtf8Buf::from_string(s) }
+ }
+
+ pub fn as_slice(&self) -> &Slice {
+ unsafe { mem::transmute(self.inner.as_slice()) }
+ }
+
+ pub fn into_string(self) -> Result<String, Buf> {
+ self.inner.into_string().map_err(|buf| Buf { inner: buf })
+ }
+
+ pub fn push_slice(&mut self, s: &Slice) {
+ self.inner.push_wtf8(&s.inner)
+ }
+
+ pub fn reserve(&mut self, additional: usize) {
+ self.inner.reserve(additional)
+ }
+
+ pub fn reserve_exact(&mut self, additional: usize) {
+ self.inner.reserve_exact(additional)
+ }
+
+ pub fn shrink_to_fit(&mut self) {
+ self.inner.shrink_to_fit()
+ }
+
+ #[inline]
+ pub fn shrink_to(&mut self, min_capacity: usize) {
+ self.inner.shrink_to(min_capacity)
+ }
+
+ #[inline]
+ pub fn into_box(self) -> Box<Slice> {
+ unsafe { mem::transmute(self.inner.into_box()) }
+ }
+
+ #[inline]
+ pub fn from_box(boxed: Box<Slice>) -> Buf {
+ let inner: Box<Wtf8> = unsafe { mem::transmute(boxed) };
+ Buf { inner: Wtf8Buf::from_box(inner) }
+ }
+
+ #[inline]
+ pub fn into_arc(&self) -> Arc<Slice> {
+ self.as_slice().into_arc()
+ }
+
+ #[inline]
+ pub fn into_rc(&self) -> Rc<Slice> {
+ self.as_slice().into_rc()
+ }
+}
+
+impl Slice {
+ pub fn from_str(s: &str) -> &Slice {
+ unsafe { mem::transmute(Wtf8::from_str(s)) }
+ }
+
+ pub fn to_str(&self) -> Option<&str> {
+ self.inner.as_str()
+ }
+
+ pub fn to_string_lossy(&self) -> Cow<'_, str> {
+ self.inner.to_string_lossy()
+ }
+
+ pub fn to_owned(&self) -> Buf {
+ let mut buf = Wtf8Buf::with_capacity(self.inner.len());
+ buf.push_wtf8(&self.inner);
+ Buf { inner: buf }
+ }
+
+ #[inline]
+ pub fn into_box(&self) -> Box<Slice> {
+ unsafe { mem::transmute(self.inner.into_box()) }
+ }
+
+ pub fn empty_box() -> Box<Slice> {
+ unsafe { mem::transmute(Wtf8::empty_box()) }
+ }
+
+ #[inline]
+ pub fn into_arc(&self) -> Arc<Slice> {
+ let arc = self.inner.into_arc();
+ unsafe { Arc::from_raw(Arc::into_raw(arc) as *const Slice) }
+ }
+
+ #[inline]
+ pub fn into_rc(&self) -> Rc<Slice> {
+ let rc = self.inner.into_rc();
+ unsafe { Rc::from_raw(Rc::into_raw(rc) as *const Slice) }
+ }
+}
diff --git a/src/libstd/sys/windows/path.rs b/src/libstd/sys/windows/path.rs
new file mode 100644
index 0000000..f3178a5e
--- /dev/null
+++ b/src/libstd/sys/windows/path.rs
@@ -0,0 +1,93 @@
+use crate::path::Prefix;
+use crate::ffi::OsStr;
+use crate::mem;
+
+fn os_str_as_u8_slice(s: &OsStr) -> &[u8] {
+ unsafe { mem::transmute(s) }
+}
+unsafe fn u8_slice_as_os_str(s: &[u8]) -> &OsStr {
+ mem::transmute(s)
+}
+
+#[inline]
+pub fn is_sep_byte(b: u8) -> bool {
+ b == b'/' || b == b'\\'
+}
+
+#[inline]
+pub fn is_verbatim_sep(b: u8) -> bool {
+ b == b'\\'
+}
+
+pub fn parse_prefix<'a>(path: &'a OsStr) -> Option<Prefix<'a>> {
+ use crate::path::Prefix::*;
+ unsafe {
+ // The unsafety here stems from converting between &OsStr and &[u8]
+ // and back. This is safe to do because (1) we only look at ASCII
+ // contents of the encoding and (2) new &OsStr values are produced
+ // only from ASCII-bounded slices of existing &OsStr values.
+ let mut path = os_str_as_u8_slice(path);
+
+ if path.starts_with(br"\\") {
+ // \\
+ path = &path[2..];
+ if path.starts_with(br"?\") {
+ // \\?\
+ path = &path[2..];
+ if path.starts_with(br"UNC\") {
+ // \\?\UNC\server\share
+ path = &path[4..];
+ let (server, share) = match parse_two_comps(path, is_verbatim_sep) {
+ Some((server, share)) =>
+ (u8_slice_as_os_str(server), u8_slice_as_os_str(share)),
+ None => (u8_slice_as_os_str(path), u8_slice_as_os_str(&[])),
+ };
+ return Some(VerbatimUNC(server, share));
+ } else {
+ // \\?\path
+ let idx = path.iter().position(|&b| b == b'\\');
+ if idx == Some(2) && path[1] == b':' {
+ let c = path[0];
+ if c.is_ascii() && (c as char).is_alphabetic() {
+ // \\?\C:\ path
+ return Some(VerbatimDisk(c.to_ascii_uppercase()));
+ }
+ }
+ let slice = &path[..idx.unwrap_or(path.len())];
+ return Some(Verbatim(u8_slice_as_os_str(slice)));
+ }
+ } else if path.starts_with(b".\\") {
+ // \\.\path
+ path = &path[2..];
+ let pos = path.iter().position(|&b| b == b'\\');
+ let slice = &path[..pos.unwrap_or(path.len())];
+ return Some(DeviceNS(u8_slice_as_os_str(slice)));
+ }
+ match parse_two_comps(path, is_sep_byte) {
+ Some((server, share)) if !server.is_empty() && !share.is_empty() => {
+ // \\server\share
+ return Some(UNC(u8_slice_as_os_str(server), u8_slice_as_os_str(share)));
+ }
+ _ => (),
+ }
+ } else if path.get(1) == Some(& b':') {
+ // C:
+ let c = path[0];
+ if c.is_ascii() && (c as char).is_alphabetic() {
+ return Some(Disk(c.to_ascii_uppercase()));
+ }
+ }
+ return None;
+ }
+
+ fn parse_two_comps(mut path: &[u8], f: fn(u8) -> bool) -> Option<(&[u8], &[u8])> {
+ let first = &path[..path.iter().position(|x| f(*x))?];
+ path = &path[(first.len() + 1)..];
+ let idx = path.iter().position(|x| f(*x));
+ let second = &path[..idx.unwrap_or(path.len())];
+ Some((first, second))
+ }
+}
+
+pub const MAIN_SEP_STR: &str = "\\";
+pub const MAIN_SEP: char = '\\';
diff --git a/src/libstd/sys/windows/pipe.rs b/src/libstd/sys/windows/pipe.rs
new file mode 100644
index 0000000..b387278
--- /dev/null
+++ b/src/libstd/sys/windows/pipe.rs
@@ -0,0 +1,354 @@
+use crate::os::windows::prelude::*;
+
+use crate::ffi::OsStr;
+use crate::io;
+use crate::mem;
+use crate::path::Path;
+use crate::ptr;
+use crate::slice;
+use crate::sync::atomic::Ordering::SeqCst;
+use crate::sync::atomic::AtomicUsize;
+use crate::sys::c;
+use crate::sys::fs::{File, OpenOptions};
+use crate::sys::handle::Handle;
+use crate::sys::hashmap_random_keys;
+
+////////////////////////////////////////////////////////////////////////////////
+// Anonymous pipes
+////////////////////////////////////////////////////////////////////////////////
+
+pub struct AnonPipe {
+ inner: Handle,
+}
+
+pub struct Pipes {
+ pub ours: AnonPipe,
+ pub theirs: AnonPipe,
+}
+
+/// Although this looks similar to `anon_pipe` in the Unix module it's actually
+/// subtly different. Here we'll return two pipes in the `Pipes` return value,
+/// but one is intended for "us" where as the other is intended for "someone
+/// else".
+///
+/// Currently the only use case for this function is pipes for stdio on
+/// processes in the standard library, so "ours" is the one that'll stay in our
+/// process whereas "theirs" will be inherited to a child.
+///
+/// The ours/theirs pipes are *not* specifically readable or writable. Each
+/// one only supports a read or a write, but which is which depends on the
+/// boolean flag given. If `ours_readable` is `true`, then `ours` is readable and
+/// `theirs` is writable. Conversely, if `ours_readable` is `false`, then `ours`
+/// is writable and `theirs` is readable.
+///
+/// Also note that the `ours` pipe is always a handle opened up in overlapped
+/// mode. This means that technically speaking it should only ever be used
+/// with `OVERLAPPED` instances, but also works out ok if it's only ever used
+/// once at a time (which we do indeed guarantee).
+pub fn anon_pipe(ours_readable: bool) -> io::Result<Pipes> {
+ // Note that we specifically do *not* use `CreatePipe` here because
+ // unfortunately the anonymous pipes returned do not support overlapped
+ // operations. Instead, we create a "hopefully unique" name and create a
+ // named pipe which has overlapped operations enabled.
+ //
+ // Once we do this, we connect do it as usual via `CreateFileW`, and then
+ // we return those reader/writer halves. Note that the `ours` pipe return
+ // value is always the named pipe, whereas `theirs` is just the normal file.
+ // This should hopefully shield us from child processes which assume their
+ // stdout is a named pipe, which would indeed be odd!
+ unsafe {
+ let ours;
+ let mut name;
+ let mut tries = 0;
+ let mut reject_remote_clients_flag = c::PIPE_REJECT_REMOTE_CLIENTS;
+ loop {
+ tries += 1;
+ name = format!(r"\\.\pipe\__rust_anonymous_pipe1__.{}.{}",
+ c::GetCurrentProcessId(),
+ random_number());
+ let wide_name = OsStr::new(&name)
+ .encode_wide()
+ .chain(Some(0))
+ .collect::<Vec<_>>();
+ let mut flags = c::FILE_FLAG_FIRST_PIPE_INSTANCE |
+ c::FILE_FLAG_OVERLAPPED;
+ if ours_readable {
+ flags |= c::PIPE_ACCESS_INBOUND;
+ } else {
+ flags |= c::PIPE_ACCESS_OUTBOUND;
+ }
+
+ let handle = c::CreateNamedPipeW(wide_name.as_ptr(),
+ flags,
+ c::PIPE_TYPE_BYTE |
+ c::PIPE_READMODE_BYTE |
+ c::PIPE_WAIT |
+ reject_remote_clients_flag,
+ 1,
+ 4096,
+ 4096,
+ 0,
+ ptr::null_mut());
+
+ // We pass the `FILE_FLAG_FIRST_PIPE_INSTANCE` flag above, and we're
+ // also just doing a best effort at selecting a unique name. If
+ // `ERROR_ACCESS_DENIED` is returned then it could mean that we
+ // accidentally conflicted with an already existing pipe, so we try
+ // again.
+ //
+ // Don't try again too much though as this could also perhaps be a
+ // legit error.
+ // If `ERROR_INVALID_PARAMETER` is returned, this probably means we're
+ // running on pre-Vista version where `PIPE_REJECT_REMOTE_CLIENTS` is
+ // not supported, so we continue retrying without it. This implies
+ // reduced security on Windows versions older than Vista by allowing
+ // connections to this pipe from remote machines.
+ // Proper fix would increase the number of FFI imports and introduce
+ // significant amount of Windows XP specific code with no clean
+ // testing strategy
+ // For more info, see https://github.com/rust-lang/rust/pull/37677.
+ if handle == c::INVALID_HANDLE_VALUE {
+ let err = io::Error::last_os_error();
+ let raw_os_err = err.raw_os_error();
+ if tries < 10 {
+ if raw_os_err == Some(c::ERROR_ACCESS_DENIED as i32) {
+ continue
+ } else if reject_remote_clients_flag != 0 &&
+ raw_os_err == Some(c::ERROR_INVALID_PARAMETER as i32) {
+ reject_remote_clients_flag = 0;
+ tries -= 1;
+ continue
+ }
+ }
+ return Err(err)
+ }
+ ours = Handle::new(handle);
+ break
+ }
+
+ // Connect to the named pipe we just created. This handle is going to be
+ // returned in `theirs`, so if `ours` is readable we want this to be
+ // writable, otherwise if `ours` is writable we want this to be
+ // readable.
+ //
+ // Additionally we don't enable overlapped mode on this because most
+ // client processes aren't enabled to work with that.
+ let mut opts = OpenOptions::new();
+ opts.write(ours_readable);
+ opts.read(!ours_readable);
+ opts.share_mode(0);
+ let theirs = File::open(Path::new(&name), &opts)?;
+ let theirs = AnonPipe { inner: theirs.into_handle() };
+
+ Ok(Pipes {
+ ours: AnonPipe { inner: ours },
+ theirs: AnonPipe { inner: theirs.into_handle() },
+ })
+ }
+}
+
+fn random_number() -> usize {
+ static N: AtomicUsize = AtomicUsize::new(0);
+ loop {
+ if N.load(SeqCst) != 0 {
+ return N.fetch_add(1, SeqCst)
+ }
+
+ N.store(hashmap_random_keys().0 as usize, SeqCst);
+ }
+}
+
+impl AnonPipe {
+ pub fn handle(&self) -> &Handle { &self.inner }
+ pub fn into_handle(self) -> Handle { self.inner }
+
+ pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
+ self.inner.read(buf)
+ }
+
+ pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
+ self.inner.write(buf)
+ }
+}
+
+pub fn read2(p1: AnonPipe,
+ v1: &mut Vec<u8>,
+ p2: AnonPipe,
+ v2: &mut Vec<u8>) -> io::Result<()> {
+ let p1 = p1.into_handle();
+ let p2 = p2.into_handle();
+
+ let mut p1 = AsyncPipe::new(p1, v1)?;
+ let mut p2 = AsyncPipe::new(p2, v2)?;
+ let objs = [p1.event.raw(), p2.event.raw()];
+
+ // In a loop we wait for either pipe's scheduled read operation to complete.
+ // If the operation completes with 0 bytes, that means EOF was reached, in
+ // which case we just finish out the other pipe entirely.
+ //
+ // Note that overlapped I/O is in general super unsafe because we have to
+ // be careful to ensure that all pointers in play are valid for the entire
+ // duration of the I/O operation (where tons of operations can also fail).
+ // The destructor for `AsyncPipe` ends up taking care of most of this.
+ loop {
+ let res = unsafe {
+ c::WaitForMultipleObjects(2, objs.as_ptr(), c::FALSE, c::INFINITE)
+ };
+ if res == c::WAIT_OBJECT_0 {
+ if !p1.result()? || !p1.schedule_read()? {
+ return p2.finish()
+ }
+ } else if res == c::WAIT_OBJECT_0 + 1 {
+ if !p2.result()? || !p2.schedule_read()? {
+ return p1.finish()
+ }
+ } else {
+ return Err(io::Error::last_os_error())
+ }
+ }
+}
+
+struct AsyncPipe<'a> {
+ pipe: Handle,
+ event: Handle,
+ overlapped: Box<c::OVERLAPPED>, // needs a stable address
+ dst: &'a mut Vec<u8>,
+ state: State,
+}
+
+#[derive(PartialEq, Debug)]
+enum State {
+ NotReading,
+ Reading,
+ Read(usize),
+}
+
+impl<'a> AsyncPipe<'a> {
+ fn new(pipe: Handle, dst: &'a mut Vec<u8>) -> io::Result<AsyncPipe<'a>> {
+ // Create an event which we'll use to coordinate our overlapped
+ // operations, this event will be used in WaitForMultipleObjects
+ // and passed as part of the OVERLAPPED handle.
+ //
+ // Note that we do a somewhat clever thing here by flagging the
+ // event as being manually reset and setting it initially to the
+ // signaled state. This means that we'll naturally fall through the
+ // WaitForMultipleObjects call above for pipes created initially,
+ // and the only time an even will go back to "unset" will be once an
+ // I/O operation is successfully scheduled (what we want).
+ let event = Handle::new_event(true, true)?;
+ let mut overlapped: Box<c::OVERLAPPED> = unsafe {
+ Box::new(mem::zeroed())
+ };
+ overlapped.hEvent = event.raw();
+ Ok(AsyncPipe {
+ pipe,
+ overlapped,
+ event,
+ dst,
+ state: State::NotReading,
+ })
+ }
+
+ /// Executes an overlapped read operation.
+ ///
+ /// Must not currently be reading, and returns whether the pipe is currently
+ /// at EOF or not. If the pipe is not at EOF then `result()` must be called
+ /// to complete the read later on (may block), but if the pipe is at EOF
+ /// then `result()` should not be called as it will just block forever.
+ fn schedule_read(&mut self) -> io::Result<bool> {
+ assert_eq!(self.state, State::NotReading);
+ let amt = unsafe {
+ let slice = slice_to_end(self.dst);
+ self.pipe.read_overlapped(slice, &mut *self.overlapped)?
+ };
+
+ // If this read finished immediately then our overlapped event will
+ // remain signaled (it was signaled coming in here) and we'll progress
+ // down to the method below.
+ //
+ // Otherwise the I/O operation is scheduled and the system set our event
+ // to not signaled, so we flag ourselves into the reading state and move
+ // on.
+ self.state = match amt {
+ Some(0) => return Ok(false),
+ Some(amt) => State::Read(amt),
+ None => State::Reading,
+ };
+ Ok(true)
+ }
+
+ /// Wait for the result of the overlapped operation previously executed.
+ ///
+ /// Takes a parameter `wait` which indicates if this pipe is currently being
+ /// read whether the function should block waiting for the read to complete.
+ ///
+ /// Returns values:
+ ///
+ /// * `true` - finished any pending read and the pipe is not at EOF (keep
+ /// going)
+ /// * `false` - finished any pending read and pipe is at EOF (stop issuing
+ /// reads)
+ fn result(&mut self) -> io::Result<bool> {
+ let amt = match self.state {
+ State::NotReading => return Ok(true),
+ State::Reading => {
+ self.pipe.overlapped_result(&mut *self.overlapped, true)?
+ }
+ State::Read(amt) => amt,
+ };
+ self.state = State::NotReading;
+ unsafe {
+ let len = self.dst.len();
+ self.dst.set_len(len + amt);
+ }
+ Ok(amt != 0)
+ }
+
+ /// Finishes out reading this pipe entirely.
+ ///
+ /// Waits for any pending and schedule read, and then calls `read_to_end`
+ /// if necessary to read all the remaining information.
+ fn finish(&mut self) -> io::Result<()> {
+ while self.result()? && self.schedule_read()? {
+ // ...
+ }
+ Ok(())
+ }
+}
+
+impl<'a> Drop for AsyncPipe<'a> {
+ fn drop(&mut self) {
+ match self.state {
+ State::Reading => {}
+ _ => return,
+ }
+
+ // If we have a pending read operation, then we have to make sure that
+ // it's *done* before we actually drop this type. The kernel requires
+ // that the `OVERLAPPED` and buffer pointers are valid for the entire
+ // I/O operation.
+ //
+ // To do that, we call `CancelIo` to cancel any pending operation, and
+ // if that succeeds we wait for the overlapped result.
+ //
+ // If anything here fails, there's not really much we can do, so we leak
+ // the buffer/OVERLAPPED pointers to ensure we're at least memory safe.
+ if self.pipe.cancel_io().is_err() || self.result().is_err() {
+ let buf = mem::replace(self.dst, Vec::new());
+ let overlapped = Box::new(unsafe { mem::zeroed() });
+ let overlapped = mem::replace(&mut self.overlapped, overlapped);
+ mem::forget((buf, overlapped));
+ }
+ }
+}
+
+unsafe fn slice_to_end(v: &mut Vec<u8>) -> &mut [u8] {
+ if v.capacity() == 0 {
+ v.reserve(16);
+ }
+ if v.capacity() == v.len() {
+ v.reserve(1);
+ }
+ slice::from_raw_parts_mut(v.as_mut_ptr().add(v.len()),
+ v.capacity() - v.len())
+}
diff --git a/src/libstd/sys/windows/process.rs b/src/libstd/sys/windows/process.rs
new file mode 100644
index 0000000..e39b7ae
--- /dev/null
+++ b/src/libstd/sys/windows/process.rs
@@ -0,0 +1,581 @@
+#![unstable(feature = "process_internals", issue = "0")]
+
+use crate::collections::BTreeMap;
+use crate::env::split_paths;
+use crate::env;
+use crate::ffi::{OsString, OsStr};
+use crate::fmt;
+use crate::fs;
+use crate::io::{self, Error, ErrorKind};
+use crate::mem;
+use crate::os::windows::ffi::OsStrExt;
+use crate::path::Path;
+use crate::ptr;
+use crate::sys::mutex::Mutex;
+use crate::sys::c;
+use crate::sys::fs::{OpenOptions, File};
+use crate::sys::handle::Handle;
+use crate::sys::pipe::{self, AnonPipe};
+use crate::sys::stdio;
+use crate::sys::cvt;
+use crate::sys_common::{AsInner, FromInner, IntoInner};
+use crate::sys_common::process::{CommandEnv, EnvKey};
+use crate::borrow::Borrow;
+
+use libc::{c_void, EXIT_SUCCESS, EXIT_FAILURE};
+
+////////////////////////////////////////////////////////////////////////////////
+// Command
+////////////////////////////////////////////////////////////////////////////////
+
+#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
+#[doc(hidden)]
+pub struct WindowsEnvKey(OsString);
+
+impl From<OsString> for WindowsEnvKey {
+ fn from(k: OsString) -> Self {
+ let mut buf = k.into_inner().into_inner();
+ buf.make_ascii_uppercase();
+ WindowsEnvKey(FromInner::from_inner(FromInner::from_inner(buf)))
+ }
+}
+
+impl From<WindowsEnvKey> for OsString {
+ fn from(k: WindowsEnvKey) -> Self { k.0 }
+}
+
+impl Borrow<OsStr> for WindowsEnvKey {
+ fn borrow(&self) -> &OsStr { &self.0 }
+}
+
+impl AsRef<OsStr> for WindowsEnvKey {
+ fn as_ref(&self) -> &OsStr { &self.0 }
+}
+
+impl EnvKey for WindowsEnvKey {}
+
+
+fn ensure_no_nuls<T: AsRef<OsStr>>(str: T) -> io::Result<T> {
+ if str.as_ref().encode_wide().any(|b| b == 0) {
+ Err(io::Error::new(ErrorKind::InvalidInput, "nul byte found in provided data"))
+ } else {
+ Ok(str)
+ }
+}
+
+pub struct Command {
+ program: OsString,
+ args: Vec<OsString>,
+ env: CommandEnv<WindowsEnvKey>,
+ cwd: Option<OsString>,
+ flags: u32,
+ detach: bool, // not currently exposed in std::process
+ stdin: Option<Stdio>,
+ stdout: Option<Stdio>,
+ stderr: Option<Stdio>,
+}
+
+pub enum Stdio {
+ Inherit,
+ Null,
+ MakePipe,
+ Handle(Handle),
+}
+
+pub struct StdioPipes {
+ pub stdin: Option<AnonPipe>,
+ pub stdout: Option<AnonPipe>,
+ pub stderr: Option<AnonPipe>,
+}
+
+struct DropGuard<'a> {
+ lock: &'a Mutex,
+}
+
+impl Command {
+ pub fn new(program: &OsStr) -> Command {
+ Command {
+ program: program.to_os_string(),
+ args: Vec::new(),
+ env: Default::default(),
+ cwd: None,
+ flags: 0,
+ detach: false,
+ stdin: None,
+ stdout: None,
+ stderr: None,
+ }
+ }
+
+ pub fn arg(&mut self, arg: &OsStr) {
+ self.args.push(arg.to_os_string())
+ }
+ pub fn env_mut(&mut self) -> &mut CommandEnv<WindowsEnvKey> {
+ &mut self.env
+ }
+ pub fn cwd(&mut self, dir: &OsStr) {
+ self.cwd = Some(dir.to_os_string())
+ }
+ pub fn stdin(&mut self, stdin: Stdio) {
+ self.stdin = Some(stdin);
+ }
+ pub fn stdout(&mut self, stdout: Stdio) {
+ self.stdout = Some(stdout);
+ }
+ pub fn stderr(&mut self, stderr: Stdio) {
+ self.stderr = Some(stderr);
+ }
+ pub fn creation_flags(&mut self, flags: u32) {
+ self.flags = flags;
+ }
+
+ pub fn spawn(&mut self, default: Stdio, needs_stdin: bool)
+ -> io::Result<(Process, StdioPipes)> {
+ let maybe_env = self.env.capture_if_changed();
+ // To have the spawning semantics of unix/windows stay the same, we need
+ // to read the *child's* PATH if one is provided. See #15149 for more
+ // details.
+ let program = maybe_env.as_ref().and_then(|env| {
+ if let Some(v) = env.get(OsStr::new("PATH")) {
+ // Split the value and test each path to see if the
+ // program exists.
+ for path in split_paths(&v) {
+ let path = path.join(self.program.to_str().unwrap())
+ .with_extension(env::consts::EXE_EXTENSION);
+ if fs::metadata(&path).is_ok() {
+ return Some(path.into_os_string())
+ }
+ }
+ }
+ None
+ });
+
+ let mut si = zeroed_startupinfo();
+ si.cb = mem::size_of::<c::STARTUPINFO>() as c::DWORD;
+ si.dwFlags = c::STARTF_USESTDHANDLES;
+
+ let program = program.as_ref().unwrap_or(&self.program);
+ let mut cmd_str = make_command_line(program, &self.args)?;
+ cmd_str.push(0); // add null terminator
+
+ // stolen from the libuv code.
+ let mut flags = self.flags | c::CREATE_UNICODE_ENVIRONMENT;
+ if self.detach {
+ flags |= c::DETACHED_PROCESS | c::CREATE_NEW_PROCESS_GROUP;
+ }
+
+ let (envp, _data) = make_envp(maybe_env)?;
+ let (dirp, _data) = make_dirp(self.cwd.as_ref())?;
+ let mut pi = zeroed_process_information();
+
+ // Prepare all stdio handles to be inherited by the child. This
+ // currently involves duplicating any existing ones with the ability to
+ // be inherited by child processes. Note, however, that once an
+ // inheritable handle is created, *any* spawned child will inherit that
+ // handle. We only want our own child to inherit this handle, so we wrap
+ // the remaining portion of this spawn in a mutex.
+ //
+ // For more information, msdn also has an article about this race:
+ // http://support.microsoft.com/kb/315939
+ static CREATE_PROCESS_LOCK: Mutex = Mutex::new();
+ let _guard = DropGuard::new(&CREATE_PROCESS_LOCK);
+
+ let mut pipes = StdioPipes {
+ stdin: None,
+ stdout: None,
+ stderr: None,
+ };
+ let null = Stdio::Null;
+ let default_stdin = if needs_stdin {&default} else {&null};
+ let stdin = self.stdin.as_ref().unwrap_or(default_stdin);
+ let stdout = self.stdout.as_ref().unwrap_or(&default);
+ let stderr = self.stderr.as_ref().unwrap_or(&default);
+ let stdin = stdin.to_handle(c::STD_INPUT_HANDLE, &mut pipes.stdin)?;
+ let stdout = stdout.to_handle(c::STD_OUTPUT_HANDLE,
+ &mut pipes.stdout)?;
+ let stderr = stderr.to_handle(c::STD_ERROR_HANDLE,
+ &mut pipes.stderr)?;
+ si.hStdInput = stdin.raw();
+ si.hStdOutput = stdout.raw();
+ si.hStdError = stderr.raw();
+
+ unsafe {
+ cvt(c::CreateProcessW(ptr::null(),
+ cmd_str.as_mut_ptr(),
+ ptr::null_mut(),
+ ptr::null_mut(),
+ c::TRUE, flags, envp, dirp,
+ &mut si, &mut pi))
+ }?;
+
+ // We close the thread handle because we don't care about keeping
+ // the thread id valid, and we aren't keeping the thread handle
+ // around to be able to close it later.
+ drop(Handle::new(pi.hThread));
+
+ Ok((Process { handle: Handle::new(pi.hProcess) }, pipes))
+ }
+
+}
+
+impl fmt::Debug for Command {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "{:?}", self.program)?;
+ for arg in &self.args {
+ write!(f, " {:?}", arg)?;
+ }
+ Ok(())
+ }
+}
+
+impl<'a> DropGuard<'a> {
+ fn new(lock: &'a Mutex) -> DropGuard<'a> {
+ unsafe {
+ lock.lock();
+ DropGuard { lock }
+ }
+ }
+}
+
+impl<'a> Drop for DropGuard<'a> {
+ fn drop(&mut self) {
+ unsafe {
+ self.lock.unlock();
+ }
+ }
+}
+
+impl Stdio {
+ fn to_handle(&self, stdio_id: c::DWORD, pipe: &mut Option<AnonPipe>)
+ -> io::Result<Handle> {
+ match *self {
+ // If no stdio handle is available, then inherit means that it
+ // should still be unavailable so propagate the
+ // INVALID_HANDLE_VALUE.
+ Stdio::Inherit => {
+ match stdio::get_handle(stdio_id) {
+ Ok(io) => {
+ let io = Handle::new(io);
+ let ret = io.duplicate(0, true,
+ c::DUPLICATE_SAME_ACCESS);
+ io.into_raw();
+ return ret
+ }
+ Err(..) => Ok(Handle::new(c::INVALID_HANDLE_VALUE)),
+ }
+ }
+
+ Stdio::MakePipe => {
+ let ours_readable = stdio_id != c::STD_INPUT_HANDLE;
+ let pipes = pipe::anon_pipe(ours_readable)?;
+ *pipe = Some(pipes.ours);
+ cvt(unsafe {
+ c::SetHandleInformation(pipes.theirs.handle().raw(),
+ c::HANDLE_FLAG_INHERIT,
+ c::HANDLE_FLAG_INHERIT)
+ })?;
+ Ok(pipes.theirs.into_handle())
+ }
+
+ Stdio::Handle(ref handle) => {
+ handle.duplicate(0, true, c::DUPLICATE_SAME_ACCESS)
+ }
+
+ // Open up a reference to NUL with appropriate read/write
+ // permissions as well as the ability to be inherited to child
+ // processes (as this is about to be inherited).
+ Stdio::Null => {
+ let size = mem::size_of::<c::SECURITY_ATTRIBUTES>();
+ let mut sa = c::SECURITY_ATTRIBUTES {
+ nLength: size as c::DWORD,
+ lpSecurityDescriptor: ptr::null_mut(),
+ bInheritHandle: 1,
+ };
+ let mut opts = OpenOptions::new();
+ opts.read(stdio_id == c::STD_INPUT_HANDLE);
+ opts.write(stdio_id != c::STD_INPUT_HANDLE);
+ opts.security_attributes(&mut sa);
+ File::open(Path::new("NUL"), &opts).map(|file| {
+ file.into_handle()
+ })
+ }
+ }
+ }
+}
+
+impl From<AnonPipe> for Stdio {
+ fn from(pipe: AnonPipe) -> Stdio {
+ Stdio::Handle(pipe.into_handle())
+ }
+}
+
+impl From<File> for Stdio {
+ fn from(file: File) -> Stdio {
+ Stdio::Handle(file.into_handle())
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Processes
+////////////////////////////////////////////////////////////////////////////////
+
+/// A value representing a child process.
+///
+/// The lifetime of this value is linked to the lifetime of the actual
+/// process - the Process destructor calls self.finish() which waits
+/// for the process to terminate.
+pub struct Process {
+ handle: Handle,
+}
+
+impl Process {
+ pub fn kill(&mut self) -> io::Result<()> {
+ cvt(unsafe {
+ c::TerminateProcess(self.handle.raw(), 1)
+ })?;
+ Ok(())
+ }
+
+ pub fn id(&self) -> u32 {
+ unsafe {
+ c::GetProcessId(self.handle.raw()) as u32
+ }
+ }
+
+ pub fn wait(&mut self) -> io::Result<ExitStatus> {
+ unsafe {
+ let res = c::WaitForSingleObject(self.handle.raw(), c::INFINITE);
+ if res != c::WAIT_OBJECT_0 {
+ return Err(Error::last_os_error())
+ }
+ let mut status = 0;
+ cvt(c::GetExitCodeProcess(self.handle.raw(), &mut status))?;
+ Ok(ExitStatus(status))
+ }
+ }
+
+ pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
+ unsafe {
+ match c::WaitForSingleObject(self.handle.raw(), 0) {
+ c::WAIT_OBJECT_0 => {}
+ c::WAIT_TIMEOUT => {
+ return Ok(None);
+ }
+ _ => return Err(io::Error::last_os_error()),
+ }
+ let mut status = 0;
+ cvt(c::GetExitCodeProcess(self.handle.raw(), &mut status))?;
+ Ok(Some(ExitStatus(status)))
+ }
+ }
+
+ pub fn handle(&self) -> &Handle { &self.handle }
+
+ pub fn into_handle(self) -> Handle { self.handle }
+}
+
+#[derive(PartialEq, Eq, Clone, Copy, Debug)]
+pub struct ExitStatus(c::DWORD);
+
+impl ExitStatus {
+ pub fn success(&self) -> bool {
+ self.0 == 0
+ }
+ pub fn code(&self) -> Option<i32> {
+ Some(self.0 as i32)
+ }
+}
+
+impl From<c::DWORD> for ExitStatus {
+ fn from(u: c::DWORD) -> ExitStatus {
+ ExitStatus(u)
+ }
+}
+
+impl fmt::Display for ExitStatus {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ // Windows exit codes with the high bit set typically mean some form of
+ // unhandled exception or warning. In this scenario printing the exit
+ // code in decimal doesn't always make sense because it's a very large
+ // and somewhat gibberish number. The hex code is a bit more
+ // recognizable and easier to search for, so print that.
+ if self.0 & 0x80000000 != 0 {
+ write!(f, "exit code: {:#x}", self.0)
+ } else {
+ write!(f, "exit code: {}", self.0)
+ }
+ }
+}
+
+#[derive(PartialEq, Eq, Clone, Copy, Debug)]
+pub struct ExitCode(c::DWORD);
+
+impl ExitCode {
+ pub const SUCCESS: ExitCode = ExitCode(EXIT_SUCCESS as _);
+ pub const FAILURE: ExitCode = ExitCode(EXIT_FAILURE as _);
+
+ #[inline]
+ pub fn as_i32(&self) -> i32 {
+ self.0 as i32
+ }
+}
+
+fn zeroed_startupinfo() -> c::STARTUPINFO {
+ c::STARTUPINFO {
+ cb: 0,
+ lpReserved: ptr::null_mut(),
+ lpDesktop: ptr::null_mut(),
+ lpTitle: ptr::null_mut(),
+ dwX: 0,
+ dwY: 0,
+ dwXSize: 0,
+ dwYSize: 0,
+ dwXCountChars: 0,
+ dwYCountCharts: 0,
+ dwFillAttribute: 0,
+ dwFlags: 0,
+ wShowWindow: 0,
+ cbReserved2: 0,
+ lpReserved2: ptr::null_mut(),
+ hStdInput: c::INVALID_HANDLE_VALUE,
+ hStdOutput: c::INVALID_HANDLE_VALUE,
+ hStdError: c::INVALID_HANDLE_VALUE,
+ }
+}
+
+fn zeroed_process_information() -> c::PROCESS_INFORMATION {
+ c::PROCESS_INFORMATION {
+ hProcess: ptr::null_mut(),
+ hThread: ptr::null_mut(),
+ dwProcessId: 0,
+ dwThreadId: 0
+ }
+}
+
+// Produces a wide string *without terminating null*; returns an error if
+// `prog` or any of the `args` contain a nul.
+fn make_command_line(prog: &OsStr, args: &[OsString]) -> io::Result<Vec<u16>> {
+ // Encode the command and arguments in a command line string such
+ // that the spawned process may recover them using CommandLineToArgvW.
+ let mut cmd: Vec<u16> = Vec::new();
+ // Always quote the program name so CreateProcess doesn't interpret args as
+ // part of the name if the binary wasn't found first time.
+ append_arg(&mut cmd, prog, true)?;
+ for arg in args {
+ cmd.push(' ' as u16);
+ append_arg(&mut cmd, arg, false)?;
+ }
+ return Ok(cmd);
+
+ fn append_arg(cmd: &mut Vec<u16>, arg: &OsStr, force_quotes: bool) -> io::Result<()> {
+ // If an argument has 0 characters then we need to quote it to ensure
+ // that it actually gets passed through on the command line or otherwise
+ // it will be dropped entirely when parsed on the other end.
+ ensure_no_nuls(arg)?;
+ let arg_bytes = &arg.as_inner().inner.as_inner();
+ let quote = force_quotes || arg_bytes.iter().any(|c| *c == b' ' || *c == b'\t')
+ || arg_bytes.is_empty();
+ if quote {
+ cmd.push('"' as u16);
+ }
+
+ let mut iter = arg.encode_wide();
+ let mut backslashes: usize = 0;
+ while let Some(x) = iter.next() {
+ if x == '\\' as u16 {
+ backslashes += 1;
+ } else {
+ if x == '"' as u16 {
+ // Add n+1 backslashes to total 2n+1 before internal '"'.
+ cmd.extend((0..=backslashes).map(|_| '\\' as u16));
+ }
+ backslashes = 0;
+ }
+ cmd.push(x);
+ }
+
+ if quote {
+ // Add n backslashes to total 2n before ending '"'.
+ cmd.extend((0..backslashes).map(|_| '\\' as u16));
+ cmd.push('"' as u16);
+ }
+ Ok(())
+ }
+}
+
+fn make_envp(maybe_env: Option<BTreeMap<WindowsEnvKey, OsString>>)
+ -> io::Result<(*mut c_void, Vec<u16>)> {
+ // On Windows we pass an "environment block" which is not a char**, but
+ // rather a concatenation of null-terminated k=v\0 sequences, with a final
+ // \0 to terminate.
+ if let Some(env) = maybe_env {
+ let mut blk = Vec::new();
+
+ for (k, v) in env {
+ blk.extend(ensure_no_nuls(k.0)?.encode_wide());
+ blk.push('=' as u16);
+ blk.extend(ensure_no_nuls(v)?.encode_wide());
+ blk.push(0);
+ }
+ blk.push(0);
+ Ok((blk.as_mut_ptr() as *mut c_void, blk))
+ } else {
+ Ok((ptr::null_mut(), Vec::new()))
+ }
+}
+
+fn make_dirp(d: Option<&OsString>) -> io::Result<(*const u16, Vec<u16>)> {
+
+ match d {
+ Some(dir) => {
+ let mut dir_str: Vec<u16> = ensure_no_nuls(dir)?.encode_wide().collect();
+ dir_str.push(0);
+ Ok((dir_str.as_ptr(), dir_str))
+ },
+ None => Ok((ptr::null(), Vec::new()))
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use crate::ffi::{OsStr, OsString};
+ use super::make_command_line;
+
+ #[test]
+ fn test_make_command_line() {
+ fn test_wrapper(prog: &str, args: &[&str]) -> String {
+ let command_line = &make_command_line(OsStr::new(prog),
+ &args.iter()
+ .map(|a| OsString::from(a))
+ .collect::<Vec<OsString>>())
+ .unwrap();
+ String::from_utf16(command_line).unwrap()
+ }
+
+ assert_eq!(
+ test_wrapper("prog", &["aaa", "bbb", "ccc"]),
+ "\"prog\" aaa bbb ccc"
+ );
+
+ assert_eq!(
+ test_wrapper("C:\\Program Files\\blah\\blah.exe", &["aaa"]),
+ "\"C:\\Program Files\\blah\\blah.exe\" aaa"
+ );
+ assert_eq!(
+ test_wrapper("C:\\Program Files\\test", &["aa\"bb"]),
+ "\"C:\\Program Files\\test\" aa\\\"bb"
+ );
+ assert_eq!(
+ test_wrapper("echo", &["a b c"]),
+ "\"echo\" \"a b c\""
+ );
+ assert_eq!(
+ test_wrapper("echo", &["\" \\\" \\", "\\"]),
+ "\"echo\" \"\\\" \\\\\\\" \\\\\" \\"
+ );
+ assert_eq!(
+ test_wrapper("\u{03c0}\u{042f}\u{97f3}\u{00e6}\u{221e}", &[]),
+ "\"\u{03c0}\u{042f}\u{97f3}\u{00e6}\u{221e}\""
+ );
+ }
+}
diff --git a/src/libstd/sys/windows/rand.rs b/src/libstd/sys/windows/rand.rs
new file mode 100644
index 0000000..0193f4d
--- /dev/null
+++ b/src/libstd/sys/windows/rand.rs
@@ -0,0 +1,16 @@
+use crate::io;
+use crate::mem;
+use crate::sys::c;
+
+pub fn hashmap_random_keys() -> (u64, u64) {
+ let mut v = (0, 0);
+ let ret = unsafe {
+ c::RtlGenRandom(&mut v as *mut _ as *mut u8,
+ mem::size_of_val(&v) as c::ULONG)
+ };
+ if ret == 0 {
+ panic!("couldn't generate random bytes: {}",
+ io::Error::last_os_error());
+ }
+ return v
+}
diff --git a/src/libstd/sys/windows/rwlock.rs b/src/libstd/sys/windows/rwlock.rs
new file mode 100644
index 0000000..ef57562
--- /dev/null
+++ b/src/libstd/sys/windows/rwlock.rs
@@ -0,0 +1,42 @@
+use crate::cell::UnsafeCell;
+use crate::sys::c;
+
+pub struct RWLock { inner: UnsafeCell<c::SRWLOCK> }
+
+unsafe impl Send for RWLock {}
+unsafe impl Sync for RWLock {}
+
+impl RWLock {
+ pub const fn new() -> RWLock {
+ RWLock { inner: UnsafeCell::new(c::SRWLOCK_INIT) }
+ }
+ #[inline]
+ pub unsafe fn read(&self) {
+ c::AcquireSRWLockShared(self.inner.get())
+ }
+ #[inline]
+ pub unsafe fn try_read(&self) -> bool {
+ c::TryAcquireSRWLockShared(self.inner.get()) != 0
+ }
+ #[inline]
+ pub unsafe fn write(&self) {
+ c::AcquireSRWLockExclusive(self.inner.get())
+ }
+ #[inline]
+ pub unsafe fn try_write(&self) -> bool {
+ c::TryAcquireSRWLockExclusive(self.inner.get()) != 0
+ }
+ #[inline]
+ pub unsafe fn read_unlock(&self) {
+ c::ReleaseSRWLockShared(self.inner.get())
+ }
+ #[inline]
+ pub unsafe fn write_unlock(&self) {
+ c::ReleaseSRWLockExclusive(self.inner.get())
+ }
+
+ #[inline]
+ pub unsafe fn destroy(&self) {
+ // ...
+ }
+}
diff --git a/src/libstd/sys/windows/stack_overflow.rs b/src/libstd/sys/windows/stack_overflow.rs
new file mode 100644
index 0000000..d5b7765
--- /dev/null
+++ b/src/libstd/sys/windows/stack_overflow.rs
@@ -0,0 +1,42 @@
+#![cfg_attr(test, allow(dead_code))]
+
+use crate::sys_common::util::report_overflow;
+use crate::sys::c;
+
+pub struct Handler;
+
+impl Handler {
+ pub unsafe fn new() -> Handler {
+ // This API isn't available on XP, so don't panic in that case and just
+ // pray it works out ok.
+ if c::SetThreadStackGuarantee(&mut 0x5000) == 0 {
+ if c::GetLastError() as u32 != c::ERROR_CALL_NOT_IMPLEMENTED as u32 {
+ panic!("failed to reserve stack space for exception handling");
+ }
+ }
+ Handler
+ }
+}
+
+extern "system" fn vectored_handler(ExceptionInfo: *mut c::EXCEPTION_POINTERS)
+ -> c::LONG {
+ unsafe {
+ let rec = &(*(*ExceptionInfo).ExceptionRecord);
+ let code = rec.ExceptionCode;
+
+ if code == c::EXCEPTION_STACK_OVERFLOW {
+ report_overflow();
+ }
+ c::EXCEPTION_CONTINUE_SEARCH
+ }
+}
+
+pub unsafe fn init() {
+ if c::AddVectoredExceptionHandler(0, vectored_handler).is_null() {
+ panic!("failed to install exception handler");
+ }
+ // Set the thread stack guarantee for the main thread.
+ let _h = Handler::new();
+}
+
+pub unsafe fn cleanup() {}
diff --git a/src/libstd/sys/windows/stdio.rs b/src/libstd/sys/windows/stdio.rs
new file mode 100644
index 0000000..b1e76b3
--- /dev/null
+++ b/src/libstd/sys/windows/stdio.rs
@@ -0,0 +1,283 @@
+#![unstable(issue = "0", feature = "windows_stdio")]
+
+use crate::char::decode_utf16;
+use crate::cmp;
+use crate::io;
+use crate::ptr;
+use crate::str;
+use crate::sys::c;
+use crate::sys::cvt;
+use crate::sys::handle::Handle;
+
+// Don't cache handles but get them fresh for every read/write. This allows us to track changes to
+// the value over time (such as if a process calls `SetStdHandle` while it's running). See #40490.
+pub struct Stdin {
+ surrogate: u16,
+}
+pub struct Stdout;
+pub struct Stderr;
+
+// Apparently Windows doesn't handle large reads on stdin or writes to stdout/stderr well (see
+// #13304 for details).
+//
+// From MSDN (2011): "The storage for this buffer is allocated from a shared heap for the
+// process that is 64 KB in size. The maximum size of the buffer will depend on heap usage."
+//
+// We choose the cap at 8 KiB because libuv does the same, and it seems to be acceptable so far.
+const MAX_BUFFER_SIZE: usize = 8192;
+
+// The standard buffer size of BufReader for Stdin should be able to hold 3x more bytes than there
+// are `u16`'s in MAX_BUFFER_SIZE. This ensures the read data can always be completely decoded from
+// UTF-16 to UTF-8.
+pub const STDIN_BUF_SIZE: usize = MAX_BUFFER_SIZE / 2 * 3;
+
+pub fn get_handle(handle_id: c::DWORD) -> io::Result<c::HANDLE> {
+ let handle = unsafe { c::GetStdHandle(handle_id) };
+ if handle == c::INVALID_HANDLE_VALUE {
+ Err(io::Error::last_os_error())
+ } else if handle.is_null() {
+ Err(io::Error::from_raw_os_error(c::ERROR_INVALID_HANDLE as i32))
+ } else {
+ Ok(handle)
+ }
+}
+
+fn is_console(handle: c::HANDLE) -> bool {
+ // `GetConsoleMode` will return false (0) if this is a pipe (we don't care about the reported
+ // mode). This will only detect Windows Console, not other terminals connected to a pipe like
+ // MSYS. Which is exactly what we need, as only Windows Console needs a conversion to UTF-16.
+ let mut mode = 0;
+ unsafe { c::GetConsoleMode(handle, &mut mode) != 0 }
+}
+
+fn write(handle_id: c::DWORD, data: &[u8]) -> io::Result<usize> {
+ let handle = get_handle(handle_id)?;
+ if !is_console(handle) {
+ let handle = Handle::new(handle);
+ let ret = handle.write(data);
+ handle.into_raw(); // Don't close the handle
+ return ret;
+ }
+
+ // As the console is meant for presenting text, we assume bytes of `data` come from a string
+ // and are encoded as UTF-8, which needs to be encoded as UTF-16.
+ //
+ // If the data is not valid UTF-8 we write out as many bytes as are valid.
+ // Only when there are no valid bytes (which will happen on the next call), return an error.
+ let len = cmp::min(data.len(), MAX_BUFFER_SIZE / 2);
+ let utf8 = match str::from_utf8(&data[..len]) {
+ Ok(s) => s,
+ Err(ref e) if e.valid_up_to() == 0 => {
+ return Err(io::Error::new(io::ErrorKind::InvalidData,
+ "Windows stdio in console mode does not support writing non-UTF-8 byte sequences"))
+ },
+ Err(e) => str::from_utf8(&data[..e.valid_up_to()]).unwrap(),
+ };
+ let mut utf16 = [0u16; MAX_BUFFER_SIZE / 2];
+ let mut len_utf16 = 0;
+ for (chr, dest) in utf8.encode_utf16().zip(utf16.iter_mut()) {
+ *dest = chr;
+ len_utf16 += 1;
+ }
+ let utf16 = &utf16[..len_utf16];
+
+ let mut written = write_u16s(handle, &utf16)?;
+
+ // Figure out how many bytes of as UTF-8 were written away as UTF-16.
+ if written == utf16.len() {
+ Ok(utf8.len())
+ } else {
+ // Make sure we didn't end up writing only half of a surrogate pair (even though the chance
+ // is tiny). Because it is not possible for user code to re-slice `data` in such a way that
+ // a missing surrogate can be produced (and also because of the UTF-8 validation above),
+ // write the missing surrogate out now.
+ // Buffering it would mean we have to lie about the number of bytes written.
+ let first_char_remaining = utf16[written];
+ if first_char_remaining >= 0xDCEE && first_char_remaining <= 0xDFFF { // low surrogate
+ // We just hope this works, and give up otherwise
+ let _ = write_u16s(handle, &utf16[written..written+1]);
+ written += 1;
+ }
+ // Calculate the number of bytes of `utf8` that were actually written.
+ let mut count = 0;
+ for ch in utf16[..written].iter() {
+ count += match ch {
+ 0x0000 ..= 0x007F => 1,
+ 0x0080 ..= 0x07FF => 2,
+ 0xDCEE ..= 0xDFFF => 1, // Low surrogate. We already counted 3 bytes for the other.
+ _ => 3,
+ };
+ }
+ debug_assert!(String::from_utf16(&utf16[..written]).unwrap() == utf8[..count]);
+ Ok(count)
+ }
+}
+
+fn write_u16s(handle: c::HANDLE, data: &[u16]) -> io::Result<usize> {
+ let mut written = 0;
+ cvt(unsafe {
+ c::WriteConsoleW(handle,
+ data.as_ptr() as c::LPCVOID,
+ data.len() as u32,
+ &mut written,
+ ptr::null_mut())
+ })?;
+ Ok(written as usize)
+}
+
+impl Stdin {
+ pub fn new() -> io::Result<Stdin> {
+ Ok(Stdin { surrogate: 0 })
+ }
+}
+
+impl io::Read for Stdin {
+ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+ let handle = get_handle(c::STD_INPUT_HANDLE)?;
+ if !is_console(handle) {
+ let handle = Handle::new(handle);
+ let ret = handle.read(buf);
+ handle.into_raw(); // Don't close the handle
+ return ret;
+ }
+
+ if buf.len() == 0 {
+ return Ok(0);
+ } else if buf.len() < 4 {
+ return Err(io::Error::new(io::ErrorKind::InvalidInput,
+ "Windows stdin in console mode does not support a buffer too small to \
+ guarantee holding one arbitrary UTF-8 character (4 bytes)"))
+ }
+
+ let mut utf16_buf = [0u16; MAX_BUFFER_SIZE / 2];
+ // In the worst case, an UTF-8 string can take 3 bytes for every `u16` of an UTF-16. So
+ // we can read at most a third of `buf.len()` chars and uphold the guarantee no data gets
+ // lost.
+ let amount = cmp::min(buf.len() / 3, utf16_buf.len());
+ let read = read_u16s_fixup_surrogates(handle, &mut utf16_buf, amount, &mut self.surrogate)?;
+
+ utf16_to_utf8(&utf16_buf[..read], buf)
+ }
+}
+
+
+// We assume that if the last `u16` is an unpaired surrogate they got sliced apart by our
+// buffer size, and keep it around for the next read hoping to put them together.
+// This is a best effort, and may not work if we are not the only reader on Stdin.
+fn read_u16s_fixup_surrogates(handle: c::HANDLE,
+ buf: &mut [u16],
+ mut amount: usize,
+ surrogate: &mut u16) -> io::Result<usize>
+{
+ // Insert possibly remaining unpaired surrogate from last read.
+ let mut start = 0;
+ if *surrogate != 0 {
+ buf[0] = *surrogate;
+ *surrogate = 0;
+ start = 1;
+ if amount == 1 {
+ // Special case: `Stdin::read` guarantees we can always read at least one new `u16`
+ // and combine it with an unpaired surrogate, because the UTF-8 buffer is at least
+ // 4 bytes.
+ amount = 2;
+ }
+ }
+ let mut amount = read_u16s(handle, &mut buf[start..amount])? + start;
+
+ if amount > 0 {
+ let last_char = buf[amount - 1];
+ if last_char >= 0xD800 && last_char <= 0xDBFF { // high surrogate
+ *surrogate = last_char;
+ amount -= 1;
+ }
+ }
+ Ok(amount)
+}
+
+fn read_u16s(handle: c::HANDLE, buf: &mut [u16]) -> io::Result<usize> {
+ // Configure the `pInputControl` parameter to not only return on `\r\n` but also Ctrl-Z, the
+ // traditional DOS method to indicate end of character stream / user input (SUB).
+ // See #38274 and https://stackoverflow.com/questions/43836040/win-api-readconsole.
+ const CTRL_Z: u16 = 0x1A;
+ const CTRL_Z_MASK: c::ULONG = 1 << CTRL_Z;
+ let mut input_control = c::CONSOLE_READCONSOLE_CONTROL {
+ nLength: crate::mem::size_of::<c::CONSOLE_READCONSOLE_CONTROL>() as c::ULONG,
+ nInitialChars: 0,
+ dwCtrlWakeupMask: CTRL_Z_MASK,
+ dwControlKeyState: 0,
+ };
+
+ let mut amount = 0;
+ cvt(unsafe {
+ c::ReadConsoleW(handle,
+ buf.as_mut_ptr() as c::LPVOID,
+ buf.len() as u32,
+ &mut amount,
+ &mut input_control as c::PCONSOLE_READCONSOLE_CONTROL)
+ })?;
+
+ if amount > 0 && buf[amount as usize - 1] == CTRL_Z {
+ amount -= 1;
+ }
+ Ok(amount as usize)
+}
+
+#[allow(unused)]
+fn utf16_to_utf8(utf16: &[u16], utf8: &mut [u8]) -> io::Result<usize> {
+ let mut written = 0;
+ for chr in decode_utf16(utf16.iter().cloned()) {
+ match chr {
+ Ok(chr) => {
+ chr.encode_utf8(&mut utf8[written..]);
+ written += chr.len_utf8();
+ }
+ Err(_) => {
+ // We can't really do any better than forget all data and return an error.
+ return Err(io::Error::new(io::ErrorKind::InvalidData,
+ "Windows stdin in console mode does not support non-UTF-16 input; \
+ encountered unpaired surrogate"))
+ }
+ }
+ }
+ Ok(written)
+}
+
+impl Stdout {
+ pub fn new() -> io::Result<Stdout> {
+ Ok(Stdout)
+ }
+}
+
+impl io::Write for Stdout {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ write(c::STD_OUTPUT_HANDLE, buf)
+ }
+
+ fn flush(&mut self) -> io::Result<()> {
+ Ok(())
+ }
+}
+
+impl Stderr {
+ pub fn new() -> io::Result<Stderr> {
+ Ok(Stderr)
+ }
+}
+
+impl io::Write for Stderr {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ write(c::STD_ERROR_HANDLE, buf)
+ }
+
+ fn flush(&mut self) -> io::Result<()> {
+ Ok(())
+ }
+}
+
+pub fn is_ebadf(err: &io::Error) -> bool {
+ err.raw_os_error() == Some(c::ERROR_INVALID_HANDLE as i32)
+}
+
+pub fn panic_output() -> Option<impl io::Write> {
+ Stderr::new().ok()
+}
diff --git a/src/libstd/sys/windows/thread.rs b/src/libstd/sys/windows/thread.rs
new file mode 100644
index 0000000..1b0a811
--- /dev/null
+++ b/src/libstd/sys/windows/thread.rs
@@ -0,0 +1,92 @@
+use crate::boxed::FnBox;
+use crate::io;
+use crate::ffi::CStr;
+use crate::mem;
+use crate::ptr;
+use crate::sys::c;
+use crate::sys::handle::Handle;
+use crate::sys_common::thread::*;
+use crate::time::Duration;
+
+use libc::c_void;
+
+use super::to_u16s;
+
+pub const DEFAULT_MIN_STACK_SIZE: usize = 2 * 1024 * 1024;
+
+pub struct Thread {
+ handle: Handle
+}
+
+impl Thread {
+ // unsafe: see thread::Builder::spawn_unchecked for safety requirements
+ pub unsafe fn new(stack: usize, p: Box<dyn FnBox()>)
+ -> io::Result<Thread> {
+ let p = box p;
+
+ // FIXME On UNIX, we guard against stack sizes that are too small but
+ // that's because pthreads enforces that stacks are at least
+ // PTHREAD_STACK_MIN bytes big. Windows has no such lower limit, it's
+ // just that below a certain threshold you can't do anything useful.
+ // That threshold is application and architecture-specific, however.
+ // Round up to the next 64 kB because that's what the NT kernel does,
+ // might as well make it explicit.
+ let stack_size = (stack + 0xfffe) & (!0xfffe);
+ let ret = c::CreateThread(ptr::null_mut(), stack_size,
+ thread_start, &*p as *const _ as *mut _,
+ c::STACK_SIZE_PARAM_IS_A_RESERVATION,
+ ptr::null_mut());
+
+ return if ret as usize == 0 {
+ Err(io::Error::last_os_error())
+ } else {
+ mem::forget(p); // ownership passed to CreateThread
+ Ok(Thread { handle: Handle::new(ret) })
+ };
+
+ extern "system" fn thread_start(main: *mut c_void) -> c::DWORD {
+ unsafe { start_thread(main as *mut u8); }
+ 0
+ }
+ }
+
+ pub fn set_name(name: &CStr) {
+ if let Ok(utf8) = name.to_str() {
+ if let Ok(utf16) = to_u16s(utf8) {
+ unsafe { c::SetThreadDescription(c::GetCurrentThread(), utf16.as_ptr()); };
+ };
+ };
+ }
+
+ pub fn join(self) {
+ let rc = unsafe { c::WaitForSingleObject(self.handle.raw(), c::INFINITE) };
+ if rc == c::WAIT_FAILED {
+ panic!("failed to join on thread: {}",
+ io::Error::last_os_error());
+ }
+ }
+
+ pub fn yield_now() {
+ // This function will return 0 if there are no other threads to execute,
+ // but this also means that the yield was useless so this isn't really a
+ // case that needs to be worried about.
+ unsafe { c::SwitchToThread(); }
+ }
+
+ pub fn sleep(dur: Duration) {
+ unsafe {
+ c::Sleep(super::dur2timeout(dur))
+ }
+ }
+
+ pub fn handle(&self) -> &Handle { &self.handle }
+
+ pub fn into_handle(self) -> Handle { self.handle }
+}
+
+#[cfg_attr(test, allow(dead_code))]
+pub mod guard {
+ pub type Guard = !;
+ pub unsafe fn current() -> Option<Guard> { None }
+ pub unsafe fn init() -> Option<Guard> { None }
+}
diff --git a/src/libstd/sys/windows/thread_local.rs b/src/libstd/sys/windows/thread_local.rs
new file mode 100644
index 0000000..4c9734f
--- /dev/null
+++ b/src/libstd/sys/windows/thread_local.rs
@@ -0,0 +1,241 @@
+use crate::mem;
+use crate::ptr;
+use crate::sync::atomic::AtomicPtr;
+use crate::sync::atomic::Ordering::SeqCst;
+use crate::sys::c;
+
+pub type Key = c::DWORD;
+pub type Dtor = unsafe extern fn(*mut u8);
+
+// Turns out, like pretty much everything, Windows is pretty close the
+// functionality that Unix provides, but slightly different! In the case of
+// TLS, Windows does not provide an API to provide a destructor for a TLS
+// variable. This ends up being pretty crucial to this implementation, so we
+// need a way around this.
+//
+// The solution here ended up being a little obscure, but fear not, the
+// internet has informed me [1][2] that this solution is not unique (no way
+// I could have thought of it as well!). The key idea is to insert some hook
+// somewhere to run arbitrary code on thread termination. With this in place
+// we'll be able to run anything we like, including all TLS destructors!
+//
+// To accomplish this feat, we perform a number of threads, all contained
+// within this module:
+//
+// * All TLS destructors are tracked by *us*, not the windows runtime. This
+// means that we have a global list of destructors for each TLS key that
+// we know about.
+// * When a thread exits, we run over the entire list and run dtors for all
+// non-null keys. This attempts to match Unix semantics in this regard.
+//
+// This ends up having the overhead of using a global list, having some
+// locks here and there, and in general just adding some more code bloat. We
+// attempt to optimize runtime by forgetting keys that don't have
+// destructors, but this only gets us so far.
+//
+// For more details and nitty-gritty, see the code sections below!
+//
+// [1]: http://www.codeproject.com/Articles/8113/Thread-Local-Storage-The-C-Way
+// [2]: https://github.com/ChromiumWebApps/chromium/blob/master/base
+// /threading/thread_local_storage_win.cc#L42
+
+// -------------------------------------------------------------------------
+// Native bindings
+//
+// This section is just raw bindings to the native functions that Windows
+// provides, There's a few extra calls to deal with destructors.
+
+#[inline]
+pub unsafe fn create(dtor: Option<Dtor>) -> Key {
+ let key = c::TlsAlloc();
+ assert!(key != c::TLS_OUT_OF_INDEXES);
+ if let Some(f) = dtor {
+ register_dtor(key, f);
+ }
+ return key;
+}
+
+#[inline]
+pub unsafe fn set(key: Key, value: *mut u8) {
+ let r = c::TlsSetValue(key, value as c::LPVOID);
+ debug_assert!(r != 0);
+}
+
+#[inline]
+pub unsafe fn get(key: Key) -> *mut u8 {
+ c::TlsGetValue(key) as *mut u8
+}
+
+#[inline]
+pub unsafe fn destroy(_key: Key) {
+ rtabort!("can't destroy tls keys on windows")
+}
+
+#[inline]
+pub fn requires_synchronized_create() -> bool {
+ true
+}
+
+// -------------------------------------------------------------------------
+// Dtor registration
+//
+// Windows has no native support for running destructors so we manage our own
+// list of destructors to keep track of how to destroy keys. We then install a
+// callback later to get invoked whenever a thread exits, running all
+// appropriate destructors.
+//
+// Currently unregistration from this list is not supported. A destructor can be
+// registered but cannot be unregistered. There's various simplifying reasons
+// for doing this, the big ones being:
+//
+// 1. Currently we don't even support deallocating TLS keys, so normal operation
+// doesn't need to deallocate a destructor.
+// 2. There is no point in time where we know we can unregister a destructor
+// because it could always be getting run by some remote thread.
+//
+// Typically processes have a statically known set of TLS keys which is pretty
+// small, and we'd want to keep this memory alive for the whole process anyway
+// really.
+//
+// Perhaps one day we can fold the `Box` here into a static allocation,
+// expanding the `StaticKey` structure to contain not only a slot for the TLS
+// key but also a slot for the destructor queue on windows. An optimization for
+// another day!
+
+static DTORS: AtomicPtr<Node> = AtomicPtr::new(ptr::null_mut());
+
+struct Node {
+ dtor: Dtor,
+ key: Key,
+ next: *mut Node,
+}
+
+unsafe fn register_dtor(key: Key, dtor: Dtor) {
+ let mut node = Box::new(Node {
+ key,
+ dtor,
+ next: ptr::null_mut(),
+ });
+
+ let mut head = DTORS.load(SeqCst);
+ loop {
+ node.next = head;
+ match DTORS.compare_exchange(head, &mut *node, SeqCst, SeqCst) {
+ Ok(_) => return mem::forget(node),
+ Err(cur) => head = cur,
+ }
+ }
+}
+
+// -------------------------------------------------------------------------
+// Where the Magic (TM) Happens
+//
+// If you're looking at this code, and wondering "what is this doing?",
+// you're not alone! I'll try to break this down step by step:
+//
+// # What's up with CRT$XLB?
+//
+// For anything about TLS destructors to work on Windows, we have to be able
+// to run *something* when a thread exits. To do so, we place a very special
+// static in a very special location. If this is encoded in just the right
+// way, the kernel's loader is apparently nice enough to run some function
+// of ours whenever a thread exits! How nice of the kernel!
+//
+// Lots of detailed information can be found in source [1] above, but the
+// gist of it is that this is leveraging a feature of Microsoft's PE format
+// (executable format) which is not actually used by any compilers today.
+// This apparently translates to any callbacks in the ".CRT$XLB" section
+// being run on certain events.
+//
+// So after all that, we use the compiler's #[link_section] feature to place
+// a callback pointer into the magic section so it ends up being called.
+//
+// # What's up with this callback?
+//
+// The callback specified receives a number of parameters from... someone!
+// (the kernel? the runtime? I'm not quite sure!) There are a few events that
+// this gets invoked for, but we're currently only interested on when a
+// thread or a process "detaches" (exits). The process part happens for the
+// last thread and the thread part happens for any normal thread.
+//
+// # Ok, what's up with running all these destructors?
+//
+// This will likely need to be improved over time, but this function
+// attempts a "poor man's" destructor callback system. Once we've got a list
+// of what to run, we iterate over all keys, check their values, and then run
+// destructors if the values turn out to be non null (setting them to null just
+// beforehand). We do this a few times in a loop to basically match Unix
+// semantics. If we don't reach a fixed point after a short while then we just
+// inevitably leak something most likely.
+//
+// # The article mentions weird stuff about "/INCLUDE"?
+//
+// It sure does! Specifically we're talking about this quote:
+//
+// The Microsoft run-time library facilitates this process by defining a
+// memory image of the TLS Directory and giving it the special name
+// “__tls_used” (Intel x86 platforms) or “_tls_used” (other platforms). The
+// linker looks for this memory image and uses the data there to create the
+// TLS Directory. Other compilers that support TLS and work with the
+// Microsoft linker must use this same technique.
+//
+// Basically what this means is that if we want support for our TLS
+// destructors/our hook being called then we need to make sure the linker does
+// not omit this symbol. Otherwise it will omit it and our callback won't be
+// wired up.
+//
+// We don't actually use the `/INCLUDE` linker flag here like the article
+// mentions because the Rust compiler doesn't propagate linker flags, but
+// instead we use a shim function which performs a volatile 1-byte load from
+// the address of the symbol to ensure it sticks around.
+
+#[link_section = ".CRT$XLB"]
+#[allow(dead_code, unused_variables)]
+#[used] // we don't want LLVM eliminating this symbol for any reason, and
+ // when the symbol makes it to the linker the linker will take over
+pub static p_thread_callback: unsafe extern "system" fn(c::LPVOID, c::DWORD,
+ c::LPVOID) =
+ on_tls_callback;
+
+#[allow(dead_code, unused_variables)]
+unsafe extern "system" fn on_tls_callback(h: c::LPVOID,
+ dwReason: c::DWORD,
+ pv: c::LPVOID) {
+ if dwReason == c::DLL_THREAD_DETACH || dwReason == c::DLL_PROCESS_DETACH {
+ run_dtors();
+ }
+
+ // See comments above for what this is doing. Note that we don't need this
+ // trickery on GNU windows, just on MSVC.
+ reference_tls_used();
+ #[cfg(target_env = "msvc")]
+ unsafe fn reference_tls_used() {
+ extern { static _tls_used: u8; }
+ crate::intrinsics::volatile_load(&_tls_used);
+ }
+ #[cfg(not(target_env = "msvc"))]
+ unsafe fn reference_tls_used() {}
+}
+
+#[allow(dead_code)] // actually called above
+unsafe fn run_dtors() {
+ let mut any_run = true;
+ for _ in 0..5 {
+ if !any_run {
+ break
+ }
+ any_run = false;
+ let mut cur = DTORS.load(SeqCst);
+ while !cur.is_null() {
+ let ptr = c::TlsGetValue((*cur).key);
+
+ if !ptr.is_null() {
+ c::TlsSetValue((*cur).key, ptr::null_mut());
+ ((*cur).dtor)(ptr as *mut _);
+ any_run = true;
+ }
+
+ cur = (*cur).next;
+ }
+ }
+}
diff --git a/src/libstd/sys/windows/time.rs b/src/libstd/sys/windows/time.rs
new file mode 100644
index 0000000..e0f0e3a
--- /dev/null
+++ b/src/libstd/sys/windows/time.rs
@@ -0,0 +1,242 @@
+use crate::cmp::Ordering;
+use crate::fmt;
+use crate::mem;
+use crate::sys::c;
+use crate::time::Duration;
+use crate::convert::TryInto;
+
+use core::hash::{Hash, Hasher};
+
+const NANOS_PER_SEC: u64 = 1_000_000_000;
+const INTERVALS_PER_SEC: u64 = NANOS_PER_SEC / 100;
+
+#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Hash)]
+pub struct Instant {
+ // This duration is relative to an arbitrary microsecond epoch
+ // from the winapi QueryPerformanceCounter function.
+ t: Duration,
+}
+
+#[derive(Copy, Clone)]
+pub struct SystemTime {
+ t: c::FILETIME,
+}
+
+const INTERVALS_TO_UNIX_EPOCH: u64 = 11_644_473_600 * INTERVALS_PER_SEC;
+
+pub const UNIX_EPOCH: SystemTime = SystemTime {
+ t: c::FILETIME {
+ dwLowDateTime: INTERVALS_TO_UNIX_EPOCH as u32,
+ dwHighDateTime: (INTERVALS_TO_UNIX_EPOCH >> 32) as u32,
+ },
+};
+
+impl Instant {
+ pub fn now() -> Instant {
+ // High precision timing on windows operates in "Performance Counter"
+ // units, as returned by the WINAPI QueryPerformanceCounter function.
+ // These relate to seconds by a factor of QueryPerformanceFrequency.
+ // In order to keep unit conversions out of normal interval math, we
+ // measure in QPC units and immediately convert to nanoseconds.
+ perf_counter::PerformanceCounterInstant::now().into()
+ }
+
+ pub fn actually_monotonic() -> bool {
+ false
+ }
+
+ pub const fn zero() -> Instant {
+ Instant { t: Duration::from_secs(0) }
+ }
+
+ pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
+ // On windows there's a threshold below which we consider two timestamps
+ // equivalent due to measurement error. For more details + doc link,
+ // check the docs on epsilon.
+ let epsilon =
+ perf_counter::PerformanceCounterInstant::epsilon();
+ if other.t > self.t && other.t - self.t <= epsilon {
+ Some(Duration::new(0, 0))
+ } else {
+ self.t.checked_sub(other.t)
+ }
+ }
+
+ pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
+ Some(Instant {
+ t: self.t.checked_add(*other)?
+ })
+ }
+
+ pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
+ Some(Instant {
+ t: self.t.checked_sub(*other)?
+ })
+ }
+}
+
+impl SystemTime {
+ pub fn now() -> SystemTime {
+ unsafe {
+ let mut t: SystemTime = mem::zeroed();
+ c::GetSystemTimeAsFileTime(&mut t.t);
+ return t
+ }
+ }
+
+ fn from_intervals(intervals: i64) -> SystemTime {
+ SystemTime {
+ t: c::FILETIME {
+ dwLowDateTime: intervals as c::DWORD,
+ dwHighDateTime: (intervals >> 32) as c::DWORD,
+ }
+ }
+ }
+
+ fn intervals(&self) -> i64 {
+ (self.t.dwLowDateTime as i64) | ((self.t.dwHighDateTime as i64) << 32)
+ }
+
+ pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
+ let me = self.intervals();
+ let other = other.intervals();
+ if me >= other {
+ Ok(intervals2dur((me - other) as u64))
+ } else {
+ Err(intervals2dur((other - me) as u64))
+ }
+ }
+
+ pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
+ let intervals = self.intervals().checked_add(checked_dur2intervals(other)?)?;
+ Some(SystemTime::from_intervals(intervals))
+ }
+
+ pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
+ let intervals = self.intervals().checked_sub(checked_dur2intervals(other)?)?;
+ Some(SystemTime::from_intervals(intervals))
+ }
+}
+
+impl PartialEq for SystemTime {
+ fn eq(&self, other: &SystemTime) -> bool {
+ self.intervals() == other.intervals()
+ }
+}
+
+impl Eq for SystemTime {}
+
+impl PartialOrd for SystemTime {
+ fn partial_cmp(&self, other: &SystemTime) -> Option<Ordering> {
+ Some(self.cmp(other))
+ }
+}
+
+impl Ord for SystemTime {
+ fn cmp(&self, other: &SystemTime) -> Ordering {
+ self.intervals().cmp(&other.intervals())
+ }
+}
+
+impl fmt::Debug for SystemTime {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("SystemTime")
+ .field("intervals", &self.intervals())
+ .finish()
+ }
+}
+
+impl From<c::FILETIME> for SystemTime {
+ fn from(t: c::FILETIME) -> SystemTime {
+ SystemTime { t }
+ }
+}
+
+impl Hash for SystemTime {
+ fn hash<H : Hasher>(&self, state: &mut H) {
+ self.intervals().hash(state)
+ }
+}
+
+fn checked_dur2intervals(dur: &Duration) -> Option<i64> {
+ dur.as_secs()
+ .checked_mul(INTERVALS_PER_SEC)?
+ .checked_add(dur.subsec_nanos() as u64 / 100)?
+ .try_into()
+ .ok()
+}
+
+fn intervals2dur(intervals: u64) -> Duration {
+ Duration::new(intervals / INTERVALS_PER_SEC,
+ ((intervals % INTERVALS_PER_SEC) * 100) as u32)
+}
+
+mod perf_counter {
+ use super::{NANOS_PER_SEC};
+ use crate::sync::atomic::{AtomicUsize, Ordering::SeqCst};
+ use crate::sys_common::mul_div_u64;
+ use crate::sys::c;
+ use crate::sys::cvt;
+ use crate::time::Duration;
+
+ pub struct PerformanceCounterInstant {
+ ts: c::LARGE_INTEGER
+ }
+ impl PerformanceCounterInstant {
+ pub fn now() -> Self {
+ Self {
+ ts: query()
+ }
+ }
+
+ // Per microsoft docs, the margin of error for cross-thread time comparisons
+ // using QueryPerformanceCounter is 1 "tick" -- defined as 1/frequency().
+ // Reference: https://docs.microsoft.com/en-us/windows/desktop/SysInfo
+ // /acquiring-high-resolution-time-stamps
+ pub fn epsilon() -> Duration {
+ let epsilon = NANOS_PER_SEC / (frequency() as u64);
+ Duration::from_nanos(epsilon)
+ }
+ }
+ impl From<PerformanceCounterInstant> for super::Instant {
+ fn from(other: PerformanceCounterInstant) -> Self {
+ let freq = frequency() as u64;
+ let instant_nsec = mul_div_u64(other.ts as u64, NANOS_PER_SEC, freq);
+ Self {
+ t: Duration::from_nanos(instant_nsec)
+ }
+ }
+ }
+
+ fn frequency() -> c::LARGE_INTEGER {
+ static mut FREQUENCY: c::LARGE_INTEGER = 0;
+ static STATE: AtomicUsize = AtomicUsize::new(0);
+
+ unsafe {
+ // If a previous thread has filled in this global state, use that.
+ if STATE.load(SeqCst) == 2 {
+ return FREQUENCY;
+ }
+
+ // ... otherwise learn for ourselves ...
+ let mut frequency = 0;
+ cvt(c::QueryPerformanceFrequency(&mut frequency)).unwrap();
+
+ // ... and attempt to be the one thread that stores it globally for
+ // all other threads
+ if STATE.compare_exchange(0, 1, SeqCst, SeqCst).is_ok() {
+ FREQUENCY = frequency;
+ STATE.store(2, SeqCst);
+ }
+ return frequency;
+ }
+ }
+
+ fn query() -> c::LARGE_INTEGER {
+ let mut qpc_value: c::LARGE_INTEGER = 0;
+ cvt(unsafe {
+ c::QueryPerformanceCounter(&mut qpc_value)
+ }).unwrap();
+ qpc_value
+ }
+}
diff --git a/src/libstd/sys_common/alloc.rs b/src/libstd/sys_common/alloc.rs
new file mode 100644
index 0000000..978a70b
--- /dev/null
+++ b/src/libstd/sys_common/alloc.rs
@@ -0,0 +1,40 @@
+#![allow(dead_code)]
+
+use crate::alloc::{GlobalAlloc, Layout, System};
+use crate::cmp;
+use crate::ptr;
+
+// The minimum alignment guaranteed by the architecture. This value is used to
+// add fast paths for low alignment values.
+#[cfg(all(any(target_arch = "x86",
+ target_arch = "arm",
+ target_arch = "mips",
+ target_arch = "powerpc",
+ target_arch = "powerpc64",
+ target_arch = "asmjs",
+ target_arch = "wasm32")))]
+pub const MIN_ALIGN: usize = 8;
+#[cfg(all(any(target_arch = "x86_64",
+ target_arch = "aarch64",
+ target_arch = "mips64",
+ target_arch = "s390x",
+ target_arch = "sparc64")))]
+pub const MIN_ALIGN: usize = 16;
+
+pub unsafe fn realloc_fallback(
+ alloc: &System,
+ ptr: *mut u8,
+ old_layout: Layout,
+ new_size: usize,
+) -> *mut u8 {
+ // Docs for GlobalAlloc::realloc require this to be valid:
+ let new_layout = Layout::from_size_align_unchecked(new_size, old_layout.align());
+
+ let new_ptr = GlobalAlloc::alloc(alloc, new_layout);
+ if !new_ptr.is_null() {
+ let size = cmp::min(old_layout.size(), new_size);
+ ptr::copy_nonoverlapping(ptr, new_ptr, size);
+ GlobalAlloc::dealloc(alloc, ptr, old_layout);
+ }
+ new_ptr
+}
diff --git a/src/libstd/sys_common/at_exit_imp.rs b/src/libstd/sys_common/at_exit_imp.rs
new file mode 100644
index 0000000..1181b86
--- /dev/null
+++ b/src/libstd/sys_common/at_exit_imp.rs
@@ -0,0 +1,76 @@
+//! Implementation of running at_exit routines
+//!
+//! Documentation can be found on the `rt::at_exit` function.
+
+use crate::boxed::FnBox;
+use crate::ptr;
+use crate::mem;
+use crate::sys_common::mutex::Mutex;
+
+type Queue = Vec<Box<dyn FnBox()>>;
+
+// NB these are specifically not types from `std::sync` as they currently rely
+// on poisoning and this module needs to operate at a lower level than requiring
+// the thread infrastructure to be in place (useful on the borders of
+// initialization/destruction).
+// We never call `LOCK.init()`, so it is UB to attempt to
+// acquire this mutex reentrantly!
+static LOCK: Mutex = Mutex::new();
+static mut QUEUE: *mut Queue = ptr::null_mut();
+
+const DONE: *mut Queue = 1_usize as *mut _;
+
+// The maximum number of times the cleanup routines will be run. While running
+// the at_exit closures new ones may be registered, and this count is the number
+// of times the new closures will be allowed to register successfully. After
+// this number of iterations all new registrations will return `false`.
+const ITERS: usize = 10;
+
+unsafe fn init() -> bool {
+ if QUEUE.is_null() {
+ let state: Box<Queue> = box Vec::new();
+ QUEUE = Box::into_raw(state);
+ } else if QUEUE == DONE {
+ // can't re-init after a cleanup
+ return false
+ }
+
+ true
+}
+
+pub fn cleanup() {
+ for i in 1..=ITERS {
+ unsafe {
+ let queue = {
+ let _guard = LOCK.lock();
+ mem::replace(&mut QUEUE, if i == ITERS { DONE } else { ptr::null_mut() })
+ };
+
+ // make sure we're not recursively cleaning up
+ assert!(queue != DONE);
+
+ // If we never called init, not need to cleanup!
+ if !queue.is_null() {
+ let queue: Box<Queue> = Box::from_raw(queue);
+ for to_run in *queue {
+ // We are not holding any lock, so reentrancy is fine.
+ to_run();
+ }
+ }
+ }
+ }
+}
+
+pub fn push(f: Box<dyn FnBox()>) -> bool {
+ unsafe {
+ let _guard = LOCK.lock();
+ if init() {
+ // We are just moving `f` around, not calling it.
+ // There is no possibility of reentrancy here.
+ (*QUEUE).push(f);
+ true
+ } else {
+ false
+ }
+ }
+}
diff --git a/src/libstd/sys_common/backtrace.rs b/src/libstd/sys_common/backtrace.rs
new file mode 100644
index 0000000..1a80908
--- /dev/null
+++ b/src/libstd/sys_common/backtrace.rs
@@ -0,0 +1,244 @@
+/// Common code for printing the backtrace in the same way across the different
+/// supported platforms.
+
+use crate::env;
+use crate::io::prelude::*;
+use crate::io;
+use crate::path::{self, Path};
+use crate::ptr;
+use crate::str;
+use crate::sync::atomic::{self, Ordering};
+use crate::sys::mutex::Mutex;
+
+use rustc_demangle::demangle;
+
+pub use crate::sys::backtrace::{
+ unwind_backtrace,
+ resolve_symname,
+ foreach_symbol_fileline,
+ BacktraceContext
+};
+
+#[cfg(target_pointer_width = "64")]
+pub const HEX_WIDTH: usize = 18;
+
+#[cfg(target_pointer_width = "32")]
+pub const HEX_WIDTH: usize = 10;
+
+/// Represents an item in the backtrace list. See `unwind_backtrace` for how
+/// it is created.
+#[derive(Debug, Copy, Clone)]
+pub struct Frame {
+ /// Exact address of the call that failed.
+ pub exact_position: *const u8,
+ /// Address of the enclosing function.
+ pub symbol_addr: *const u8,
+ /// Which inlined function is this frame referring to
+ pub inline_context: u32,
+}
+
+/// Max number of frames to print.
+const MAX_NB_FRAMES: usize = 100;
+
+/// Prints the current backtrace.
+pub fn print(w: &mut dyn Write, format: PrintFormat) -> io::Result<()> {
+ static LOCK: Mutex = Mutex::new();
+
+ // There are issues currently linking libbacktrace into tests, and in
+ // general during libstd's own unit tests we're not testing this path. In
+ // test mode immediately return here to optimize away any references to the
+ // libbacktrace symbols
+ if cfg!(test) {
+ return Ok(())
+ }
+
+ // Use a lock to prevent mixed output in multithreading context.
+ // Some platforms also requires it, like `SymFromAddr` on Windows.
+ unsafe {
+ LOCK.lock();
+ let res = _print(w, format);
+ LOCK.unlock();
+ res
+ }
+}
+
+fn _print(w: &mut dyn Write, format: PrintFormat) -> io::Result<()> {
+ let mut frames = [Frame {
+ exact_position: ptr::null(),
+ symbol_addr: ptr::null(),
+ inline_context: 0,
+ }; MAX_NB_FRAMES];
+ let (nb_frames, context) = unwind_backtrace(&mut frames)?;
+ let (skipped_before, skipped_after) =
+ filter_frames(&frames[..nb_frames], format, &context);
+ if skipped_before + skipped_after > 0 {
+ writeln!(w, "note: Some details are omitted, \
+ run with `RUST_BACKTRACE=full` for a verbose backtrace.")?;
+ }
+ writeln!(w, "stack backtrace:")?;
+
+ let filtered_frames = &frames[..nb_frames - skipped_after];
+ for (index, frame) in filtered_frames.iter().skip(skipped_before).enumerate() {
+ resolve_symname(*frame, |symname| {
+ output(w, index, *frame, symname, format)
+ }, &context)?;
+ let has_more_filenames = foreach_symbol_fileline(*frame, |file, line| {
+ output_fileline(w, file, line, format)
+ }, &context)?;
+ if has_more_filenames {
+ w.write_all(b" <... and possibly more>")?;
+ }
+ }
+
+ Ok(())
+}
+
+/// Returns a number of frames to remove at the beginning and at the end of the
+/// backtrace, according to the backtrace format.
+fn filter_frames(frames: &[Frame],
+ format: PrintFormat,
+ context: &BacktraceContext) -> (usize, usize)
+{
+ if format == PrintFormat::Full {
+ return (0, 0);
+ }
+
+ let skipped_before = 0;
+
+ let skipped_after = frames.len() - frames.iter().position(|frame| {
+ let mut is_marker = false;
+ let _ = resolve_symname(*frame, |symname| {
+ if let Some(mangled_symbol_name) = symname {
+ // Use grep to find the concerned functions
+ if mangled_symbol_name.contains("__rust_begin_short_backtrace") {
+ is_marker = true;
+ }
+ }
+ Ok(())
+ }, context);
+ is_marker
+ }).unwrap_or(frames.len());
+
+ if skipped_before + skipped_after >= frames.len() {
+ // Avoid showing completely empty backtraces
+ return (0, 0);
+ }
+
+ (skipped_before, skipped_after)
+}
+
+
+/// Fixed frame used to clean the backtrace with `RUST_BACKTRACE=1`.
+#[inline(never)]
+pub fn __rust_begin_short_backtrace<F, T>(f: F) -> T
+ where F: FnOnce() -> T, F: Send, T: Send
+{
+ f()
+}
+
+/// Controls how the backtrace should be formatted.
+#[derive(Debug, Copy, Clone, Eq, PartialEq)]
+pub enum PrintFormat {
+ /// Show only relevant data from the backtrace.
+ Short = 2,
+ /// Show all the frames with absolute path for files.
+ Full = 3,
+}
+
+// For now logging is turned off by default, and this function checks to see
+// whether the magical environment variable is present to see if it's turned on.
+pub fn log_enabled() -> Option<PrintFormat> {
+ static ENABLED: atomic::AtomicIsize = atomic::AtomicIsize::new(0);
+ match ENABLED.load(Ordering::SeqCst) {
+ 0 => {}
+ 1 => return None,
+ 2 => return Some(PrintFormat::Short),
+ _ => return Some(PrintFormat::Full),
+ }
+
+ let val = env::var_os("RUST_BACKTRACE").and_then(|x|
+ if &x == "0" {
+ None
+ } else if &x == "full" {
+ Some(PrintFormat::Full)
+ } else {
+ Some(PrintFormat::Short)
+ }
+ );
+ ENABLED.store(match val {
+ Some(v) => v as isize,
+ None => 1,
+ }, Ordering::SeqCst);
+ val
+}
+
+/// Prints the symbol of the backtrace frame.
+///
+/// These output functions should now be used everywhere to ensure consistency.
+/// You may want to also use `output_fileline`.
+fn output(w: &mut dyn Write, idx: usize, frame: Frame,
+ s: Option<&str>, format: PrintFormat) -> io::Result<()> {
+ // Remove the `17: 0x0 - <unknown>` line.
+ if format == PrintFormat::Short && frame.exact_position == ptr::null() {
+ return Ok(());
+ }
+ match format {
+ PrintFormat::Full => write!(w,
+ " {:2}: {:2$?} - ",
+ idx,
+ frame.exact_position,
+ HEX_WIDTH)?,
+ PrintFormat::Short => write!(w, " {:2}: ", idx)?,
+ }
+ match s {
+ Some(string) => {
+ let symbol = demangle(string);
+ match format {
+ PrintFormat::Full => write!(w, "{}", symbol)?,
+ // strip the trailing hash if short mode
+ PrintFormat::Short => write!(w, "{:#}", symbol)?,
+ }
+ }
+ None => w.write_all(b"<unknown>")?,
+ }
+ w.write_all(b"\n")
+}
+
+/// Prints the filename and line number of the backtrace frame.
+///
+/// See also `output`.
+#[allow(dead_code)]
+fn output_fileline(w: &mut dyn Write,
+ file: &[u8],
+ line: u32,
+ format: PrintFormat) -> io::Result<()> {
+ // prior line: " ##: {:2$} - func"
+ w.write_all(b"")?;
+ match format {
+ PrintFormat::Full => write!(w,
+ " {:1$}",
+ "",
+ HEX_WIDTH)?,
+ PrintFormat::Short => write!(w, " ")?,
+ }
+
+ let file = str::from_utf8(file).unwrap_or("<unknown>");
+ let file_path = Path::new(file);
+ let mut already_printed = false;
+ if format == PrintFormat::Short && file_path.is_absolute() {
+ if let Ok(cwd) = env::current_dir() {
+ if let Ok(stripped) = file_path.strip_prefix(&cwd) {
+ if let Some(s) = stripped.to_str() {
+ write!(w, " at .{}{}:{}", path::MAIN_SEPARATOR, s, line)?;
+ already_printed = true;
+ }
+ }
+ }
+ }
+ if !already_printed {
+ write!(w, " at {}:{}", file, line)?;
+ }
+
+ w.write_all(b"\n")
+}
+
diff --git a/src/libstd/sys_common/bytestring.rs b/src/libstd/sys_common/bytestring.rs
new file mode 100644
index 0000000..429ecf6
--- /dev/null
+++ b/src/libstd/sys_common/bytestring.rs
@@ -0,0 +1,46 @@
+#![allow(dead_code)]
+
+use crate::fmt::{Formatter, Result, Write};
+use core::str::lossy::{Utf8Lossy, Utf8LossyChunk};
+
+pub fn debug_fmt_bytestring(slice: &[u8], f: &mut Formatter<'_>) -> Result {
+ // Writes out a valid unicode string with the correct escape sequences
+ fn write_str_escaped(f: &mut Formatter<'_>, s: &str) -> Result {
+ for c in s.chars().flat_map(|c| c.escape_debug()) {
+ f.write_char(c)?
+ }
+ Ok(())
+ }
+
+ f.write_str("\"")?;
+ for Utf8LossyChunk { valid, broken } in Utf8Lossy::from_bytes(slice).chunks() {
+ write_str_escaped(f, valid)?;
+ for b in broken {
+ write!(f, "\\x{:02X}", b)?;
+ }
+ }
+ f.write_str("\"")
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use crate::fmt::{Formatter, Result, Debug};
+
+ #[test]
+ fn smoke() {
+ struct Helper<'a>(&'a [u8]);
+
+ impl Debug for Helper<'_> {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result {
+ debug_fmt_bytestring(self.0, f)
+ }
+ }
+
+ let input = b"\xF0hello,\tworld";
+ let expected = r#""\xF0hello,\tworld""#;
+ let output = format!("{:?}", Helper(input));
+
+ assert!(output == expected);
+ }
+}
diff --git a/src/libstd/sys_common/condvar.rs b/src/libstd/sys_common/condvar.rs
new file mode 100644
index 0000000..fc59c83
--- /dev/null
+++ b/src/libstd/sys_common/condvar.rs
@@ -0,0 +1,60 @@
+use crate::time::Duration;
+use crate::sys_common::mutex::{self, Mutex};
+use crate::sys::condvar as imp;
+
+/// An OS-based condition variable.
+///
+/// This structure is the lowest layer possible on top of the OS-provided
+/// condition variables. It is consequently entirely unsafe to use. It is
+/// recommended to use the safer types at the top level of this crate instead of
+/// this type.
+pub struct Condvar(imp::Condvar);
+
+impl Condvar {
+ /// Creates a new condition variable for use.
+ ///
+ /// Behavior is undefined if the condition variable is moved after it is
+ /// first used with any of the functions below.
+ pub const fn new() -> Condvar { Condvar(imp::Condvar::new()) }
+
+ /// Prepares the condition variable for use.
+ ///
+ /// This should be called once the condition variable is at a stable memory
+ /// address.
+ #[inline]
+ pub unsafe fn init(&mut self) { self.0.init() }
+
+ /// Signals one waiter on this condition variable to wake up.
+ #[inline]
+ pub unsafe fn notify_one(&self) { self.0.notify_one() }
+
+ /// Awakens all current waiters on this condition variable.
+ #[inline]
+ pub unsafe fn notify_all(&self) { self.0.notify_all() }
+
+ /// Waits for a signal on the specified mutex.
+ ///
+ /// Behavior is undefined if the mutex is not locked by the current thread.
+ /// Behavior is also undefined if more than one mutex is used concurrently
+ /// on this condition variable.
+ #[inline]
+ pub unsafe fn wait(&self, mutex: &Mutex) { self.0.wait(mutex::raw(mutex)) }
+
+ /// Waits for a signal on the specified mutex with a timeout duration
+ /// specified by `dur` (a relative time into the future).
+ ///
+ /// Behavior is undefined if the mutex is not locked by the current thread.
+ /// Behavior is also undefined if more than one mutex is used concurrently
+ /// on this condition variable.
+ #[inline]
+ pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
+ self.0.wait_timeout(mutex::raw(mutex), dur)
+ }
+
+ /// Deallocates all resources associated with this condition variable.
+ ///
+ /// Behavior is undefined if there are current or will be future users of
+ /// this condition variable.
+ #[inline]
+ pub unsafe fn destroy(&self) { self.0.destroy() }
+}
diff --git a/src/libstd/sys_common/fs.rs b/src/libstd/sys_common/fs.rs
new file mode 100644
index 0000000..7152fcd
--- /dev/null
+++ b/src/libstd/sys_common/fs.rs
@@ -0,0 +1,41 @@
+#![allow(dead_code)] // not used on all platforms
+
+use crate::path::Path;
+use crate::fs;
+use crate::io::{self, Error, ErrorKind};
+
+pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
+ if !from.is_file() {
+ return Err(Error::new(ErrorKind::InvalidInput,
+ "the source path is not an existing regular file"))
+ }
+
+ let mut reader = fs::File::open(from)?;
+ let mut writer = fs::File::create(to)?;
+ let perm = reader.metadata()?.permissions();
+
+ let ret = io::copy(&mut reader, &mut writer)?;
+ fs::set_permissions(to, perm)?;
+ Ok(ret)
+}
+
+pub fn remove_dir_all(path: &Path) -> io::Result<()> {
+ let filetype = fs::symlink_metadata(path)?.file_type();
+ if filetype.is_symlink() {
+ fs::remove_file(path)
+ } else {
+ remove_dir_all_recursive(path)
+ }
+}
+
+fn remove_dir_all_recursive(path: &Path) -> io::Result<()> {
+ for child in fs::read_dir(path)? {
+ let child = child?;
+ if child.file_type()?.is_dir() {
+ remove_dir_all_recursive(&child.path())?;
+ } else {
+ fs::remove_file(&child.path())?;
+ }
+ }
+ fs::remove_dir(path)
+}
diff --git a/src/libstd/sys_common/gnu/libbacktrace.rs b/src/libstd/sys_common/gnu/libbacktrace.rs
new file mode 100644
index 0000000..6cd0502
--- /dev/null
+++ b/src/libstd/sys_common/gnu/libbacktrace.rs
@@ -0,0 +1,175 @@
+use backtrace_sys::backtrace_state;
+
+use crate::ffi::CStr;
+use crate::io;
+use crate::mem;
+use crate::ptr;
+use crate::sys::backtrace::BacktraceContext;
+use crate::sys_common::backtrace::Frame;
+
+pub fn foreach_symbol_fileline<F>(frame: Frame,
+ mut f: F,
+ _: &BacktraceContext) -> io::Result<bool>
+where F: FnMut(&[u8], u32) -> io::Result<()>
+{
+ // pcinfo may return an arbitrary number of file:line pairs,
+ // in the order of stack trace (i.e., inlined calls first).
+ // in order to avoid allocation, we stack-allocate a fixed size of entries.
+ const FILELINE_SIZE: usize = 32;
+ let mut fileline_buf = [(ptr::null(), !0); FILELINE_SIZE];
+ let ret;
+ let fileline_count = {
+ let state = unsafe { init_state() };
+ if state.is_null() {
+ return Err(io::Error::new(
+ io::ErrorKind::Other,
+ "failed to allocate libbacktrace state")
+ )
+ }
+ let mut fileline_win: &mut [FileLine] = &mut fileline_buf;
+ let fileline_addr = &mut fileline_win as *mut &mut [FileLine];
+ ret = unsafe {
+ backtrace_sys::backtrace_pcinfo(
+ state,
+ frame.exact_position as libc::uintptr_t,
+ pcinfo_cb,
+ error_cb,
+ fileline_addr as *mut libc::c_void,
+ )
+ };
+ FILELINE_SIZE - fileline_win.len()
+ };
+ if ret == 0 {
+ for &(file, line) in &fileline_buf[..fileline_count] {
+ if file.is_null() { continue; } // just to be sure
+ let file = unsafe { CStr::from_ptr(file).to_bytes() };
+ f(file, line)?;
+ }
+ Ok(fileline_count == FILELINE_SIZE)
+ } else {
+ Ok(false)
+ }
+}
+
+/// Converts a pointer to symbol to its string value.
+pub fn resolve_symname<F>(frame: Frame,
+ callback: F,
+ _: &BacktraceContext) -> io::Result<()>
+ where F: FnOnce(Option<&str>) -> io::Result<()>
+{
+ let symname = {
+ let state = unsafe { init_state() };
+ if state.is_null() {
+ return Err(io::Error::new(
+ io::ErrorKind::Other,
+ "failed to allocate libbacktrace state")
+ )
+ }
+ let mut data: *const libc::c_char = ptr::null();
+ let data_addr = &mut data as *mut *const libc::c_char;
+ let ret = unsafe {
+ backtrace_sys::backtrace_syminfo(
+ state,
+ frame.symbol_addr as libc::uintptr_t,
+ syminfo_cb,
+ error_cb,
+ data_addr as *mut libc::c_void,
+ )
+ };
+ if ret == 0 || data.is_null() {
+ None
+ } else {
+ unsafe {
+ CStr::from_ptr(data).to_str().ok()
+ }
+ }
+ };
+ callback(symname)
+}
+
+////////////////////////////////////////////////////////////////////////
+// helper callbacks
+////////////////////////////////////////////////////////////////////////
+
+type FileLine = (*const libc::c_char, u32);
+
+extern fn error_cb(_data: *mut libc::c_void, _msg: *const libc::c_char,
+ _errnum: libc::c_int) {
+ // do nothing for now
+}
+extern fn syminfo_cb(data: *mut libc::c_void,
+ _pc: libc::uintptr_t,
+ symname: *const libc::c_char,
+ _symval: libc::uintptr_t,
+ _symsize: libc::uintptr_t) {
+ let slot = data as *mut *const libc::c_char;
+ unsafe { *slot = symname; }
+}
+extern fn pcinfo_cb(data: *mut libc::c_void,
+ _pc: libc::uintptr_t,
+ filename: *const libc::c_char,
+ lineno: libc::c_int,
+ _function: *const libc::c_char) -> libc::c_int {
+ if !filename.is_null() {
+ let slot = data as *mut &mut [FileLine];
+ let buffer = unsafe {ptr::read(slot)};
+
+ // if the buffer is not full, add file:line to the buffer
+ // and adjust the buffer for next possible calls to pcinfo_cb.
+ if !buffer.is_empty() {
+ buffer[0] = (filename, lineno as u32);
+ unsafe { ptr::write(slot, &mut buffer[1..]); }
+ }
+ }
+
+ 0
+}
+
+// The libbacktrace API supports creating a state, but it does not
+// support destroying a state. I personally take this to mean that a
+// state is meant to be created and then live forever.
+//
+// I would love to register an at_exit() handler which cleans up this
+// state, but libbacktrace provides no way to do so.
+//
+// With these constraints, this function has a statically cached state
+// that is calculated the first time this is requested. Remember that
+// backtracing all happens serially (one global lock).
+//
+// Things don't work so well on not-Linux since libbacktrace can't track
+// down that executable this is. We at one point used env::current_exe but
+// it turns out that there are some serious security issues with that
+// approach.
+//
+// Specifically, on certain platforms like BSDs, a malicious actor can cause
+// an arbitrary file to be placed at the path returned by current_exe.
+// libbacktrace does not behave defensively in the presence of ill-formed
+// DWARF information, and has been demonstrated to segfault in at least one
+// case. There is no evidence at the moment to suggest that a more carefully
+// constructed file can't cause arbitrary code execution. As a result of all
+// of this, we don't hint libbacktrace with the path to the current process.
+unsafe fn init_state() -> *mut backtrace_state {
+ static mut STATE: *mut backtrace_state = ptr::null_mut();
+ if !STATE.is_null() { return STATE }
+
+ let filename = match crate::sys::backtrace::gnu::get_executable_filename() {
+ Ok((filename, file)) => {
+ // filename is purposely leaked here since libbacktrace requires
+ // it to stay allocated permanently, file is also leaked so that
+ // the file stays locked
+ let filename_ptr = filename.as_ptr();
+ mem::forget(filename);
+ mem::forget(file);
+ filename_ptr
+ },
+ Err(_) => ptr::null(),
+ };
+
+ STATE = backtrace_sys::backtrace_create_state(
+ filename,
+ 0,
+ error_cb,
+ ptr::null_mut(),
+ );
+ STATE
+}
diff --git a/src/libstd/sys_common/gnu/mod.rs b/src/libstd/sys_common/gnu/mod.rs
new file mode 100644
index 0000000..d695969
--- /dev/null
+++ b/src/libstd/sys_common/gnu/mod.rs
@@ -0,0 +1,5 @@
+#![allow(missing_docs)]
+#![allow(non_camel_case_types)]
+#![allow(non_snake_case)]
+
+pub mod libbacktrace;
diff --git a/src/libstd/sys_common/io.rs b/src/libstd/sys_common/io.rs
new file mode 100644
index 0000000..44b0963
--- /dev/null
+++ b/src/libstd/sys_common/io.rs
@@ -0,0 +1,41 @@
+pub const DEFAULT_BUF_SIZE: usize = 8 * 1024;
+
+#[cfg(test)]
+#[allow(dead_code)] // not used on emscripten
+pub mod test {
+ use crate::path::{Path, PathBuf};
+ use crate::env;
+ use crate::fs;
+ use rand::RngCore;
+
+ pub struct TempDir(PathBuf);
+
+ impl TempDir {
+ pub fn join(&self, path: &str) -> PathBuf {
+ let TempDir(ref p) = *self;
+ p.join(path)
+ }
+
+ pub fn path<'a>(&'a self) -> &'a Path {
+ let TempDir(ref p) = *self;
+ p
+ }
+ }
+
+ impl Drop for TempDir {
+ fn drop(&mut self) {
+ // Gee, seeing how we're testing the fs module I sure hope that we
+ // at least implement this correctly!
+ let TempDir(ref p) = *self;
+ fs::remove_dir_all(p).unwrap();
+ }
+ }
+
+ pub fn tmpdir() -> TempDir {
+ let p = env::temp_dir();
+ let mut r = rand::thread_rng();
+ let ret = p.join(&format!("rust-{}", r.next_u32()));
+ fs::create_dir(&ret).unwrap();
+ TempDir(ret)
+ }
+}
diff --git a/src/libstd/sys_common/mod.rs b/src/libstd/sys_common/mod.rs
new file mode 100644
index 0000000..6260c3b
--- /dev/null
+++ b/src/libstd/sys_common/mod.rs
@@ -0,0 +1,151 @@
+//! Platform-independent platform abstraction
+//!
+//! This is the platform-independent portion of the standard library's
+//! platform abstraction layer, whereas `std::sys` is the
+//! platform-specific portion.
+//!
+//! The relationship between `std::sys_common`, `std::sys` and the
+//! rest of `std` is complex, with dependencies going in all
+//! directions: `std` depending on `sys_common`, `sys_common`
+//! depending on `sys`, and `sys` depending on `sys_common` and `std`.
+//! Ideally `sys_common` would be split into two and the dependencies
+//! between them all would form a dag, facilitating the extraction of
+//! `std::sys` from the standard library.
+
+#![allow(missing_docs)]
+#![allow(missing_debug_implementations)]
+
+use crate::sync::Once;
+use crate::sys;
+
+macro_rules! rtabort {
+ ($($t:tt)*) => (crate::sys_common::util::abort(format_args!($($t)*)))
+}
+
+macro_rules! rtassert {
+ ($e:expr) => (if !$e {
+ rtabort!(concat!("assertion failed: ", stringify!($e)));
+ })
+}
+
+#[allow(unused_macros)] // not used on all platforms
+macro_rules! rtunwrap {
+ ($ok:ident, $e:expr) => (if let $ok(v) = $e {
+ v
+ } else {
+ rtabort!(concat!("unwrap failed: ", stringify!($e)));
+ })
+}
+
+pub mod alloc;
+pub mod at_exit_imp;
+#[cfg(feature = "backtrace")]
+pub mod backtrace;
+pub mod condvar;
+pub mod io;
+pub mod mutex;
+#[cfg(any(rustdoc, // see `mod os`, docs are generated for multiple platforms
+ unix,
+ target_os = "redox",
+ target_os = "cloudabi",
+ target_arch = "wasm32",
+ all(target_vendor = "fortanix", target_env = "sgx")))]
+pub mod os_str_bytes;
+pub mod poison;
+pub mod remutex;
+pub mod rwlock;
+pub mod thread;
+pub mod thread_info;
+pub mod thread_local;
+pub mod util;
+pub mod wtf8;
+pub mod bytestring;
+pub mod process;
+pub mod fs;
+
+cfg_if! {
+ if #[cfg(any(target_os = "cloudabi",
+ target_os = "l4re",
+ target_os = "redox",
+ all(target_arch = "wasm32", not(target_os = "emscripten")),
+ all(target_vendor = "fortanix", target_env = "sgx")))] {
+ pub use crate::sys::net;
+ } else {
+ pub mod net;
+ }
+}
+
+#[cfg(feature = "backtrace")]
+#[cfg(any(all(unix, not(target_os = "emscripten")),
+ all(windows, target_env = "gnu"),
+ target_os = "redox"))]
+pub mod gnu;
+
+// common error constructors
+
+/// A trait for viewing representations from std types
+#[doc(hidden)]
+pub trait AsInner<Inner: ?Sized> {
+ fn as_inner(&self) -> &Inner;
+}
+
+/// A trait for viewing representations from std types
+#[doc(hidden)]
+pub trait AsInnerMut<Inner: ?Sized> {
+ fn as_inner_mut(&mut self) -> &mut Inner;
+}
+
+/// A trait for extracting representations from std types
+#[doc(hidden)]
+pub trait IntoInner<Inner> {
+ fn into_inner(self) -> Inner;
+}
+
+/// A trait for creating std types from internal representations
+#[doc(hidden)]
+pub trait FromInner<Inner> {
+ fn from_inner(inner: Inner) -> Self;
+}
+
+/// Enqueues a procedure to run when the main thread exits.
+///
+/// Currently these closures are only run once the main *Rust* thread exits.
+/// Once the `at_exit` handlers begin running, more may be enqueued, but not
+/// infinitely so. Eventually a handler registration will be forced to fail.
+///
+/// Returns `Ok` if the handler was successfully registered, meaning that the
+/// closure will be run once the main thread exits. Returns `Err` to indicate
+/// that the closure could not be registered, meaning that it is not scheduled
+/// to be run.
+pub fn at_exit<F: FnOnce() + Send + 'static>(f: F) -> Result<(), ()> {
+ if at_exit_imp::push(Box::new(f)) {Ok(())} else {Err(())}
+}
+
+/// One-time runtime cleanup.
+pub fn cleanup() {
+ static CLEANUP: Once = Once::new();
+ CLEANUP.call_once(|| unsafe {
+ sys::args::cleanup();
+ sys::stack_overflow::cleanup();
+ at_exit_imp::cleanup();
+ });
+}
+
+// Computes (value*numer)/denom without overflow, as long as both
+// (numer*denom) and the overall result fit into i64 (which is the case
+// for our time conversions).
+#[allow(dead_code)] // not used on all platforms
+pub fn mul_div_u64(value: u64, numer: u64, denom: u64) -> u64 {
+ let q = value / denom;
+ let r = value % denom;
+ // Decompose value as (value/denom*denom + value%denom),
+ // substitute into (value*numer)/denom and simplify.
+ // r < denom, so (denom*numer) is the upper bound of (r*numer)
+ q * numer + r * numer / denom
+}
+
+#[test]
+fn test_muldiv() {
+ assert_eq!(mul_div_u64( 1_000_000_000_001, 1_000_000_000, 1_000_000),
+ 1_000_000_000_001_000);
+}
diff --git a/src/libstd/sys_common/mutex.rs b/src/libstd/sys_common/mutex.rs
new file mode 100644
index 0000000..28d8594
--- /dev/null
+++ b/src/libstd/sys_common/mutex.rs
@@ -0,0 +1,84 @@
+use crate::sys::mutex as imp;
+
+/// An OS-based mutual exclusion lock.
+///
+/// This is the thinnest cross-platform wrapper around OS mutexes. All usage of
+/// this mutex is unsafe and it is recommended to instead use the safe wrapper
+/// at the top level of the crate instead of this type.
+pub struct Mutex(imp::Mutex);
+
+unsafe impl Sync for Mutex {}
+
+impl Mutex {
+ /// Creates a new mutex for use.
+ ///
+ /// Behavior is undefined if the mutex is moved after it is
+ /// first used with any of the functions below.
+ /// Also, until `init` is called, behavior is undefined if this
+ /// mutex is ever used reentrantly, i.e., `raw_lock` or `try_lock`
+ /// are called by the thread currently holding the lock.
+ pub const fn new() -> Mutex { Mutex(imp::Mutex::new()) }
+
+ /// Prepare the mutex for use.
+ ///
+ /// This should be called once the mutex is at a stable memory address.
+ /// If called, this must be the very first thing that happens to the mutex.
+ /// Calling it in parallel with or after any operation (including another
+ /// `init()`) is undefined behavior.
+ #[inline]
+ pub unsafe fn init(&mut self) { self.0.init() }
+
+ /// Locks the mutex blocking the current thread until it is available.
+ ///
+ /// Behavior is undefined if the mutex has been moved between this and any
+ /// previous function call.
+ #[inline]
+ pub unsafe fn raw_lock(&self) { self.0.lock() }
+
+ /// Calls raw_lock() and then returns an RAII guard to guarantee the mutex
+ /// will be unlocked.
+ #[inline]
+ pub unsafe fn lock(&self) -> MutexGuard<'_> {
+ self.raw_lock();
+ MutexGuard(&self.0)
+ }
+
+ /// Attempts to lock the mutex without blocking, returning whether it was
+ /// successfully acquired or not.
+ ///
+ /// Behavior is undefined if the mutex has been moved between this and any
+ /// previous function call.
+ #[inline]
+ pub unsafe fn try_lock(&self) -> bool { self.0.try_lock() }
+
+ /// Unlocks the mutex.
+ ///
+ /// Behavior is undefined if the current thread does not actually hold the
+ /// mutex.
+ ///
+ /// Consider switching from the pair of raw_lock() and raw_unlock() to
+ /// lock() whenever possible.
+ #[inline]
+ pub unsafe fn raw_unlock(&self) { self.0.unlock() }
+
+ /// Deallocates all resources associated with this mutex.
+ ///
+ /// Behavior is undefined if there are current or will be future users of
+ /// this mutex.
+ #[inline]
+ pub unsafe fn destroy(&self) { self.0.destroy() }
+}
+
+// not meant to be exported to the outside world, just the containing module
+pub fn raw(mutex: &Mutex) -> &imp::Mutex { &mutex.0 }
+
+#[must_use]
+/// A simple RAII utility for the above Mutex without the poisoning semantics.
+pub struct MutexGuard<'a>(&'a imp::Mutex);
+
+impl Drop for MutexGuard<'_> {
+ #[inline]
+ fn drop(&mut self) {
+ unsafe { self.0.unlock(); }
+ }
+}
diff --git a/src/libstd/sys_common/net.rs b/src/libstd/sys_common/net.rs
new file mode 100644
index 0000000..02bd91c
--- /dev/null
+++ b/src/libstd/sys_common/net.rs
@@ -0,0 +1,676 @@
+use crate::cmp;
+use crate::ffi::CString;
+use crate::fmt;
+use crate::io::{self, Error, ErrorKind, IoVec, IoVecMut};
+use crate::mem;
+use crate::net::{SocketAddr, Shutdown, Ipv4Addr, Ipv6Addr};
+use crate::ptr;
+use crate::sys::net::{cvt, cvt_r, cvt_gai, Socket, init, wrlen_t};
+use crate::sys::net::netc as c;
+use crate::sys_common::{AsInner, FromInner, IntoInner};
+use crate::time::Duration;
+use crate::convert::{TryFrom, TryInto};
+
+use libc::{c_int, c_void};
+
+#[cfg(any(target_os = "dragonfly", target_os = "freebsd",
+ target_os = "ios", target_os = "macos",
+ target_os = "openbsd", target_os = "netbsd",
+ target_os = "solaris", target_os = "haiku", target_os = "l4re"))]
+use crate::sys::net::netc::IPV6_JOIN_GROUP as IPV6_ADD_MEMBERSHIP;
+#[cfg(not(any(target_os = "dragonfly", target_os = "freebsd",
+ target_os = "ios", target_os = "macos",
+ target_os = "openbsd", target_os = "netbsd",
+ target_os = "solaris", target_os = "haiku", target_os = "l4re")))]
+use crate::sys::net::netc::IPV6_ADD_MEMBERSHIP;
+#[cfg(any(target_os = "dragonfly", target_os = "freebsd",
+ target_os = "ios", target_os = "macos",
+ target_os = "openbsd", target_os = "netbsd",
+ target_os = "solaris", target_os = "haiku", target_os = "l4re"))]
+use crate::sys::net::netc::IPV6_LEAVE_GROUP as IPV6_DROP_MEMBERSHIP;
+#[cfg(not(any(target_os = "dragonfly", target_os = "freebsd",
+ target_os = "ios", target_os = "macos",
+ target_os = "openbsd", target_os = "netbsd",
+ target_os = "solaris", target_os = "haiku", target_os = "l4re")))]
+use crate::sys::net::netc::IPV6_DROP_MEMBERSHIP;
+
+#[cfg(any(target_os = "linux", target_os = "android",
+ target_os = "dragonfly", target_os = "freebsd",
+ target_os = "openbsd", target_os = "netbsd",
+ target_os = "haiku", target_os = "bitrig"))]
+use libc::MSG_NOSIGNAL;
+#[cfg(not(any(target_os = "linux", target_os = "android",
+ target_os = "dragonfly", target_os = "freebsd",
+ target_os = "openbsd", target_os = "netbsd",
+ target_os = "haiku", target_os = "bitrig")))]
+const MSG_NOSIGNAL: c_int = 0x0;
+
+////////////////////////////////////////////////////////////////////////////////
+// sockaddr and misc bindings
+////////////////////////////////////////////////////////////////////////////////
+
+pub fn setsockopt<T>(sock: &Socket, opt: c_int, val: c_int,
+ payload: T) -> io::Result<()> {
+ unsafe {
+ let payload = &payload as *const T as *const c_void;
+ cvt(c::setsockopt(*sock.as_inner(), opt, val, payload,
+ mem::size_of::<T>() as c::socklen_t))?;
+ Ok(())
+ }
+}
+
+pub fn getsockopt<T: Copy>(sock: &Socket, opt: c_int,
+ val: c_int) -> io::Result<T> {
+ unsafe {
+ let mut slot: T = mem::zeroed();
+ let mut len = mem::size_of::<T>() as c::socklen_t;
+ cvt(c::getsockopt(*sock.as_inner(), opt, val,
+ &mut slot as *mut _ as *mut _,
+ &mut len))?;
+ assert_eq!(len as usize, mem::size_of::<T>());
+ Ok(slot)
+ }
+}
+
+fn sockname<F>(f: F) -> io::Result<SocketAddr>
+ where F: FnOnce(*mut c::sockaddr, *mut c::socklen_t) -> c_int
+{
+ unsafe {
+ let mut storage: c::sockaddr_storage = mem::zeroed();
+ let mut len = mem::size_of_val(&storage) as c::socklen_t;
+ cvt(f(&mut storage as *mut _ as *mut _, &mut len))?;
+ sockaddr_to_addr(&storage, len as usize)
+ }
+}
+
+pub fn sockaddr_to_addr(storage: &c::sockaddr_storage,
+ len: usize) -> io::Result<SocketAddr> {
+ match storage.ss_family as c_int {
+ c::AF_INET => {
+ assert!(len as usize >= mem::size_of::<c::sockaddr_in>());
+ Ok(SocketAddr::V4(FromInner::from_inner(unsafe {
+ *(storage as *const _ as *const c::sockaddr_in)
+ })))
+ }
+ c::AF_INET6 => {
+ assert!(len as usize >= mem::size_of::<c::sockaddr_in6>());
+ Ok(SocketAddr::V6(FromInner::from_inner(unsafe {
+ *(storage as *const _ as *const c::sockaddr_in6)
+ })))
+ }
+ _ => {
+ Err(Error::new(ErrorKind::InvalidInput, "invalid argument"))
+ }
+ }
+}
+
+#[cfg(target_os = "android")]
+fn to_ipv6mr_interface(value: u32) -> c_int {
+ value as c_int
+}
+
+#[cfg(not(target_os = "android"))]
+fn to_ipv6mr_interface(value: u32) -> libc::c_uint {
+ value as libc::c_uint
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// get_host_addresses
+////////////////////////////////////////////////////////////////////////////////
+
+pub struct LookupHost {
+ original: *mut c::addrinfo,
+ cur: *mut c::addrinfo,
+ port: u16
+}
+
+impl LookupHost {
+ pub fn port(&self) -> u16 {
+ self.port
+ }
+}
+
+impl Iterator for LookupHost {
+ type Item = SocketAddr;
+ fn next(&mut self) -> Option<SocketAddr> {
+ loop {
+ unsafe {
+ let cur = self.cur.as_ref()?;
+ self.cur = cur.ai_next;
+ match sockaddr_to_addr(mem::transmute(cur.ai_addr),
+ cur.ai_addrlen as usize)
+ {
+ Ok(addr) => return Some(addr),
+ Err(_) => continue,
+ }
+ }
+ }
+ }
+}
+
+unsafe impl Sync for LookupHost {}
+unsafe impl Send for LookupHost {}
+
+impl Drop for LookupHost {
+ fn drop(&mut self) {
+ unsafe { c::freeaddrinfo(self.original) }
+ }
+}
+
+impl TryFrom<&str> for LookupHost {
+ type Error = io::Error;
+
+ fn try_from(s: &str) -> io::Result<LookupHost> {
+ macro_rules! try_opt {
+ ($e:expr, $msg:expr) => (
+ match $e {
+ Some(r) => r,
+ None => return Err(io::Error::new(io::ErrorKind::InvalidInput,
+ $msg)),
+ }
+ )
+ }
+
+ // split the string by ':' and convert the second part to u16
+ let mut parts_iter = s.rsplitn(2, ':');
+ let port_str = try_opt!(parts_iter.next(), "invalid socket address");
+ let host = try_opt!(parts_iter.next(), "invalid socket address");
+ let port: u16 = try_opt!(port_str.parse().ok(), "invalid port value");
+
+ (host, port).try_into()
+ }
+}
+
+impl<'a> TryFrom<(&'a str, u16)> for LookupHost {
+ type Error = io::Error;
+
+ fn try_from((host, port): (&'a str, u16)) -> io::Result<LookupHost> {
+ init();
+
+ let c_host = CString::new(host)?;
+ let mut hints: c::addrinfo = unsafe { mem::zeroed() };
+ hints.ai_socktype = c::SOCK_STREAM;
+ let mut res = ptr::null_mut();
+ unsafe {
+ cvt_gai(c::getaddrinfo(c_host.as_ptr(), ptr::null(), &hints, &mut res)).map(|_| {
+ LookupHost { original: res, cur: res, port }
+ })
+ }
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// TCP streams
+////////////////////////////////////////////////////////////////////////////////
+
+pub struct TcpStream {
+ inner: Socket,
+}
+
+impl TcpStream {
+ pub fn connect(addr: io::Result<&SocketAddr>) -> io::Result<TcpStream> {
+ let addr = addr?;
+
+ init();
+
+ let sock = Socket::new(addr, c::SOCK_STREAM)?;
+
+ let (addrp, len) = addr.into_inner();
+ cvt_r(|| unsafe { c::connect(*sock.as_inner(), addrp, len) })?;
+ Ok(TcpStream { inner: sock })
+ }
+
+ pub fn connect_timeout(addr: &SocketAddr, timeout: Duration) -> io::Result<TcpStream> {
+ init();
+
+ let sock = Socket::new(addr, c::SOCK_STREAM)?;
+ sock.connect_timeout(addr, timeout)?;
+ Ok(TcpStream { inner: sock })
+ }
+
+ pub fn socket(&self) -> &Socket { &self.inner }
+
+ pub fn into_socket(self) -> Socket { self.inner }
+
+ pub fn set_read_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
+ self.inner.set_timeout(dur, c::SO_RCVTIMEO)
+ }
+
+ pub fn set_write_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
+ self.inner.set_timeout(dur, c::SO_SNDTIMEO)
+ }
+
+ pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
+ self.inner.timeout(c::SO_RCVTIMEO)
+ }
+
+ pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
+ self.inner.timeout(c::SO_SNDTIMEO)
+ }
+
+ pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
+ self.inner.peek(buf)
+ }
+
+ pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
+ self.inner.read(buf)
+ }
+
+ pub fn read_vectored(&self, bufs: &mut [IoVecMut<'_>]) -> io::Result<usize> {
+ self.inner.read_vectored(bufs)
+ }
+
+ pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
+ let len = cmp::min(buf.len(), <wrlen_t>::max_value() as usize) as wrlen_t;
+ let ret = cvt(unsafe {
+ c::send(*self.inner.as_inner(),
+ buf.as_ptr() as *const c_void,
+ len,
+ MSG_NOSIGNAL)
+ })?;
+ Ok(ret as usize)
+ }
+
+ pub fn write_vectored(&self, bufs: &[IoVec<'_>]) -> io::Result<usize> {
+ self.inner.write_vectored(bufs)
+ }
+
+ pub fn peer_addr(&self) -> io::Result<SocketAddr> {
+ sockname(|buf, len| unsafe {
+ c::getpeername(*self.inner.as_inner(), buf, len)
+ })
+ }
+
+ pub fn socket_addr(&self) -> io::Result<SocketAddr> {
+ sockname(|buf, len| unsafe {
+ c::getsockname(*self.inner.as_inner(), buf, len)
+ })
+ }
+
+ pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
+ self.inner.shutdown(how)
+ }
+
+ pub fn duplicate(&self) -> io::Result<TcpStream> {
+ self.inner.duplicate().map(|s| TcpStream { inner: s })
+ }
+
+ pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> {
+ self.inner.set_nodelay(nodelay)
+ }
+
+ pub fn nodelay(&self) -> io::Result<bool> {
+ self.inner.nodelay()
+ }
+
+ pub fn set_ttl(&self, ttl: u32) -> io::Result<()> {
+ setsockopt(&self.inner, c::IPPROTO_IP, c::IP_TTL, ttl as c_int)
+ }
+
+ pub fn ttl(&self) -> io::Result<u32> {
+ let raw: c_int = getsockopt(&self.inner, c::IPPROTO_IP, c::IP_TTL)?;
+ Ok(raw as u32)
+ }
+
+ pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+ self.inner.take_error()
+ }
+
+ pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
+ self.inner.set_nonblocking(nonblocking)
+ }
+}
+
+impl FromInner<Socket> for TcpStream {
+ fn from_inner(socket: Socket) -> TcpStream {
+ TcpStream { inner: socket }
+ }
+}
+
+impl fmt::Debug for TcpStream {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ let mut res = f.debug_struct("TcpStream");
+
+ if let Ok(addr) = self.socket_addr() {
+ res.field("addr", &addr);
+ }
+
+ if let Ok(peer) = self.peer_addr() {
+ res.field("peer", &peer);
+ }
+
+ let name = if cfg!(windows) {"socket"} else {"fd"};
+ res.field(name, &self.inner.as_inner())
+ .finish()
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// TCP listeners
+////////////////////////////////////////////////////////////////////////////////
+
+pub struct TcpListener {
+ inner: Socket,
+}
+
+impl TcpListener {
+ pub fn bind(addr: io::Result<&SocketAddr>) -> io::Result<TcpListener> {
+ let addr = addr?;
+
+ init();
+
+ let sock = Socket::new(addr, c::SOCK_STREAM)?;
+
+ // On platforms with Berkeley-derived sockets, this allows
+ // to quickly rebind a socket, without needing to wait for
+ // the OS to clean up the previous one.
+ if !cfg!(windows) {
+ setsockopt(&sock, c::SOL_SOCKET, c::SO_REUSEADDR,
+ 1 as c_int)?;
+ }
+
+ // Bind our new socket
+ let (addrp, len) = addr.into_inner();
+ cvt(unsafe { c::bind(*sock.as_inner(), addrp, len as _) })?;
+
+ // Start listening
+ cvt(unsafe { c::listen(*sock.as_inner(), 128) })?;
+ Ok(TcpListener { inner: sock })
+ }
+
+ pub fn socket(&self) -> &Socket { &self.inner }
+
+ pub fn into_socket(self) -> Socket { self.inner }
+
+ pub fn socket_addr(&self) -> io::Result<SocketAddr> {
+ sockname(|buf, len| unsafe {
+ c::getsockname(*self.inner.as_inner(), buf, len)
+ })
+ }
+
+ pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> {
+ let mut storage: c::sockaddr_storage = unsafe { mem::zeroed() };
+ let mut len = mem::size_of_val(&storage) as c::socklen_t;
+ let sock = self.inner.accept(&mut storage as *mut _ as *mut _,
+ &mut len)?;
+ let addr = sockaddr_to_addr(&storage, len as usize)?;
+ Ok((TcpStream { inner: sock, }, addr))
+ }
+
+ pub fn duplicate(&self) -> io::Result<TcpListener> {
+ self.inner.duplicate().map(|s| TcpListener { inner: s })
+ }
+
+ pub fn set_ttl(&self, ttl: u32) -> io::Result<()> {
+ setsockopt(&self.inner, c::IPPROTO_IP, c::IP_TTL, ttl as c_int)
+ }
+
+ pub fn ttl(&self) -> io::Result<u32> {
+ let raw: c_int = getsockopt(&self.inner, c::IPPROTO_IP, c::IP_TTL)?;
+ Ok(raw as u32)
+ }
+
+ pub fn set_only_v6(&self, only_v6: bool) -> io::Result<()> {
+ setsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_V6ONLY, only_v6 as c_int)
+ }
+
+ pub fn only_v6(&self) -> io::Result<bool> {
+ let raw: c_int = getsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_V6ONLY)?;
+ Ok(raw != 0)
+ }
+
+ pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+ self.inner.take_error()
+ }
+
+ pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
+ self.inner.set_nonblocking(nonblocking)
+ }
+}
+
+impl FromInner<Socket> for TcpListener {
+ fn from_inner(socket: Socket) -> TcpListener {
+ TcpListener { inner: socket }
+ }
+}
+
+impl fmt::Debug for TcpListener {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ let mut res = f.debug_struct("TcpListener");
+
+ if let Ok(addr) = self.socket_addr() {
+ res.field("addr", &addr);
+ }
+
+ let name = if cfg!(windows) {"socket"} else {"fd"};
+ res.field(name, &self.inner.as_inner())
+ .finish()
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// UDP
+////////////////////////////////////////////////////////////////////////////////
+
+pub struct UdpSocket {
+ inner: Socket,
+}
+
+impl UdpSocket {
+ pub fn bind(addr: io::Result<&SocketAddr>) -> io::Result<UdpSocket> {
+ let addr = addr?;
+
+ init();
+
+ let sock = Socket::new(addr, c::SOCK_DGRAM)?;
+ let (addrp, len) = addr.into_inner();
+ cvt(unsafe { c::bind(*sock.as_inner(), addrp, len as _) })?;
+ Ok(UdpSocket { inner: sock })
+ }
+
+ pub fn socket(&self) -> &Socket { &self.inner }
+
+ pub fn into_socket(self) -> Socket { self.inner }
+
+ pub fn peer_addr(&self) -> io::Result<SocketAddr> {
+ sockname(|buf, len| unsafe {
+ c::getpeername(*self.inner.as_inner(), buf, len)
+ })
+ }
+
+ pub fn socket_addr(&self) -> io::Result<SocketAddr> {
+ sockname(|buf, len| unsafe {
+ c::getsockname(*self.inner.as_inner(), buf, len)
+ })
+ }
+
+ pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+ self.inner.recv_from(buf)
+ }
+
+ pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+ self.inner.peek_from(buf)
+ }
+
+ pub fn send_to(&self, buf: &[u8], dst: &SocketAddr) -> io::Result<usize> {
+ let len = cmp::min(buf.len(), <wrlen_t>::max_value() as usize) as wrlen_t;
+ let (dstp, dstlen) = dst.into_inner();
+ let ret = cvt(unsafe {
+ c::sendto(*self.inner.as_inner(),
+ buf.as_ptr() as *const c_void, len,
+ MSG_NOSIGNAL, dstp, dstlen)
+ })?;
+ Ok(ret as usize)
+ }
+
+ pub fn duplicate(&self) -> io::Result<UdpSocket> {
+ self.inner.duplicate().map(|s| UdpSocket { inner: s })
+ }
+
+ pub fn set_read_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
+ self.inner.set_timeout(dur, c::SO_RCVTIMEO)
+ }
+
+ pub fn set_write_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
+ self.inner.set_timeout(dur, c::SO_SNDTIMEO)
+ }
+
+ pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
+ self.inner.timeout(c::SO_RCVTIMEO)
+ }
+
+ pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
+ self.inner.timeout(c::SO_SNDTIMEO)
+ }
+
+ pub fn set_broadcast(&self, broadcast: bool) -> io::Result<()> {
+ setsockopt(&self.inner, c::SOL_SOCKET, c::SO_BROADCAST, broadcast as c_int)
+ }
+
+ pub fn broadcast(&self) -> io::Result<bool> {
+ let raw: c_int = getsockopt(&self.inner, c::SOL_SOCKET, c::SO_BROADCAST)?;
+ Ok(raw != 0)
+ }
+
+ pub fn set_multicast_loop_v4(&self, multicast_loop_v4: bool) -> io::Result<()> {
+ setsockopt(&self.inner, c::IPPROTO_IP, c::IP_MULTICAST_LOOP, multicast_loop_v4 as c_int)
+ }
+
+ pub fn multicast_loop_v4(&self) -> io::Result<bool> {
+ let raw: c_int = getsockopt(&self.inner, c::IPPROTO_IP, c::IP_MULTICAST_LOOP)?;
+ Ok(raw != 0)
+ }
+
+ pub fn set_multicast_ttl_v4(&self, multicast_ttl_v4: u32) -> io::Result<()> {
+ setsockopt(&self.inner, c::IPPROTO_IP, c::IP_MULTICAST_TTL, multicast_ttl_v4 as c_int)
+ }
+
+ pub fn multicast_ttl_v4(&self) -> io::Result<u32> {
+ let raw: c_int = getsockopt(&self.inner, c::IPPROTO_IP, c::IP_MULTICAST_TTL)?;
+ Ok(raw as u32)
+ }
+
+ pub fn set_multicast_loop_v6(&self, multicast_loop_v6: bool) -> io::Result<()> {
+ setsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_MULTICAST_LOOP, multicast_loop_v6 as c_int)
+ }
+
+ pub fn multicast_loop_v6(&self) -> io::Result<bool> {
+ let raw: c_int = getsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_MULTICAST_LOOP)?;
+ Ok(raw != 0)
+ }
+
+ pub fn join_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr)
+ -> io::Result<()> {
+ let mreq = c::ip_mreq {
+ imr_multiaddr: *multiaddr.as_inner(),
+ imr_interface: *interface.as_inner(),
+ };
+ setsockopt(&self.inner, c::IPPROTO_IP, c::IP_ADD_MEMBERSHIP, mreq)
+ }
+
+ pub fn join_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32)
+ -> io::Result<()> {
+ let mreq = c::ipv6_mreq {
+ ipv6mr_multiaddr: *multiaddr.as_inner(),
+ ipv6mr_interface: to_ipv6mr_interface(interface),
+ };
+ setsockopt(&self.inner, c::IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, mreq)
+ }
+
+ pub fn leave_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr)
+ -> io::Result<()> {
+ let mreq = c::ip_mreq {
+ imr_multiaddr: *multiaddr.as_inner(),
+ imr_interface: *interface.as_inner(),
+ };
+ setsockopt(&self.inner, c::IPPROTO_IP, c::IP_DROP_MEMBERSHIP, mreq)
+ }
+
+ pub fn leave_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32)
+ -> io::Result<()> {
+ let mreq = c::ipv6_mreq {
+ ipv6mr_multiaddr: *multiaddr.as_inner(),
+ ipv6mr_interface: to_ipv6mr_interface(interface),
+ };
+ setsockopt(&self.inner, c::IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, mreq)
+ }
+
+ pub fn set_ttl(&self, ttl: u32) -> io::Result<()> {
+ setsockopt(&self.inner, c::IPPROTO_IP, c::IP_TTL, ttl as c_int)
+ }
+
+ pub fn ttl(&self) -> io::Result<u32> {
+ let raw: c_int = getsockopt(&self.inner, c::IPPROTO_IP, c::IP_TTL)?;
+ Ok(raw as u32)
+ }
+
+ pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+ self.inner.take_error()
+ }
+
+ pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
+ self.inner.set_nonblocking(nonblocking)
+ }
+
+ pub fn recv(&self, buf: &mut [u8]) -> io::Result<usize> {
+ self.inner.read(buf)
+ }
+
+ pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
+ self.inner.peek(buf)
+ }
+
+ pub fn send(&self, buf: &[u8]) -> io::Result<usize> {
+ let len = cmp::min(buf.len(), <wrlen_t>::max_value() as usize) as wrlen_t;
+ let ret = cvt(unsafe {
+ c::send(*self.inner.as_inner(),
+ buf.as_ptr() as *const c_void,
+ len,
+ MSG_NOSIGNAL)
+ })?;
+ Ok(ret as usize)
+ }
+
+ pub fn connect(&self, addr: io::Result<&SocketAddr>) -> io::Result<()> {
+ let (addrp, len) = addr?.into_inner();
+ cvt_r(|| unsafe { c::connect(*self.inner.as_inner(), addrp, len) }).map(|_| ())
+ }
+}
+
+impl FromInner<Socket> for UdpSocket {
+ fn from_inner(socket: Socket) -> UdpSocket {
+ UdpSocket { inner: socket }
+ }
+}
+
+impl fmt::Debug for UdpSocket {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ let mut res = f.debug_struct("UdpSocket");
+
+ if let Ok(addr) = self.socket_addr() {
+ res.field("addr", &addr);
+ }
+
+ let name = if cfg!(windows) {"socket"} else {"fd"};
+ res.field(name, &self.inner.as_inner())
+ .finish()
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use crate::collections::HashMap;
+
+ #[test]
+ fn no_lookup_host_duplicates() {
+ let mut addrs = HashMap::new();
+ let lh = match LookupHost::try_from(("localhost", 0)) {
+ Ok(lh) => lh,
+ Err(e) => panic!("couldn't resolve `localhost': {}", e)
+ };
+ for sa in lh { *addrs.entry(sa).or_insert(0) += 1; };
+ assert_eq!(addrs.iter().filter(|&(_, &v)| v > 1).collect::<Vec<_>>(), vec![],
+ "There should be no duplicate localhost entries");
+ }
+}
diff --git a/src/libstd/sys_common/os_str_bytes.rs b/src/libstd/sys_common/os_str_bytes.rs
new file mode 100644
index 0000000..a496197
--- /dev/null
+++ b/src/libstd/sys_common/os_str_bytes.rs
@@ -0,0 +1,247 @@
+//! The underlying OsString/OsStr implementation on Unix and many other
+//! systems: just a `Vec<u8>`/`[u8]`.
+
+use crate::borrow::Cow;
+use crate::ffi::{OsStr, OsString};
+use crate::fmt;
+use crate::str;
+use crate::mem;
+use crate::rc::Rc;
+use crate::sync::Arc;
+use crate::sys_common::{FromInner, IntoInner, AsInner};
+use crate::sys_common::bytestring::debug_fmt_bytestring;
+
+use core::str::lossy::Utf8Lossy;
+
+#[derive(Clone, Hash)]
+pub(crate) struct Buf {
+ pub inner: Vec<u8>
+}
+
+pub(crate) struct Slice {
+ pub inner: [u8]
+}
+
+impl fmt::Debug for Slice {
+ fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+ debug_fmt_bytestring(&self.inner, formatter)
+ }
+}
+
+impl fmt::Display for Slice {
+ fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt::Display::fmt(&Utf8Lossy::from_bytes(&self.inner), formatter)
+ }
+}
+
+impl fmt::Debug for Buf {
+ fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt::Debug::fmt(self.as_slice(), formatter)
+ }
+}
+
+impl fmt::Display for Buf {
+ fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt::Display::fmt(self.as_slice(), formatter)
+ }
+}
+
+impl IntoInner<Vec<u8>> for Buf {
+ fn into_inner(self) -> Vec<u8> {
+ self.inner
+ }
+}
+
+impl AsInner<[u8]> for Buf {
+ fn as_inner(&self) -> &[u8] {
+ &self.inner
+ }
+}
+
+
+impl Buf {
+ pub fn from_string(s: String) -> Buf {
+ Buf { inner: s.into_bytes() }
+ }
+
+ #[inline]
+ pub fn with_capacity(capacity: usize) -> Buf {
+ Buf {
+ inner: Vec::with_capacity(capacity)
+ }
+ }
+
+ #[inline]
+ pub fn clear(&mut self) {
+ self.inner.clear()
+ }
+
+ #[inline]
+ pub fn capacity(&self) -> usize {
+ self.inner.capacity()
+ }
+
+ #[inline]
+ pub fn reserve(&mut self, additional: usize) {
+ self.inner.reserve(additional)
+ }
+
+ #[inline]
+ pub fn reserve_exact(&mut self, additional: usize) {
+ self.inner.reserve_exact(additional)
+ }
+
+ #[inline]
+ pub fn shrink_to_fit(&mut self) {
+ self.inner.shrink_to_fit()
+ }
+
+ #[inline]
+ pub fn shrink_to(&mut self, min_capacity: usize) {
+ self.inner.shrink_to(min_capacity)
+ }
+
+ pub fn as_slice(&self) -> &Slice {
+ unsafe { mem::transmute(&*self.inner) }
+ }
+
+ pub fn into_string(self) -> Result<String, Buf> {
+ String::from_utf8(self.inner).map_err(|p| Buf { inner: p.into_bytes() } )
+ }
+
+ pub fn push_slice(&mut self, s: &Slice) {
+ self.inner.extend_from_slice(&s.inner)
+ }
+
+ #[inline]
+ pub fn into_box(self) -> Box<Slice> {
+ unsafe { mem::transmute(self.inner.into_boxed_slice()) }
+ }
+
+ #[inline]
+ pub fn from_box(boxed: Box<Slice>) -> Buf {
+ let inner: Box<[u8]> = unsafe { mem::transmute(boxed) };
+ Buf { inner: inner.into_vec() }
+ }
+
+ #[inline]
+ pub fn into_arc(&self) -> Arc<Slice> {
+ self.as_slice().into_arc()
+ }
+
+ #[inline]
+ pub fn into_rc(&self) -> Rc<Slice> {
+ self.as_slice().into_rc()
+ }
+}
+
+impl Slice {
+ fn from_u8_slice(s: &[u8]) -> &Slice {
+ unsafe { mem::transmute(s) }
+ }
+
+ pub fn from_str(s: &str) -> &Slice {
+ Slice::from_u8_slice(s.as_bytes())
+ }
+
+ pub fn to_str(&self) -> Option<&str> {
+ str::from_utf8(&self.inner).ok()
+ }
+
+ pub fn to_string_lossy(&self) -> Cow<'_, str> {
+ String::from_utf8_lossy(&self.inner)
+ }
+
+ pub fn to_owned(&self) -> Buf {
+ Buf { inner: self.inner.to_vec() }
+ }
+
+ #[inline]
+ pub fn into_box(&self) -> Box<Slice> {
+ let boxed: Box<[u8]> = self.inner.into();
+ unsafe { mem::transmute(boxed) }
+ }
+
+ pub fn empty_box() -> Box<Slice> {
+ let boxed: Box<[u8]> = Default::default();
+ unsafe { mem::transmute(boxed) }
+ }
+
+ #[inline]
+ pub fn into_arc(&self) -> Arc<Slice> {
+ let arc: Arc<[u8]> = Arc::from(&self.inner);
+ unsafe { Arc::from_raw(Arc::into_raw(arc) as *const Slice) }
+ }
+
+ #[inline]
+ pub fn into_rc(&self) -> Rc<Slice> {
+ let rc: Rc<[u8]> = Rc::from(&self.inner);
+ unsafe { Rc::from_raw(Rc::into_raw(rc) as *const Slice) }
+ }
+}
+
+/// Platform-specific extensions to [`OsString`].
+///
+/// [`OsString`]: ../../../../std/ffi/struct.OsString.html
+#[stable(feature = "rust1", since = "1.0.0")]
+pub trait OsStringExt {
+ /// Creates an [`OsString`] from a byte vector.
+ ///
+ /// See the module docmentation for an example.
+ ///
+ /// [`OsString`]: ../../../ffi/struct.OsString.html
+ #[stable(feature = "rust1", since = "1.0.0")]
+ fn from_vec(vec: Vec<u8>) -> Self;
+
+ /// Yields the underlying byte vector of this [`OsString`].
+ ///
+ /// See the module docmentation for an example.
+ ///
+ /// [`OsString`]: ../../../ffi/struct.OsString.html
+ #[stable(feature = "rust1", since = "1.0.0")]
+ fn into_vec(self) -> Vec<u8>;
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl OsStringExt for OsString {
+ fn from_vec(vec: Vec<u8>) -> OsString {
+ FromInner::from_inner(Buf { inner: vec })
+ }
+ fn into_vec(self) -> Vec<u8> {
+ self.into_inner().inner
+ }
+}
+
+/// Platform-specific extensions to [`OsStr`].
+///
+/// [`OsStr`]: ../../../../std/ffi/struct.OsStr.html
+#[stable(feature = "rust1", since = "1.0.0")]
+pub trait OsStrExt {
+ #[stable(feature = "rust1", since = "1.0.0")]
+ /// Creates an [`OsStr`] from a byte slice.
+ ///
+ /// See the module docmentation for an example.
+ ///
+ /// [`OsStr`]: ../../../ffi/struct.OsStr.html
+ fn from_bytes(slice: &[u8]) -> &Self;
+
+ /// Gets the underlying byte view of the [`OsStr`] slice.
+ ///
+ /// See the module docmentation for an example.
+ ///
+ /// [`OsStr`]: ../../../ffi/struct.OsStr.html
+ #[stable(feature = "rust1", since = "1.0.0")]
+ fn as_bytes(&self) -> &[u8];
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl OsStrExt for OsStr {
+ #[inline]
+ fn from_bytes(slice: &[u8]) -> &OsStr {
+ unsafe { mem::transmute(slice) }
+ }
+ #[inline]
+ fn as_bytes(&self) -> &[u8] {
+ &self.as_inner().inner
+ }
+}
diff --git a/src/libstd/sys_common/poison.rs b/src/libstd/sys_common/poison.rs
new file mode 100644
index 0000000..adac45f
--- /dev/null
+++ b/src/libstd/sys_common/poison.rs
@@ -0,0 +1,259 @@
+use crate::error::{Error};
+use crate::fmt;
+use crate::sync::atomic::{AtomicBool, Ordering};
+use crate::thread;
+
+pub struct Flag { failed: AtomicBool }
+
+// Note that the Ordering uses to access the `failed` field of `Flag` below is
+// always `Relaxed`, and that's because this isn't actually protecting any data,
+// it's just a flag whether we've panicked or not.
+//
+// The actual location that this matters is when a mutex is **locked** which is
+// where we have external synchronization ensuring that we see memory
+// reads/writes to this flag.
+//
+// As a result, if it matters, we should see the correct value for `failed` in
+// all cases.
+
+impl Flag {
+ pub const fn new() -> Flag {
+ Flag { failed: AtomicBool::new(false) }
+ }
+
+ #[inline]
+ pub fn borrow(&self) -> LockResult<Guard> {
+ let ret = Guard { panicking: thread::panicking() };
+ if self.get() {
+ Err(PoisonError::new(ret))
+ } else {
+ Ok(ret)
+ }
+ }
+
+ #[inline]
+ pub fn done(&self, guard: &Guard) {
+ if !guard.panicking && thread::panicking() {
+ self.failed.store(true, Ordering::Relaxed);
+ }
+ }
+
+ #[inline]
+ pub fn get(&self) -> bool {
+ self.failed.load(Ordering::Relaxed)
+ }
+}
+
+pub struct Guard {
+ panicking: bool,
+}
+
+/// A type of error which can be returned whenever a lock is acquired.
+///
+/// Both [`Mutex`]es and [`RwLock`]s are poisoned whenever a thread fails while the lock
+/// is held. The precise semantics for when a lock is poisoned is documented on
+/// each lock, but once a lock is poisoned then all future acquisitions will
+/// return this error.
+///
+/// # Examples
+///
+/// ```
+/// use std::sync::{Arc, Mutex};
+/// use std::thread;
+///
+/// let mutex = Arc::new(Mutex::new(1));
+///
+/// // poison the mutex
+/// let c_mutex = mutex.clone();
+/// let _ = thread::spawn(move || {
+/// let mut data = c_mutex.lock().unwrap();
+/// *data = 2;
+/// panic!();
+/// }).join();
+///
+/// match mutex.lock() {
+/// Ok(_) => unreachable!(),
+/// Err(p_err) => {
+/// let data = p_err.get_ref();
+/// println!("recovered: {}", data);
+/// }
+/// };
+/// ```
+///
+/// [`Mutex`]: ../../std/sync/struct.Mutex.html
+/// [`RwLock`]: ../../std/sync/struct.RwLock.html
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct PoisonError<T> {
+ guard: T,
+}
+
+/// An enumeration of possible errors associated with a [`TryLockResult`] which
+/// can occur while trying to acquire a lock, from the [`try_lock`] method on a
+/// [`Mutex`] or the [`try_read`] and [`try_write`] methods on an [`RwLock`].
+///
+/// [`Mutex`]: struct.Mutex.html
+/// [`RwLock`]: struct.RwLock.html
+/// [`TryLockResult`]: type.TryLockResult.html
+/// [`try_lock`]: struct.Mutex.html#method.try_lock
+/// [`try_read`]: struct.RwLock.html#method.try_read
+/// [`try_write`]: struct.RwLock.html#method.try_write
+#[stable(feature = "rust1", since = "1.0.0")]
+pub enum TryLockError<T> {
+ /// The lock could not be acquired because another thread failed while holding
+ /// the lock.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ Poisoned(#[stable(feature = "rust1", since = "1.0.0")] PoisonError<T>),
+ /// The lock could not be acquired at this time because the operation would
+ /// otherwise block.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ WouldBlock,
+}
+
+/// A type alias for the result of a lock method which can be poisoned.
+///
+/// The [`Ok`] variant of this result indicates that the primitive was not
+/// poisoned, and the `Guard` is contained within. The [`Err`] variant indicates
+/// that the primitive was poisoned. Note that the [`Err`] variant *also* carries
+/// the associated guard, and it can be acquired through the [`into_inner`]
+/// method.
+///
+/// [`Ok`]: ../../std/result/enum.Result.html#variant.Ok
+/// [`Err`]: ../../std/result/enum.Result.html#variant.Err
+/// [`into_inner`]: ../../std/sync/struct.PoisonError.html#method.into_inner
+#[stable(feature = "rust1", since = "1.0.0")]
+pub type LockResult<Guard> = Result<Guard, PoisonError<Guard>>;
+
+/// A type alias for the result of a nonblocking locking method.
+///
+/// For more information, see [`LockResult`]. A `TryLockResult` doesn't
+/// necessarily hold the associated guard in the [`Err`] type as the lock may not
+/// have been acquired for other reasons.
+///
+/// [`LockResult`]: ../../std/sync/type.LockResult.html
+/// [`Err`]: ../../std/result/enum.Result.html#variant.Err
+#[stable(feature = "rust1", since = "1.0.0")]
+pub type TryLockResult<Guard> = Result<Guard, TryLockError<Guard>>;
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T> fmt::Debug for PoisonError<T> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ "PoisonError { inner: .. }".fmt(f)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T> fmt::Display for PoisonError<T> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ "poisoned lock: another task failed inside".fmt(f)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T> Error for PoisonError<T> {
+ fn description(&self) -> &str {
+ "poisoned lock: another task failed inside"
+ }
+}
+
+impl<T> PoisonError<T> {
+ /// Creates a `PoisonError`.
+ ///
+ /// This is generally created by methods like [`Mutex::lock`] or [`RwLock::read`].
+ ///
+ /// [`Mutex::lock`]: ../../std/sync/struct.Mutex.html#method.lock
+ /// [`RwLock::read`]: ../../std/sync/struct.RwLock.html#method.read
+ #[stable(feature = "sync_poison", since = "1.2.0")]
+ pub fn new(guard: T) -> PoisonError<T> {
+ PoisonError { guard }
+ }
+
+ /// Consumes this error indicating that a lock is poisoned, returning the
+ /// underlying guard to allow access regardless.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::HashSet;
+ /// use std::sync::{Arc, Mutex};
+ /// use std::thread;
+ ///
+ /// let mutex = Arc::new(Mutex::new(HashSet::new()));
+ ///
+ /// // poison the mutex
+ /// let c_mutex = mutex.clone();
+ /// let _ = thread::spawn(move || {
+ /// let mut data = c_mutex.lock().unwrap();
+ /// data.insert(10);
+ /// panic!();
+ /// }).join();
+ ///
+ /// let p_err = mutex.lock().unwrap_err();
+ /// let data = p_err.into_inner();
+ /// println!("recovered {} items", data.len());
+ /// ```
+ #[stable(feature = "sync_poison", since = "1.2.0")]
+ pub fn into_inner(self) -> T { self.guard }
+
+ /// Reaches into this error indicating that a lock is poisoned, returning a
+ /// reference to the underlying guard to allow access regardless.
+ #[stable(feature = "sync_poison", since = "1.2.0")]
+ pub fn get_ref(&self) -> &T { &self.guard }
+
+ /// Reaches into this error indicating that a lock is poisoned, returning a
+ /// mutable reference to the underlying guard to allow access regardless.
+ #[stable(feature = "sync_poison", since = "1.2.0")]
+ pub fn get_mut(&mut self) -> &mut T { &mut self.guard }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T> From<PoisonError<T>> for TryLockError<T> {
+ fn from(err: PoisonError<T>) -> TryLockError<T> {
+ TryLockError::Poisoned(err)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T> fmt::Debug for TryLockError<T> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match *self {
+ TryLockError::Poisoned(..) => "Poisoned(..)".fmt(f),
+ TryLockError::WouldBlock => "WouldBlock".fmt(f)
+ }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T> fmt::Display for TryLockError<T> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match *self {
+ TryLockError::Poisoned(..) => "poisoned lock: another task failed inside",
+ TryLockError::WouldBlock => "try_lock failed because the operation would block"
+ }.fmt(f)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T> Error for TryLockError<T> {
+ fn description(&self) -> &str {
+ match *self {
+ TryLockError::Poisoned(ref p) => p.description(),
+ TryLockError::WouldBlock => "try_lock failed because the operation would block"
+ }
+ }
+
+ fn cause(&self) -> Option<&dyn Error> {
+ match *self {
+ TryLockError::Poisoned(ref p) => Some(p),
+ _ => None
+ }
+ }
+}
+
+pub fn map_result<T, U, F>(result: LockResult<T>, f: F)
+ -> LockResult<U>
+ where F: FnOnce(T) -> U {
+ match result {
+ Ok(t) => Ok(f(t)),
+ Err(PoisonError { guard }) => Err(PoisonError::new(f(guard)))
+ }
+}
diff --git a/src/libstd/sys_common/process.rs b/src/libstd/sys_common/process.rs
new file mode 100644
index 0000000..4d40dec
--- /dev/null
+++ b/src/libstd/sys_common/process.rs
@@ -0,0 +1,126 @@
+#![allow(dead_code)]
+#![unstable(feature = "process_internals", issue = "0")]
+
+use crate::ffi::{OsStr, OsString};
+use crate::env;
+use crate::collections::BTreeMap;
+use crate::borrow::Borrow;
+
+pub trait EnvKey:
+ From<OsString> + Into<OsString> +
+ Borrow<OsStr> + Borrow<Self> + AsRef<OsStr> +
+ Ord + Clone {}
+
+// Implement a case-sensitive environment variable key
+#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
+pub struct DefaultEnvKey(OsString);
+
+impl From<OsString> for DefaultEnvKey {
+ fn from(k: OsString) -> Self { DefaultEnvKey(k) }
+}
+
+impl From<DefaultEnvKey> for OsString {
+ fn from(k: DefaultEnvKey) -> Self { k.0 }
+}
+
+impl Borrow<OsStr> for DefaultEnvKey {
+ fn borrow(&self) -> &OsStr { &self.0 }
+}
+
+impl AsRef<OsStr> for DefaultEnvKey {
+ fn as_ref(&self) -> &OsStr { &self.0 }
+}
+
+impl EnvKey for DefaultEnvKey {}
+
+// Stores a set of changes to an environment
+#[derive(Clone, Debug)]
+pub struct CommandEnv<K> {
+ clear: bool,
+ saw_path: bool,
+ vars: BTreeMap<K, Option<OsString>>
+}
+
+impl<K: EnvKey> Default for CommandEnv<K> {
+ fn default() -> Self {
+ CommandEnv {
+ clear: false,
+ saw_path: false,
+ vars: Default::default()
+ }
+ }
+}
+
+impl<K: EnvKey> CommandEnv<K> {
+ // Capture the current environment with these changes applied
+ pub fn capture(&self) -> BTreeMap<K, OsString> {
+ let mut result = BTreeMap::<K, OsString>::new();
+ if !self.clear {
+ for (k, v) in env::vars_os() {
+ result.insert(k.into(), v);
+ }
+ }
+ for (k, maybe_v) in &self.vars {
+ if let &Some(ref v) = maybe_v {
+ result.insert(k.clone(), v.clone());
+ } else {
+ result.remove(k);
+ }
+ }
+ result
+ }
+
+ // Apply these changes directly to the current environment
+ pub fn apply(&self) {
+ if self.clear {
+ for (k, _) in env::vars_os() {
+ env::remove_var(k);
+ }
+ }
+ for (key, maybe_val) in self.vars.iter() {
+ if let &Some(ref val) = maybe_val {
+ env::set_var(key, val);
+ } else {
+ env::remove_var(key);
+ }
+ }
+ }
+
+ pub fn is_unchanged(&self) -> bool {
+ !self.clear && self.vars.is_empty()
+ }
+
+ pub fn capture_if_changed(&self) -> Option<BTreeMap<K, OsString>> {
+ if self.is_unchanged() {
+ None
+ } else {
+ Some(self.capture())
+ }
+ }
+
+ // The following functions build up changes
+ pub fn set(&mut self, key: &OsStr, value: &OsStr) {
+ self.maybe_saw_path(&key);
+ self.vars.insert(key.to_owned().into(), Some(value.to_owned()));
+ }
+ pub fn remove(&mut self, key: &OsStr) {
+ self.maybe_saw_path(&key);
+ if self.clear {
+ self.vars.remove(key);
+ } else {
+ self.vars.insert(key.to_owned().into(), None);
+ }
+ }
+ pub fn clear(&mut self) {
+ self.clear = true;
+ self.vars.clear();
+ }
+ pub fn have_changed_path(&self) -> bool {
+ self.saw_path || self.clear
+ }
+ fn maybe_saw_path(&mut self, key: &OsStr) {
+ if !self.saw_path && key == "PATH" {
+ self.saw_path = true;
+ }
+ }
+}
diff --git a/src/libstd/sys_common/remutex.rs b/src/libstd/sys_common/remutex.rs
new file mode 100644
index 0000000..f08b13c
--- /dev/null
+++ b/src/libstd/sys_common/remutex.rs
@@ -0,0 +1,239 @@
+use crate::fmt;
+use crate::marker;
+use crate::ops::Deref;
+use crate::sys_common::poison::{self, TryLockError, TryLockResult, LockResult};
+use crate::sys::mutex as sys;
+use crate::panic::{UnwindSafe, RefUnwindSafe};
+
+/// A re-entrant mutual exclusion
+///
+/// This mutex will block *other* threads waiting for the lock to become
+/// available. The thread which has already locked the mutex can lock it
+/// multiple times without blocking, preventing a common source of deadlocks.
+pub struct ReentrantMutex<T> {
+ inner: Box<sys::ReentrantMutex>,
+ poison: poison::Flag,
+ data: T,
+}
+
+unsafe impl<T: Send> Send for ReentrantMutex<T> {}
+unsafe impl<T: Send> Sync for ReentrantMutex<T> {}
+
+impl<T> UnwindSafe for ReentrantMutex<T> {}
+impl<T> RefUnwindSafe for ReentrantMutex<T> {}
+
+
+/// An RAII implementation of a "scoped lock" of a mutex. When this structure is
+/// dropped (falls out of scope), the lock will be unlocked.
+///
+/// The data protected by the mutex can be accessed through this guard via its
+/// Deref implementation.
+///
+/// # Mutability
+///
+/// Unlike `MutexGuard`, `ReentrantMutexGuard` does not implement `DerefMut`,
+/// because implementation of the trait would violate Rust’s reference aliasing
+/// rules. Use interior mutability (usually `RefCell`) in order to mutate the
+/// guarded data.
+#[must_use = "if unused the ReentrantMutex will immediately unlock"]
+pub struct ReentrantMutexGuard<'a, T: 'a> {
+ // funny underscores due to how Deref currently works (it disregards field
+ // privacy).
+ __lock: &'a ReentrantMutex<T>,
+ __poison: poison::Guard,
+}
+
+impl<T> !marker::Send for ReentrantMutexGuard<'_, T> {}
+
+
+impl<T> ReentrantMutex<T> {
+ /// Creates a new reentrant mutex in an unlocked state.
+ pub fn new(t: T) -> ReentrantMutex<T> {
+ unsafe {
+ let mut mutex = ReentrantMutex {
+ inner: box sys::ReentrantMutex::uninitialized(),
+ poison: poison::Flag::new(),
+ data: t,
+ };
+ mutex.inner.init();
+ mutex
+ }
+ }
+
+ /// Acquires a mutex, blocking the current thread until it is able to do so.
+ ///
+ /// This function will block the caller until it is available to acquire the mutex.
+ /// Upon returning, the thread is the only thread with the mutex held. When the thread
+ /// calling this method already holds the lock, the call shall succeed without
+ /// blocking.
+ ///
+ /// # Errors
+ ///
+ /// If another user of this mutex panicked while holding the mutex, then
+ /// this call will return failure if the mutex would otherwise be
+ /// acquired.
+ pub fn lock(&self) -> LockResult<ReentrantMutexGuard<'_, T>> {
+ unsafe { self.inner.lock() }
+ ReentrantMutexGuard::new(&self)
+ }
+
+ /// Attempts to acquire this lock.
+ ///
+ /// If the lock could not be acquired at this time, then `Err` is returned.
+ /// Otherwise, an RAII guard is returned.
+ ///
+ /// This function does not block.
+ ///
+ /// # Errors
+ ///
+ /// If another user of this mutex panicked while holding the mutex, then
+ /// this call will return failure if the mutex would otherwise be
+ /// acquired.
+ pub fn try_lock(&self) -> TryLockResult<ReentrantMutexGuard<'_, T>> {
+ if unsafe { self.inner.try_lock() } {
+ Ok(ReentrantMutexGuard::new(&self)?)
+ } else {
+ Err(TryLockError::WouldBlock)
+ }
+ }
+}
+
+impl<T> Drop for ReentrantMutex<T> {
+ fn drop(&mut self) {
+ // This is actually safe b/c we know that there is no further usage of
+ // this mutex (it's up to the user to arrange for a mutex to get
+ // dropped, that's not our job)
+ unsafe { self.inner.destroy() }
+ }
+}
+
+impl<T: fmt::Debug + 'static> fmt::Debug for ReentrantMutex<T> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self.try_lock() {
+ Ok(guard) => f.debug_struct("ReentrantMutex").field("data", &*guard).finish(),
+ Err(TryLockError::Poisoned(err)) => {
+ f.debug_struct("ReentrantMutex").field("data", &**err.get_ref()).finish()
+ },
+ Err(TryLockError::WouldBlock) => {
+ struct LockedPlaceholder;
+ impl fmt::Debug for LockedPlaceholder {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.write_str("<locked>")
+ }
+ }
+
+ f.debug_struct("ReentrantMutex").field("data", &LockedPlaceholder).finish()
+ }
+ }
+ }
+}
+
+impl<'mutex, T> ReentrantMutexGuard<'mutex, T> {
+ fn new(lock: &'mutex ReentrantMutex<T>)
+ -> LockResult<ReentrantMutexGuard<'mutex, T>> {
+ poison::map_result(lock.poison.borrow(), |guard| {
+ ReentrantMutexGuard {
+ __lock: lock,
+ __poison: guard,
+ }
+ })
+ }
+}
+
+impl<T> Deref for ReentrantMutexGuard<'_, T> {
+ type Target = T;
+
+ fn deref(&self) -> &T {
+ &self.__lock.data
+ }
+}
+
+impl<T> Drop for ReentrantMutexGuard<'_, T> {
+ #[inline]
+ fn drop(&mut self) {
+ unsafe {
+ self.__lock.poison.done(&self.__poison);
+ self.__lock.inner.unlock();
+ }
+ }
+}
+
+
+#[cfg(all(test, not(target_os = "emscripten")))]
+mod tests {
+ use crate::sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard};
+ use crate::cell::RefCell;
+ use crate::sync::Arc;
+ use crate::thread;
+
+ #[test]
+ fn smoke() {
+ let m = ReentrantMutex::new(());
+ {
+ let a = m.lock().unwrap();
+ {
+ let b = m.lock().unwrap();
+ {
+ let c = m.lock().unwrap();
+ assert_eq!(*c, ());
+ }
+ assert_eq!(*b, ());
+ }
+ assert_eq!(*a, ());
+ }
+ }
+
+ #[test]
+ fn is_mutex() {
+ let m = Arc::new(ReentrantMutex::new(RefCell::new(0)));
+ let m2 = m.clone();
+ let lock = m.lock().unwrap();
+ let child = thread::spawn(move || {
+ let lock = m2.lock().unwrap();
+ assert_eq!(*lock.borrow(), 4950);
+ });
+ for i in 0..100 {
+ let lock = m.lock().unwrap();
+ *lock.borrow_mut() += i;
+ }
+ drop(lock);
+ child.join().unwrap();
+ }
+
+ #[test]
+ fn trylock_works() {
+ let m = Arc::new(ReentrantMutex::new(()));
+ let m2 = m.clone();
+ let _lock = m.try_lock().unwrap();
+ let _lock2 = m.try_lock().unwrap();
+ thread::spawn(move || {
+ let lock = m2.try_lock();
+ assert!(lock.is_err());
+ }).join().unwrap();
+ let _lock3 = m.try_lock().unwrap();
+ }
+
+ pub struct Answer<'a>(pub ReentrantMutexGuard<'a, RefCell<u32>>);
+ impl Drop for Answer<'_> {
+ fn drop(&mut self) {
+ *self.0.borrow_mut() = 42;
+ }
+ }
+
+ #[test]
+ fn poison_works() {
+ let m = Arc::new(ReentrantMutex::new(RefCell::new(0)));
+ let mc = m.clone();
+ let result = thread::spawn(move ||{
+ let lock = mc.lock().unwrap();
+ *lock.borrow_mut() = 1;
+ let lock2 = mc.lock().unwrap();
+ *lock.borrow_mut() = 2;
+ let _answer = Answer(lock2);
+ panic!("What the answer to my lifetimes dilemma is?");
+ }).join();
+ assert!(result.is_err());
+ let r = m.lock().err().unwrap().into_inner();
+ assert_eq!(*r.borrow(), 42);
+ }
+}
diff --git a/src/libstd/sys_common/rwlock.rs b/src/libstd/sys_common/rwlock.rs
new file mode 100644
index 0000000..0b1a092
--- /dev/null
+++ b/src/libstd/sys_common/rwlock.rs
@@ -0,0 +1,72 @@
+use crate::sys::rwlock as imp;
+
+/// An OS-based reader-writer lock.
+///
+/// This structure is entirely unsafe and serves as the lowest layer of a
+/// cross-platform binding of system rwlocks. It is recommended to use the
+/// safer types at the top level of this crate instead of this type.
+pub struct RWLock(imp::RWLock);
+
+impl RWLock {
+ /// Creates a new reader-writer lock for use.
+ ///
+ /// Behavior is undefined if the reader-writer lock is moved after it is
+ /// first used with any of the functions below.
+ pub const fn new() -> RWLock { RWLock(imp::RWLock::new()) }
+
+ /// Acquires shared access to the underlying lock, blocking the current
+ /// thread to do so.
+ ///
+ /// Behavior is undefined if the rwlock has been moved between this and any
+ /// previous method call.
+ #[inline]
+ pub unsafe fn read(&self) { self.0.read() }
+
+ /// Attempts to acquire shared access to this lock, returning whether it
+ /// succeeded or not.
+ ///
+ /// This function does not block the current thread.
+ ///
+ /// Behavior is undefined if the rwlock has been moved between this and any
+ /// previous method call.
+ #[inline]
+ pub unsafe fn try_read(&self) -> bool { self.0.try_read() }
+
+ /// Acquires write access to the underlying lock, blocking the current thread
+ /// to do so.
+ ///
+ /// Behavior is undefined if the rwlock has been moved between this and any
+ /// previous method call.
+ #[inline]
+ pub unsafe fn write(&self) { self.0.write() }
+
+ /// Attempts to acquire exclusive access to this lock, returning whether it
+ /// succeeded or not.
+ ///
+ /// This function does not block the current thread.
+ ///
+ /// Behavior is undefined if the rwlock has been moved between this and any
+ /// previous method call.
+ #[inline]
+ pub unsafe fn try_write(&self) -> bool { self.0.try_write() }
+
+ /// Unlocks previously acquired shared access to this lock.
+ ///
+ /// Behavior is undefined if the current thread does not have shared access.
+ #[inline]
+ pub unsafe fn read_unlock(&self) { self.0.read_unlock() }
+
+ /// Unlocks previously acquired exclusive access to this lock.
+ ///
+ /// Behavior is undefined if the current thread does not currently have
+ /// exclusive access.
+ #[inline]
+ pub unsafe fn write_unlock(&self) { self.0.write_unlock() }
+
+ /// Destroys OS-related resources with this RWLock.
+ ///
+ /// Behavior is undefined if there are any currently active users of this
+ /// lock.
+ #[inline]
+ pub unsafe fn destroy(&self) { self.0.destroy() }
+}
diff --git a/src/libstd/sys_common/thread.rs b/src/libstd/sys_common/thread.rs
new file mode 100644
index 0000000..b2142e7
--- /dev/null
+++ b/src/libstd/sys_common/thread.rs
@@ -0,0 +1,30 @@
+use crate::boxed::FnBox;
+use crate::env;
+use crate::sync::atomic::{self, Ordering};
+use crate::sys::stack_overflow;
+use crate::sys::thread as imp;
+
+#[allow(dead_code)]
+pub unsafe fn start_thread(main: *mut u8) {
+ // Next, set up our stack overflow handler which may get triggered if we run
+ // out of stack.
+ let _handler = stack_overflow::Handler::new();
+
+ // Finally, let's run some code.
+ Box::from_raw(main as *mut Box<dyn FnBox()>)()
+}
+
+pub fn min_stack() -> usize {
+ static MIN: atomic::AtomicUsize = atomic::AtomicUsize::new(0);
+ match MIN.load(Ordering::SeqCst) {
+ 0 => {}
+ n => return n - 1,
+ }
+ let amt = env::var("RUST_MIN_STACK").ok().and_then(|s| s.parse().ok());
+ let amt = amt.unwrap_or(imp::DEFAULT_MIN_STACK_SIZE);
+
+ // 0 is our sentinel value, so ensure that we'll never see 0 after
+ // initialization has run
+ MIN.store(amt + 1, Ordering::SeqCst);
+ amt
+}
diff --git a/src/libstd/sys_common/thread_info.rs b/src/libstd/sys_common/thread_info.rs
new file mode 100644
index 0000000..b3c21ec
--- /dev/null
+++ b/src/libstd/sys_common/thread_info.rs
@@ -0,0 +1,46 @@
+#![allow(dead_code)] // stack_guard isn't used right now on all platforms
+
+use crate::cell::RefCell;
+use crate::sys::thread::guard::Guard;
+use crate::thread::Thread;
+
+struct ThreadInfo {
+ stack_guard: Option<Guard>,
+ thread: Thread,
+}
+
+thread_local! { static THREAD_INFO: RefCell<Option<ThreadInfo>> = RefCell::new(None) }
+
+impl ThreadInfo {
+ fn with<R, F>(f: F) -> Option<R> where F: FnOnce(&mut ThreadInfo) -> R {
+ THREAD_INFO.try_with(move |c| {
+ if c.borrow().is_none() {
+ *c.borrow_mut() = Some(ThreadInfo {
+ stack_guard: None,
+ thread: Thread::new(None),
+ })
+ }
+ f(c.borrow_mut().as_mut().unwrap())
+ }).ok()
+ }
+}
+
+pub fn current_thread() -> Option<Thread> {
+ ThreadInfo::with(|info| info.thread.clone())
+}
+
+pub fn stack_guard() -> Option<Guard> {
+ ThreadInfo::with(|info| info.stack_guard.clone()).and_then(|o| o)
+}
+
+pub fn set(stack_guard: Option<Guard>, thread: Thread) {
+ THREAD_INFO.with(|c| assert!(c.borrow().is_none()));
+ THREAD_INFO.with(move |c| *c.borrow_mut() = Some(ThreadInfo{
+ stack_guard,
+ thread,
+ }));
+}
+
+pub fn reset_guard(stack_guard: Option<Guard>) {
+ THREAD_INFO.with(move |c| c.borrow_mut().as_mut().unwrap().stack_guard = stack_guard);
+}
diff --git a/src/libstd/sys_common/thread_local.rs b/src/libstd/sys_common/thread_local.rs
new file mode 100644
index 0000000..bdf7900
--- /dev/null
+++ b/src/libstd/sys_common/thread_local.rs
@@ -0,0 +1,301 @@
+//! OS-based thread local storage
+//!
+//! This module provides an implementation of OS-based thread local storage,
+//! using the native OS-provided facilities (think `TlsAlloc` or
+//! `pthread_setspecific`). The interface of this differs from the other types
+//! of thread-local-storage provided in this crate in that OS-based TLS can only
+//! get/set pointers,
+//!
+//! This module also provides two flavors of TLS. One is intended for static
+//! initialization, and does not contain a `Drop` implementation to deallocate
+//! the OS-TLS key. The other is a type which does implement `Drop` and hence
+//! has a safe interface.
+//!
+//! # Usage
+//!
+//! This module should likely not be used directly unless other primitives are
+//! being built on. types such as `thread_local::spawn::Key` are likely much
+//! more useful in practice than this OS-based version which likely requires
+//! unsafe code to interoperate with.
+//!
+//! # Examples
+//!
+//! Using a dynamically allocated TLS key. Note that this key can be shared
+//! among many threads via an `Arc`.
+//!
+//! ```ignore (cannot-doctest-private-modules)
+//! let key = Key::new(None);
+//! assert!(key.get().is_null());
+//! key.set(1 as *mut u8);
+//! assert!(!key.get().is_null());
+//!
+//! drop(key); // deallocate this TLS slot.
+//! ```
+//!
+//! Sometimes a statically allocated key is either required or easier to work
+//! with, however.
+//!
+//! ```ignore (cannot-doctest-private-modules)
+//! static KEY: StaticKey = INIT;
+//!
+//! unsafe {
+//! assert!(KEY.get().is_null());
+//! KEY.set(1 as *mut u8);
+//! }
+//! ```
+
+#![allow(non_camel_case_types)]
+#![unstable(feature = "thread_local_internals", issue = "0")]
+#![allow(dead_code)] // sys isn't exported yet
+
+use crate::ptr;
+use crate::sync::atomic::{self, AtomicUsize, Ordering};
+use crate::sys::thread_local as imp;
+use crate::sys_common::mutex::Mutex;
+
+/// A type for TLS keys that are statically allocated.
+///
+/// This type is entirely `unsafe` to use as it does not protect against
+/// use-after-deallocation or use-during-deallocation.
+///
+/// The actual OS-TLS key is lazily allocated when this is used for the first
+/// time. The key is also deallocated when the Rust runtime exits or `destroy`
+/// is called, whichever comes first.
+///
+/// # Examples
+///
+/// ```ignore (cannot-doctest-private-modules)
+/// use tls::os::{StaticKey, INIT};
+///
+/// static KEY: StaticKey = INIT;
+///
+/// unsafe {
+/// assert!(KEY.get().is_null());
+/// KEY.set(1 as *mut u8);
+/// }
+/// ```
+pub struct StaticKey {
+ /// Inner static TLS key (internals).
+ key: AtomicUsize,
+ /// Destructor for the TLS value.
+ ///
+ /// See `Key::new` for information about when the destructor runs and how
+ /// it runs.
+ dtor: Option<unsafe extern fn(*mut u8)>,
+}
+
+/// A type for a safely managed OS-based TLS slot.
+///
+/// This type allocates an OS TLS key when it is initialized and will deallocate
+/// the key when it falls out of scope. When compared with `StaticKey`, this
+/// type is entirely safe to use.
+///
+/// Implementations will likely, however, contain unsafe code as this type only
+/// operates on `*mut u8`, a raw pointer.
+///
+/// # Examples
+///
+/// ```ignore (cannot-doctest-private-modules)
+/// use tls::os::Key;
+///
+/// let key = Key::new(None);
+/// assert!(key.get().is_null());
+/// key.set(1 as *mut u8);
+/// assert!(!key.get().is_null());
+///
+/// drop(key); // deallocate this TLS slot.
+/// ```
+pub struct Key {
+ key: imp::Key,
+}
+
+/// Constant initialization value for static TLS keys.
+///
+/// This value specifies no destructor by default.
+pub const INIT: StaticKey = StaticKey::new(None);
+
+impl StaticKey {
+ pub const fn new(dtor: Option<unsafe extern fn(*mut u8)>) -> StaticKey {
+ StaticKey {
+ key: atomic::AtomicUsize::new(0),
+ dtor,
+ }
+ }
+
+ /// Gets the value associated with this TLS key
+ ///
+ /// This will lazily allocate a TLS key from the OS if one has not already
+ /// been allocated.
+ #[inline]
+ pub unsafe fn get(&self) -> *mut u8 { imp::get(self.key()) }
+
+ /// Sets this TLS key to a new value.
+ ///
+ /// This will lazily allocate a TLS key from the OS if one has not already
+ /// been allocated.
+ #[inline]
+ pub unsafe fn set(&self, val: *mut u8) { imp::set(self.key(), val) }
+
+ #[inline]
+ unsafe fn key(&self) -> imp::Key {
+ match self.key.load(Ordering::Relaxed) {
+ 0 => self.lazy_init() as imp::Key,
+ n => n as imp::Key
+ }
+ }
+
+ unsafe fn lazy_init(&self) -> usize {
+ // Currently the Windows implementation of TLS is pretty hairy, and
+ // it greatly simplifies creation if we just synchronize everything.
+ //
+ // Additionally a 0-index of a tls key hasn't been seen on windows, so
+ // we just simplify the whole branch.
+ if imp::requires_synchronized_create() {
+ // We never call `INIT_LOCK.init()`, so it is UB to attempt to
+ // acquire this mutex reentrantly!
+ static INIT_LOCK: Mutex = Mutex::new();
+ let _guard = INIT_LOCK.lock();
+ let mut key = self.key.load(Ordering::SeqCst);
+ if key == 0 {
+ key = imp::create(self.dtor) as usize;
+ self.key.store(key, Ordering::SeqCst);
+ }
+ rtassert!(key != 0);
+ return key
+ }
+
+ // POSIX allows the key created here to be 0, but the compare_and_swap
+ // below relies on using 0 as a sentinel value to check who won the
+ // race to set the shared TLS key. As far as I know, there is no
+ // guaranteed value that cannot be returned as a posix_key_create key,
+ // so there is no value we can initialize the inner key with to
+ // prove that it has not yet been set. As such, we'll continue using a
+ // value of 0, but with some gyrations to make sure we have a non-0
+ // value returned from the creation routine.
+ // FIXME: this is clearly a hack, and should be cleaned up.
+ let key1 = imp::create(self.dtor);
+ let key = if key1 != 0 {
+ key1
+ } else {
+ let key2 = imp::create(self.dtor);
+ imp::destroy(key1);
+ key2
+ };
+ rtassert!(key != 0);
+ match self.key.compare_and_swap(0, key as usize, Ordering::SeqCst) {
+ // The CAS succeeded, so we've created the actual key
+ 0 => key as usize,
+ // If someone beat us to the punch, use their key instead
+ n => { imp::destroy(key); n }
+ }
+ }
+}
+
+impl Key {
+ /// Creates a new managed OS TLS key.
+ ///
+ /// This key will be deallocated when the key falls out of scope.
+ ///
+ /// The argument provided is an optionally-specified destructor for the
+ /// value of this TLS key. When a thread exits and the value for this key
+ /// is non-null the destructor will be invoked. The TLS value will be reset
+ /// to null before the destructor is invoked.
+ ///
+ /// Note that the destructor will not be run when the `Key` goes out of
+ /// scope.
+ #[inline]
+ pub fn new(dtor: Option<unsafe extern fn(*mut u8)>) -> Key {
+ Key { key: unsafe { imp::create(dtor) } }
+ }
+
+ /// See StaticKey::get
+ #[inline]
+ pub fn get(&self) -> *mut u8 {
+ unsafe { imp::get(self.key) }
+ }
+
+ /// See StaticKey::set
+ #[inline]
+ pub fn set(&self, val: *mut u8) {
+ unsafe { imp::set(self.key, val) }
+ }
+}
+
+impl Drop for Key {
+ fn drop(&mut self) {
+ // Right now Windows doesn't support TLS key destruction, but this also
+ // isn't used anywhere other than tests, so just leak the TLS key.
+ // unsafe { imp::destroy(self.key) }
+ }
+}
+
+pub unsafe fn register_dtor_fallback(t: *mut u8,
+ dtor: unsafe extern fn(*mut u8)) {
+ // The fallback implementation uses a vanilla OS-based TLS key to track
+ // the list of destructors that need to be run for this thread. The key
+ // then has its own destructor which runs all the other destructors.
+ //
+ // The destructor for DTORS is a little special in that it has a `while`
+ // loop to continuously drain the list of registered destructors. It
+ // *should* be the case that this loop always terminates because we
+ // provide the guarantee that a TLS key cannot be set after it is
+ // flagged for destruction.
+
+ static DTORS: StaticKey = StaticKey::new(Some(run_dtors));
+ type List = Vec<(*mut u8, unsafe extern fn(*mut u8))>;
+ if DTORS.get().is_null() {
+ let v: Box<List> = box Vec::new();
+ DTORS.set(Box::into_raw(v) as *mut u8);
+ }
+ let list: &mut List = &mut *(DTORS.get() as *mut List);
+ list.push((t, dtor));
+
+ unsafe extern fn run_dtors(mut ptr: *mut u8) {
+ while !ptr.is_null() {
+ let list: Box<List> = Box::from_raw(ptr as *mut List);
+ for (ptr, dtor) in list.into_iter() {
+ dtor(ptr);
+ }
+ ptr = DTORS.get();
+ DTORS.set(ptr::null_mut());
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::{Key, StaticKey};
+
+ fn assert_sync<T: Sync>() {}
+ fn assert_send<T: Send>() {}
+
+ #[test]
+ fn smoke() {
+ assert_sync::<Key>();
+ assert_send::<Key>();
+
+ let k1 = Key::new(None);
+ let k2 = Key::new(None);
+ assert!(k1.get().is_null());
+ assert!(k2.get().is_null());
+ k1.set(1 as *mut _);
+ k2.set(2 as *mut _);
+ assert_eq!(k1.get() as usize, 1);
+ assert_eq!(k2.get() as usize, 2);
+ }
+
+ #[test]
+ fn statik() {
+ static K1: StaticKey = StaticKey::new(None);
+ static K2: StaticKey = StaticKey::new(None);
+
+ unsafe {
+ assert!(K1.get().is_null());
+ assert!(K2.get().is_null());
+ K1.set(1 as *mut _);
+ K2.set(2 as *mut _);
+ assert_eq!(K1.get() as usize, 1);
+ assert_eq!(K2.get() as usize, 2);
+ }
+ }
+}
diff --git a/src/libstd/sys_common/util.rs b/src/libstd/sys_common/util.rs
new file mode 100644
index 0000000..7936dd3
--- /dev/null
+++ b/src/libstd/sys_common/util.rs
@@ -0,0 +1,26 @@
+use crate::fmt;
+use crate::io::prelude::*;
+use crate::sys::stdio::panic_output;
+use crate::thread;
+
+pub fn dumb_print(args: fmt::Arguments<'_>) {
+ if let Some(mut out) = panic_output() {
+ let _ = out.write_fmt(args);
+ }
+}
+
+// Other platforms should use the appropriate platform-specific mechanism for
+// aborting the process. If no platform-specific mechanism is available,
+// crate::intrinsics::abort() may be used instead. The above implementations cover
+// all targets currently supported by libstd.
+
+pub fn abort(args: fmt::Arguments<'_>) -> ! {
+ dumb_print(format_args!("fatal runtime error: {}\n", args));
+ unsafe { crate::sys::abort_internal(); }
+}
+
+#[allow(dead_code)] // stack overflow detection not enabled on all platforms
+pub unsafe fn report_overflow() {
+ dumb_print(format_args!("\nthread '{}' has overflowed its stack\n",
+ thread::current().name().unwrap_or("<unknown>")));
+}
diff --git a/src/libstd/sys_common/wtf8.rs b/src/libstd/sys_common/wtf8.rs
new file mode 100644
index 0000000..f17020d
--- /dev/null
+++ b/src/libstd/sys_common/wtf8.rs
@@ -0,0 +1,1255 @@
+//! Implementation of [the WTF-8 encoding](https://simonsapin.github.io/wtf-8/).
+//!
+//! This library uses Rust’s type system to maintain
+//! [well-formedness](https://simonsapin.github.io/wtf-8/#well-formed),
+//! like the `String` and `&str` types do for UTF-8.
+//!
+//! Since [WTF-8 must not be used
+//! for interchange](https://simonsapin.github.io/wtf-8/#intended-audience),
+//! this library deliberately does not provide access to the underlying bytes
+//! of WTF-8 strings,
+//! nor can it decode WTF-8 from arbitrary bytes.
+//! WTF-8 strings can be obtained from UTF-8, UTF-16, or code points.
+
+// this module is imported from @SimonSapin's repo and has tons of dead code on
+// unix (it's mostly used on windows), so don't worry about dead code here.
+#![allow(dead_code)]
+
+use core::str::next_code_point;
+
+use crate::borrow::Cow;
+use crate::char;
+use crate::fmt;
+use crate::hash::{Hash, Hasher};
+use crate::iter::FromIterator;
+use crate::mem;
+use crate::ops;
+use crate::rc::Rc;
+use crate::slice;
+use crate::str;
+use crate::sync::Arc;
+use crate::sys_common::AsInner;
+
+const UTF8_REPLACEMENT_CHARACTER: &str = "\u{FFFD}";
+
+/// A Unicode code point: from U+0000 to U+10FFFF.
+///
+/// Compares with the `char` type,
+/// which represents a Unicode scalar value:
+/// a code point that is not a surrogate (U+D800 to U+DFFF).
+#[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Copy)]
+pub struct CodePoint {
+ value: u32
+}
+
+/// Format the code point as `U+` followed by four to six hexadecimal digits.
+/// Example: `U+1F4A9`
+impl fmt::Debug for CodePoint {
+ #[inline]
+ fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(formatter, "U+{:04X}", self.value)
+ }
+}
+
+impl CodePoint {
+ /// Unsafely creates a new `CodePoint` without checking the value.
+ ///
+ /// Only use when `value` is known to be less than or equal to 0x10FFFF.
+ #[inline]
+ pub unsafe fn from_u32_unchecked(value: u32) -> CodePoint {
+ CodePoint { value }
+ }
+
+ /// Creates a new `CodePoint` if the value is a valid code point.
+ ///
+ /// Returns `None` if `value` is above 0x10FFFF.
+ #[inline]
+ pub fn from_u32(value: u32) -> Option<CodePoint> {
+ match value {
+ 0 ..= 0x10FFFF => Some(CodePoint { value }),
+ _ => None
+ }
+ }
+
+ /// Creates a new `CodePoint` from a `char`.
+ ///
+ /// Since all Unicode scalar values are code points, this always succeeds.
+ #[inline]
+ pub fn from_char(value: char) -> CodePoint {
+ CodePoint { value: value as u32 }
+ }
+
+ /// Returns the numeric value of the code point.
+ #[inline]
+ pub fn to_u32(&self) -> u32 {
+ self.value
+ }
+
+ /// Optionally returns a Unicode scalar value for the code point.
+ ///
+ /// Returns `None` if the code point is a surrogate (from U+D800 to U+DFFF).
+ #[inline]
+ pub fn to_char(&self) -> Option<char> {
+ match self.value {
+ 0xD800 ..= 0xDFFF => None,
+ _ => Some(unsafe { char::from_u32_unchecked(self.value) })
+ }
+ }
+
+ /// Returns a Unicode scalar value for the code point.
+ ///
+ /// Returns `'\u{FFFD}'` (the replacement character “�”)
+ /// if the code point is a surrogate (from U+D800 to U+DFFF).
+ #[inline]
+ pub fn to_char_lossy(&self) -> char {
+ self.to_char().unwrap_or('\u{FFFD}')
+ }
+}
+
+/// An owned, growable string of well-formed WTF-8 data.
+///
+/// Similar to `String`, but can additionally contain surrogate code points
+/// if they’re not in a surrogate pair.
+#[derive(Eq, PartialEq, Ord, PartialOrd, Clone)]
+pub struct Wtf8Buf {
+ bytes: Vec<u8>
+}
+
+impl ops::Deref for Wtf8Buf {
+ type Target = Wtf8;
+
+ fn deref(&self) -> &Wtf8 {
+ self.as_slice()
+ }
+}
+
+impl ops::DerefMut for Wtf8Buf {
+ fn deref_mut(&mut self) -> &mut Wtf8 {
+ self.as_mut_slice()
+ }
+}
+
+/// Format the string with double quotes,
+/// and surrogates as `\u` followed by four hexadecimal digits.
+/// Example: `"a\u{D800}"` for a string with code points [U+0061, U+D800]
+impl fmt::Debug for Wtf8Buf {
+ #[inline]
+ fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt::Debug::fmt(&**self, formatter)
+ }
+}
+
+impl Wtf8Buf {
+ /// Creates a new, empty WTF-8 string.
+ #[inline]
+ pub fn new() -> Wtf8Buf {
+ Wtf8Buf { bytes: Vec::new() }
+ }
+
+ /// Creates a new, empty WTF-8 string with pre-allocated capacity for `n` bytes.
+ #[inline]
+ pub fn with_capacity(n: usize) -> Wtf8Buf {
+ Wtf8Buf { bytes: Vec::with_capacity(n) }
+ }
+
+ /// Creates a WTF-8 string from a UTF-8 `String`.
+ ///
+ /// This takes ownership of the `String` and does not copy.
+ ///
+ /// Since WTF-8 is a superset of UTF-8, this always succeeds.
+ #[inline]
+ pub fn from_string(string: String) -> Wtf8Buf {
+ Wtf8Buf { bytes: string.into_bytes() }
+ }
+
+ /// Creates a WTF-8 string from a UTF-8 `&str` slice.
+ ///
+ /// This copies the content of the slice.
+ ///
+ /// Since WTF-8 is a superset of UTF-8, this always succeeds.
+ #[inline]
+ pub fn from_str(str: &str) -> Wtf8Buf {
+ Wtf8Buf { bytes: <[_]>::to_vec(str.as_bytes()) }
+ }
+
+ pub fn clear(&mut self) {
+ self.bytes.clear()
+ }
+
+ /// Creates a WTF-8 string from a potentially ill-formed UTF-16 slice of 16-bit code units.
+ ///
+ /// This is lossless: calling `.encode_wide()` on the resulting string
+ /// will always return the original code units.
+ pub fn from_wide(v: &[u16]) -> Wtf8Buf {
+ let mut string = Wtf8Buf::with_capacity(v.len());
+ for item in char::decode_utf16(v.iter().cloned()) {
+ match item {
+ Ok(ch) => string.push_char(ch),
+ Err(surrogate) => {
+ let surrogate = surrogate.unpaired_surrogate();
+ // Surrogates are known to be in the code point range.
+ let code_point = unsafe {
+ CodePoint::from_u32_unchecked(surrogate as u32)
+ };
+ // Skip the WTF-8 concatenation check,
+ // surrogate pairs are already decoded by decode_utf16
+ string.push_code_point_unchecked(code_point)
+ }
+ }
+ }
+ string
+ }
+
+ /// Copied from String::push
+ /// This does **not** include the WTF-8 concatenation check.
+ fn push_code_point_unchecked(&mut self, code_point: CodePoint) {
+ let c = unsafe {
+ char::from_u32_unchecked(code_point.value)
+ };
+ let mut bytes = [0; 4];
+ let bytes = c.encode_utf8(&mut bytes).as_bytes();
+ self.bytes.extend_from_slice(bytes)
+ }
+
+ #[inline]
+ pub fn as_slice(&self) -> &Wtf8 {
+ unsafe { Wtf8::from_bytes_unchecked(&self.bytes) }
+ }
+
+ #[inline]
+ pub fn as_mut_slice(&mut self) -> &mut Wtf8 {
+ unsafe { Wtf8::from_mut_bytes_unchecked(&mut self.bytes) }
+ }
+
+ /// Reserves capacity for at least `additional` more bytes to be inserted
+ /// in the given `Wtf8Buf`.
+ /// The collection may reserve more space to avoid frequent reallocations.
+ ///
+ /// # Panics
+ ///
+ /// Panics if the new capacity overflows `usize`.
+ #[inline]
+ pub fn reserve(&mut self, additional: usize) {
+ self.bytes.reserve(additional)
+ }
+
+ #[inline]
+ pub fn reserve_exact(&mut self, additional: usize) {
+ self.bytes.reserve_exact(additional)
+ }
+
+ #[inline]
+ pub fn shrink_to_fit(&mut self) {
+ self.bytes.shrink_to_fit()
+ }
+
+ #[inline]
+ pub fn shrink_to(&mut self, min_capacity: usize) {
+ self.bytes.shrink_to(min_capacity)
+ }
+
+ /// Returns the number of bytes that this string buffer can hold without reallocating.
+ #[inline]
+ pub fn capacity(&self) -> usize {
+ self.bytes.capacity()
+ }
+
+ /// Append a UTF-8 slice at the end of the string.
+ #[inline]
+ pub fn push_str(&mut self, other: &str) {
+ self.bytes.extend_from_slice(other.as_bytes())
+ }
+
+ /// Append a WTF-8 slice at the end of the string.
+ ///
+ /// This replaces newly paired surrogates at the boundary
+ /// with a supplementary code point,
+ /// like concatenating ill-formed UTF-16 strings effectively would.
+ #[inline]
+ pub fn push_wtf8(&mut self, other: &Wtf8) {
+ match ((&*self).final_lead_surrogate(), other.initial_trail_surrogate()) {
+ // Replace newly paired surrogates by a supplementary code point.
+ (Some(lead), Some(trail)) => {
+ let len_without_lead_surrogate = self.len() - 3;
+ self.bytes.truncate(len_without_lead_surrogate);
+ let other_without_trail_surrogate = &other.bytes[3..];
+ // 4 bytes for the supplementary code point
+ self.bytes.reserve(4 + other_without_trail_surrogate.len());
+ self.push_char(decode_surrogate_pair(lead, trail));
+ self.bytes.extend_from_slice(other_without_trail_surrogate);
+ }
+ _ => self.bytes.extend_from_slice(&other.bytes)
+ }
+ }
+
+ /// Append a Unicode scalar value at the end of the string.
+ #[inline]
+ pub fn push_char(&mut self, c: char) {
+ self.push_code_point_unchecked(CodePoint::from_char(c))
+ }
+
+ /// Append a code point at the end of the string.
+ ///
+ /// This replaces newly paired surrogates at the boundary
+ /// with a supplementary code point,
+ /// like concatenating ill-formed UTF-16 strings effectively would.
+ #[inline]
+ pub fn push(&mut self, code_point: CodePoint) {
+ if let trail @ 0xDC00..=0xDFFF = code_point.to_u32() {
+ if let Some(lead) = (&*self).final_lead_surrogate() {
+ let len_without_lead_surrogate = self.len() - 3;
+ self.bytes.truncate(len_without_lead_surrogate);
+ self.push_char(decode_surrogate_pair(lead, trail as u16));
+ return
+ }
+ }
+
+ // No newly paired surrogates at the boundary.
+ self.push_code_point_unchecked(code_point)
+ }
+
+ /// Shortens a string to the specified length.
+ ///
+ /// # Panics
+ ///
+ /// Panics if `new_len` > current length,
+ /// or if `new_len` is not a code point boundary.
+ #[inline]
+ pub fn truncate(&mut self, new_len: usize) {
+ assert!(is_code_point_boundary(self, new_len));
+ self.bytes.truncate(new_len)
+ }
+
+ /// Consumes the WTF-8 string and tries to convert it to UTF-8.
+ ///
+ /// This does not copy the data.
+ ///
+ /// If the contents are not well-formed UTF-8
+ /// (that is, if the string contains surrogates),
+ /// the original WTF-8 string is returned instead.
+ pub fn into_string(self) -> Result<String, Wtf8Buf> {
+ match self.next_surrogate(0) {
+ None => Ok(unsafe { String::from_utf8_unchecked(self.bytes) }),
+ Some(_) => Err(self),
+ }
+ }
+
+ /// Consumes the WTF-8 string and converts it lossily to UTF-8.
+ ///
+ /// This does not copy the data (but may overwrite parts of it in place).
+ ///
+ /// Surrogates are replaced with `"\u{FFFD}"` (the replacement character “�”)
+ pub fn into_string_lossy(mut self) -> String {
+ let mut pos = 0;
+ loop {
+ match self.next_surrogate(pos) {
+ Some((surrogate_pos, _)) => {
+ pos = surrogate_pos + 3;
+ self.bytes[surrogate_pos..pos]
+ .copy_from_slice(UTF8_REPLACEMENT_CHARACTER.as_bytes());
+ },
+ None => return unsafe { String::from_utf8_unchecked(self.bytes) }
+ }
+ }
+ }
+
+ /// Converts this `Wtf8Buf` into a boxed `Wtf8`.
+ #[inline]
+ pub fn into_box(self) -> Box<Wtf8> {
+ unsafe { mem::transmute(self.bytes.into_boxed_slice()) }
+ }
+
+ /// Converts a `Box<Wtf8>` into a `Wtf8Buf`.
+ pub fn from_box(boxed: Box<Wtf8>) -> Wtf8Buf {
+ let bytes: Box<[u8]> = unsafe { mem::transmute(boxed) };
+ Wtf8Buf { bytes: bytes.into_vec() }
+ }
+}
+
+/// Creates a new WTF-8 string from an iterator of code points.
+///
+/// This replaces surrogate code point pairs with supplementary code points,
+/// like concatenating ill-formed UTF-16 strings effectively would.
+impl FromIterator<CodePoint> for Wtf8Buf {
+ fn from_iter<T: IntoIterator<Item=CodePoint>>(iter: T) -> Wtf8Buf {
+ let mut string = Wtf8Buf::new();
+ string.extend(iter);
+ string
+ }
+}
+
+/// Append code points from an iterator to the string.
+///
+/// This replaces surrogate code point pairs with supplementary code points,
+/// like concatenating ill-formed UTF-16 strings effectively would.
+impl Extend<CodePoint> for Wtf8Buf {
+ fn extend<T: IntoIterator<Item=CodePoint>>(&mut self, iter: T) {
+ let iterator = iter.into_iter();
+ let (low, _high) = iterator.size_hint();
+ // Lower bound of one byte per code point (ASCII only)
+ self.bytes.reserve(low);
+ iterator.for_each(move |code_point| self.push(code_point));
+ }
+}
+
+/// A borrowed slice of well-formed WTF-8 data.
+///
+/// Similar to `&str`, but can additionally contain surrogate code points
+/// if they’re not in a surrogate pair.
+#[derive(Eq, Ord, PartialEq, PartialOrd)]
+pub struct Wtf8 {
+ bytes: [u8]
+}
+
+impl AsInner<[u8]> for Wtf8 {
+ fn as_inner(&self) -> &[u8] { &self.bytes }
+}
+
+/// Format the slice with double quotes,
+/// and surrogates as `\u` followed by four hexadecimal digits.
+/// Example: `"a\u{D800}"` for a slice with code points [U+0061, U+D800]
+impl fmt::Debug for Wtf8 {
+ fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fn write_str_escaped(f: &mut fmt::Formatter<'_>, s: &str) -> fmt::Result {
+ use crate::fmt::Write;
+ for c in s.chars().flat_map(|c| c.escape_debug()) {
+ f.write_char(c)?
+ }
+ Ok(())
+ }
+
+ formatter.write_str("\"")?;
+ let mut pos = 0;
+ while let Some((surrogate_pos, surrogate)) = self.next_surrogate(pos) {
+ write_str_escaped(
+ formatter,
+ unsafe { str::from_utf8_unchecked(
+ &self.bytes[pos .. surrogate_pos]
+ )},
+ )?;
+ write!(formatter, "\\u{{{:x}}}", surrogate)?;
+ pos = surrogate_pos + 3;
+ }
+ write_str_escaped(
+ formatter,
+ unsafe { str::from_utf8_unchecked(&self.bytes[pos..]) },
+ )?;
+ formatter.write_str("\"")
+ }
+}
+
+impl fmt::Display for Wtf8 {
+ fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+ let wtf8_bytes = &self.bytes;
+ let mut pos = 0;
+ loop {
+ match self.next_surrogate(pos) {
+ Some((surrogate_pos, _)) => {
+ formatter.write_str(unsafe {
+ str::from_utf8_unchecked(&wtf8_bytes[pos .. surrogate_pos])
+ })?;
+ formatter.write_str(UTF8_REPLACEMENT_CHARACTER)?;
+ pos = surrogate_pos + 3;
+ },
+ None => {
+ let s = unsafe {
+ str::from_utf8_unchecked(&wtf8_bytes[pos..])
+ };
+ if pos == 0 {
+ return s.fmt(formatter)
+ } else {
+ return formatter.write_str(s)
+ }
+ }
+ }
+ }
+ }
+}
+
+impl Wtf8 {
+ /// Creates a WTF-8 slice from a UTF-8 `&str` slice.
+ ///
+ /// Since WTF-8 is a superset of UTF-8, this always succeeds.
+ #[inline]
+ pub fn from_str(value: &str) -> &Wtf8 {
+ unsafe { Wtf8::from_bytes_unchecked(value.as_bytes()) }
+ }
+
+ /// Creates a WTF-8 slice from a WTF-8 byte slice.
+ ///
+ /// Since the byte slice is not checked for valid WTF-8, this functions is
+ /// marked unsafe.
+ #[inline]
+ unsafe fn from_bytes_unchecked(value: &[u8]) -> &Wtf8 {
+ mem::transmute(value)
+ }
+
+ /// Creates a mutable WTF-8 slice from a mutable WTF-8 byte slice.
+ ///
+ /// Since the byte slice is not checked for valid WTF-8, this functions is
+ /// marked unsafe.
+ #[inline]
+ unsafe fn from_mut_bytes_unchecked(value: &mut [u8]) -> &mut Wtf8 {
+ mem::transmute(value)
+ }
+
+ /// Returns the length, in WTF-8 bytes.
+ #[inline]
+ pub fn len(&self) -> usize {
+ self.bytes.len()
+ }
+
+ #[inline]
+ pub fn is_empty(&self) -> bool {
+ self.bytes.is_empty()
+ }
+
+ /// Returns the code point at `position` if it is in the ASCII range,
+ /// or `b'\xFF' otherwise.
+ ///
+ /// # Panics
+ ///
+ /// Panics if `position` is beyond the end of the string.
+ #[inline]
+ pub fn ascii_byte_at(&self, position: usize) -> u8 {
+ match self.bytes[position] {
+ ascii_byte @ 0x00 ..= 0x7F => ascii_byte,
+ _ => 0xFF
+ }
+ }
+
+ /// Returns an iterator for the string’s code points.
+ #[inline]
+ pub fn code_points(&self) -> Wtf8CodePoints<'_> {
+ Wtf8CodePoints { bytes: self.bytes.iter() }
+ }
+
+ /// Tries to convert the string to UTF-8 and return a `&str` slice.
+ ///
+ /// Returns `None` if the string contains surrogates.
+ ///
+ /// This does not copy the data.
+ #[inline]
+ pub fn as_str(&self) -> Option<&str> {
+ // Well-formed WTF-8 is also well-formed UTF-8
+ // if and only if it contains no surrogate.
+ match self.next_surrogate(0) {
+ None => Some(unsafe { str::from_utf8_unchecked(&self.bytes) }),
+ Some(_) => None,
+ }
+ }
+
+ /// Lossily converts the string to UTF-8.
+ /// Returns a UTF-8 `&str` slice if the contents are well-formed in UTF-8.
+ ///
+ /// Surrogates are replaced with `"\u{FFFD}"` (the replacement character “�”).
+ ///
+ /// This only copies the data if necessary (if it contains any surrogate).
+ pub fn to_string_lossy(&self) -> Cow<'_, str> {
+ let surrogate_pos = match self.next_surrogate(0) {
+ None => return Cow::Borrowed(unsafe { str::from_utf8_unchecked(&self.bytes) }),
+ Some((pos, _)) => pos,
+ };
+ let wtf8_bytes = &self.bytes;
+ let mut utf8_bytes = Vec::with_capacity(self.len());
+ utf8_bytes.extend_from_slice(&wtf8_bytes[..surrogate_pos]);
+ utf8_bytes.extend_from_slice(UTF8_REPLACEMENT_CHARACTER.as_bytes());
+ let mut pos = surrogate_pos + 3;
+ loop {
+ match self.next_surrogate(pos) {
+ Some((surrogate_pos, _)) => {
+ utf8_bytes.extend_from_slice(&wtf8_bytes[pos .. surrogate_pos]);
+ utf8_bytes.extend_from_slice(UTF8_REPLACEMENT_CHARACTER.as_bytes());
+ pos = surrogate_pos + 3;
+ },
+ None => {
+ utf8_bytes.extend_from_slice(&wtf8_bytes[pos..]);
+ return Cow::Owned(unsafe { String::from_utf8_unchecked(utf8_bytes) })
+ }
+ }
+ }
+ }
+
+ /// Converts the WTF-8 string to potentially ill-formed UTF-16
+ /// and return an iterator of 16-bit code units.
+ ///
+ /// This is lossless:
+ /// calling `Wtf8Buf::from_ill_formed_utf16` on the resulting code units
+ /// would always return the original WTF-8 string.
+ #[inline]
+ pub fn encode_wide(&self) -> EncodeWide<'_> {
+ EncodeWide { code_points: self.code_points(), extra: 0 }
+ }
+
+ #[inline]
+ fn next_surrogate(&self, mut pos: usize) -> Option<(usize, u16)> {
+ let mut iter = self.bytes[pos..].iter();
+ loop {
+ let b = *iter.next()?;
+ if b < 0x80 {
+ pos += 1;
+ } else if b < 0xE0 {
+ iter.next();
+ pos += 2;
+ } else if b == 0xED {
+ match (iter.next(), iter.next()) {
+ (Some(&b2), Some(&b3)) if b2 >= 0xA0 => {
+ return Some((pos, decode_surrogate(b2, b3)))
+ }
+ _ => pos += 3
+ }
+ } else if b < 0xF0 {
+ iter.next();
+ iter.next();
+ pos += 3;
+ } else {
+ iter.next();
+ iter.next();
+ iter.next();
+ pos += 4;
+ }
+ }
+ }
+
+ #[inline]
+ fn final_lead_surrogate(&self) -> Option<u16> {
+ let len = self.len();
+ if len < 3 {
+ return None
+ }
+ match &self.bytes[(len - 3)..] {
+ &[0xED, b2 @ 0xA0..=0xAF, b3] => Some(decode_surrogate(b2, b3)),
+ _ => None
+ }
+ }
+
+ #[inline]
+ fn initial_trail_surrogate(&self) -> Option<u16> {
+ let len = self.len();
+ if len < 3 {
+ return None
+ }
+ match &self.bytes[..3] {
+ &[0xED, b2 @ 0xB0..=0xBF, b3] => Some(decode_surrogate(b2, b3)),
+ _ => None
+ }
+ }
+
+ /// Boxes this `Wtf8`.
+ #[inline]
+ pub fn into_box(&self) -> Box<Wtf8> {
+ let boxed: Box<[u8]> = self.bytes.into();
+ unsafe { mem::transmute(boxed) }
+ }
+
+ /// Creates a boxed, empty `Wtf8`.
+ pub fn empty_box() -> Box<Wtf8> {
+ let boxed: Box<[u8]> = Default::default();
+ unsafe { mem::transmute(boxed) }
+ }
+
+ #[inline]
+ pub fn into_arc(&self) -> Arc<Wtf8> {
+ let arc: Arc<[u8]> = Arc::from(&self.bytes);
+ unsafe { Arc::from_raw(Arc::into_raw(arc) as *const Wtf8) }
+ }
+
+ #[inline]
+ pub fn into_rc(&self) -> Rc<Wtf8> {
+ let rc: Rc<[u8]> = Rc::from(&self.bytes);
+ unsafe { Rc::from_raw(Rc::into_raw(rc) as *const Wtf8) }
+ }
+}
+
+
+/// Returns a slice of the given string for the byte range [`begin`..`end`).
+///
+/// # Panics
+///
+/// Panics when `begin` and `end` do not point to code point boundaries,
+/// or point beyond the end of the string.
+impl ops::Index<ops::Range<usize>> for Wtf8 {
+ type Output = Wtf8;
+
+ #[inline]
+ fn index(&self, range: ops::Range<usize>) -> &Wtf8 {
+ // is_code_point_boundary checks that the index is in [0, .len()]
+ if range.start <= range.end &&
+ is_code_point_boundary(self, range.start) &&
+ is_code_point_boundary(self, range.end) {
+ unsafe { slice_unchecked(self, range.start, range.end) }
+ } else {
+ slice_error_fail(self, range.start, range.end)
+ }
+ }
+}
+
+/// Returns a slice of the given string from byte `begin` to its end.
+///
+/// # Panics
+///
+/// Panics when `begin` is not at a code point boundary,
+/// or is beyond the end of the string.
+impl ops::Index<ops::RangeFrom<usize>> for Wtf8 {
+ type Output = Wtf8;
+
+ #[inline]
+ fn index(&self, range: ops::RangeFrom<usize>) -> &Wtf8 {
+ // is_code_point_boundary checks that the index is in [0, .len()]
+ if is_code_point_boundary(self, range.start) {
+ unsafe { slice_unchecked(self, range.start, self.len()) }
+ } else {
+ slice_error_fail(self, range.start, self.len())
+ }
+ }
+}
+
+/// Returns a slice of the given string from its beginning to byte `end`.
+///
+/// # Panics
+///
+/// Panics when `end` is not at a code point boundary,
+/// or is beyond the end of the string.
+impl ops::Index<ops::RangeTo<usize>> for Wtf8 {
+ type Output = Wtf8;
+
+ #[inline]
+ fn index(&self, range: ops::RangeTo<usize>) -> &Wtf8 {
+ // is_code_point_boundary checks that the index is in [0, .len()]
+ if is_code_point_boundary(self, range.end) {
+ unsafe { slice_unchecked(self, 0, range.end) }
+ } else {
+ slice_error_fail(self, 0, range.end)
+ }
+ }
+}
+
+impl ops::Index<ops::RangeFull> for Wtf8 {
+ type Output = Wtf8;
+
+ #[inline]
+ fn index(&self, _range: ops::RangeFull) -> &Wtf8 {
+ self
+ }
+}
+
+#[inline]
+fn decode_surrogate(second_byte: u8, third_byte: u8) -> u16 {
+ // The first byte is assumed to be 0xED
+ 0xD800 | (second_byte as u16 & 0x3F) << 6 | third_byte as u16 & 0x3F
+}
+
+#[inline]
+fn decode_surrogate_pair(lead: u16, trail: u16) -> char {
+ let code_point = 0x10000 + ((((lead - 0xD800) as u32) << 10) | (trail - 0xDC00) as u32);
+ unsafe { char::from_u32_unchecked(code_point) }
+}
+
+/// Copied from core::str::StrPrelude::is_char_boundary
+#[inline]
+pub fn is_code_point_boundary(slice: &Wtf8, index: usize) -> bool {
+ if index == slice.len() { return true; }
+ match slice.bytes.get(index) {
+ None => false,
+ Some(&b) => b < 128 || b >= 192,
+ }
+}
+
+/// Copied from core::str::raw::slice_unchecked
+#[inline]
+pub unsafe fn slice_unchecked(s: &Wtf8, begin: usize, end: usize) -> &Wtf8 {
+ // memory layout of an &[u8] and &Wtf8 are the same
+ Wtf8::from_bytes_unchecked(slice::from_raw_parts(
+ s.bytes.as_ptr().add(begin),
+ end - begin
+ ))
+}
+
+/// Copied from core::str::raw::slice_error_fail
+#[inline(never)]
+pub fn slice_error_fail(s: &Wtf8, begin: usize, end: usize) -> ! {
+ assert!(begin <= end);
+ panic!("index {} and/or {} in `{:?}` do not lie on character boundary",
+ begin, end, s);
+}
+
+/// Iterator for the code points of a WTF-8 string.
+///
+/// Created with the method `.code_points()`.
+#[derive(Clone)]
+pub struct Wtf8CodePoints<'a> {
+ bytes: slice::Iter<'a, u8>
+}
+
+impl<'a> Iterator for Wtf8CodePoints<'a> {
+ type Item = CodePoint;
+
+ #[inline]
+ fn next(&mut self) -> Option<CodePoint> {
+ next_code_point(&mut self.bytes).map(|c| CodePoint { value: c })
+ }
+
+ #[inline]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ let len = self.bytes.len();
+ (len.saturating_add(3) / 4, Some(len))
+ }
+}
+
+/// Generates a wide character sequence for potentially ill-formed UTF-16.
+#[stable(feature = "rust1", since = "1.0.0")]
+#[derive(Clone)]
+pub struct EncodeWide<'a> {
+ code_points: Wtf8CodePoints<'a>,
+ extra: u16
+}
+
+// Copied from libunicode/u_str.rs
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a> Iterator for EncodeWide<'a> {
+ type Item = u16;
+
+ #[inline]
+ fn next(&mut self) -> Option<u16> {
+ if self.extra != 0 {
+ let tmp = self.extra;
+ self.extra = 0;
+ return Some(tmp);
+ }
+
+ let mut buf = [0; 2];
+ self.code_points.next().map(|code_point| {
+ let c = unsafe {
+ char::from_u32_unchecked(code_point.value)
+ };
+ let n = c.encode_utf16(&mut buf).len();
+ if n == 2 {
+ self.extra = buf[1];
+ }
+ buf[0]
+ })
+ }
+
+ #[inline]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ let (low, high) = self.code_points.size_hint();
+ // every code point gets either one u16 or two u16,
+ // so this iterator is between 1 or 2 times as
+ // long as the underlying iterator.
+ (low, high.and_then(|n| n.checked_mul(2)))
+ }
+}
+
+impl Hash for CodePoint {
+ #[inline]
+ fn hash<H: Hasher>(&self, state: &mut H) {
+ self.value.hash(state)
+ }
+}
+
+impl Hash for Wtf8Buf {
+ #[inline]
+ fn hash<H: Hasher>(&self, state: &mut H) {
+ state.write(&self.bytes);
+ 0xfeu8.hash(state)
+ }
+}
+
+impl Hash for Wtf8 {
+ #[inline]
+ fn hash<H: Hasher>(&self, state: &mut H) {
+ state.write(&self.bytes);
+ 0xfeu8.hash(state)
+ }
+}
+
+impl Wtf8 {
+ pub fn make_ascii_uppercase(&mut self) { self.bytes.make_ascii_uppercase() }
+}
+
+#[cfg(test)]
+mod tests {
+ use crate::borrow::Cow;
+ use super::*;
+
+ #[test]
+ fn code_point_from_u32() {
+ assert!(CodePoint::from_u32(0).is_some());
+ assert!(CodePoint::from_u32(0xD800).is_some());
+ assert!(CodePoint::from_u32(0x10FFFF).is_some());
+ assert!(CodePoint::from_u32(0x110000).is_none());
+ }
+
+ #[test]
+ fn code_point_to_u32() {
+ fn c(value: u32) -> CodePoint { CodePoint::from_u32(value).unwrap() }
+ assert_eq!(c(0).to_u32(), 0);
+ assert_eq!(c(0xD800).to_u32(), 0xD800);
+ assert_eq!(c(0x10FFFF).to_u32(), 0x10FFFF);
+ }
+
+ #[test]
+ fn code_point_from_char() {
+ assert_eq!(CodePoint::from_char('a').to_u32(), 0x61);
+ assert_eq!(CodePoint::from_char('💩').to_u32(), 0x1F4A9);
+ }
+
+ #[test]
+ fn code_point_to_string() {
+ assert_eq!(format!("{:?}", CodePoint::from_char('a')), "U+0061");
+ assert_eq!(format!("{:?}", CodePoint::from_char('💩')), "U+1F4A9");
+ }
+
+ #[test]
+ fn code_point_to_char() {
+ fn c(value: u32) -> CodePoint { CodePoint::from_u32(value).unwrap() }
+ assert_eq!(c(0x61).to_char(), Some('a'));
+ assert_eq!(c(0x1F4A9).to_char(), Some('💩'));
+ assert_eq!(c(0xD800).to_char(), None);
+ }
+
+ #[test]
+ fn code_point_to_char_lossy() {
+ fn c(value: u32) -> CodePoint { CodePoint::from_u32(value).unwrap() }
+ assert_eq!(c(0x61).to_char_lossy(), 'a');
+ assert_eq!(c(0x1F4A9).to_char_lossy(), '💩');
+ assert_eq!(c(0xD800).to_char_lossy(), '\u{FFFD}');
+ }
+
+ #[test]
+ fn wtf8buf_new() {
+ assert_eq!(Wtf8Buf::new().bytes, b"");
+ }
+
+ #[test]
+ fn wtf8buf_from_str() {
+ assert_eq!(Wtf8Buf::from_str("").bytes, b"");
+ assert_eq!(Wtf8Buf::from_str("aé 💩").bytes,
+ b"a\xC3\xA9 \xF0\x9F\x92\xA9");
+ }
+
+ #[test]
+ fn wtf8buf_from_string() {
+ assert_eq!(Wtf8Buf::from_string(String::from("")).bytes, b"");
+ assert_eq!(Wtf8Buf::from_string(String::from("aé 💩")).bytes,
+ b"a\xC3\xA9 \xF0\x9F\x92\xA9");
+ }
+
+ #[test]
+ fn wtf8buf_from_wide() {
+ assert_eq!(Wtf8Buf::from_wide(&[]).bytes, b"");
+ assert_eq!(Wtf8Buf::from_wide(
+ &[0x61, 0xE9, 0x20, 0xD83D, 0xD83D, 0xDCA9]).bytes,
+ b"a\xC3\xA9 \xED\xA0\xBD\xF0\x9F\x92\xA9");
+ }
+
+ #[test]
+ fn wtf8buf_push_str() {
+ let mut string = Wtf8Buf::new();
+ assert_eq!(string.bytes, b"");
+ string.push_str("aé 💩");
+ assert_eq!(string.bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9");
+ }
+
+ #[test]
+ fn wtf8buf_push_char() {
+ let mut string = Wtf8Buf::from_str("aé ");
+ assert_eq!(string.bytes, b"a\xC3\xA9 ");
+ string.push_char('💩');
+ assert_eq!(string.bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9");
+ }
+
+ #[test]
+ fn wtf8buf_push() {
+ let mut string = Wtf8Buf::from_str("aé ");
+ assert_eq!(string.bytes, b"a\xC3\xA9 ");
+ string.push(CodePoint::from_char('💩'));
+ assert_eq!(string.bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9");
+
+ fn c(value: u32) -> CodePoint { CodePoint::from_u32(value).unwrap() }
+
+ let mut string = Wtf8Buf::new();
+ string.push(c(0xD83D)); // lead
+ string.push(c(0xDCA9)); // trail
+ assert_eq!(string.bytes, b"\xF0\x9F\x92\xA9"); // Magic!
+
+ let mut string = Wtf8Buf::new();
+ string.push(c(0xD83D)); // lead
+ string.push(c(0x20)); // not surrogate
+ string.push(c(0xDCA9)); // trail
+ assert_eq!(string.bytes, b"\xED\xA0\xBD \xED\xB2\xA9");
+
+ let mut string = Wtf8Buf::new();
+ string.push(c(0xD800)); // lead
+ string.push(c(0xDBFF)); // lead
+ assert_eq!(string.bytes, b"\xED\xA0\x80\xED\xAF\xBF");
+
+ let mut string = Wtf8Buf::new();
+ string.push(c(0xD800)); // lead
+ string.push(c(0xE000)); // not surrogate
+ assert_eq!(string.bytes, b"\xED\xA0\x80\xEE\x80\x80");
+
+ let mut string = Wtf8Buf::new();
+ string.push(c(0xD7FF)); // not surrogate
+ string.push(c(0xDC00)); // trail
+ assert_eq!(string.bytes, b"\xED\x9F\xBF\xED\xB0\x80");
+
+ let mut string = Wtf8Buf::new();
+ string.push(c(0x61)); // not surrogate, < 3 bytes
+ string.push(c(0xDC00)); // trail
+ assert_eq!(string.bytes, b"\x61\xED\xB0\x80");
+
+ let mut string = Wtf8Buf::new();
+ string.push(c(0xDC00)); // trail
+ assert_eq!(string.bytes, b"\xED\xB0\x80");
+ }
+
+ #[test]
+ fn wtf8buf_push_wtf8() {
+ let mut string = Wtf8Buf::from_str("aé");
+ assert_eq!(string.bytes, b"a\xC3\xA9");
+ string.push_wtf8(Wtf8::from_str(" 💩"));
+ assert_eq!(string.bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9");
+
+ fn w(v: &[u8]) -> &Wtf8 { unsafe { Wtf8::from_bytes_unchecked(v) } }
+
+ let mut string = Wtf8Buf::new();
+ string.push_wtf8(w(b"\xED\xA0\xBD")); // lead
+ string.push_wtf8(w(b"\xED\xB2\xA9")); // trail
+ assert_eq!(string.bytes, b"\xF0\x9F\x92\xA9"); // Magic!
+
+ let mut string = Wtf8Buf::new();
+ string.push_wtf8(w(b"\xED\xA0\xBD")); // lead
+ string.push_wtf8(w(b" ")); // not surrogate
+ string.push_wtf8(w(b"\xED\xB2\xA9")); // trail
+ assert_eq!(string.bytes, b"\xED\xA0\xBD \xED\xB2\xA9");
+
+ let mut string = Wtf8Buf::new();
+ string.push_wtf8(w(b"\xED\xA0\x80")); // lead
+ string.push_wtf8(w(b"\xED\xAF\xBF")); // lead
+ assert_eq!(string.bytes, b"\xED\xA0\x80\xED\xAF\xBF");
+
+ let mut string = Wtf8Buf::new();
+ string.push_wtf8(w(b"\xED\xA0\x80")); // lead
+ string.push_wtf8(w(b"\xEE\x80\x80")); // not surrogate
+ assert_eq!(string.bytes, b"\xED\xA0\x80\xEE\x80\x80");
+
+ let mut string = Wtf8Buf::new();
+ string.push_wtf8(w(b"\xED\x9F\xBF")); // not surrogate
+ string.push_wtf8(w(b"\xED\xB0\x80")); // trail
+ assert_eq!(string.bytes, b"\xED\x9F\xBF\xED\xB0\x80");
+
+ let mut string = Wtf8Buf::new();
+ string.push_wtf8(w(b"a")); // not surrogate, < 3 bytes
+ string.push_wtf8(w(b"\xED\xB0\x80")); // trail
+ assert_eq!(string.bytes, b"\x61\xED\xB0\x80");
+
+ let mut string = Wtf8Buf::new();
+ string.push_wtf8(w(b"\xED\xB0\x80")); // trail
+ assert_eq!(string.bytes, b"\xED\xB0\x80");
+ }
+
+ #[test]
+ fn wtf8buf_truncate() {
+ let mut string = Wtf8Buf::from_str("aé");
+ string.truncate(1);
+ assert_eq!(string.bytes, b"a");
+ }
+
+ #[test]
+ #[should_panic]
+ fn wtf8buf_truncate_fail_code_point_boundary() {
+ let mut string = Wtf8Buf::from_str("aé");
+ string.truncate(2);
+ }
+
+ #[test]
+ #[should_panic]
+ fn wtf8buf_truncate_fail_longer() {
+ let mut string = Wtf8Buf::from_str("aé");
+ string.truncate(4);
+ }
+
+ #[test]
+ fn wtf8buf_into_string() {
+ let mut string = Wtf8Buf::from_str("aé 💩");
+ assert_eq!(string.clone().into_string(), Ok(String::from("aé 💩")));
+ string.push(CodePoint::from_u32(0xD800).unwrap());
+ assert_eq!(string.clone().into_string(), Err(string));
+ }
+
+ #[test]
+ fn wtf8buf_into_string_lossy() {
+ let mut string = Wtf8Buf::from_str("aé 💩");
+ assert_eq!(string.clone().into_string_lossy(), String::from("aé 💩"));
+ string.push(CodePoint::from_u32(0xD800).unwrap());
+ assert_eq!(string.clone().into_string_lossy(), String::from("aé 💩�"));
+ }
+
+ #[test]
+ fn wtf8buf_from_iterator() {
+ fn f(values: &[u32]) -> Wtf8Buf {
+ values.iter().map(|&c| CodePoint::from_u32(c).unwrap()).collect::<Wtf8Buf>()
+ }
+ assert_eq!(f(&[0x61, 0xE9, 0x20, 0x1F4A9]).bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9");
+
+ assert_eq!(f(&[0xD83D, 0xDCA9]).bytes, b"\xF0\x9F\x92\xA9"); // Magic!
+ assert_eq!(f(&[0xD83D, 0x20, 0xDCA9]).bytes, b"\xED\xA0\xBD \xED\xB2\xA9");
+ assert_eq!(f(&[0xD800, 0xDBFF]).bytes, b"\xED\xA0\x80\xED\xAF\xBF");
+ assert_eq!(f(&[0xD800, 0xE000]).bytes, b"\xED\xA0\x80\xEE\x80\x80");
+ assert_eq!(f(&[0xD7FF, 0xDC00]).bytes, b"\xED\x9F\xBF\xED\xB0\x80");
+ assert_eq!(f(&[0x61, 0xDC00]).bytes, b"\x61\xED\xB0\x80");
+ assert_eq!(f(&[0xDC00]).bytes, b"\xED\xB0\x80");
+ }
+
+ #[test]
+ fn wtf8buf_extend() {
+ fn e(initial: &[u32], extended: &[u32]) -> Wtf8Buf {
+ fn c(value: &u32) -> CodePoint { CodePoint::from_u32(*value).unwrap() }
+ let mut string = initial.iter().map(c).collect::<Wtf8Buf>();
+ string.extend(extended.iter().map(c));
+ string
+ }
+
+ assert_eq!(e(&[0x61, 0xE9], &[0x20, 0x1F4A9]).bytes,
+ b"a\xC3\xA9 \xF0\x9F\x92\xA9");
+
+ assert_eq!(e(&[0xD83D], &[0xDCA9]).bytes, b"\xF0\x9F\x92\xA9"); // Magic!
+ assert_eq!(e(&[0xD83D, 0x20], &[0xDCA9]).bytes, b"\xED\xA0\xBD \xED\xB2\xA9");
+ assert_eq!(e(&[0xD800], &[0xDBFF]).bytes, b"\xED\xA0\x80\xED\xAF\xBF");
+ assert_eq!(e(&[0xD800], &[0xE000]).bytes, b"\xED\xA0\x80\xEE\x80\x80");
+ assert_eq!(e(&[0xD7FF], &[0xDC00]).bytes, b"\xED\x9F\xBF\xED\xB0\x80");
+ assert_eq!(e(&[0x61], &[0xDC00]).bytes, b"\x61\xED\xB0\x80");
+ assert_eq!(e(&[], &[0xDC00]).bytes, b"\xED\xB0\x80");
+ }
+
+ #[test]
+ fn wtf8buf_show() {
+ let mut string = Wtf8Buf::from_str("a\té \u{7f}💩\r");
+ string.push(CodePoint::from_u32(0xD800).unwrap());
+ assert_eq!(format!("{:?}", string), "\"a\\té \\u{7f}\u{1f4a9}\\r\\u{d800}\"");
+ }
+
+ #[test]
+ fn wtf8buf_as_slice() {
+ assert_eq!(Wtf8Buf::from_str("aé").as_slice(), Wtf8::from_str("aé"));
+ }
+
+ #[test]
+ fn wtf8buf_show_str() {
+ let text = "a\té 💩\r";
+ let string = Wtf8Buf::from_str(text);
+ assert_eq!(format!("{:?}", text), format!("{:?}", string));
+ }
+
+ #[test]
+ fn wtf8_from_str() {
+ assert_eq!(&Wtf8::from_str("").bytes, b"");
+ assert_eq!(&Wtf8::from_str("aé 💩").bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9");
+ }
+
+ #[test]
+ fn wtf8_len() {
+ assert_eq!(Wtf8::from_str("").len(), 0);
+ assert_eq!(Wtf8::from_str("aé 💩").len(), 8);
+ }
+
+ #[test]
+ fn wtf8_slice() {
+ assert_eq!(&Wtf8::from_str("aé 💩")[1.. 4].bytes, b"\xC3\xA9 ");
+ }
+
+ #[test]
+ #[should_panic]
+ fn wtf8_slice_not_code_point_boundary() {
+ &Wtf8::from_str("aé 💩")[2.. 4];
+ }
+
+ #[test]
+ fn wtf8_slice_from() {
+ assert_eq!(&Wtf8::from_str("aé 💩")[1..].bytes, b"\xC3\xA9 \xF0\x9F\x92\xA9");
+ }
+
+ #[test]
+ #[should_panic]
+ fn wtf8_slice_from_not_code_point_boundary() {
+ &Wtf8::from_str("aé 💩")[2..];
+ }
+
+ #[test]
+ fn wtf8_slice_to() {
+ assert_eq!(&Wtf8::from_str("aé 💩")[..4].bytes, b"a\xC3\xA9 ");
+ }
+
+ #[test]
+ #[should_panic]
+ fn wtf8_slice_to_not_code_point_boundary() {
+ &Wtf8::from_str("aé 💩")[5..];
+ }
+
+ #[test]
+ fn wtf8_ascii_byte_at() {
+ let slice = Wtf8::from_str("aé 💩");
+ assert_eq!(slice.ascii_byte_at(0), b'a');
+ assert_eq!(slice.ascii_byte_at(1), b'\xFF');
+ assert_eq!(slice.ascii_byte_at(2), b'\xFF');
+ assert_eq!(slice.ascii_byte_at(3), b' ');
+ assert_eq!(slice.ascii_byte_at(4), b'\xFF');
+ }
+
+ #[test]
+ fn wtf8_code_points() {
+ fn c(value: u32) -> CodePoint { CodePoint::from_u32(value).unwrap() }
+ fn cp(string: &Wtf8Buf) -> Vec<Option<char>> {
+ string.code_points().map(|c| c.to_char()).collect::<Vec<_>>()
+ }
+ let mut string = Wtf8Buf::from_str("é ");
+ assert_eq!(cp(&string), [Some('é'), Some(' ')]);
+ string.push(c(0xD83D));
+ assert_eq!(cp(&string), [Some('é'), Some(' '), None]);
+ string.push(c(0xDCA9));
+ assert_eq!(cp(&string), [Some('é'), Some(' '), Some('💩')]);
+ }
+
+ #[test]
+ fn wtf8_as_str() {
+ assert_eq!(Wtf8::from_str("").as_str(), Some(""));
+ assert_eq!(Wtf8::from_str("aé 💩").as_str(), Some("aé 💩"));
+ let mut string = Wtf8Buf::new();
+ string.push(CodePoint::from_u32(0xD800).unwrap());
+ assert_eq!(string.as_str(), None);
+ }
+
+ #[test]
+ fn wtf8_to_string_lossy() {
+ assert_eq!(Wtf8::from_str("").to_string_lossy(), Cow::Borrowed(""));
+ assert_eq!(Wtf8::from_str("aé 💩").to_string_lossy(), Cow::Borrowed("aé 💩"));
+ let mut string = Wtf8Buf::from_str("aé 💩");
+ string.push(CodePoint::from_u32(0xD800).unwrap());
+ let expected: Cow<'_, str> = Cow::Owned(String::from("aé 💩�"));
+ assert_eq!(string.to_string_lossy(), expected);
+ }
+
+ #[test]
+ fn wtf8_display() {
+ fn d(b: &[u8]) -> String {
+ (&unsafe { Wtf8::from_bytes_unchecked(b) }).to_string()
+ }
+
+ assert_eq!("", d("".as_bytes()));
+ assert_eq!("aé 💩", d("aé 💩".as_bytes()));
+
+ let mut string = Wtf8Buf::from_str("aé 💩");
+ string.push(CodePoint::from_u32(0xD800).unwrap());
+ assert_eq!("aé 💩�", d(string.as_inner()));
+ }
+
+ #[test]
+ fn wtf8_encode_wide() {
+ let mut string = Wtf8Buf::from_str("aé ");
+ string.push(CodePoint::from_u32(0xD83D).unwrap());
+ string.push_char('💩');
+ assert_eq!(string.encode_wide().collect::<Vec<_>>(),
+ vec![0x61, 0xE9, 0x20, 0xD83D, 0xD83D, 0xDCA9]);
+ }
+}
diff --git a/src/libstd/tests/env.rs b/src/libstd/tests/env.rs
new file mode 100644
index 0000000..06fb553
--- /dev/null
+++ b/src/libstd/tests/env.rs
@@ -0,0 +1,83 @@
+use std::env::*;
+use std::ffi::{OsString, OsStr};
+
+use rand::{thread_rng, Rng};
+use rand::distributions::Alphanumeric;
+
+fn make_rand_name() -> OsString {
+ let mut rng = thread_rng();
+ let n = format!("TEST{}", rng.sample_iter(&Alphanumeric).take(10)
+ .collect::<String>());
+ let n = OsString::from(n);
+ assert!(var_os(&n).is_none());
+ n
+}
+
+fn eq(a: Option<OsString>, b: Option<&str>) {
+ assert_eq!(a.as_ref().map(|s| &**s), b.map(OsStr::new).map(|s| &*s));
+}
+
+#[test]
+fn test_set_var() {
+ let n = make_rand_name();
+ set_var(&n, "VALUE");
+ eq(var_os(&n), Some("VALUE"));
+}
+
+#[test]
+fn test_remove_var() {
+ let n = make_rand_name();
+ set_var(&n, "VALUE");
+ remove_var(&n);
+ eq(var_os(&n), None);
+}
+
+#[test]
+fn test_set_var_overwrite() {
+ let n = make_rand_name();
+ set_var(&n, "1");
+ set_var(&n, "2");
+ eq(var_os(&n), Some("2"));
+ set_var(&n, "");
+ eq(var_os(&n), Some(""));
+}
+
+#[test]
+#[cfg_attr(target_os = "emscripten", ignore)]
+fn test_var_big() {
+ let mut s = "".to_string();
+ let mut i = 0;
+ while i < 100 {
+ s.push_str("aaaaaaaaaa");
+ i += 1;
+ }
+ let n = make_rand_name();
+ set_var(&n, &s);
+ eq(var_os(&n), Some(&s));
+}
+
+#[test]
+#[cfg_attr(target_os = "emscripten", ignore)]
+fn test_env_set_get_huge() {
+ let n = make_rand_name();
+ let s = "x".repeat(10000);
+ set_var(&n, &s);
+ eq(var_os(&n), Some(&s));
+ remove_var(&n);
+ eq(var_os(&n), None);
+}
+
+#[test]
+fn test_env_set_var() {
+ let n = make_rand_name();
+
+ let mut e = vars_os();
+ set_var(&n, "VALUE");
+ assert!(!e.any(|(k, v)| {
+ &*k == &*n && &*v == "VALUE"
+ }));
+
+ assert!(vars_os().any(|(k, v)| {
+ &*k == &*n && &*v == "VALUE"
+ }));
+}
diff --git a/src/libstd/tests/run-time-detect.rs b/src/libstd/tests/run-time-detect.rs
new file mode 100644
index 0000000..eacce1e
--- /dev/null
+++ b/src/libstd/tests/run-time-detect.rs
@@ -0,0 +1,100 @@
+//! These tests just check that the macros are available in libstd.
+
+#![cfg_attr(
+ any(
+ all(target_arch = "arm", any(target_os = "linux", target_os = "android")),
+ all(target_arch = "aarch64", any(target_os = "linux", target_os = "android")),
+ all(target_arch = "powerpc", target_os = "linux"),
+ all(target_arch = "powerpc64", target_os = "linux"),
+ ),
+ feature(stdsimd)
+)]
+
+#[test]
+#[cfg(all(target_arch = "arm",
+ any(target_os = "linux", target_os = "android")))]
+fn arm_linux() {
+ println!("neon: {}", is_arm_feature_detected!("neon"));
+ println!("pmull: {}", is_arm_feature_detected!("pmull"));
+}
+
+#[test]
+#[cfg(all(
+ target_arch = "aarch64",
+ any(target_os = "linux", target_os = "android")
+))]
+fn aarch64_linux() {
+ println!("fp: {}", is_aarch64_feature_detected!("fp"));
+ println!("fp16: {}", is_aarch64_feature_detected!("fp16"));
+ println!("neon: {}", is_aarch64_feature_detected!("neon"));
+ println!("asimd: {}", is_aarch64_feature_detected!("asimd"));
+ println!("sve: {}", is_aarch64_feature_detected!("sve"));
+ println!("crc: {}", is_aarch64_feature_detected!("crc"));
+ println!("crypto: {}", is_aarch64_feature_detected!("crypto"));
+ println!("lse: {}", is_aarch64_feature_detected!("lse"));
+ println!("rdm: {}", is_aarch64_feature_detected!("rdm"));
+ println!("rcpc: {}", is_aarch64_feature_detected!("rcpc"));
+ println!("dotprod: {}", is_aarch64_feature_detected!("dotprod"));
+}
+
+#[test]
+#[cfg(all(target_arch = "powerpc", target_os = "linux"))]
+fn powerpc_linux() {
+ println!("altivec: {}", is_powerpc_feature_detected!("altivec"));
+ println!("vsx: {}", is_powerpc_feature_detected!("vsx"));
+ println!("power8: {}", is_powerpc_feature_detected!("power8"));
+}
+
+#[test]
+#[cfg(all(target_arch = "powerpc64", target_os = "linux"))]
+fn powerpc64_linux() {
+ println!("altivec: {}", is_powerpc64_feature_detected!("altivec"));
+ println!("vsx: {}", is_powerpc64_feature_detected!("vsx"));
+ println!("power8: {}", is_powerpc64_feature_detected!("power8"));
+}
+
+#[test]
+#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+fn x86_all() {
+ println!("aes: {:?}", is_x86_feature_detected!("aes"));
+ println!("pcmulqdq: {:?}", is_x86_feature_detected!("pclmulqdq"));
+ println!("rdrand: {:?}", is_x86_feature_detected!("rdrand"));
+ println!("rdseed: {:?}", is_x86_feature_detected!("rdseed"));
+ println!("tsc: {:?}", is_x86_feature_detected!("tsc"));
+ println!("mmx: {:?}", is_x86_feature_detected!("mmx"));
+ println!("sse: {:?}", is_x86_feature_detected!("sse"));
+ println!("sse2: {:?}", is_x86_feature_detected!("sse2"));
+ println!("sse3: {:?}", is_x86_feature_detected!("sse3"));
+ println!("ssse3: {:?}", is_x86_feature_detected!("ssse3"));
+ println!("sse4.1: {:?}", is_x86_feature_detected!("sse4.1"));
+ println!("sse4.2: {:?}", is_x86_feature_detected!("sse4.2"));
+ println!("sse4a: {:?}", is_x86_feature_detected!("sse4a"));
+ println!("sha: {:?}", is_x86_feature_detected!("sha"));
+ println!("avx: {:?}", is_x86_feature_detected!("avx"));
+ println!("avx2: {:?}", is_x86_feature_detected!("avx2"));
+ println!("avx512f {:?}", is_x86_feature_detected!("avx512f"));
+ println!("avx512cd {:?}", is_x86_feature_detected!("avx512cd"));
+ println!("avx512er {:?}", is_x86_feature_detected!("avx512er"));
+ println!("avx512pf {:?}", is_x86_feature_detected!("avx512pf"));
+ println!("avx512bw {:?}", is_x86_feature_detected!("avx512bw"));
+ println!("avx512dq {:?}", is_x86_feature_detected!("avx512dq"));
+ println!("avx512vl {:?}", is_x86_feature_detected!("avx512vl"));
+ println!("avx512_ifma {:?}", is_x86_feature_detected!("avx512ifma"));
+ println!("avx512_vbmi {:?}", is_x86_feature_detected!("avx512vbmi"));
+ println!(
+ "avx512_vpopcntdq {:?}",
+ is_x86_feature_detected!("avx512vpopcntdq")
+ );
+ println!("fma: {:?}", is_x86_feature_detected!("fma"));
+ println!("bmi1: {:?}", is_x86_feature_detected!("bmi1"));
+ println!("bmi2: {:?}", is_x86_feature_detected!("bmi2"));
+ println!("abm: {:?}", is_x86_feature_detected!("abm"));
+ println!("lzcnt: {:?}", is_x86_feature_detected!("lzcnt"));
+ println!("tbm: {:?}", is_x86_feature_detected!("tbm"));
+ println!("popcnt: {:?}", is_x86_feature_detected!("popcnt"));
+ println!("fxsr: {:?}", is_x86_feature_detected!("fxsr"));
+ println!("xsave: {:?}", is_x86_feature_detected!("xsave"));
+ println!("xsaveopt: {:?}", is_x86_feature_detected!("xsaveopt"));
+ println!("xsaves: {:?}", is_x86_feature_detected!("xsaves"));
+ println!("xsavec: {:?}", is_x86_feature_detected!("xsavec"));
+}
diff --git a/src/libstd/thread/local.rs b/src/libstd/thread/local.rs
new file mode 100644
index 0000000..bfc1ded
--- /dev/null
+++ b/src/libstd/thread/local.rs
@@ -0,0 +1,671 @@
+//! Thread local storage
+
+#![unstable(feature = "thread_local_internals", issue = "0")]
+
+use crate::cell::UnsafeCell;
+use crate::fmt;
+use crate::hint;
+use crate::mem;
+
+/// A thread local storage key which owns its contents.
+///
+/// This key uses the fastest possible implementation available to it for the
+/// target platform. It is instantiated with the [`thread_local!`] macro and the
+/// primary method is the [`with`] method.
+///
+/// The [`with`] method yields a reference to the contained value which cannot be
+/// sent across threads or escape the given closure.
+///
+/// # Initialization and Destruction
+///
+/// Initialization is dynamically performed on the first call to [`with`]
+/// within a thread, and values that implement [`Drop`] get destructed when a
+/// thread exits. Some caveats apply, which are explained below.
+///
+/// A `LocalKey`'s initializer cannot recursively depend on itself, and using
+/// a `LocalKey` in this way will cause the initializer to infinitely recurse
+/// on the first call to `with`.
+///
+/// # Examples
+///
+/// ```
+/// use std::cell::RefCell;
+/// use std::thread;
+///
+/// thread_local!(static FOO: RefCell<u32> = RefCell::new(1));
+///
+/// FOO.with(|f| {
+/// assert_eq!(*f.borrow(), 1);
+/// *f.borrow_mut() = 2;
+/// });
+///
+/// // each thread starts out with the initial value of 1
+/// let t = thread::spawn(move|| {
+/// FOO.with(|f| {
+/// assert_eq!(*f.borrow(), 1);
+/// *f.borrow_mut() = 3;
+/// });
+/// });
+///
+/// // wait for the thread to complete and bail out on panic
+/// t.join().unwrap();
+///
+/// // we retain our original value of 2 despite the child thread
+/// FOO.with(|f| {
+/// assert_eq!(*f.borrow(), 2);
+/// });
+/// ```
+///
+/// # Platform-specific behavior
+///
+/// Note that a "best effort" is made to ensure that destructors for types
+/// stored in thread local storage are run, but not all platforms can guarantee
+/// that destructors will be run for all types in thread local storage. For
+/// example, there are a number of known caveats where destructors are not run:
+///
+/// 1. On Unix systems when pthread-based TLS is being used, destructors will
+/// not be run for TLS values on the main thread when it exits. Note that the
+/// application will exit immediately after the main thread exits as well.
+/// 2. On all platforms it's possible for TLS to re-initialize other TLS slots
+/// during destruction. Some platforms ensure that this cannot happen
+/// infinitely by preventing re-initialization of any slot that has been
+/// destroyed, but not all platforms have this guard. Those platforms that do
+/// not guard typically have a synthetic limit after which point no more
+/// destructors are run.
+///
+/// [`with`]: ../../std/thread/struct.LocalKey.html#method.with
+/// [`thread_local!`]: ../../std/macro.thread_local.html
+/// [`Drop`]: ../../std/ops/trait.Drop.html
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct LocalKey<T: 'static> {
+ // This outer `LocalKey<T>` type is what's going to be stored in statics,
+ // but actual data inside will sometimes be tagged with #[thread_local].
+ // It's not valid for a true static to reference a #[thread_local] static,
+ // so we get around that by exposing an accessor through a layer of function
+ // indirection (this thunk).
+ //
+ // Note that the thunk is itself unsafe because the returned lifetime of the
+ // slot where data lives, `'static`, is not actually valid. The lifetime
+ // here is actually slightly shorter than the currently running thread!
+ //
+ // Although this is an extra layer of indirection, it should in theory be
+ // trivially devirtualizable by LLVM because the value of `inner` never
+ // changes and the constant should be readonly within a crate. This mainly
+ // only runs into problems when TLS statics are exported across crates.
+ inner: unsafe fn() -> Option<&'static UnsafeCell<Option<T>>>,
+
+ // initialization routine to invoke to create a value
+ init: fn() -> T,
+}
+
+#[stable(feature = "std_debug", since = "1.16.0")]
+impl<T: 'static> fmt::Debug for LocalKey<T> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.pad("LocalKey { .. }")
+ }
+}
+
+/// Declare a new thread local storage key of type [`std::thread::LocalKey`].
+///
+/// # Syntax
+///
+/// The macro wraps any number of static declarations and makes them thread local.
+/// Publicity and attributes for each static are allowed. Example:
+///
+/// ```
+/// use std::cell::RefCell;
+/// thread_local! {
+/// pub static FOO: RefCell<u32> = RefCell::new(1);
+///
+/// #[allow(unused)]
+/// static BAR: RefCell<f32> = RefCell::new(1.0);
+/// }
+/// # fn main() {}
+/// ```
+///
+/// See [LocalKey documentation][`std::thread::LocalKey`] for more
+/// information.
+///
+/// [`std::thread::LocalKey`]: ../std/thread/struct.LocalKey.html
+#[macro_export]
+#[stable(feature = "rust1", since = "1.0.0")]
+#[allow_internal_unstable(thread_local_internals)]
+macro_rules! thread_local {
+ // empty (base case for the recursion)
+ () => {};
+
+ // process multiple declarations
+ ($(#[$attr:meta])* $vis:vis static $name:ident: $t:ty = $init:expr; $($rest:tt)*) => (
+ $crate::__thread_local_inner!($(#[$attr])* $vis $name, $t, $init);
+ $crate::thread_local!($($rest)*);
+ );
+
+ // handle a single declaration
+ ($(#[$attr:meta])* $vis:vis static $name:ident: $t:ty = $init:expr) => (
+ $crate::__thread_local_inner!($(#[$attr])* $vis $name, $t, $init);
+ );
+}
+
+#[doc(hidden)]
+#[unstable(feature = "thread_local_internals",
+ reason = "should not be necessary",
+ issue = "0")]
+#[macro_export]
+#[allow_internal_unstable(thread_local_internals, cfg_target_thread_local, thread_local)]
+#[allow_internal_unsafe]
+macro_rules! __thread_local_inner {
+ (@key $(#[$attr:meta])* $vis:vis $name:ident, $t:ty, $init:expr) => {
+ {
+ #[inline]
+ fn __init() -> $t { $init }
+
+ unsafe fn __getit() -> $crate::option::Option<
+ &'static $crate::cell::UnsafeCell<
+ $crate::option::Option<$t>>>
+ {
+ #[cfg(all(target_arch = "wasm32", not(target_feature = "atomics")))]
+ static __KEY: $crate::thread::__StaticLocalKeyInner<$t> =
+ $crate::thread::__StaticLocalKeyInner::new();
+
+ #[thread_local]
+ #[cfg(all(
+ target_thread_local,
+ not(all(target_arch = "wasm32", not(target_feature = "atomics"))),
+ ))]
+ static __KEY: $crate::thread::__FastLocalKeyInner<$t> =
+ $crate::thread::__FastLocalKeyInner::new();
+
+ #[cfg(all(
+ not(target_thread_local),
+ not(all(target_arch = "wasm32", not(target_feature = "atomics"))),
+ ))]
+ static __KEY: $crate::thread::__OsLocalKeyInner<$t> =
+ $crate::thread::__OsLocalKeyInner::new();
+
+ __KEY.get()
+ }
+
+ unsafe {
+ $crate::thread::LocalKey::new(__getit, __init)
+ }
+ }
+ };
+ ($(#[$attr:meta])* $vis:vis $name:ident, $t:ty, $init:expr) => {
+ $(#[$attr])* $vis const $name: $crate::thread::LocalKey<$t> =
+ $crate::__thread_local_inner!(@key $(#[$attr])* $vis $name, $t, $init);
+ }
+}
+
+/// An error returned by [`LocalKey::try_with`](struct.LocalKey.html#method.try_with).
+#[stable(feature = "thread_local_try_with", since = "1.26.0")]
+pub struct AccessError {
+ _private: (),
+}
+
+#[stable(feature = "thread_local_try_with", since = "1.26.0")]
+impl fmt::Debug for AccessError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("AccessError").finish()
+ }
+}
+
+#[stable(feature = "thread_local_try_with", since = "1.26.0")]
+impl fmt::Display for AccessError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt::Display::fmt("already destroyed", f)
+ }
+}
+
+impl<T: 'static> LocalKey<T> {
+ #[doc(hidden)]
+ #[unstable(feature = "thread_local_internals",
+ reason = "recently added to create a key",
+ issue = "0")]
+ pub const unsafe fn new(inner: unsafe fn() -> Option<&'static UnsafeCell<Option<T>>>,
+ init: fn() -> T) -> LocalKey<T> {
+ LocalKey {
+ inner,
+ init,
+ }
+ }
+
+ /// Acquires a reference to the value in this TLS key.
+ ///
+ /// This will lazily initialize the value if this thread has not referenced
+ /// this key yet.
+ ///
+ /// # Panics
+ ///
+ /// This function will `panic!()` if the key currently has its
+ /// destructor running, and it **may** panic if the destructor has
+ /// previously been run for this thread.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn with<F, R>(&'static self, f: F) -> R
+ where F: FnOnce(&T) -> R {
+ self.try_with(f).expect("cannot access a TLS value during or \
+ after it is destroyed")
+ }
+
+ unsafe fn init(&self, slot: &UnsafeCell<Option<T>>) -> &T {
+ // Execute the initialization up front, *then* move it into our slot,
+ // just in case initialization fails.
+ let value = (self.init)();
+ let ptr = slot.get();
+
+ // note that this can in theory just be `*ptr = Some(value)`, but due to
+ // the compiler will currently codegen that pattern with something like:
+ //
+ // ptr::drop_in_place(ptr)
+ // ptr::write(ptr, Some(value))
+ //
+ // Due to this pattern it's possible for the destructor of the value in
+ // `ptr` (e.g., if this is being recursively initialized) to re-access
+ // TLS, in which case there will be a `&` and `&mut` pointer to the same
+ // value (an aliasing violation). To avoid setting the "I'm running a
+ // destructor" flag we just use `mem::replace` which should sequence the
+ // operations a little differently and make this safe to call.
+ mem::replace(&mut *ptr, Some(value));
+
+ // After storing `Some` we want to get a reference to the contents of
+ // what we just stored. While we could use `unwrap` here and it should
+ // always work it empirically doesn't seem to always get optimized away,
+ // which means that using something like `try_with` can pull in
+ // panicking code and cause a large size bloat.
+ match *ptr {
+ Some(ref x) => x,
+ None => hint::unreachable_unchecked(),
+ }
+ }
+
+ /// Acquires a reference to the value in this TLS key.
+ ///
+ /// This will lazily initialize the value if this thread has not referenced
+ /// this key yet. If the key has been destroyed (which may happen if this is called
+ /// in a destructor), this function will return an [`AccessError`](struct.AccessError.html).
+ ///
+ /// # Panics
+ ///
+ /// This function will still `panic!()` if the key is uninitialized and the
+ /// key's initializer panics.
+ #[stable(feature = "thread_local_try_with", since = "1.26.0")]
+ pub fn try_with<F, R>(&'static self, f: F) -> Result<R, AccessError>
+ where
+ F: FnOnce(&T) -> R,
+ {
+ unsafe {
+ let slot = (self.inner)().ok_or(AccessError {
+ _private: (),
+ })?;
+ Ok(f(match *slot.get() {
+ Some(ref inner) => inner,
+ None => self.init(slot),
+ }))
+ }
+ }
+}
+
+/// On some platforms like wasm32 there's no threads, so no need to generate
+/// thread locals and we can instead just use plain statics!
+#[doc(hidden)]
+#[cfg(all(target_arch = "wasm32", not(target_feature = "atomics")))]
+pub mod statik {
+ use crate::cell::UnsafeCell;
+ use crate::fmt;
+
+ pub struct Key<T> {
+ inner: UnsafeCell<Option<T>>,
+ }
+
+ unsafe impl<T> Sync for Key<T> { }
+
+ impl<T> fmt::Debug for Key<T> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.pad("Key { .. }")
+ }
+ }
+
+ impl<T> Key<T> {
+ pub const fn new() -> Key<T> {
+ Key {
+ inner: UnsafeCell::new(None),
+ }
+ }
+
+ pub unsafe fn get(&self) -> Option<&'static UnsafeCell<Option<T>>> {
+ Some(&*(&self.inner as *const _))
+ }
+ }
+}
+
+#[doc(hidden)]
+#[cfg(target_thread_local)]
+pub mod fast {
+ use crate::cell::{Cell, UnsafeCell};
+ use crate::fmt;
+ use crate::mem;
+ use crate::ptr;
+ use crate::sys::fast_thread_local::{register_dtor, requires_move_before_drop};
+
+ pub struct Key<T> {
+ inner: UnsafeCell<Option<T>>,
+
+ // Metadata to keep track of the state of the destructor. Remember that
+ // these variables are thread-local, not global.
+ dtor_registered: Cell<bool>,
+ dtor_running: Cell<bool>,
+ }
+
+ impl<T> fmt::Debug for Key<T> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.pad("Key { .. }")
+ }
+ }
+
+ impl<T> Key<T> {
+ pub const fn new() -> Key<T> {
+ Key {
+ inner: UnsafeCell::new(None),
+ dtor_registered: Cell::new(false),
+ dtor_running: Cell::new(false)
+ }
+ }
+
+ pub unsafe fn get(&self) -> Option<&'static UnsafeCell<Option<T>>> {
+ if mem::needs_drop::<T>() && self.dtor_running.get() {
+ return None
+ }
+ self.register_dtor();
+ Some(&*(&self.inner as *const _))
+ }
+
+ unsafe fn register_dtor(&self) {
+ if !mem::needs_drop::<T>() || self.dtor_registered.get() {
+ return
+ }
+
+ register_dtor(self as *const _ as *mut u8,
+ destroy_value::<T>);
+ self.dtor_registered.set(true);
+ }
+ }
+
+ unsafe extern fn destroy_value<T>(ptr: *mut u8) {
+ let ptr = ptr as *mut Key<T>;
+ // Right before we run the user destructor be sure to flag the
+ // destructor as running for this thread so calls to `get` will return
+ // `None`.
+ (*ptr).dtor_running.set(true);
+
+ // Some implementations may require us to move the value before we drop
+ // it as it could get re-initialized in-place during destruction.
+ //
+ // Hence, we use `ptr::read` on those platforms (to move to a "safe"
+ // location) instead of drop_in_place.
+ if requires_move_before_drop() {
+ ptr::read((*ptr).inner.get());
+ } else {
+ ptr::drop_in_place((*ptr).inner.get());
+ }
+ }
+}
+
+#[doc(hidden)]
+pub mod os {
+ use crate::cell::{Cell, UnsafeCell};
+ use crate::fmt;
+ use crate::marker;
+ use crate::ptr;
+ use crate::sys_common::thread_local::StaticKey as OsStaticKey;
+
+ pub struct Key<T> {
+ // OS-TLS key that we'll use to key off.
+ os: OsStaticKey,
+ marker: marker::PhantomData<Cell<T>>,
+ }
+
+ impl<T> fmt::Debug for Key<T> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.pad("Key { .. }")
+ }
+ }
+
+ unsafe impl<T> Sync for Key<T> { }
+
+ struct Value<T: 'static> {
+ key: &'static Key<T>,
+ value: UnsafeCell<Option<T>>,
+ }
+
+ impl<T: 'static> Key<T> {
+ pub const fn new() -> Key<T> {
+ Key {
+ os: OsStaticKey::new(Some(destroy_value::<T>)),
+ marker: marker::PhantomData
+ }
+ }
+
+ pub unsafe fn get(&'static self) -> Option<&'static UnsafeCell<Option<T>>> {
+ let ptr = self.os.get() as *mut Value<T>;
+ if !ptr.is_null() {
+ if ptr as usize == 1 {
+ return None
+ }
+ return Some(&(*ptr).value);
+ }
+
+ // If the lookup returned null, we haven't initialized our own
+ // local copy, so do that now.
+ let ptr: Box<Value<T>> = box Value {
+ key: self,
+ value: UnsafeCell::new(None),
+ };
+ let ptr = Box::into_raw(ptr);
+ self.os.set(ptr as *mut u8);
+ Some(&(*ptr).value)
+ }
+ }
+
+ unsafe extern fn destroy_value<T: 'static>(ptr: *mut u8) {
+ // The OS TLS ensures that this key contains a NULL value when this
+ // destructor starts to run. We set it back to a sentinel value of 1 to
+ // ensure that any future calls to `get` for this thread will return
+ // `None`.
+ //
+ // Note that to prevent an infinite loop we reset it back to null right
+ // before we return from the destructor ourselves.
+ let ptr = Box::from_raw(ptr as *mut Value<T>);
+ let key = ptr.key;
+ key.os.set(1 as *mut u8);
+ drop(ptr);
+ key.os.set(ptr::null_mut());
+ }
+}
+
+#[cfg(all(test, not(target_os = "emscripten")))]
+mod tests {
+ use crate::sync::mpsc::{channel, Sender};
+ use crate::cell::{Cell, UnsafeCell};
+ use crate::thread;
+
+ struct Foo(Sender<()>);
+
+ impl Drop for Foo {
+ fn drop(&mut self) {
+ let Foo(ref s) = *self;
+ s.send(()).unwrap();
+ }
+ }
+
+ #[test]
+ fn smoke_no_dtor() {
+ thread_local!(static FOO: Cell<i32> = Cell::new(1));
+
+ FOO.with(|f| {
+ assert_eq!(f.get(), 1);
+ f.set(2);
+ });
+ let (tx, rx) = channel();
+ let _t = thread::spawn(move|| {
+ FOO.with(|f| {
+ assert_eq!(f.get(), 1);
+ });
+ tx.send(()).unwrap();
+ });
+ rx.recv().unwrap();
+
+ FOO.with(|f| {
+ assert_eq!(f.get(), 2);
+ });
+ }
+
+ #[test]
+ fn states() {
+ struct Foo;
+ impl Drop for Foo {
+ fn drop(&mut self) {
+ assert!(FOO.try_with(|_| ()).is_err());
+ }
+ }
+ thread_local!(static FOO: Foo = Foo);
+
+ thread::spawn(|| {
+ assert!(FOO.try_with(|_| ()).is_ok());
+ }).join().ok().expect("thread panicked");
+ }
+
+ #[test]
+ fn smoke_dtor() {
+ thread_local!(static FOO: UnsafeCell<Option<Foo>> = UnsafeCell::new(None));
+
+ let (tx, rx) = channel();
+ let _t = thread::spawn(move|| unsafe {
+ let mut tx = Some(tx);
+ FOO.with(|f| {
+ *f.get() = Some(Foo(tx.take().unwrap()));
+ });
+ });
+ rx.recv().unwrap();
+ }
+
+ #[test]
+ fn circular() {
+ struct S1;
+ struct S2;
+ thread_local!(static K1: UnsafeCell<Option<S1>> = UnsafeCell::new(None));
+ thread_local!(static K2: UnsafeCell<Option<S2>> = UnsafeCell::new(None));
+ static mut HITS: u32 = 0;
+
+ impl Drop for S1 {
+ fn drop(&mut self) {
+ unsafe {
+ HITS += 1;
+ if K2.try_with(|_| ()).is_err() {
+ assert_eq!(HITS, 3);
+ } else {
+ if HITS == 1 {
+ K2.with(|s| *s.get() = Some(S2));
+ } else {
+ assert_eq!(HITS, 3);
+ }
+ }
+ }
+ }
+ }
+ impl Drop for S2 {
+ fn drop(&mut self) {
+ unsafe {
+ HITS += 1;
+ assert!(K1.try_with(|_| ()).is_ok());
+ assert_eq!(HITS, 2);
+ K1.with(|s| *s.get() = Some(S1));
+ }
+ }
+ }
+
+ thread::spawn(move|| {
+ drop(S1);
+ }).join().ok().expect("thread panicked");
+ }
+
+ #[test]
+ fn self_referential() {
+ struct S1;
+ thread_local!(static K1: UnsafeCell<Option<S1>> = UnsafeCell::new(None));
+
+ impl Drop for S1 {
+ fn drop(&mut self) {
+ assert!(K1.try_with(|_| ()).is_err());
+ }
+ }
+
+ thread::spawn(move|| unsafe {
+ K1.with(|s| *s.get() = Some(S1));
+ }).join().ok().expect("thread panicked");
+ }
+
+ // Note that this test will deadlock if TLS destructors aren't run (this
+ // requires the destructor to be run to pass the test).
+ #[test]
+ fn dtors_in_dtors_in_dtors() {
+ struct S1(Sender<()>);
+ thread_local!(static K1: UnsafeCell<Option<S1>> = UnsafeCell::new(None));
+ thread_local!(static K2: UnsafeCell<Option<Foo>> = UnsafeCell::new(None));
+
+ impl Drop for S1 {
+ fn drop(&mut self) {
+ let S1(ref tx) = *self;
+ unsafe {
+ let _ = K2.try_with(|s| *s.get() = Some(Foo(tx.clone())));
+ }
+ }
+ }
+
+ let (tx, rx) = channel();
+ let _t = thread::spawn(move|| unsafe {
+ let mut tx = Some(tx);
+ K1.with(|s| *s.get() = Some(S1(tx.take().unwrap())));
+ });
+ rx.recv().unwrap();
+ }
+}
+
+#[cfg(test)]
+mod dynamic_tests {
+ use crate::cell::RefCell;
+ use crate::collections::HashMap;
+
+ #[test]
+ fn smoke() {
+ fn square(i: i32) -> i32 { i * i }
+ thread_local!(static FOO: i32 = square(3));
+
+ FOO.with(|f| {
+ assert_eq!(*f, 9);
+ });
+ }
+
+ #[test]
+ fn hashmap() {
+ fn map() -> RefCell<HashMap<i32, i32>> {
+ let mut m = HashMap::new();
+ m.insert(1, 2);
+ RefCell::new(m)
+ }
+ thread_local!(static FOO: RefCell<HashMap<i32, i32>> = map());
+
+ FOO.with(|map| {
+ assert_eq!(map.borrow()[&1], 2);
+ });
+ }
+
+ #[test]
+ fn refcell_vec() {
+ thread_local!(static FOO: RefCell<Vec<u32>> = RefCell::new(vec![1, 2, 3]));
+
+ FOO.with(|vec| {
+ assert_eq!(vec.borrow().len(), 3);
+ vec.borrow_mut().push(4);
+ assert_eq!(vec.borrow()[3], 4);
+ });
+ }
+}
diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs
new file mode 100644
index 0000000..cb50797
--- /dev/null
+++ b/src/libstd/thread/mod.rs
@@ -0,0 +1,1745 @@
+//! Native threads.
+//!
+//! ## The threading model
+//!
+//! An executing Rust program consists of a collection of native OS threads,
+//! each with their own stack and local state. Threads can be named, and
+//! provide some built-in support for low-level synchronization.
+//!
+//! Communication between threads can be done through
+//! [channels], Rust's message-passing types, along with [other forms of thread
+//! synchronization](../../std/sync/index.html) and shared-memory data
+//! structures. In particular, types that are guaranteed to be
+//! threadsafe are easily shared between threads using the
+//! atomically-reference-counted container, [`Arc`].
+//!
+//! Fatal logic errors in Rust cause *thread panic*, during which
+//! a thread will unwind the stack, running destructors and freeing
+//! owned resources. While not meant as a 'try/catch' mechanism, panics
+//! in Rust can nonetheless be caught (unless compiling with `panic=abort`) with
+//! [`catch_unwind`](../../std/panic/fn.catch_unwind.html) and recovered
+//! from, or alternatively be resumed with
+//! [`resume_unwind`](../../std/panic/fn.resume_unwind.html). If the panic
+//! is not caught the thread will exit, but the panic may optionally be
+//! detected from a different thread with [`join`]. If the main thread panics
+//! without the panic being caught, the application will exit with a
+//! non-zero exit code.
+//!
+//! When the main thread of a Rust program terminates, the entire program shuts
+//! down, even if other threads are still running. However, this module provides
+//! convenient facilities for automatically waiting for the termination of a
+//! child thread (i.e., join).
+//!
+//! ## Spawning a thread
+//!
+//! A new thread can be spawned using the [`thread::spawn`][`spawn`] function:
+//!
+//! ```rust
+//! use std::thread;
+//!
+//! thread::spawn(move || {
+//! // some work here
+//! });
+//! ```
+//!
+//! In this example, the spawned thread is "detached" from the current
+//! thread. This means that it can outlive its parent (the thread that spawned
+//! it), unless this parent is the main thread.
+//!
+//! The parent thread can also wait on the completion of the child
+//! thread; a call to [`spawn`] produces a [`JoinHandle`], which provides
+//! a `join` method for waiting:
+//!
+//! ```rust
+//! use std::thread;
+//!
+//! let child = thread::spawn(move || {
+//! // some work here
+//! });
+//! // some work here
+//! let res = child.join();
+//! ```
+//!
+//! The [`join`] method returns a [`thread::Result`] containing [`Ok`] of the final
+//! value produced by the child thread, or [`Err`] of the value given to
+//! a call to [`panic!`] if the child panicked.
+//!
+//! ## Configuring threads
+//!
+//! A new thread can be configured before it is spawned via the [`Builder`] type,
+//! which currently allows you to set the name and stack size for the child thread:
+//!
+//! ```rust
+//! # #![allow(unused_must_use)]
+//! use std::thread;
+//!
+//! thread::Builder::new().name("child1".to_string()).spawn(move || {
+//! println!("Hello, world!");
+//! });
+//! ```
+//!
+//! ## The `Thread` type
+//!
+//! Threads are represented via the [`Thread`] type, which you can get in one of
+//! two ways:
+//!
+//! * By spawning a new thread, e.g., using the [`thread::spawn`][`spawn`]
+//! function, and calling [`thread`][`JoinHandle::thread`] on the [`JoinHandle`].
+//! * By requesting the current thread, using the [`thread::current`] function.
+//!
+//! The [`thread::current`] function is available even for threads not spawned
+//! by the APIs of this module.
+//!
+//! ## Thread-local storage
+//!
+//! This module also provides an implementation of thread-local storage for Rust
+//! programs. Thread-local storage is a method of storing data into a global
+//! variable that each thread in the program will have its own copy of.
+//! Threads do not share this data, so accesses do not need to be synchronized.
+//!
+//! A thread-local key owns the value it contains and will destroy the value when the
+//! thread exits. It is created with the [`thread_local!`] macro and can contain any
+//! value that is `'static` (no borrowed pointers). It provides an accessor function,
+//! [`with`], that yields a shared reference to the value to the specified
+//! closure. Thread-local keys allow only shared access to values, as there would be no
+//! way to guarantee uniqueness if mutable borrows were allowed. Most values
+//! will want to make use of some form of **interior mutability** through the
+//! [`Cell`] or [`RefCell`] types.
+//!
+//! ## Naming threads
+//!
+//! Threads are able to have associated names for identification purposes. By default, spawned
+//! threads are unnamed. To specify a name for a thread, build the thread with [`Builder`] and pass
+//! the desired thread name to [`Builder::name`]. To retrieve the thread name from within the
+//! thread, use [`Thread::name`]. A couple examples of where the name of a thread gets used:
+//!
+//! * If a panic occurs in a named thread, the thread name will be printed in the panic message.
+//! * The thread name is provided to the OS where applicable (e.g., `pthread_setname_np` in
+//! unix-like platforms).
+//!
+//! ## Stack size
+//!
+//! The default stack size for spawned threads is 2 MiB, though this particular stack size is
+//! subject to change in the future. There are two ways to manually specify the stack size for
+//! spawned threads:
+//!
+//! * Build the thread with [`Builder`] and pass the desired stack size to [`Builder::stack_size`].
+//! * Set the `RUST_MIN_STACK` environment variable to an integer representing the desired stack
+//! size (in bytes). Note that setting [`Builder::stack_size`] will override this.
+//!
+//! Note that the stack size of the main thread is *not* determined by Rust.
+//!
+//! [channels]: ../../std/sync/mpsc/index.html
+//! [`Arc`]: ../../std/sync/struct.Arc.html
+//! [`spawn`]: ../../std/thread/fn.spawn.html
+//! [`JoinHandle`]: ../../std/thread/struct.JoinHandle.html
+//! [`JoinHandle::thread`]: ../../std/thread/struct.JoinHandle.html#method.thread
+//! [`join`]: ../../std/thread/struct.JoinHandle.html#method.join
+//! [`Result`]: ../../std/result/enum.Result.html
+//! [`Ok`]: ../../std/result/enum.Result.html#variant.Ok
+//! [`Err`]: ../../std/result/enum.Result.html#variant.Err
+//! [`panic!`]: ../../std/macro.panic.html
+//! [`Builder`]: ../../std/thread/struct.Builder.html
+//! [`Builder::stack_size`]: ../../std/thread/struct.Builder.html#method.stack_size
+//! [`Builder::name`]: ../../std/thread/struct.Builder.html#method.name
+//! [`thread::current`]: ../../std/thread/fn.current.html
+//! [`thread::Result`]: ../../std/thread/type.Result.html
+//! [`Thread`]: ../../std/thread/struct.Thread.html
+//! [`park`]: ../../std/thread/fn.park.html
+//! [`unpark`]: ../../std/thread/struct.Thread.html#method.unpark
+//! [`Thread::name`]: ../../std/thread/struct.Thread.html#method.name
+//! [`thread::park_timeout`]: ../../std/thread/fn.park_timeout.html
+//! [`Cell`]: ../cell/struct.Cell.html
+//! [`RefCell`]: ../cell/struct.RefCell.html
+//! [`thread_local!`]: ../macro.thread_local.html
+//! [`with`]: struct.LocalKey.html#method.with
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+use crate::any::Any;
+use crate::boxed::FnBox;
+use crate::cell::UnsafeCell;
+use crate::ffi::{CStr, CString};
+use crate::fmt;
+use crate::io;
+use crate::mem;
+use crate::num::NonZeroU64;
+use crate::panic;
+use crate::panicking;
+use crate::str;
+use crate::sync::{Mutex, Condvar, Arc};
+use crate::sync::atomic::AtomicUsize;
+use crate::sync::atomic::Ordering::SeqCst;
+use crate::sys::thread as imp;
+use crate::sys_common::mutex;
+use crate::sys_common::thread_info;
+use crate::sys_common::thread;
+use crate::sys_common::{AsInner, IntoInner};
+use crate::time::Duration;
+
+////////////////////////////////////////////////////////////////////////////////
+// Thread-local storage
+////////////////////////////////////////////////////////////////////////////////
+
+#[macro_use] mod local;
+
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use self::local::{LocalKey, AccessError};
+
+// The types used by the thread_local! macro to access TLS keys. Note that there
+// are two types, the "OS" type and the "fast" type. The OS thread local key
+// type is accessed via platform-specific API calls and is slow, while the fast
+// key type is accessed via code generated via LLVM, where TLS keys are set up
+// by the elf linker. Note that the OS TLS type is always available: on macOS
+// the standard library is compiled with support for older platform versions
+// where fast TLS was not available; end-user code is compiled with fast TLS
+// where available, but both are needed.
+
+#[unstable(feature = "libstd_thread_internals", issue = "0")]
+#[cfg(all(target_arch = "wasm32", not(target_feature = "atomics")))]
+#[doc(hidden)] pub use self::local::statik::Key as __StaticLocalKeyInner;
+#[unstable(feature = "libstd_thread_internals", issue = "0")]
+#[cfg(target_thread_local)]
+#[doc(hidden)] pub use self::local::fast::Key as __FastLocalKeyInner;
+#[unstable(feature = "libstd_thread_internals", issue = "0")]
+#[doc(hidden)] pub use self::local::os::Key as __OsLocalKeyInner;
+
+////////////////////////////////////////////////////////////////////////////////
+// Builder
+////////////////////////////////////////////////////////////////////////////////
+
+/// Thread factory, which can be used in order to configure the properties of
+/// a new thread.
+///
+/// Methods can be chained on it in order to configure it.
+///
+/// The two configurations available are:
+///
+/// - [`name`]: specifies an [associated name for the thread][naming-threads]
+/// - [`stack_size`]: specifies the [desired stack size for the thread][stack-size]
+///
+/// The [`spawn`] method will take ownership of the builder and create an
+/// [`io::Result`] to the thread handle with the given configuration.
+///
+/// The [`thread::spawn`] free function uses a `Builder` with default
+/// configuration and [`unwrap`]s its return value.
+///
+/// You may want to use [`spawn`] instead of [`thread::spawn`], when you want
+/// to recover from a failure to launch a thread, indeed the free function will
+/// panic where the `Builder` method will return a [`io::Result`].
+///
+/// # Examples
+///
+/// ```
+/// use std::thread;
+///
+/// let builder = thread::Builder::new();
+///
+/// let handler = builder.spawn(|| {
+/// // thread code
+/// }).unwrap();
+///
+/// handler.join().unwrap();
+/// ```
+///
+/// [`thread::spawn`]: ../../std/thread/fn.spawn.html
+/// [`stack_size`]: ../../std/thread/struct.Builder.html#method.stack_size
+/// [`name`]: ../../std/thread/struct.Builder.html#method.name
+/// [`spawn`]: ../../std/thread/struct.Builder.html#method.spawn
+/// [`io::Result`]: ../../std/io/type.Result.html
+/// [`unwrap`]: ../../std/result/enum.Result.html#method.unwrap
+/// [naming-threads]: ./index.html#naming-threads
+/// [stack-size]: ./index.html#stack-size
+#[stable(feature = "rust1", since = "1.0.0")]
+#[derive(Debug)]
+pub struct Builder {
+ // A name for the thread-to-be, for identification in panic messages
+ name: Option<String>,
+ // The size of the stack for the spawned thread in bytes
+ stack_size: Option<usize>,
+}
+
+impl Builder {
+ /// Generates the base configuration for spawning a thread, from which
+ /// configuration methods can be chained.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::thread;
+ ///
+ /// let builder = thread::Builder::new()
+ /// .name("foo".into())
+ /// .stack_size(10);
+ ///
+ /// let handler = builder.spawn(|| {
+ /// // thread code
+ /// }).unwrap();
+ ///
+ /// handler.join().unwrap();
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn new() -> Builder {
+ Builder {
+ name: None,
+ stack_size: None,
+ }
+ }
+
+ /// Names the thread-to-be. Currently the name is used for identification
+ /// only in panic messages.
+ ///
+ /// The name must not contain null bytes (`\0`).
+ ///
+ /// For more information about named threads, see
+ /// [this module-level documentation][naming-threads].
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::thread;
+ ///
+ /// let builder = thread::Builder::new()
+ /// .name("foo".into());
+ ///
+ /// let handler = builder.spawn(|| {
+ /// assert_eq!(thread::current().name(), Some("foo"))
+ /// }).unwrap();
+ ///
+ /// handler.join().unwrap();
+ /// ```
+ ///
+ /// [naming-threads]: ./index.html#naming-threads
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn name(mut self, name: String) -> Builder {
+ self.name = Some(name);
+ self
+ }
+
+ /// Sets the size of the stack (in bytes) for the new thread.
+ ///
+ /// The actual stack size may be greater than this value if
+ /// the platform specifies a minimal stack size.
+ ///
+ /// For more information about the stack size for threads, see
+ /// [this module-level documentation][stack-size].
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::thread;
+ ///
+ /// let builder = thread::Builder::new().stack_size(32 * 1024);
+ /// ```
+ ///
+ /// [stack-size]: ./index.html#stack-size
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn stack_size(mut self, size: usize) -> Builder {
+ self.stack_size = Some(size);
+ self
+ }
+
+ /// Spawns a new thread by taking ownership of the `Builder`, and returns an
+ /// [`io::Result`] to its [`JoinHandle`].
+ ///
+ /// The spawned thread may outlive the caller (unless the caller thread
+ /// is the main thread; the whole process is terminated when the main
+ /// thread finishes). The join handle can be used to block on
+ /// termination of the child thread, including recovering its panics.
+ ///
+ /// For a more complete documentation see [`thread::spawn`][`spawn`].
+ ///
+ /// # Errors
+ ///
+ /// Unlike the [`spawn`] free function, this method yields an
+ /// [`io::Result`] to capture any failure to create the thread at
+ /// the OS level.
+ ///
+ /// [`spawn`]: ../../std/thread/fn.spawn.html
+ /// [`io::Result`]: ../../std/io/type.Result.html
+ /// [`JoinHandle`]: ../../std/thread/struct.JoinHandle.html
+ ///
+ /// # Panics
+ ///
+ /// Panics if a thread name was set and it contained null bytes.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::thread;
+ ///
+ /// let builder = thread::Builder::new();
+ ///
+ /// let handler = builder.spawn(|| {
+ /// // thread code
+ /// }).unwrap();
+ ///
+ /// handler.join().unwrap();
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn spawn<F, T>(self, f: F) -> io::Result<JoinHandle<T>> where
+ F: FnOnce() -> T, F: Send + 'static, T: Send + 'static
+ {
+ unsafe { self.spawn_unchecked(f) }
+ }
+
+ /// Spawns a new thread without any lifetime restrictions by taking ownership
+ /// of the `Builder`, and returns an [`io::Result`] to its [`JoinHandle`].
+ ///
+ /// The spawned thread may outlive the caller (unless the caller thread
+ /// is the main thread; the whole process is terminated when the main
+ /// thread finishes). The join handle can be used to block on
+ /// termination of the child thread, including recovering its panics.
+ ///
+ /// This method is identical to [`thread::Builder::spawn`][`Builder::spawn`],
+ /// except for the relaxed lifetime bounds, which render it unsafe.
+ /// For a more complete documentation see [`thread::spawn`][`spawn`].
+ ///
+ /// # Errors
+ ///
+ /// Unlike the [`spawn`] free function, this method yields an
+ /// [`io::Result`] to capture any failure to create the thread at
+ /// the OS level.
+ ///
+ /// # Panics
+ ///
+ /// Panics if a thread name was set and it contained null bytes.
+ ///
+ /// # Safety
+ ///
+ /// The caller has to ensure that no references in the supplied thread closure
+ /// or its return type can outlive the spawned thread's lifetime. This can be
+ /// guaranteed in two ways:
+ ///
+ /// - ensure that [`join`][`JoinHandle::join`] is called before any referenced
+ /// data is dropped
+ /// - use only types with `'static` lifetime bounds, i.e., those with no or only
+ /// `'static` references (both [`thread::Builder::spawn`][`Builder::spawn`]
+ /// and [`thread::spawn`][`spawn`] enforce this property statically)
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(thread_spawn_unchecked)]
+ /// use std::thread;
+ ///
+ /// let builder = thread::Builder::new();
+ ///
+ /// let x = 1;
+ /// let thread_x = &x;
+ ///
+ /// let handler = unsafe {
+ /// builder.spawn_unchecked(move || {
+ /// println!("x = {}", *thread_x);
+ /// }).unwrap()
+ /// };
+ ///
+ /// // caller has to ensure `join()` is called, otherwise
+ /// // it is possible to access freed memory if `x` gets
+ /// // dropped before the thread closure is executed!
+ /// handler.join().unwrap();
+ /// ```
+ ///
+ /// [`spawn`]: ../../std/thread/fn.spawn.html
+ /// [`Builder::spawn`]: ../../std/thread/struct.Builder.html#method.spawn
+ /// [`io::Result`]: ../../std/io/type.Result.html
+ /// [`JoinHandle`]: ../../std/thread/struct.JoinHandle.html
+ #[unstable(feature = "thread_spawn_unchecked", issue = "55132")]
+ pub unsafe fn spawn_unchecked<'a, F, T>(self, f: F) -> io::Result<JoinHandle<T>> where
+ F: FnOnce() -> T, F: Send + 'a, T: Send + 'a
+ {
+ let Builder { name, stack_size } = self;
+
+ let stack_size = stack_size.unwrap_or_else(thread::min_stack);
+
+ let my_thread = Thread::new(name);
+ let their_thread = my_thread.clone();
+
+ let my_packet : Arc<UnsafeCell<Option<Result<T>>>>
+ = Arc::new(UnsafeCell::new(None));
+ let their_packet = my_packet.clone();
+
+ let main = move || {
+ if let Some(name) = their_thread.cname() {
+ imp::Thread::set_name(name);
+ }
+
+ thread_info::set(imp::guard::current(), their_thread);
+ #[cfg(feature = "backtrace")]
+ let try_result = panic::catch_unwind(panic::AssertUnwindSafe(|| {
+ crate::sys_common::backtrace::__rust_begin_short_backtrace(f)
+ }));
+ #[cfg(not(feature = "backtrace"))]
+ let try_result = panic::catch_unwind(panic::AssertUnwindSafe(f));
+ *their_packet.get() = Some(try_result);
+ };
+
+ Ok(JoinHandle(JoinInner {
+ // `imp::Thread::new` takes a closure with a `'static` lifetime, since it's passed
+ // through FFI or otherwise used with low-level threading primitives that have no
+ // notion of or way to enforce lifetimes.
+ //
+ // As mentioned in the `Safety` section of this function's documentation, the caller of
+ // this function needs to guarantee that the passed-in lifetime is sufficiently long
+ // for the lifetime of the thread.
+ //
+ // Similarly, the `sys` implementation must guarantee that no references to the closure
+ // exist after the thread has terminated, which is signaled by `Thread::join`
+ // returning.
+ native: Some(imp::Thread::new(
+ stack_size,
+ mem::transmute::<Box<dyn FnBox() + 'a>, Box<dyn FnBox() + 'static>>(Box::new(main))
+ )?),
+ thread: my_thread,
+ packet: Packet(my_packet),
+ }))
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Free functions
+////////////////////////////////////////////////////////////////////////////////
+
+/// Spawns a new thread, returning a [`JoinHandle`] for it.
+///
+/// The join handle will implicitly *detach* the child thread upon being
+/// dropped. In this case, the child thread may outlive the parent (unless
+/// the parent thread is the main thread; the whole process is terminated when
+/// the main thread finishes). Additionally, the join handle provides a [`join`]
+/// method that can be used to join the child thread. If the child thread
+/// panics, [`join`] will return an [`Err`] containing the argument given to
+/// [`panic`].
+///
+/// This will create a thread using default parameters of [`Builder`], if you
+/// want to specify the stack size or the name of the thread, use this API
+/// instead.
+///
+/// As you can see in the signature of `spawn` there are two constraints on
+/// both the closure given to `spawn` and its return value, let's explain them:
+///
+/// - The `'static` constraint means that the closure and its return value
+/// must have a lifetime of the whole program execution. The reason for this
+/// is that threads can `detach` and outlive the lifetime they have been
+/// created in.
+/// Indeed if the thread, and by extension its return value, can outlive their
+/// caller, we need to make sure that they will be valid afterwards, and since
+/// we *can't* know when it will return we need to have them valid as long as
+/// possible, that is until the end of the program, hence the `'static`
+/// lifetime.
+/// - The [`Send`] constraint is because the closure will need to be passed
+/// *by value* from the thread where it is spawned to the new thread. Its
+/// return value will need to be passed from the new thread to the thread
+/// where it is `join`ed.
+/// As a reminder, the [`Send`] marker trait expresses that it is safe to be
+/// passed from thread to thread. [`Sync`] expresses that it is safe to have a
+/// reference be passed from thread to thread.
+///
+/// # Panics
+///
+/// Panics if the OS fails to create a thread; use [`Builder::spawn`]
+/// to recover from such errors.
+///
+/// # Examples
+///
+/// Creating a thread.
+///
+/// ```
+/// use std::thread;
+///
+/// let handler = thread::spawn(|| {
+/// // thread code
+/// });
+///
+/// handler.join().unwrap();
+/// ```
+///
+/// As mentioned in the module documentation, threads are usually made to
+/// communicate using [`channels`], here is how it usually looks.
+///
+/// This example also shows how to use `move`, in order to give ownership
+/// of values to a thread.
+///
+/// ```
+/// use std::thread;
+/// use std::sync::mpsc::channel;
+///
+/// let (tx, rx) = channel();
+///
+/// let sender = thread::spawn(move || {
+/// tx.send("Hello, thread".to_owned())
+/// .expect("Unable to send on channel");
+/// });
+///
+/// let receiver = thread::spawn(move || {
+/// let value = rx.recv().expect("Unable to receive from channel");
+/// println!("{}", value);
+/// });
+///
+/// sender.join().expect("The sender thread has panicked");
+/// receiver.join().expect("The receiver thread has panicked");
+/// ```
+///
+/// A thread can also return a value through its [`JoinHandle`], you can use
+/// this to make asynchronous computations (futures might be more appropriate
+/// though).
+///
+/// ```
+/// use std::thread;
+///
+/// let computation = thread::spawn(|| {
+/// // Some expensive computation.
+/// 42
+/// });
+///
+/// let result = computation.join().unwrap();
+/// println!("{}", result);
+/// ```
+///
+/// [`channels`]: ../../std/sync/mpsc/index.html
+/// [`JoinHandle`]: ../../std/thread/struct.JoinHandle.html
+/// [`join`]: ../../std/thread/struct.JoinHandle.html#method.join
+/// [`Err`]: ../../std/result/enum.Result.html#variant.Err
+/// [`panic`]: ../../std/macro.panic.html
+/// [`Builder::spawn`]: ../../std/thread/struct.Builder.html#method.spawn
+/// [`Builder`]: ../../std/thread/struct.Builder.html
+/// [`Send`]: ../../std/marker/trait.Send.html
+/// [`Sync`]: ../../std/marker/trait.Sync.html
+#[stable(feature = "rust1", since = "1.0.0")]
+pub fn spawn<F, T>(f: F) -> JoinHandle<T> where
+ F: FnOnce() -> T, F: Send + 'static, T: Send + 'static
+{
+ Builder::new().spawn(f).expect("failed to spawn thread")
+}
+
+/// Gets a handle to the thread that invokes it.
+///
+/// # Examples
+///
+/// Getting a handle to the current thread with `thread::current()`:
+///
+/// ```
+/// use std::thread;
+///
+/// let handler = thread::Builder::new()
+/// .name("named thread".into())
+/// .spawn(|| {
+/// let handle = thread::current();
+/// assert_eq!(handle.name(), Some("named thread"));
+/// })
+/// .unwrap();
+///
+/// handler.join().unwrap();
+/// ```
+#[stable(feature = "rust1", since = "1.0.0")]
+pub fn current() -> Thread {
+ thread_info::current_thread().expect("use of std::thread::current() is not \
+ possible after the thread's local \
+ data has been destroyed")
+}
+
+/// Cooperatively gives up a timeslice to the OS scheduler.
+///
+/// This is used when the programmer knows that the thread will have nothing
+/// to do for some time, and thus avoid wasting computing time.
+///
+/// For example when polling on a resource, it is common to check that it is
+/// available, and if not to yield in order to avoid busy waiting.
+///
+/// Thus the pattern of `yield`ing after a failed poll is rather common when
+/// implementing low-level shared resources or synchronization primitives.
+///
+/// However programmers will usually prefer to use [`channel`]s, [`Condvar`]s,
+/// [`Mutex`]es or [`join`] for their synchronization routines, as they avoid
+/// thinking about thread scheduling.
+///
+/// Note that [`channel`]s for example are implemented using this primitive.
+/// Indeed when you call `send` or `recv`, which are blocking, they will yield
+/// if the channel is not available.
+///
+/// # Examples
+///
+/// ```
+/// use std::thread;
+///
+/// thread::yield_now();
+/// ```
+///
+/// [`channel`]: ../../std/sync/mpsc/index.html
+/// [`spawn`]: ../../std/thread/fn.spawn.html
+/// [`join`]: ../../std/thread/struct.JoinHandle.html#method.join
+/// [`Mutex`]: ../../std/sync/struct.Mutex.html
+/// [`Condvar`]: ../../std/sync/struct.Condvar.html
+#[stable(feature = "rust1", since = "1.0.0")]
+pub fn yield_now() {
+ imp::Thread::yield_now()
+}
+
+/// Determines whether the current thread is unwinding because of panic.
+///
+/// A common use of this feature is to poison shared resources when writing
+/// unsafe code, by checking `panicking` when the `drop` is called.
+///
+/// This is usually not needed when writing safe code, as [`Mutex`es][Mutex]
+/// already poison themselves when a thread panics while holding the lock.
+///
+/// This can also be used in multithreaded applications, in order to send a
+/// message to other threads warning that a thread has panicked (e.g., for
+/// monitoring purposes).
+///
+/// # Examples
+///
+/// ```should_panic
+/// use std::thread;
+///
+/// struct SomeStruct;
+///
+/// impl Drop for SomeStruct {
+/// fn drop(&mut self) {
+/// if thread::panicking() {
+/// println!("dropped while unwinding");
+/// } else {
+/// println!("dropped while not unwinding");
+/// }
+/// }
+/// }
+///
+/// {
+/// print!("a: ");
+/// let a = SomeStruct;
+/// }
+///
+/// {
+/// print!("b: ");
+/// let b = SomeStruct;
+/// panic!()
+/// }
+/// ```
+///
+/// [Mutex]: ../../std/sync/struct.Mutex.html
+#[inline]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub fn panicking() -> bool {
+ panicking::panicking()
+}
+
+/// Puts the current thread to sleep for at least the specified amount of time.
+///
+/// The thread may sleep longer than the duration specified due to scheduling
+/// specifics or platform-dependent functionality. It will never sleep less.
+///
+/// # Platform-specific behavior
+///
+/// On Unix platforms, the underlying syscall may be interrupted by a
+/// spurious wakeup or signal handler. To ensure the sleep occurs for at least
+/// the specified duration, this function may invoke that system call multiple
+/// times.
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::thread;
+///
+/// // Let's sleep for 2 seconds:
+/// thread::sleep_ms(2000);
+/// ```
+#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_deprecated(since = "1.6.0", reason = "replaced by `std::thread::sleep`")]
+pub fn sleep_ms(ms: u32) {
+ sleep(Duration::from_millis(ms as u64))
+}
+
+/// Puts the current thread to sleep for at least the specified amount of time.
+///
+/// The thread may sleep longer than the duration specified due to scheduling
+/// specifics or platform-dependent functionality. It will never sleep less.
+///
+/// # Platform-specific behavior
+///
+/// On Unix platforms, the underlying syscall may be interrupted by a
+/// spurious wakeup or signal handler. To ensure the sleep occurs for at least
+/// the specified duration, this function may invoke that system call multiple
+/// times.
+/// Platforms which do not support nanosecond precision for sleeping will
+/// have `dur` rounded up to the nearest granularity of time they can sleep for.
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::{thread, time};
+///
+/// let ten_millis = time::Duration::from_millis(10);
+/// let now = time::Instant::now();
+///
+/// thread::sleep(ten_millis);
+///
+/// assert!(now.elapsed() >= ten_millis);
+/// ```
+#[stable(feature = "thread_sleep", since = "1.4.0")]
+pub fn sleep(dur: Duration) {
+ imp::Thread::sleep(dur)
+}
+
+// constants for park/unpark
+const EMPTY: usize = 0;
+const PARKED: usize = 1;
+const NOTIFIED: usize = 2;
+
+/// Blocks unless or until the current thread's token is made available.
+///
+/// A call to `park` does not guarantee that the thread will remain parked
+/// forever, and callers should be prepared for this possibility.
+///
+/// # park and unpark
+///
+/// Every thread is equipped with some basic low-level blocking support, via the
+/// [`thread::park`][`park`] function and [`thread::Thread::unpark`][`unpark`]
+/// method. [`park`] blocks the current thread, which can then be resumed from
+/// another thread by calling the [`unpark`] method on the blocked thread's
+/// handle.
+///
+/// Conceptually, each [`Thread`] handle has an associated token, which is
+/// initially not present:
+///
+/// * The [`thread::park`][`park`] function blocks the current thread unless or
+/// until the token is available for its thread handle, at which point it
+/// atomically consumes the token. It may also return *spuriously*, without
+/// consuming the token. [`thread::park_timeout`] does the same, but allows
+/// specifying a maximum time to block the thread for.
+///
+/// * The [`unpark`] method on a [`Thread`] atomically makes the token available
+/// if it wasn't already. Because the token is initially absent, [`unpark`]
+/// followed by [`park`] will result in the second call returning immediately.
+///
+/// In other words, each [`Thread`] acts a bit like a spinlock that can be
+/// locked and unlocked using `park` and `unpark`.
+///
+/// Notice that being unblocked does not imply any synchronization with someone
+/// that unparked this thread, it could also be spurious.
+/// For example, it would be a valid, but inefficient, implementation to make both [`park`] and
+/// [`unpark`] return immediately without doing anything.
+///
+/// The API is typically used by acquiring a handle to the current thread,
+/// placing that handle in a shared data structure so that other threads can
+/// find it, and then `park`ing in a loop. When some desired condition is met, another
+/// thread calls [`unpark`] on the handle.
+///
+/// The motivation for this design is twofold:
+///
+/// * It avoids the need to allocate mutexes and condvars when building new
+/// synchronization primitives; the threads already provide basic
+/// blocking/signaling.
+///
+/// * It can be implemented very efficiently on many platforms.
+///
+/// # Examples
+///
+/// ```
+/// use std::thread;
+/// use std::sync::{Arc, atomic::{Ordering, AtomicBool}};
+/// use std::time::Duration;
+///
+/// let flag = Arc::new(AtomicBool::new(false));
+/// let flag2 = Arc::clone(&flag);
+///
+/// let parked_thread = thread::spawn(move || {
+/// // We want to wait until the flag is set. We *could* just spin, but using
+/// // park/unpark is more efficient.
+/// while !flag2.load(Ordering::Acquire) {
+/// println!("Parking thread");
+/// thread::park();
+/// // We *could* get here spuriously, i.e., way before the 10ms below are over!
+/// // But that is no problem, we are in a loop until the flag is set anyway.
+/// println!("Thread unparked");
+/// }
+/// println!("Flag received");
+/// });
+///
+/// // Let some time pass for the thread to be spawned.
+/// thread::sleep(Duration::from_millis(10));
+///
+/// // Set the flag, and let the thread wake up.
+/// // There is no race condition here, if `unpark`
+/// // happens first, `park` will return immediately.
+/// // Hence there is no risk of a deadlock.
+/// flag.store(true, Ordering::Release);
+/// println!("Unpark the thread");
+/// parked_thread.thread().unpark();
+///
+/// parked_thread.join().unwrap();
+/// ```
+///
+/// [`Thread`]: ../../std/thread/struct.Thread.html
+/// [`park`]: ../../std/thread/fn.park.html
+/// [`unpark`]: ../../std/thread/struct.Thread.html#method.unpark
+/// [`thread::park_timeout`]: ../../std/thread/fn.park_timeout.html
+//
+// The implementation currently uses the trivial strategy of a Mutex+Condvar
+// with wakeup flag, which does not actually allow spurious wakeups. In the
+// future, this will be implemented in a more efficient way, perhaps along the lines of
+// http://cr.openjdk.java.net/~stefank/6989984.1/raw_files/new/src/os/linux/vm/os_linux.cpp
+// or futuxes, and in either case may allow spurious wakeups.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub fn park() {
+ let thread = current();
+
+ // If we were previously notified then we consume this notification and
+ // return quickly.
+ if thread.inner.state.compare_exchange(NOTIFIED, EMPTY, SeqCst, SeqCst).is_ok() {
+ return
+ }
+
+ // Otherwise we need to coordinate going to sleep
+ let mut m = thread.inner.lock.lock().unwrap();
+ match thread.inner.state.compare_exchange(EMPTY, PARKED, SeqCst, SeqCst) {
+ Ok(_) => {}
+ Err(NOTIFIED) => {
+ // We must read here, even though we know it will be `NOTIFIED`.
+ // This is because `unpark` may have been called again since we read
+ // `NOTIFIED` in the `compare_exchange` above. We must perform an
+ // acquire operation that synchronizes with that `unpark` to observe
+ // any writes it made before the call to unpark. To do that we must
+ // read from the write it made to `state`.
+ let old = thread.inner.state.swap(EMPTY, SeqCst);
+ assert_eq!(old, NOTIFIED, "park state changed unexpectedly");
+ return;
+ } // should consume this notification, so prohibit spurious wakeups in next park.
+ Err(_) => panic!("inconsistent park state"),
+ }
+ loop {
+ m = thread.inner.cvar.wait(m).unwrap();
+ match thread.inner.state.compare_exchange(NOTIFIED, EMPTY, SeqCst, SeqCst) {
+ Ok(_) => return, // got a notification
+ Err(_) => {} // spurious wakeup, go back to sleep
+ }
+ }
+}
+
+/// Use [`park_timeout`].
+///
+/// Blocks unless or until the current thread's token is made available or
+/// the specified duration has been reached (may wake spuriously).
+///
+/// The semantics of this function are equivalent to [`park`] except
+/// that the thread will be blocked for roughly no longer than `dur`. This
+/// method should not be used for precise timing due to anomalies such as
+/// preemption or platform differences that may not cause the maximum
+/// amount of time waited to be precisely `ms` long.
+///
+/// See the [park documentation][`park`] for more detail.
+///
+/// [`park_timeout`]: fn.park_timeout.html
+/// [`park`]: ../../std/thread/fn.park.html
+#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_deprecated(since = "1.6.0", reason = "replaced by `std::thread::park_timeout`")]
+pub fn park_timeout_ms(ms: u32) {
+ park_timeout(Duration::from_millis(ms as u64))
+}
+
+/// Blocks unless or until the current thread's token is made available or
+/// the specified duration has been reached (may wake spuriously).
+///
+/// The semantics of this function are equivalent to [`park`][park] except
+/// that the thread will be blocked for roughly no longer than `dur`. This
+/// method should not be used for precise timing due to anomalies such as
+/// preemption or platform differences that may not cause the maximum
+/// amount of time waited to be precisely `dur` long.
+///
+/// See the [park documentation][park] for more details.
+///
+/// # Platform-specific behavior
+///
+/// Platforms which do not support nanosecond precision for sleeping will have
+/// `dur` rounded up to the nearest granularity of time they can sleep for.
+///
+/// # Examples
+///
+/// Waiting for the complete expiration of the timeout:
+///
+/// ```rust,no_run
+/// use std::thread::park_timeout;
+/// use std::time::{Instant, Duration};
+///
+/// let timeout = Duration::from_secs(2);
+/// let beginning_park = Instant::now();
+///
+/// let mut timeout_remaining = timeout;
+/// loop {
+/// park_timeout(timeout_remaining);
+/// let elapsed = beginning_park.elapsed();
+/// if elapsed >= timeout {
+/// break;
+/// }
+/// println!("restarting park_timeout after {:?}", elapsed);
+/// timeout_remaining = timeout - elapsed;
+/// }
+/// ```
+///
+/// [park]: fn.park.html
+#[stable(feature = "park_timeout", since = "1.4.0")]
+pub fn park_timeout(dur: Duration) {
+ let thread = current();
+
+ // Like `park` above we have a fast path for an already-notified thread, and
+ // afterwards we start coordinating for a sleep.
+ // return quickly.
+ if thread.inner.state.compare_exchange(NOTIFIED, EMPTY, SeqCst, SeqCst).is_ok() {
+ return
+ }
+ let m = thread.inner.lock.lock().unwrap();
+ match thread.inner.state.compare_exchange(EMPTY, PARKED, SeqCst, SeqCst) {
+ Ok(_) => {}
+ Err(NOTIFIED) => {
+ // We must read again here, see `park`.
+ let old = thread.inner.state.swap(EMPTY, SeqCst);
+ assert_eq!(old, NOTIFIED, "park state changed unexpectedly");
+ return;
+ } // should consume this notification, so prohibit spurious wakeups in next park.
+ Err(_) => panic!("inconsistent park_timeout state"),
+ }
+
+ // Wait with a timeout, and if we spuriously wake up or otherwise wake up
+ // from a notification we just want to unconditionally set the state back to
+ // empty, either consuming a notification or un-flagging ourselves as
+ // parked.
+ let (_m, _result) = thread.inner.cvar.wait_timeout(m, dur).unwrap();
+ match thread.inner.state.swap(EMPTY, SeqCst) {
+ NOTIFIED => {} // got a notification, hurray!
+ PARKED => {} // no notification, alas
+ n => panic!("inconsistent park_timeout state: {}", n),
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// ThreadId
+////////////////////////////////////////////////////////////////////////////////
+
+/// A unique identifier for a running thread.
+///
+/// A `ThreadId` is an opaque object that has a unique value for each thread
+/// that creates one. `ThreadId`s are not guaranteed to correspond to a thread's
+/// system-designated identifier. A `ThreadId` can be retrieved from the [`id`]
+/// method on a [`Thread`].
+///
+/// # Examples
+///
+/// ```
+/// use std::thread;
+///
+/// let other_thread = thread::spawn(|| {
+/// thread::current().id()
+/// });
+///
+/// let other_thread_id = other_thread.join().unwrap();
+/// assert!(thread::current().id() != other_thread_id);
+/// ```
+///
+/// [`id`]: ../../std/thread/struct.Thread.html#method.id
+/// [`Thread`]: ../../std/thread/struct.Thread.html
+#[stable(feature = "thread_id", since = "1.19.0")]
+#[derive(Eq, PartialEq, Clone, Copy, Hash, Debug)]
+pub struct ThreadId(NonZeroU64);
+
+impl ThreadId {
+ // Generate a new unique thread ID.
+ fn new() -> ThreadId {
+ // We never call `GUARD.init()`, so it is UB to attempt to
+ // acquire this mutex reentrantly!
+ static GUARD: mutex::Mutex = mutex::Mutex::new();
+ static mut COUNTER: u64 = 1;
+
+ unsafe {
+ let _guard = GUARD.lock();
+
+ // If we somehow use up all our bits, panic so that we're not
+ // covering up subtle bugs of IDs being reused.
+ if COUNTER == crate::u64::MAX {
+ panic!("failed to generate unique thread ID: bitspace exhausted");
+ }
+
+ let id = COUNTER;
+ COUNTER += 1;
+
+ ThreadId(NonZeroU64::new(id).unwrap())
+ }
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Thread
+////////////////////////////////////////////////////////////////////////////////
+
+/// The internal representation of a `Thread` handle
+struct Inner {
+ name: Option<CString>, // Guaranteed to be UTF-8
+ id: ThreadId,
+
+ // state for thread park/unpark
+ state: AtomicUsize,
+ lock: Mutex<()>,
+ cvar: Condvar,
+}
+
+#[derive(Clone)]
+#[stable(feature = "rust1", since = "1.0.0")]
+/// A handle to a thread.
+///
+/// Threads are represented via the `Thread` type, which you can get in one of
+/// two ways:
+///
+/// * By spawning a new thread, e.g., using the [`thread::spawn`][`spawn`]
+/// function, and calling [`thread`][`JoinHandle::thread`] on the
+/// [`JoinHandle`].
+/// * By requesting the current thread, using the [`thread::current`] function.
+///
+/// The [`thread::current`] function is available even for threads not spawned
+/// by the APIs of this module.
+///
+/// There is usually no need to create a `Thread` struct yourself, one
+/// should instead use a function like `spawn` to create new threads, see the
+/// docs of [`Builder`] and [`spawn`] for more details.
+///
+/// [`Builder`]: ../../std/thread/struct.Builder.html
+/// [`JoinHandle::thread`]: ../../std/thread/struct.JoinHandle.html#method.thread
+/// [`JoinHandle`]: ../../std/thread/struct.JoinHandle.html
+/// [`thread::current`]: ../../std/thread/fn.current.html
+/// [`spawn`]: ../../std/thread/fn.spawn.html
+
+pub struct Thread {
+ inner: Arc<Inner>,
+}
+
+impl Thread {
+ // Used only internally to construct a thread object without spawning
+ // Panics if the name contains nuls.
+ pub(crate) fn new(name: Option<String>) -> Thread {
+ let cname = name.map(|n| {
+ CString::new(n).expect("thread name may not contain interior null bytes")
+ });
+ Thread {
+ inner: Arc::new(Inner {
+ name: cname,
+ id: ThreadId::new(),
+ state: AtomicUsize::new(EMPTY),
+ lock: Mutex::new(()),
+ cvar: Condvar::new(),
+ })
+ }
+ }
+
+ /// Atomically makes the handle's token available if it is not already.
+ ///
+ /// Every thread is equipped with some basic low-level blocking support, via
+ /// the [`park`][park] function and the `unpark()` method. These can be
+ /// used as a more CPU-efficient implementation of a spinlock.
+ ///
+ /// See the [park documentation][park] for more details.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::thread;
+ /// use std::time::Duration;
+ ///
+ /// let parked_thread = thread::Builder::new()
+ /// .spawn(|| {
+ /// println!("Parking thread");
+ /// thread::park();
+ /// println!("Thread unparked");
+ /// })
+ /// .unwrap();
+ ///
+ /// // Let some time pass for the thread to be spawned.
+ /// thread::sleep(Duration::from_millis(10));
+ ///
+ /// println!("Unpark the thread");
+ /// parked_thread.thread().unpark();
+ ///
+ /// parked_thread.join().unwrap();
+ /// ```
+ ///
+ /// [park]: fn.park.html
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn unpark(&self) {
+ // To ensure the unparked thread will observe any writes we made
+ // before this call, we must perform a release operation that `park`
+ // can synchronize with. To do that we must write `NOTIFIED` even if
+ // `state` is already `NOTIFIED`. That is why this must be a swap
+ // rather than a compare-and-swap that returns if it reads `NOTIFIED`
+ // on failure.
+ match self.inner.state.swap(NOTIFIED, SeqCst) {
+ EMPTY => return, // no one was waiting
+ NOTIFIED => return, // already unparked
+ PARKED => {} // gotta go wake someone up
+ _ => panic!("inconsistent state in unpark"),
+ }
+
+ // There is a period between when the parked thread sets `state` to
+ // `PARKED` (or last checked `state` in the case of a spurious wake
+ // up) and when it actually waits on `cvar`. If we were to notify
+ // during this period it would be ignored and then when the parked
+ // thread went to sleep it would never wake up. Fortunately, it has
+ // `lock` locked at this stage so we can acquire `lock` to wait until
+ // it is ready to receive the notification.
+ //
+ // Releasing `lock` before the call to `notify_one` means that when the
+ // parked thread wakes it doesn't get woken only to have to wait for us
+ // to release `lock`.
+ drop(self.inner.lock.lock().unwrap());
+ self.inner.cvar.notify_one()
+ }
+
+ /// Gets the thread's unique identifier.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::thread;
+ ///
+ /// let other_thread = thread::spawn(|| {
+ /// thread::current().id()
+ /// });
+ ///
+ /// let other_thread_id = other_thread.join().unwrap();
+ /// assert!(thread::current().id() != other_thread_id);
+ /// ```
+ #[stable(feature = "thread_id", since = "1.19.0")]
+ pub fn id(&self) -> ThreadId {
+ self.inner.id
+ }
+
+ /// Gets the thread's name.
+ ///
+ /// For more information about named threads, see
+ /// [this module-level documentation][naming-threads].
+ ///
+ /// # Examples
+ ///
+ /// Threads by default have no name specified:
+ ///
+ /// ```
+ /// use std::thread;
+ ///
+ /// let builder = thread::Builder::new();
+ ///
+ /// let handler = builder.spawn(|| {
+ /// assert!(thread::current().name().is_none());
+ /// }).unwrap();
+ ///
+ /// handler.join().unwrap();
+ /// ```
+ ///
+ /// Thread with a specified name:
+ ///
+ /// ```
+ /// use std::thread;
+ ///
+ /// let builder = thread::Builder::new()
+ /// .name("foo".into());
+ ///
+ /// let handler = builder.spawn(|| {
+ /// assert_eq!(thread::current().name(), Some("foo"))
+ /// }).unwrap();
+ ///
+ /// handler.join().unwrap();
+ /// ```
+ ///
+ /// [naming-threads]: ./index.html#naming-threads
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn name(&self) -> Option<&str> {
+ self.cname().map(|s| unsafe { str::from_utf8_unchecked(s.to_bytes()) } )
+ }
+
+ fn cname(&self) -> Option<&CStr> {
+ self.inner.name.as_ref().map(|s| &**s)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl fmt::Debug for Thread {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("Thread")
+ .field("id", &self.id())
+ .field("name", &self.name())
+ .finish()
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// JoinHandle
+////////////////////////////////////////////////////////////////////////////////
+
+/// A specialized [`Result`] type for threads.
+///
+/// Indicates the manner in which a thread exited.
+///
+/// A thread that completes without panicking is considered to exit successfully.
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::thread;
+/// use std::fs;
+///
+/// fn copy_in_thread() -> thread::Result<()> {
+/// thread::spawn(move || { fs::copy("foo.txt", "bar.txt").unwrap(); }).join()
+/// }
+///
+/// fn main() {
+/// match copy_in_thread() {
+/// Ok(_) => println!("this is fine"),
+/// Err(_) => println!("thread panicked"),
+/// }
+/// }
+/// ```
+///
+/// [`Result`]: ../../std/result/enum.Result.html
+#[stable(feature = "rust1", since = "1.0.0")]
+pub type Result<T> = crate::result::Result<T, Box<dyn Any + Send + 'static>>;
+
+// This packet is used to communicate the return value between the child thread
+// and the parent thread. Memory is shared through the `Arc` within and there's
+// no need for a mutex here because synchronization happens with `join()` (the
+// parent thread never reads this packet until the child has exited).
+//
+// This packet itself is then stored into a `JoinInner` which in turns is placed
+// in `JoinHandle` and `JoinGuard`. Due to the usage of `UnsafeCell` we need to
+// manually worry about impls like Send and Sync. The type `T` should
+// already always be Send (otherwise the thread could not have been created) and
+// this type is inherently Sync because no methods take &self. Regardless,
+// however, we add inheriting impls for Send/Sync to this type to ensure it's
+// Send/Sync and that future modifications will still appropriately classify it.
+struct Packet<T>(Arc<UnsafeCell<Option<Result<T>>>>);
+
+unsafe impl<T: Send> Send for Packet<T> {}
+unsafe impl<T: Sync> Sync for Packet<T> {}
+
+/// Inner representation for JoinHandle
+struct JoinInner<T> {
+ native: Option<imp::Thread>,
+ thread: Thread,
+ packet: Packet<T>,
+}
+
+impl<T> JoinInner<T> {
+ fn join(&mut self) -> Result<T> {
+ self.native.take().unwrap().join();
+ unsafe {
+ (*self.packet.0.get()).take().unwrap()
+ }
+ }
+}
+
+/// An owned permission to join on a thread (block on its termination).
+///
+/// A `JoinHandle` *detaches* the associated thread when it is dropped, which
+/// means that there is no longer any handle to thread and no way to `join`
+/// on it.
+///
+/// Due to platform restrictions, it is not possible to [`Clone`] this
+/// handle: the ability to join a thread is a uniquely-owned permission.
+///
+/// This `struct` is created by the [`thread::spawn`] function and the
+/// [`thread::Builder::spawn`] method.
+///
+/// # Examples
+///
+/// Creation from [`thread::spawn`]:
+///
+/// ```
+/// use std::thread;
+///
+/// let join_handle: thread::JoinHandle<_> = thread::spawn(|| {
+/// // some work here
+/// });
+/// ```
+///
+/// Creation from [`thread::Builder::spawn`]:
+///
+/// ```
+/// use std::thread;
+///
+/// let builder = thread::Builder::new();
+///
+/// let join_handle: thread::JoinHandle<_> = builder.spawn(|| {
+/// // some work here
+/// }).unwrap();
+/// ```
+///
+/// Child being detached and outliving its parent:
+///
+/// ```no_run
+/// use std::thread;
+/// use std::time::Duration;
+///
+/// let original_thread = thread::spawn(|| {
+/// let _detached_thread = thread::spawn(|| {
+/// // Here we sleep to make sure that the first thread returns before.
+/// thread::sleep(Duration::from_millis(10));
+/// // This will be called, even though the JoinHandle is dropped.
+/// println!("♫ Still alive ♫");
+/// });
+/// });
+///
+/// original_thread.join().expect("The thread being joined has panicked");
+/// println!("Original thread is joined.");
+///
+/// // We make sure that the new thread has time to run, before the main
+/// // thread returns.
+///
+/// thread::sleep(Duration::from_millis(1000));
+/// ```
+///
+/// [`Clone`]: ../../std/clone/trait.Clone.html
+/// [`thread::spawn`]: fn.spawn.html
+/// [`thread::Builder::spawn`]: struct.Builder.html#method.spawn
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct JoinHandle<T>(JoinInner<T>);
+
+#[stable(feature = "joinhandle_impl_send_sync", since = "1.29.0")]
+unsafe impl<T> Send for JoinHandle<T> {}
+#[stable(feature = "joinhandle_impl_send_sync", since = "1.29.0")]
+unsafe impl<T> Sync for JoinHandle<T> {}
+
+impl<T> JoinHandle<T> {
+ /// Extracts a handle to the underlying thread.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::thread;
+ ///
+ /// let builder = thread::Builder::new();
+ ///
+ /// let join_handle: thread::JoinHandle<_> = builder.spawn(|| {
+ /// // some work here
+ /// }).unwrap();
+ ///
+ /// let thread = join_handle.thread();
+ /// println!("thread id: {:?}", thread.id());
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn thread(&self) -> &Thread {
+ &self.0.thread
+ }
+
+ /// Waits for the associated thread to finish.
+ ///
+ /// In terms of [atomic memory orderings], the completion of the associated
+ /// thread synchronizes with this function returning. In other words, all
+ /// operations performed by that thread are ordered before all
+ /// operations that happen after `join` returns.
+ ///
+ /// If the child thread panics, [`Err`] is returned with the parameter given
+ /// to [`panic`].
+ ///
+ /// [`Err`]: ../../std/result/enum.Result.html#variant.Err
+ /// [`panic`]: ../../std/macro.panic.html
+ /// [atomic memory orderings]: ../../std/sync/atomic/index.html
+ ///
+ /// # Panics
+ ///
+ /// This function may panic on some platforms if a thread attempts to join
+ /// itself or otherwise may create a deadlock with joining threads.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::thread;
+ ///
+ /// let builder = thread::Builder::new();
+ ///
+ /// let join_handle: thread::JoinHandle<_> = builder.spawn(|| {
+ /// // some work here
+ /// }).unwrap();
+ /// join_handle.join().expect("Couldn't join on the associated thread");
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn join(mut self) -> Result<T> {
+ self.0.join()
+ }
+}
+
+impl<T> AsInner<imp::Thread> for JoinHandle<T> {
+ fn as_inner(&self) -> &imp::Thread { self.0.native.as_ref().unwrap() }
+}
+
+impl<T> IntoInner<imp::Thread> for JoinHandle<T> {
+ fn into_inner(self) -> imp::Thread { self.0.native.unwrap() }
+}
+
+#[stable(feature = "std_debug", since = "1.16.0")]
+impl<T> fmt::Debug for JoinHandle<T> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.pad("JoinHandle { .. }")
+ }
+}
+
+fn _assert_sync_and_send() {
+ fn _assert_both<T: Send + Sync>() {}
+ _assert_both::<JoinHandle<()>>();
+ _assert_both::<Thread>();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Tests
+////////////////////////////////////////////////////////////////////////////////
+
+#[cfg(all(test, not(target_os = "emscripten")))]
+mod tests {
+ use super::Builder;
+ use crate::any::Any;
+ use crate::mem;
+ use crate::sync::mpsc::{channel, Sender};
+ use crate::result;
+ use crate::thread::{self, ThreadId};
+ use crate::time::Duration;
+ use crate::u32;
+
+ // !!! These tests are dangerous. If something is buggy, they will hang, !!!
+ // !!! instead of exiting cleanly. This might wedge the buildbots. !!!
+
+ #[test]
+ fn test_unnamed_thread() {
+ thread::spawn(move|| {
+ assert!(thread::current().name().is_none());
+ }).join().ok().expect("thread panicked");
+ }
+
+ #[test]
+ fn test_named_thread() {
+ Builder::new().name("ada lovelace".to_string()).spawn(move|| {
+ assert!(thread::current().name().unwrap() == "ada lovelace".to_string());
+ }).unwrap().join().unwrap();
+ }
+
+ #[test]
+ #[should_panic]
+ fn test_invalid_named_thread() {
+ let _ = Builder::new().name("ada l\0velace".to_string()).spawn(|| {});
+ }
+
+ #[test]
+ fn test_run_basic() {
+ let (tx, rx) = channel();
+ thread::spawn(move|| {
+ tx.send(()).unwrap();
+ });
+ rx.recv().unwrap();
+ }
+
+ #[test]
+ fn test_join_panic() {
+ match thread::spawn(move|| {
+ panic!()
+ }).join() {
+ result::Result::Err(_) => (),
+ result::Result::Ok(()) => panic!()
+ }
+ }
+
+ #[test]
+ fn test_spawn_sched() {
+ let (tx, rx) = channel();
+
+ fn f(i: i32, tx: Sender<()>) {
+ let tx = tx.clone();
+ thread::spawn(move|| {
+ if i == 0 {
+ tx.send(()).unwrap();
+ } else {
+ f(i - 1, tx);
+ }
+ });
+
+ }
+ f(10, tx);
+ rx.recv().unwrap();
+ }
+
+ #[test]
+ fn test_spawn_sched_childs_on_default_sched() {
+ let (tx, rx) = channel();
+
+ thread::spawn(move|| {
+ thread::spawn(move|| {
+ tx.send(()).unwrap();
+ });
+ });
+
+ rx.recv().unwrap();
+ }
+
+ fn avoid_copying_the_body<F>(spawnfn: F) where F: FnOnce(Box<dyn Fn() + Send>) {
+ let (tx, rx) = channel();
+
+ let x: Box<_> = box 1;
+ let x_in_parent = (&*x) as *const i32 as usize;
+
+ spawnfn(Box::new(move|| {
+ let x_in_child = (&*x) as *const i32 as usize;
+ tx.send(x_in_child).unwrap();
+ }));
+
+ let x_in_child = rx.recv().unwrap();
+ assert_eq!(x_in_parent, x_in_child);
+ }
+
+ #[test]
+ fn test_avoid_copying_the_body_spawn() {
+ avoid_copying_the_body(|v| {
+ thread::spawn(move || v());
+ });
+ }
+
+ #[test]
+ fn test_avoid_copying_the_body_thread_spawn() {
+ avoid_copying_the_body(|f| {
+ thread::spawn(move|| {
+ f();
+ });
+ })
+ }
+
+ #[test]
+ fn test_avoid_copying_the_body_join() {
+ avoid_copying_the_body(|f| {
+ let _ = thread::spawn(move|| {
+ f()
+ }).join();
+ })
+ }
+
+ #[test]
+ fn test_child_doesnt_ref_parent() {
+ // If the child refcounts the parent thread, this will stack overflow when
+ // climbing the thread tree to dereference each ancestor. (See #1789)
+ // (well, it would if the constant were 8000+ - I lowered it to be more
+ // valgrind-friendly. try this at home, instead..!)
+ const GENERATIONS: u32 = 16;
+ fn child_no(x: u32) -> Box<dyn Fn() + Send> {
+ return Box::new(move|| {
+ if x < GENERATIONS {
+ thread::spawn(move|| child_no(x+1)());
+ }
+ });
+ }
+ thread::spawn(|| child_no(0)());
+ }
+
+ #[test]
+ fn test_simple_newsched_spawn() {
+ thread::spawn(move || {});
+ }
+
+ #[test]
+ fn test_try_panic_message_static_str() {
+ match thread::spawn(move|| {
+ panic!("static string");
+ }).join() {
+ Err(e) => {
+ type T = &'static str;
+ assert!(e.is::<T>());
+ assert_eq!(*e.downcast::<T>().unwrap(), "static string");
+ }
+ Ok(()) => panic!()
+ }
+ }
+
+ #[test]
+ fn test_try_panic_message_owned_str() {
+ match thread::spawn(move|| {
+ panic!("owned string".to_string());
+ }).join() {
+ Err(e) => {
+ type T = String;
+ assert!(e.is::<T>());
+ assert_eq!(*e.downcast::<T>().unwrap(), "owned string".to_string());
+ }
+ Ok(()) => panic!()
+ }
+ }
+
+ #[test]
+ fn test_try_panic_message_any() {
+ match thread::spawn(move|| {
+ panic!(box 413u16 as Box<dyn Any + Send>);
+ }).join() {
+ Err(e) => {
+ type T = Box<dyn Any + Send>;
+ assert!(e.is::<T>());
+ let any = e.downcast::<T>().unwrap();
+ assert!(any.is::<u16>());
+ assert_eq!(*any.downcast::<u16>().unwrap(), 413);
+ }
+ Ok(()) => panic!()
+ }
+ }
+
+ #[test]
+ fn test_try_panic_message_unit_struct() {
+ struct Juju;
+
+ match thread::spawn(move|| {
+ panic!(Juju)
+ }).join() {
+ Err(ref e) if e.is::<Juju>() => {}
+ Err(_) | Ok(()) => panic!()
+ }
+ }
+
+ #[test]
+ fn test_park_timeout_unpark_before() {
+ for _ in 0..10 {
+ thread::current().unpark();
+ thread::park_timeout(Duration::from_millis(u32::MAX as u64));
+ }
+ }
+
+ #[test]
+ #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
+ fn test_park_timeout_unpark_not_called() {
+ for _ in 0..10 {
+ thread::park_timeout(Duration::from_millis(10));
+ }
+ }
+
+ #[test]
+ #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
+ fn test_park_timeout_unpark_called_other_thread() {
+ for _ in 0..10 {
+ let th = thread::current();
+
+ let _guard = thread::spawn(move || {
+ super::sleep(Duration::from_millis(50));
+ th.unpark();
+ });
+
+ thread::park_timeout(Duration::from_millis(u32::MAX as u64));
+ }
+ }
+
+ #[test]
+ #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
+ fn sleep_ms_smoke() {
+ thread::sleep(Duration::from_millis(2));
+ }
+
+ #[test]
+ fn test_size_of_option_thread_id() {
+ assert_eq!(mem::size_of::<Option<ThreadId>>(), mem::size_of::<ThreadId>());
+ }
+
+ #[test]
+ fn test_thread_id_equal() {
+ assert!(thread::current().id() == thread::current().id());
+ }
+
+ #[test]
+ fn test_thread_id_not_equal() {
+ let spawned_id = thread::spawn(|| thread::current().id()).join().unwrap();
+ assert!(thread::current().id() != spawned_id);
+ }
+
+ // NOTE: the corresponding test for stderr is in run-pass/thread-stderr, due
+ // to the test harness apparently interfering with stderr configuration.
+}
diff --git a/src/libstd/time.rs b/src/libstd/time.rs
new file mode 100644
index 0000000..dc97f8c
--- /dev/null
+++ b/src/libstd/time.rs
@@ -0,0 +1,764 @@
+//! Temporal quantification.
+//!
+//! Example:
+//!
+//! ```
+//! use std::time::Duration;
+//!
+//! let five_seconds = Duration::new(5, 0);
+//! // both declarations are equivalent
+//! assert_eq!(Duration::new(5, 0), Duration::from_secs(5));
+//! ```
+
+#![stable(feature = "time", since = "1.3.0")]
+
+use crate::cmp;
+use crate::error::Error;
+use crate::fmt;
+use crate::ops::{Add, Sub, AddAssign, SubAssign};
+use crate::sys::time;
+use crate::sys_common::FromInner;
+use crate::sys_common::mutex::Mutex;
+
+#[stable(feature = "time", since = "1.3.0")]
+pub use core::time::Duration;
+
+/// A measurement of a monotonically nondecreasing clock.
+/// Opaque and useful only with `Duration`.
+///
+/// Instants are always guaranteed to be no less than any previously measured
+/// instant when created, and are often useful for tasks such as measuring
+/// benchmarks or timing how long an operation takes.
+///
+/// Note, however, that instants are not guaranteed to be **steady**. In other
+/// words, each tick of the underlying clock may not be the same length (e.g.
+/// some seconds may be longer than others). An instant may jump forwards or
+/// experience time dilation (slow down or speed up), but it will never go
+/// backwards.
+///
+/// Instants are opaque types that can only be compared to one another. There is
+/// no method to get "the number of seconds" from an instant. Instead, it only
+/// allows measuring the duration between two instants (or comparing two
+/// instants).
+///
+/// The size of an `Instant` struct may vary depending on the target operating
+/// system.
+///
+/// Example:
+///
+/// ```no_run
+/// use std::time::{Duration, Instant};
+/// use std::thread::sleep;
+///
+/// fn main() {
+/// let now = Instant::now();
+///
+/// // we sleep for 2 seconds
+/// sleep(Duration::new(2, 0));
+/// // it prints '2'
+/// println!("{}", now.elapsed().as_secs());
+/// }
+/// ```
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
+#[stable(feature = "time2", since = "1.8.0")]
+pub struct Instant(time::Instant);
+
+/// A measurement of the system clock, useful for talking to
+/// external entities like the file system or other processes.
+///
+/// Distinct from the [`Instant`] type, this time measurement **is not
+/// monotonic**. This means that you can save a file to the file system, then
+/// save another file to the file system, **and the second file has a
+/// `SystemTime` measurement earlier than the first**. In other words, an
+/// operation that happens after another operation in real time may have an
+/// earlier `SystemTime`!
+///
+/// Consequently, comparing two `SystemTime` instances to learn about the
+/// duration between them returns a [`Result`] instead of an infallible [`Duration`]
+/// to indicate that this sort of time drift may happen and needs to be handled.
+///
+/// Although a `SystemTime` cannot be directly inspected, the [`UNIX_EPOCH`]
+/// constant is provided in this module as an anchor in time to learn
+/// information about a `SystemTime`. By calculating the duration from this
+/// fixed point in time, a `SystemTime` can be converted to a human-readable time,
+/// or perhaps some other string representation.
+///
+/// The size of a `SystemTime` struct may vary depending on the target operating
+/// system.
+///
+/// [`Instant`]: ../../std/time/struct.Instant.html
+/// [`Result`]: ../../std/result/enum.Result.html
+/// [`Duration`]: ../../std/time/struct.Duration.html
+/// [`UNIX_EPOCH`]: ../../std/time/constant.UNIX_EPOCH.html
+///
+/// Example:
+///
+/// ```no_run
+/// use std::time::{Duration, SystemTime};
+/// use std::thread::sleep;
+///
+/// fn main() {
+/// let now = SystemTime::now();
+///
+/// // we sleep for 2 seconds
+/// sleep(Duration::new(2, 0));
+/// match now.elapsed() {
+/// Ok(elapsed) => {
+/// // it prints '2'
+/// println!("{}", elapsed.as_secs());
+/// }
+/// Err(e) => {
+/// // an error occurred!
+/// println!("Error: {:?}", e);
+/// }
+/// }
+/// }
+/// ```
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
+#[stable(feature = "time2", since = "1.8.0")]
+pub struct SystemTime(time::SystemTime);
+
+/// An error returned from the `duration_since` and `elapsed` methods on
+/// `SystemTime`, used to learn how far in the opposite direction a system time
+/// lies.
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::thread::sleep;
+/// use std::time::{Duration, SystemTime};
+///
+/// let sys_time = SystemTime::now();
+/// sleep(Duration::from_secs(1));
+/// let new_sys_time = SystemTime::now();
+/// match sys_time.duration_since(new_sys_time) {
+/// Ok(_) => {}
+/// Err(e) => println!("SystemTimeError difference: {:?}", e.duration()),
+/// }
+/// ```
+#[derive(Clone, Debug)]
+#[stable(feature = "time2", since = "1.8.0")]
+pub struct SystemTimeError(Duration);
+
+impl Instant {
+ /// Returns an instant corresponding to "now".
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::time::Instant;
+ ///
+ /// let now = Instant::now();
+ /// ```
+ #[stable(feature = "time2", since = "1.8.0")]
+ pub fn now() -> Instant {
+ let os_now = time::Instant::now();
+
+ // And here we come upon a sad state of affairs. The whole point of
+ // `Instant` is that it's monotonically increasing. We've found in the
+ // wild, however, that it's not actually monotonically increasing for
+ // one reason or another. These appear to be OS and hardware level bugs,
+ // and there's not really a whole lot we can do about them. Here's a
+ // taste of what we've found:
+ //
+ // * #48514 - OpenBSD, x86_64
+ // * #49281 - linux arm64 and s390x
+ // * #51648 - windows, x86
+ // * #56560 - windows, x86_64, AWS
+ // * #56612 - windows, x86, vm (?)
+ // * #56940 - linux, arm64
+ // * https://bugzilla.mozilla.org/show_bug.cgi?id=1487778 - a similar
+ // Firefox bug
+ //
+ // It simply seems that this it just happens so that a lot in the wild
+ // we're seeing panics across various platforms where consecutive calls
+ // to `Instant::now`, such as via the `elapsed` function, are panicking
+ // as they're going backwards. Placed here is a last-ditch effort to try
+ // to fix things up. We keep a global "latest now" instance which is
+ // returned instead of what the OS says if the OS goes backwards.
+ //
+ // To hopefully mitigate the impact of this though a few platforms are
+ // whitelisted as "these at least haven't gone backwards yet".
+ if time::Instant::actually_monotonic() {
+ return Instant(os_now)
+ }
+
+ static LOCK: Mutex = Mutex::new();
+ static mut LAST_NOW: time::Instant = time::Instant::zero();
+ unsafe {
+ let _lock = LOCK.lock();
+ let now = cmp::max(LAST_NOW, os_now);
+ LAST_NOW = now;
+ Instant(now)
+ }
+ }
+
+ /// Returns the amount of time elapsed from another instant to this one.
+ ///
+ /// # Panics
+ ///
+ /// This function will panic if `earlier` is later than `self`.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::time::{Duration, Instant};
+ /// use std::thread::sleep;
+ ///
+ /// let now = Instant::now();
+ /// sleep(Duration::new(1, 0));
+ /// let new_now = Instant::now();
+ /// println!("{:?}", new_now.duration_since(now));
+ /// ```
+ #[stable(feature = "time2", since = "1.8.0")]
+ pub fn duration_since(&self, earlier: Instant) -> Duration {
+ self.0.checked_sub_instant(&earlier.0).expect("supplied instant is later than self")
+ }
+
+ /// Returns the amount of time elapsed from another instant to this one,
+ /// or None if that instant is earlier than this one.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// #![feature(checked_duration_since)]
+ /// use std::time::{Duration, Instant};
+ /// use std::thread::sleep;
+ ///
+ /// let now = Instant::now();
+ /// sleep(Duration::new(1, 0));
+ /// let new_now = Instant::now();
+ /// println!("{:?}", new_now.checked_duration_since(now));
+ /// println!("{:?}", now.checked_duration_since(new_now)); // None
+ /// ```
+ #[unstable(feature = "checked_duration_since", issue = "58402")]
+ pub fn checked_duration_since(&self, earlier: Instant) -> Option<Duration> {
+ self.0.checked_sub_instant(&earlier.0)
+ }
+
+ /// Returns the amount of time elapsed from another instant to this one,
+ /// or zero duration if that instant is earlier than this one.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// #![feature(checked_duration_since)]
+ /// use std::time::{Duration, Instant};
+ /// use std::thread::sleep;
+ ///
+ /// let now = Instant::now();
+ /// sleep(Duration::new(1, 0));
+ /// let new_now = Instant::now();
+ /// println!("{:?}", new_now.saturating_duration_since(now));
+ /// println!("{:?}", now.saturating_duration_since(new_now)); // 0ns
+ /// ```
+ #[unstable(feature = "checked_duration_since", issue = "58402")]
+ pub fn saturating_duration_since(&self, earlier: Instant) -> Duration {
+ self.checked_duration_since(earlier).unwrap_or(Duration::new(0, 0))
+ }
+
+ /// Returns the amount of time elapsed since this instant was created.
+ ///
+ /// # Panics
+ ///
+ /// This function may panic if the current time is earlier than this
+ /// instant, which is something that can happen if an `Instant` is
+ /// produced synthetically.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::thread::sleep;
+ /// use std::time::{Duration, Instant};
+ ///
+ /// let instant = Instant::now();
+ /// let three_secs = Duration::from_secs(3);
+ /// sleep(three_secs);
+ /// assert!(instant.elapsed() >= three_secs);
+ /// ```
+ #[stable(feature = "time2", since = "1.8.0")]
+ pub fn elapsed(&self) -> Duration {
+ Instant::now() - *self
+ }
+
+ /// Returns `Some(t)` where `t` is the time `self + duration` if `t` can be represented as
+ /// `Instant` (which means it's inside the bounds of the underlying data structure), `None`
+ /// otherwise.
+ #[stable(feature = "time_checked_add", since = "1.34.0")]
+ pub fn checked_add(&self, duration: Duration) -> Option<Instant> {
+ self.0.checked_add_duration(&duration).map(Instant)
+ }
+
+ /// Returns `Some(t)` where `t` is the time `self - duration` if `t` can be represented as
+ /// `Instant` (which means it's inside the bounds of the underlying data structure), `None`
+ /// otherwise.
+ #[stable(feature = "time_checked_add", since = "1.34.0")]
+ pub fn checked_sub(&self, duration: Duration) -> Option<Instant> {
+ self.0.checked_sub_duration(&duration).map(Instant)
+ }
+}
+
+#[stable(feature = "time2", since = "1.8.0")]
+impl Add<Duration> for Instant {
+ type Output = Instant;
+
+ /// # Panics
+ ///
+ /// This function may panic if the resulting point in time cannot be represented by the
+ /// underlying data structure. See [`checked_add`] for a version without panic.
+ ///
+ /// [`checked_add`]: ../../std/time/struct.Instant.html#method.checked_add
+ fn add(self, other: Duration) -> Instant {
+ self.checked_add(other)
+ .expect("overflow when adding duration to instant")
+ }
+}
+
+#[stable(feature = "time_augmented_assignment", since = "1.9.0")]
+impl AddAssign<Duration> for Instant {
+ fn add_assign(&mut self, other: Duration) {
+ *self = *self + other;
+ }
+}
+
+#[stable(feature = "time2", since = "1.8.0")]
+impl Sub<Duration> for Instant {
+ type Output = Instant;
+
+ fn sub(self, other: Duration) -> Instant {
+ self.checked_sub(other)
+ .expect("overflow when subtracting duration from instant")
+ }
+}
+
+#[stable(feature = "time_augmented_assignment", since = "1.9.0")]
+impl SubAssign<Duration> for Instant {
+ fn sub_assign(&mut self, other: Duration) {
+ *self = *self - other;
+ }
+}
+
+#[stable(feature = "time2", since = "1.8.0")]
+impl Sub<Instant> for Instant {
+ type Output = Duration;
+
+ fn sub(self, other: Instant) -> Duration {
+ self.duration_since(other)
+ }
+}
+
+#[stable(feature = "time2", since = "1.8.0")]
+impl fmt::Debug for Instant {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ self.0.fmt(f)
+ }
+}
+
+impl SystemTime {
+ /// An anchor in time which can be used to create new `SystemTime` instances or
+ /// learn about where in time a `SystemTime` lies.
+ ///
+ /// This constant is defined to be "1970-01-01 00:00:00 UTC" on all systems with
+ /// respect to the system clock. Using `duration_since` on an existing
+ /// `SystemTime` instance can tell how far away from this point in time a
+ /// measurement lies, and using `UNIX_EPOCH + duration` can be used to create a
+ /// `SystemTime` instance to represent another fixed point in time.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::time::SystemTime;
+ ///
+ /// match SystemTime::now().duration_since(SystemTime::UNIX_EPOCH) {
+ /// Ok(n) => println!("1970-01-01 00:00:00 UTC was {} seconds ago!", n.as_secs()),
+ /// Err(_) => panic!("SystemTime before UNIX EPOCH!"),
+ /// }
+ /// ```
+ #[stable(feature = "assoc_unix_epoch", since = "1.28.0")]
+ pub const UNIX_EPOCH: SystemTime = UNIX_EPOCH;
+
+ /// Returns the system time corresponding to "now".
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::time::SystemTime;
+ ///
+ /// let sys_time = SystemTime::now();
+ /// ```
+ #[stable(feature = "time2", since = "1.8.0")]
+ pub fn now() -> SystemTime {
+ SystemTime(time::SystemTime::now())
+ }
+
+ /// Returns the amount of time elapsed from an earlier point in time.
+ ///
+ /// This function may fail because measurements taken earlier are not
+ /// guaranteed to always be before later measurements (due to anomalies such
+ /// as the system clock being adjusted either forwards or backwards).
+ ///
+ /// If successful, [`Ok`]`(`[`Duration`]`)` is returned where the duration represents
+ /// the amount of time elapsed from the specified measurement to this one.
+ ///
+ /// Returns an [`Err`] if `earlier` is later than `self`, and the error
+ /// contains how far from `self` the time is.
+ ///
+ /// [`Ok`]: ../../std/result/enum.Result.html#variant.Ok
+ /// [`Duration`]: ../../std/time/struct.Duration.html
+ /// [`Err`]: ../../std/result/enum.Result.html#variant.Err
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::time::SystemTime;
+ ///
+ /// let sys_time = SystemTime::now();
+ /// let difference = sys_time.duration_since(sys_time)
+ /// .expect("SystemTime::duration_since failed");
+ /// println!("{:?}", difference);
+ /// ```
+ #[stable(feature = "time2", since = "1.8.0")]
+ pub fn duration_since(&self, earlier: SystemTime)
+ -> Result<Duration, SystemTimeError> {
+ self.0.sub_time(&earlier.0).map_err(SystemTimeError)
+ }
+
+ /// Returns the amount of time elapsed since this system time was created.
+ ///
+ /// This function may fail as the underlying system clock is susceptible to
+ /// drift and updates (e.g., the system clock could go backwards), so this
+ /// function may not always succeed. If successful, [`Ok`]`(`[`Duration`]`)` is
+ /// returned where the duration represents the amount of time elapsed from
+ /// this time measurement to the current time.
+ ///
+ /// Returns an [`Err`] if `self` is later than the current system time, and
+ /// the error contains how far from the current system time `self` is.
+ ///
+ /// [`Ok`]: ../../std/result/enum.Result.html#variant.Ok
+ /// [`Duration`]: ../../std/time/struct.Duration.html
+ /// [`Err`]: ../../std/result/enum.Result.html#variant.Err
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::thread::sleep;
+ /// use std::time::{Duration, SystemTime};
+ ///
+ /// let sys_time = SystemTime::now();
+ /// let one_sec = Duration::from_secs(1);
+ /// sleep(one_sec);
+ /// assert!(sys_time.elapsed().unwrap() >= one_sec);
+ /// ```
+ #[stable(feature = "time2", since = "1.8.0")]
+ pub fn elapsed(&self) -> Result<Duration, SystemTimeError> {
+ SystemTime::now().duration_since(*self)
+ }
+
+ /// Returns `Some(t)` where `t` is the time `self + duration` if `t` can be represented as
+ /// `SystemTime` (which means it's inside the bounds of the underlying data structure), `None`
+ /// otherwise.
+ #[stable(feature = "time_checked_add", since = "1.34.0")]
+ pub fn checked_add(&self, duration: Duration) -> Option<SystemTime> {
+ self.0.checked_add_duration(&duration).map(SystemTime)
+ }
+
+ /// Returns `Some(t)` where `t` is the time `self - duration` if `t` can be represented as
+ /// `SystemTime` (which means it's inside the bounds of the underlying data structure), `None`
+ /// otherwise.
+ #[stable(feature = "time_checked_add", since = "1.34.0")]
+ pub fn checked_sub(&self, duration: Duration) -> Option<SystemTime> {
+ self.0.checked_sub_duration(&duration).map(SystemTime)
+ }
+}
+
+#[stable(feature = "time2", since = "1.8.0")]
+impl Add<Duration> for SystemTime {
+ type Output = SystemTime;
+
+ /// # Panics
+ ///
+ /// This function may panic if the resulting point in time cannot be represented by the
+ /// underlying data structure. See [`checked_add`] for a version without panic.
+ ///
+ /// [`checked_add`]: ../../std/time/struct.SystemTime.html#method.checked_add
+ fn add(self, dur: Duration) -> SystemTime {
+ self.checked_add(dur)
+ .expect("overflow when adding duration to instant")
+ }
+}
+
+#[stable(feature = "time_augmented_assignment", since = "1.9.0")]
+impl AddAssign<Duration> for SystemTime {
+ fn add_assign(&mut self, other: Duration) {
+ *self = *self + other;
+ }
+}
+
+#[stable(feature = "time2", since = "1.8.0")]
+impl Sub<Duration> for SystemTime {
+ type Output = SystemTime;
+
+ fn sub(self, dur: Duration) -> SystemTime {
+ self.checked_sub(dur)
+ .expect("overflow when subtracting duration from instant")
+ }
+}
+
+#[stable(feature = "time_augmented_assignment", since = "1.9.0")]
+impl SubAssign<Duration> for SystemTime {
+ fn sub_assign(&mut self, other: Duration) {
+ *self = *self - other;
+ }
+}
+
+#[stable(feature = "time2", since = "1.8.0")]
+impl fmt::Debug for SystemTime {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ self.0.fmt(f)
+ }
+}
+
+/// An anchor in time which can be used to create new `SystemTime` instances or
+/// learn about where in time a `SystemTime` lies.
+///
+/// This constant is defined to be "1970-01-01 00:00:00 UTC" on all systems with
+/// respect to the system clock. Using `duration_since` on an existing
+/// [`SystemTime`] instance can tell how far away from this point in time a
+/// measurement lies, and using `UNIX_EPOCH + duration` can be used to create a
+/// [`SystemTime`] instance to represent another fixed point in time.
+///
+/// [`SystemTime`]: ../../std/time/struct.SystemTime.html
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::time::{SystemTime, UNIX_EPOCH};
+///
+/// match SystemTime::now().duration_since(UNIX_EPOCH) {
+/// Ok(n) => println!("1970-01-01 00:00:00 UTC was {} seconds ago!", n.as_secs()),
+/// Err(_) => panic!("SystemTime before UNIX EPOCH!"),
+/// }
+/// ```
+#[stable(feature = "time2", since = "1.8.0")]
+pub const UNIX_EPOCH: SystemTime = SystemTime(time::UNIX_EPOCH);
+
+impl SystemTimeError {
+ /// Returns the positive duration which represents how far forward the
+ /// second system time was from the first.
+ ///
+ /// A `SystemTimeError` is returned from the [`duration_since`] and [`elapsed`]
+ /// methods of [`SystemTime`] whenever the second system time represents a point later
+ /// in time than the `self` of the method call.
+ ///
+ /// [`duration_since`]: ../../std/time/struct.SystemTime.html#method.duration_since
+ /// [`elapsed`]: ../../std/time/struct.SystemTime.html#method.elapsed
+ /// [`SystemTime`]: ../../std/time/struct.SystemTime.html
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::thread::sleep;
+ /// use std::time::{Duration, SystemTime};
+ ///
+ /// let sys_time = SystemTime::now();
+ /// sleep(Duration::from_secs(1));
+ /// let new_sys_time = SystemTime::now();
+ /// match sys_time.duration_since(new_sys_time) {
+ /// Ok(_) => {}
+ /// Err(e) => println!("SystemTimeError difference: {:?}", e.duration()),
+ /// }
+ /// ```
+ #[stable(feature = "time2", since = "1.8.0")]
+ pub fn duration(&self) -> Duration {
+ self.0
+ }
+}
+
+#[stable(feature = "time2", since = "1.8.0")]
+impl Error for SystemTimeError {
+ fn description(&self) -> &str { "other time was not earlier than self" }
+}
+
+#[stable(feature = "time2", since = "1.8.0")]
+impl fmt::Display for SystemTimeError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "second time provided was later than self")
+ }
+}
+
+impl FromInner<time::SystemTime> for SystemTime {
+ fn from_inner(time: time::SystemTime) -> SystemTime {
+ SystemTime(time)
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::{Instant, SystemTime, Duration, UNIX_EPOCH};
+
+ macro_rules! assert_almost_eq {
+ ($a:expr, $b:expr) => ({
+ let (a, b) = ($a, $b);
+ if a != b {
+ let (a, b) = if a > b {(a, b)} else {(b, a)};
+ assert!(a - Duration::new(0, 1000) <= b,
+ "{:?} is not almost equal to {:?}", a, b);
+ }
+ })
+ }
+
+ #[test]
+ fn instant_monotonic() {
+ let a = Instant::now();
+ let b = Instant::now();
+ assert!(b >= a);
+ }
+
+ #[test]
+ fn instant_elapsed() {
+ let a = Instant::now();
+ a.elapsed();
+ }
+
+ #[test]
+ fn instant_math() {
+ let a = Instant::now();
+ let b = Instant::now();
+ println!("a: {:?}", a);
+ println!("b: {:?}", b);
+ let dur = b.duration_since(a);
+ println!("dur: {:?}", dur);
+ assert_almost_eq!(b - dur, a);
+ assert_almost_eq!(a + dur, b);
+
+ let second = Duration::new(1, 0);
+ assert_almost_eq!(a - second + second, a);
+ assert_almost_eq!(a.checked_sub(second).unwrap().checked_add(second).unwrap(), a);
+
+ // checked_add_duration will not panic on overflow
+ let mut maybe_t = Some(Instant::now());
+ let max_duration = Duration::from_secs(u64::max_value());
+ // in case `Instant` can store `>= now + max_duration`.
+ for _ in 0..2 {
+ maybe_t = maybe_t.and_then(|t| t.checked_add(max_duration));
+ }
+ assert_eq!(maybe_t, None);
+
+ // checked_add_duration calculates the right time and will work for another year
+ let year = Duration::from_secs(60 * 60 * 24 * 365);
+ assert_eq!(a + year, a.checked_add(year).unwrap());
+ }
+
+ #[test]
+ fn instant_math_is_associative() {
+ let now = Instant::now();
+ let offset = Duration::from_millis(5);
+ // Changing the order of instant math shouldn't change the results,
+ // especially when the expression reduces to X + identity.
+ assert_eq!((now + offset) - now, (now - now) + offset);
+ }
+
+ #[test]
+ #[should_panic]
+ fn instant_duration_since_panic() {
+ let a = Instant::now();
+ (a - Duration::new(1, 0)).duration_since(a);
+ }
+
+ #[test]
+ fn instant_checked_duration_since_nopanic() {
+ let now = Instant::now();
+ let earlier = now - Duration::new(1, 0);
+ let later = now + Duration::new(1, 0);
+ assert_eq!(earlier.checked_duration_since(now), None);
+ assert_eq!(later.checked_duration_since(now), Some(Duration::new(1, 0)));
+ assert_eq!(now.checked_duration_since(now), Some(Duration::new(0, 0)));
+ }
+
+ #[test]
+ fn instant_saturating_duration_since_nopanic() {
+ let a = Instant::now();
+ let ret = (a - Duration::new(1, 0)).saturating_duration_since(a);
+ assert_eq!(ret, Duration::new(0,0));
+ }
+
+ #[test]
+ fn system_time_math() {
+ let a = SystemTime::now();
+ let b = SystemTime::now();
+ match b.duration_since(a) {
+ Ok(dur) if dur == Duration::new(0, 0) => {
+ assert_almost_eq!(a, b);
+ }
+ Ok(dur) => {
+ assert!(b > a);
+ assert_almost_eq!(b - dur, a);
+ assert_almost_eq!(a + dur, b);
+ }
+ Err(dur) => {
+ let dur = dur.duration();
+ assert!(a > b);
+ assert_almost_eq!(b + dur, a);
+ assert_almost_eq!(a - dur, b);
+ }
+ }
+
+ let second = Duration::new(1, 0);
+ assert_almost_eq!(a.duration_since(a - second).unwrap(), second);
+ assert_almost_eq!(a.duration_since(a + second).unwrap_err()
+ .duration(), second);
+
+ assert_almost_eq!(a - second + second, a);
+ assert_almost_eq!(a.checked_sub(second).unwrap().checked_add(second).unwrap(), a);
+
+ let one_second_from_epoch = UNIX_EPOCH + Duration::new(1, 0);
+ let one_second_from_epoch2 = UNIX_EPOCH + Duration::new(0, 500_000_000)
+ + Duration::new(0, 500_000_000);
+ assert_eq!(one_second_from_epoch, one_second_from_epoch2);
+
+ // checked_add_duration will not panic on overflow
+ let mut maybe_t = Some(SystemTime::UNIX_EPOCH);
+ let max_duration = Duration::from_secs(u64::max_value());
+ // in case `SystemTime` can store `>= UNIX_EPOCH + max_duration`.
+ for _ in 0..2 {
+ maybe_t = maybe_t.and_then(|t| t.checked_add(max_duration));
+ }
+ assert_eq!(maybe_t, None);
+
+ // checked_add_duration calculates the right time and will work for another year
+ let year = Duration::from_secs(60 * 60 * 24 * 365);
+ assert_eq!(a + year, a.checked_add(year).unwrap());
+ }
+
+ #[test]
+ fn system_time_elapsed() {
+ let a = SystemTime::now();
+ drop(a.elapsed());
+ }
+
+ #[test]
+ fn since_epoch() {
+ let ts = SystemTime::now();
+ let a = ts.duration_since(UNIX_EPOCH + Duration::new(1, 0)).unwrap();
+ let b = ts.duration_since(UNIX_EPOCH).unwrap();
+ assert!(b > a);
+ assert_eq!(b - a, Duration::new(1, 0));
+
+ let thirty_years = Duration::new(1, 0) * 60 * 60 * 24 * 365 * 30;
+
+ // Right now for CI this test is run in an emulator, and apparently the
+ // aarch64 emulator's sense of time is that we're still living in the
+ // 70s.
+ //
+ // Otherwise let's assume that we're all running computers later than
+ // 2000.
+ if !cfg!(target_arch = "aarch64") {
+ assert!(a > thirty_years);
+ }
+
+ // let's assume that we're all running computers earlier than 2090.
+ // Should give us ~70 years to fix this!
+ let hundred_twenty_years = thirty_years * 4;
+ assert!(a < hundred_twenty_years);
+ }
+}