about summary refs log tree commit diff
path: root/library/std/src/sys_common
diff options
context:
space:
mode:
authormark <markm@cs.wisc.edu>2020-06-11 21:31:49 -0500
committermark <markm@cs.wisc.edu>2020-07-27 19:51:13 -0500
commit2c31b45ae878b821975c4ebd94cc1e49f6073fd0 (patch)
tree14f64e683e3f64dcbcfb8c2c7cb45ac7592e6e09 /library/std/src/sys_common
parent9be8ffcb0206fc1558069a7b4766090df7877659 (diff)
downloadrust-2c31b45ae878b821975c4ebd94cc1e49f6073fd0.tar.gz
rust-2c31b45ae878b821975c4ebd94cc1e49f6073fd0.zip
mv std libs to library/
Diffstat (limited to 'library/std/src/sys_common')
-rw-r--r--library/std/src/sys_common/alloc.rs46
-rw-r--r--library/std/src/sys_common/at_exit_imp.rs75
-rw-r--r--library/std/src/sys_common/backtrace.rs215
-rw-r--r--library/std/src/sys_common/bytestring.rs46
-rw-r--r--library/std/src/sys_common/condvar.rs72
-rw-r--r--library/std/src/sys_common/fs.rs39
-rw-r--r--library/std/src/sys_common/io.rs41
-rw-r--r--library/std/src/sys_common/mod.rs148
-rw-r--r--library/std/src/sys_common/mutex.rs101
-rw-r--r--library/std/src/sys_common/net.rs697
-rw-r--r--library/std/src/sys_common/os_str_bytes.rs298
-rw-r--r--library/std/src/sys_common/poison.rs268
-rw-r--r--library/std/src/sys_common/process.rs95
-rw-r--r--library/std/src/sys_common/remutex.rs224
-rw-r--r--library/std/src/sys_common/rwlock.rs88
-rw-r--r--library/std/src/sys_common/thread.rs18
-rw-r--r--library/std/src/sys_common/thread_info.rs46
-rw-r--r--library/std/src/sys_common/thread_local_dtor.rs49
-rw-r--r--library/std/src/sys_common/thread_local_key.rs271
-rw-r--r--library/std/src/sys_common/util.rs28
-rw-r--r--library/std/src/sys_common/wtf8.rs1285
21 files changed, 4150 insertions, 0 deletions
diff --git a/library/std/src/sys_common/alloc.rs b/library/std/src/sys_common/alloc.rs
new file mode 100644
index 00000000000..c6694100785
--- /dev/null
+++ b/library/std/src/sys_common/alloc.rs
@@ -0,0 +1,46 @@
+#![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",
+    target_arch = "hexagon"
+)))]
+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",
+    target_arch = "riscv64"
+)))]
+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/library/std/src/sys_common/at_exit_imp.rs b/library/std/src/sys_common/at_exit_imp.rs
new file mode 100644
index 00000000000..6b799db856e
--- /dev/null
+++ b/library/std/src/sys_common/at_exit_imp.rs
@@ -0,0 +1,75 @@
+//! Implementation of running at_exit routines
+//!
+//! Documentation can be found on the `rt::at_exit` function.
+
+use crate::mem;
+use crate::ptr;
+use crate::sys_common::mutex::Mutex;
+
+type Queue = Vec<Box<dyn FnOnce()>>;
+
+// 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 FnOnce()>) -> 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/library/std/src/sys_common/backtrace.rs b/library/std/src/sys_common/backtrace.rs
new file mode 100644
index 00000000000..e9b1e86d7ae
--- /dev/null
+++ b/library/std/src/sys_common/backtrace.rs
@@ -0,0 +1,215 @@
+use crate::borrow::Cow;
+/// Common code for printing the backtrace in the same way across the different
+/// supported platforms.
+use crate::env;
+use crate::fmt;
+use crate::io;
+use crate::io::prelude::*;
+use crate::path::{self, Path, PathBuf};
+use crate::sync::atomic::{self, Ordering};
+use crate::sys::mutex::Mutex;
+
+use backtrace_rs::{BacktraceFmt, BytesOrWideString, PrintFmt};
+
+/// Max number of frames to print.
+const MAX_NB_FRAMES: usize = 100;
+
+pub fn lock() -> impl Drop {
+    struct Guard;
+    static LOCK: Mutex = Mutex::new();
+
+    impl Drop for Guard {
+        fn drop(&mut self) {
+            unsafe {
+                LOCK.unlock();
+            }
+        }
+    }
+
+    unsafe {
+        LOCK.lock();
+        Guard
+    }
+}
+
+/// Prints the current backtrace.
+pub fn print(w: &mut dyn Write, format: PrintFmt) -> io::Result<()> {
+    // 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 {
+        let _lock = lock();
+        _print(w, format)
+    }
+}
+
+unsafe fn _print(w: &mut dyn Write, format: PrintFmt) -> io::Result<()> {
+    struct DisplayBacktrace {
+        format: PrintFmt,
+    }
+    impl fmt::Display for DisplayBacktrace {
+        fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+            unsafe { _print_fmt(fmt, self.format) }
+        }
+    }
+    write!(w, "{}", DisplayBacktrace { format })
+}
+
+unsafe fn _print_fmt(fmt: &mut fmt::Formatter<'_>, print_fmt: PrintFmt) -> fmt::Result {
+    // Always 'fail' to get the cwd when running under Miri -
+    // this allows Miri to display backtraces in isolation mode
+    let cwd = if !cfg!(miri) { env::current_dir().ok() } else { None };
+
+    let mut print_path = move |fmt: &mut fmt::Formatter<'_>, bows: BytesOrWideString<'_>| {
+        output_filename(fmt, bows, print_fmt, cwd.as_ref())
+    };
+    writeln!(fmt, "stack backtrace:")?;
+    let mut bt_fmt = BacktraceFmt::new(fmt, print_fmt, &mut print_path);
+    bt_fmt.add_context()?;
+    let mut idx = 0;
+    let mut res = Ok(());
+    backtrace_rs::trace_unsynchronized(|frame| {
+        if print_fmt == PrintFmt::Short && idx > MAX_NB_FRAMES {
+            return false;
+        }
+
+        let mut hit = false;
+        let mut stop = false;
+        backtrace_rs::resolve_frame_unsynchronized(frame, |symbol| {
+            hit = true;
+            if print_fmt == PrintFmt::Short {
+                if let Some(sym) = symbol.name().and_then(|s| s.as_str()) {
+                    if sym.contains("__rust_begin_short_backtrace") {
+                        stop = true;
+                        return;
+                    }
+                }
+            }
+
+            res = bt_fmt.frame().symbol(frame, symbol);
+        });
+        if stop {
+            return false;
+        }
+        if !hit {
+            res = bt_fmt.frame().print_raw(frame.ip(), None, None, None);
+        }
+
+        idx += 1;
+        res.is_ok()
+    });
+    res?;
+    bt_fmt.finish()?;
+    if print_fmt == PrintFmt::Short {
+        writeln!(
+            fmt,
+            "note: Some details are omitted, \
+             run with `RUST_BACKTRACE=full` for a verbose backtrace."
+        )?;
+    }
+    Ok(())
+}
+
+/// Fixed frame used to clean the backtrace with `RUST_BACKTRACE=1`. Note that
+/// this is only inline(never) when backtraces in libstd are enabled, otherwise
+/// it's fine to optimize away.
+#[cfg_attr(feature = "backtrace", inline(never))]
+pub fn __rust_begin_short_backtrace<F, T>(f: F) -> T
+where
+    F: FnOnce() -> T,
+    F: Send,
+    T: Send,
+{
+    f()
+}
+
+pub enum RustBacktrace {
+    Print(PrintFmt),
+    Disabled,
+    RuntimeDisabled,
+}
+
+// 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 rust_backtrace_env() -> RustBacktrace {
+    // If the `backtrace` feature of this crate isn't enabled quickly return
+    // `None` so this can be constant propagated all over the place to turn
+    // optimize away callers.
+    if !cfg!(feature = "backtrace") {
+        return RustBacktrace::Disabled;
+    }
+
+    // Setting environment variables for Fuchsia components isn't a standard
+    // or easily supported workflow. For now, always display backtraces.
+    if cfg!(target_os = "fuchsia") {
+        return RustBacktrace::Print(PrintFmt::Full);
+    }
+
+    static ENABLED: atomic::AtomicIsize = atomic::AtomicIsize::new(0);
+    match ENABLED.load(Ordering::SeqCst) {
+        0 => {}
+        1 => return RustBacktrace::RuntimeDisabled,
+        2 => return RustBacktrace::Print(PrintFmt::Short),
+        _ => return RustBacktrace::Print(PrintFmt::Full),
+    }
+
+    let (format, cache) = env::var_os("RUST_BACKTRACE")
+        .map(|x| {
+            if &x == "0" {
+                (RustBacktrace::RuntimeDisabled, 1)
+            } else if &x == "full" {
+                (RustBacktrace::Print(PrintFmt::Full), 3)
+            } else {
+                (RustBacktrace::Print(PrintFmt::Short), 2)
+            }
+        })
+        .unwrap_or((RustBacktrace::RuntimeDisabled, 1));
+    ENABLED.store(cache, Ordering::SeqCst);
+    format
+}
+
+/// Prints the filename of the backtrace frame.
+///
+/// See also `output`.
+pub fn output_filename(
+    fmt: &mut fmt::Formatter<'_>,
+    bows: BytesOrWideString<'_>,
+    print_fmt: PrintFmt,
+    cwd: Option<&PathBuf>,
+) -> fmt::Result {
+    let file: Cow<'_, Path> = match bows {
+        #[cfg(unix)]
+        BytesOrWideString::Bytes(bytes) => {
+            use crate::os::unix::prelude::*;
+            Path::new(crate::ffi::OsStr::from_bytes(bytes)).into()
+        }
+        #[cfg(not(unix))]
+        BytesOrWideString::Bytes(bytes) => {
+            Path::new(crate::str::from_utf8(bytes).unwrap_or("<unknown>")).into()
+        }
+        #[cfg(windows)]
+        BytesOrWideString::Wide(wide) => {
+            use crate::os::windows::prelude::*;
+            Cow::Owned(crate::ffi::OsString::from_wide(wide).into())
+        }
+        #[cfg(not(windows))]
+        BytesOrWideString::Wide(_wide) => Path::new("<unknown>").into(),
+    };
+    if print_fmt == PrintFmt::Short && file.is_absolute() {
+        if let Some(cwd) = cwd {
+            if let Ok(stripped) = file.strip_prefix(&cwd) {
+                if let Some(s) = stripped.to_str() {
+                    return write!(fmt, ".{}{}", path::MAIN_SEPARATOR, s);
+                }
+            }
+        }
+    }
+    fmt::Display::fmt(&file.display(), fmt)
+}
diff --git a/library/std/src/sys_common/bytestring.rs b/library/std/src/sys_common/bytestring.rs
new file mode 100644
index 00000000000..dccc3bc4a19
--- /dev/null
+++ b/library/std/src/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::{Debug, Formatter, Result};
+
+    #[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/library/std/src/sys_common/condvar.rs b/library/std/src/sys_common/condvar.rs
new file mode 100644
index 00000000000..f9611bc6f7b
--- /dev/null
+++ b/library/std/src/sys_common/condvar.rs
@@ -0,0 +1,72 @@
+use crate::sys::condvar as imp;
+use crate::sys_common::mutex::{self, Mutex};
+use crate::time::Duration;
+
+/// 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/library/std/src/sys_common/fs.rs b/library/std/src/sys_common/fs.rs
new file mode 100644
index 00000000000..e30e8018a31
--- /dev/null
+++ b/library/std/src/sys_common/fs.rs
@@ -0,0 +1,39 @@
+#![allow(dead_code)] // not used on all platforms
+
+use crate::fs;
+use crate::io::{self, Error, ErrorKind};
+use crate::path::Path;
+
+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/library/std/src/sys_common/io.rs b/library/std/src/sys_common/io.rs
new file mode 100644
index 00000000000..7c1d98a5abd
--- /dev/null
+++ b/library/std/src/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::env;
+    use crate::fs;
+    use crate::path::{Path, PathBuf};
+    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(&self) -> &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/library/std/src/sys_common/mod.rs b/library/std/src/sys_common/mod.rs
new file mode 100644
index 00000000000..840f9093e00
--- /dev/null
+++ b/library/std/src/sys_common/mod.rs
@@ -0,0 +1,148 @@
+//! 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) => {
+        match $e {
+            $ok(v) => v,
+            ref err => {
+                let err = err.as_ref().map(drop); // map Ok/Some which might not be Debug
+                rtabort!(concat!("unwrap failed: ", stringify!($e), " = {:?}"), err)
+            }
+        }
+    };
+}
+
+pub mod alloc;
+pub mod at_exit_imp;
+pub mod backtrace;
+pub mod bytestring;
+pub mod condvar;
+pub mod fs;
+pub mod io;
+pub mod mutex;
+// `doc` is required because `sys/mod.rs` imports `unix/ext/mod.rs` on Windows
+// when generating documentation.
+#[cfg(any(doc, not(windows)))]
+pub mod os_str_bytes;
+pub mod poison;
+pub mod process;
+pub mod remutex;
+pub mod rwlock;
+pub mod thread;
+pub mod thread_info;
+pub mod thread_local_dtor;
+pub mod thread_local_key;
+pub mod util;
+pub mod wtf8;
+
+cfg_if::cfg_if! {
+    if #[cfg(any(target_os = "cloudabi",
+                 target_os = "l4re",
+                 target_os = "hermit",
+                 feature = "restricted-std",
+                 all(target_arch = "wasm32", not(target_os = "emscripten")),
+                 all(target_vendor = "fortanix", target_env = "sgx")))] {
+        pub use crate::sys::net;
+    } else {
+        pub mod net;
+    }
+}
+
+// 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/library/std/src/sys_common/mutex.rs b/library/std/src/sys_common/mutex.rs
new file mode 100644
index 00000000000..e66d8994147
--- /dev/null
+++ b/library/std/src/sys_common/mutex.rs
@@ -0,0 +1,101 @@
+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.
+    #[rustc_const_stable(feature = "const_sys_mutex_new", since = "1.0.0")]
+    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/library/std/src/sys_common/net.rs b/library/std/src/sys_common/net.rs
new file mode 100644
index 00000000000..81a5ef95e82
--- /dev/null
+++ b/library/std/src/sys_common/net.rs
@@ -0,0 +1,697 @@
+use crate::cmp;
+use crate::convert::{TryFrom, TryInto};
+use crate::ffi::CString;
+use crate::fmt;
+use crate::io::{self, Error, ErrorKind, IoSlice, IoSliceMut};
+use crate::mem;
+use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr};
+use crate::ptr;
+use crate::sys::net::netc as c;
+use crate::sys::net::{cvt, cvt_gai, cvt_r, init, wrlen_t, Socket};
+use crate::sys_common::{AsInner, FromInner, IntoInner};
+use crate::time::Duration;
+
+use libc::{c_int, c_void};
+
+cfg_if::cfg_if! {
+    if #[cfg(any(
+        target_os = "dragonfly", target_os = "freebsd",
+        target_os = "ios", target_os = "macos",
+        target_os = "openbsd", target_os = "netbsd", target_os = "illumos",
+        target_os = "solaris", target_os = "haiku", target_os = "l4re"))] {
+        use crate::sys::net::netc::IPV6_JOIN_GROUP as IPV6_ADD_MEMBERSHIP;
+        use crate::sys::net::netc::IPV6_LEAVE_GROUP as IPV6_DROP_MEMBERSHIP;
+    } else {
+        use crate::sys::net::netc::IPV6_ADD_MEMBERSHIP;
+        use crate::sys::net::netc::IPV6_DROP_MEMBERSHIP;
+    }
+}
+
+cfg_if::cfg_if! {
+    if #[cfg(any(
+        target_os = "linux", target_os = "android",
+        target_os = "dragonfly", target_os = "freebsd",
+        target_os = "openbsd", target_os = "netbsd",
+        target_os = "haiku"))] {
+        use libc::MSG_NOSIGNAL;
+    } else {
+        const MSG_NOSIGNAL: c_int = 0x0;
+    }
+}
+
+cfg_if::cfg_if! {
+    if #[cfg(any(
+        target_os = "dragonfly", target_os = "freebsd",
+        target_os = "openbsd", target_os = "netbsd",
+        target_os = "solaris", target_os = "illumos"))] {
+        use libc::c_uchar;
+        type IpV4MultiCastType = c_uchar;
+    } else {
+        type IpV4MultiCastType = c_int;
+    }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// 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 [IoSliceMut<'_>]) -> io::Result<usize> {
+        self.inner.read_vectored(bufs)
+    }
+
+    #[inline]
+    pub fn is_read_vectored(&self) -> bool {
+        self.inner.is_read_vectored()
+    }
+
+    pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
+        let len = cmp::min(buf.len(), <wrlen_t>::MAX 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: &[IoSlice<'_>]) -> io::Result<usize> {
+        self.inner.write_vectored(bufs)
+    }
+
+    #[inline]
+    pub fn is_write_vectored(&self) -> bool {
+        self.inner.is_write_vectored()
+    }
+
+    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.
+        //
+        // On Windows, this allows rebinding sockets which are actively in use,
+        // which allows “socket hijacking”, so we explicitly don't set it here.
+        // https://docs.microsoft.com/en-us/windows/win32/winsock/using-so-reuseaddr-and-so-exclusiveaddruse
+        #[cfg(not(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 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 IpV4MultiCastType,
+        )
+    }
+
+    pub fn multicast_loop_v4(&self) -> io::Result<bool> {
+        let raw: IpV4MultiCastType = 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 IpV4MultiCastType,
+        )
+    }
+
+    pub fn multicast_ttl_v4(&self) -> io::Result<u32> {
+        let raw: IpV4MultiCastType = 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 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(drop)
+    }
+}
+
+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/library/std/src/sys_common/os_str_bytes.rs b/library/std/src/sys_common/os_str_bytes.rs
new file mode 100644
index 00000000000..984c032e2a3
--- /dev/null
+++ b/library/std/src/sys_common/os_str_bytes.rs
@@ -0,0 +1,298 @@
+//! 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::mem;
+use crate::rc::Rc;
+use crate::str;
+use crate::sync::Arc;
+use crate::sys_common::bytestring::debug_fmt_bytestring;
+use crate::sys_common::{AsInner, FromInner, IntoInner};
+
+use core::str::lossy::Utf8Lossy;
+
+#[derive(Clone, Hash)]
+pub(crate) struct Buf {
+    pub inner: Vec<u8>,
+}
+
+// FIXME:
+// `Buf::as_slice` current implementation relies
+// on `Slice` being layout-compatible with `[u8]`.
+// When attribute privacy is implemented, `Slice` should be annotated as `#[repr(transparent)]`.
+// Anyway, `Slice` representation and layout are considered implementation detail, are
+// not documented and must not be relied upon.
+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)
+    }
+
+    #[inline]
+    pub fn as_slice(&self) -> &Slice {
+        // Safety: Slice just wraps [u8],
+        // and &*self.inner is &[u8], therefore
+        // transmuting &[u8] to &Slice is safe.
+        unsafe { mem::transmute(&*self.inner) }
+    }
+
+    #[inline]
+    pub fn as_mut_slice(&mut self) -> &mut Slice {
+        // Safety: Slice just wraps [u8],
+        // and &mut *self.inner is &mut [u8], therefore
+        // transmuting &mut [u8] to &mut Slice is safe.
+        unsafe { mem::transmute(&mut *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 {
+    #[inline]
+    fn from_u8_slice(s: &[u8]) -> &Slice {
+        unsafe { mem::transmute(s) }
+    }
+
+    #[inline]
+    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() }
+    }
+
+    pub fn clone_into(&self, buf: &mut Buf) {
+        self.inner.clone_into(&mut buf.inner)
+    }
+
+    #[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) }
+    }
+
+    #[inline]
+    pub fn make_ascii_lowercase(&mut self) {
+        self.inner.make_ascii_lowercase()
+    }
+
+    #[inline]
+    pub fn make_ascii_uppercase(&mut self) {
+        self.inner.make_ascii_uppercase()
+    }
+
+    #[inline]
+    pub fn to_ascii_lowercase(&self) -> Buf {
+        Buf { inner: self.inner.to_ascii_lowercase() }
+    }
+
+    #[inline]
+    pub fn to_ascii_uppercase(&self) -> Buf {
+        Buf { inner: self.inner.to_ascii_uppercase() }
+    }
+
+    #[inline]
+    pub fn is_ascii(&self) -> bool {
+        self.inner.is_ascii()
+    }
+
+    #[inline]
+    pub fn eq_ignore_ascii_case(&self, other: &Self) -> bool {
+        self.inner.eq_ignore_ascii_case(&other.inner)
+    }
+}
+
+/// 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 documentation 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 documentation 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 documentation 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 documentation 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/library/std/src/sys_common/poison.rs b/library/std/src/sys_common/poison.rs
new file mode 100644
index 00000000000..285851d631a
--- /dev/null
+++ b/library/std/src/sys_common/poison.rs
@@ -0,0 +1,268 @@
+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> {
+    #[allow(deprecated)]
+    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> {
+    #[allow(deprecated, deprecated_in_future)]
+    fn description(&self) -> &str {
+        match *self {
+            TryLockError::Poisoned(ref p) => p.description(),
+            TryLockError::WouldBlock => "try_lock failed because the operation would block",
+        }
+    }
+
+    #[allow(deprecated)]
+    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/library/std/src/sys_common/process.rs b/library/std/src/sys_common/process.rs
new file mode 100644
index 00000000000..f3a2962098b
--- /dev/null
+++ b/library/std/src/sys_common/process.rs
@@ -0,0 +1,95 @@
+#![allow(dead_code)]
+#![unstable(feature = "process_internals", issue = "none")]
+
+use crate::collections::BTreeMap;
+use crate::env;
+use crate::ffi::{OsStr, OsString};
+use crate::sys::process::EnvKey;
+
+// Stores a set of changes to an environment
+#[derive(Clone, Debug)]
+pub struct CommandEnv {
+    clear: bool,
+    saw_path: bool,
+    vars: BTreeMap<EnvKey, Option<OsString>>,
+}
+
+impl Default for CommandEnv {
+    fn default() -> Self {
+        CommandEnv { clear: false, saw_path: false, vars: Default::default() }
+    }
+}
+
+impl CommandEnv {
+    // Capture the current environment with these changes applied
+    pub fn capture(&self) -> BTreeMap<EnvKey, OsString> {
+        let mut result = BTreeMap::<EnvKey, 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<EnvKey, 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/library/std/src/sys_common/remutex.rs b/library/std/src/sys_common/remutex.rs
new file mode 100644
index 00000000000..4f19bbc467f
--- /dev/null
+++ b/library/std/src/sys_common/remutex.rs
@@ -0,0 +1,224 @@
+use crate::fmt;
+use crate::marker;
+use crate::ops::Deref;
+use crate::panic::{RefUnwindSafe, UnwindSafe};
+use crate::sys::mutex as sys;
+
+/// 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: sys::ReentrantMutex,
+    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>,
+}
+
+impl<T> !marker::Send for ReentrantMutexGuard<'_, T> {}
+
+impl<T> ReentrantMutex<T> {
+    /// Creates a new reentrant mutex in an unlocked state.
+    ///
+    /// # Unsafety
+    ///
+    /// This function is unsafe because it is required that `init` is called
+    /// once this mutex is in its final resting place, and only then are the
+    /// lock/unlock methods safe.
+    pub const unsafe fn new(t: T) -> ReentrantMutex<T> {
+        ReentrantMutex { inner: sys::ReentrantMutex::uninitialized(), data: t }
+    }
+
+    /// Initializes this mutex so it's ready for use.
+    ///
+    /// # Unsafety
+    ///
+    /// Unsafe to call more than once, and must be called after this will no
+    /// longer move in memory.
+    pub unsafe fn init(&self) {
+        self.inner.init();
+    }
+
+    /// 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) -> 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) -> Option<ReentrantMutexGuard<'_, T>> {
+        if unsafe { self.inner.try_lock() } { Some(ReentrantMutexGuard::new(&self)) } else { None }
+    }
+}
+
+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() {
+            Some(guard) => f.debug_struct("ReentrantMutex").field("data", &*guard).finish(),
+            None => {
+                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>) -> ReentrantMutexGuard<'mutex, T> {
+        ReentrantMutexGuard { __lock: lock }
+    }
+}
+
+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.inner.unlock();
+        }
+    }
+}
+
+#[cfg(all(test, not(target_os = "emscripten")))]
+mod tests {
+    use crate::cell::RefCell;
+    use crate::sync::Arc;
+    use crate::sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard};
+    use crate::thread;
+
+    #[test]
+    fn smoke() {
+        let m = unsafe {
+            let m = ReentrantMutex::new(());
+            m.init();
+            m
+        };
+        {
+            let a = m.lock();
+            {
+                let b = m.lock();
+                {
+                    let c = m.lock();
+                    assert_eq!(*c, ());
+                }
+                assert_eq!(*b, ());
+            }
+            assert_eq!(*a, ());
+        }
+    }
+
+    #[test]
+    fn is_mutex() {
+        let m = unsafe {
+            let m = Arc::new(ReentrantMutex::new(RefCell::new(0)));
+            m.init();
+            m
+        };
+        let m2 = m.clone();
+        let lock = m.lock();
+        let child = thread::spawn(move || {
+            let lock = m2.lock();
+            assert_eq!(*lock.borrow(), 4950);
+        });
+        for i in 0..100 {
+            let lock = m.lock();
+            *lock.borrow_mut() += i;
+        }
+        drop(lock);
+        child.join().unwrap();
+    }
+
+    #[test]
+    fn trylock_works() {
+        let m = unsafe {
+            let m = Arc::new(ReentrantMutex::new(()));
+            m.init();
+            m
+        };
+        let m2 = m.clone();
+        let _lock = m.try_lock();
+        let _lock2 = m.try_lock();
+        thread::spawn(move || {
+            let lock = m2.try_lock();
+            assert!(lock.is_none());
+        })
+        .join()
+        .unwrap();
+        let _lock3 = m.try_lock();
+    }
+
+    pub struct Answer<'a>(pub ReentrantMutexGuard<'a, RefCell<u32>>);
+    impl Drop for Answer<'_> {
+        fn drop(&mut self) {
+            *self.0.borrow_mut() = 42;
+        }
+    }
+}
diff --git a/library/std/src/sys_common/rwlock.rs b/library/std/src/sys_common/rwlock.rs
new file mode 100644
index 00000000000..3705d641a1b
--- /dev/null
+++ b/library/std/src/sys_common/rwlock.rs
@@ -0,0 +1,88 @@
+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/library/std/src/sys_common/thread.rs b/library/std/src/sys_common/thread.rs
new file mode 100644
index 00000000000..f3a8bef8f71
--- /dev/null
+++ b/library/std/src/sys_common/thread.rs
@@ -0,0 +1,18 @@
+use crate::env;
+use crate::sync::atomic::{self, Ordering};
+use crate::sys::thread as imp;
+
+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/library/std/src/sys_common/thread_info.rs b/library/std/src/sys_common/thread_info.rs
new file mode 100644
index 00000000000..f09d16c33e6
--- /dev/null
+++ b/library/std/src/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/library/std/src/sys_common/thread_local_dtor.rs b/library/std/src/sys_common/thread_local_dtor.rs
new file mode 100644
index 00000000000..6f5ebf4a271
--- /dev/null
+++ b/library/std/src/sys_common/thread_local_dtor.rs
@@ -0,0 +1,49 @@
+//! Thread-local destructor
+//!
+//! Besides thread-local "keys" (pointer-sized non-adressable thread-local store
+//! with an associated destructor), many platforms also provide thread-local
+//! destructors that are not associated with any particular data. These are
+//! often more efficient.
+//!
+//! This module provides a fallback implementation for that interface, based
+//! on the less efficient thread-local "keys". Each platform provides
+//! a `thread_local_dtor` module which will either re-export the fallback,
+//! or implement something more efficient.
+
+#![unstable(feature = "thread_local_internals", issue = "none")]
+#![allow(dead_code)] // sys isn't exported yet
+
+use crate::ptr;
+use crate::sys_common::thread_local_key::StaticKey;
+
+pub unsafe fn register_dtor_fallback(t: *mut u8, dtor: unsafe extern "C" 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 "C" 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 "C" 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());
+        }
+    }
+}
diff --git a/library/std/src/sys_common/thread_local_key.rs b/library/std/src/sys_common/thread_local_key.rs
new file mode 100644
index 00000000000..ac5b128298d
--- /dev/null
+++ b/library/std/src/sys_common/thread_local_key.rs
@@ -0,0 +1,271 @@
+//! 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 pointer-sized data, possibly with an associated destructor.
+//!
+//! 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 = "none")]
+#![allow(dead_code)] // sys isn't exported yet
+
+use crate::sync::atomic::{self, AtomicUsize, Ordering};
+use crate::sys::thread_local_key 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 "C" 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 "C" 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 "C" 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) }
+    }
+}
+
+#[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/library/std/src/sys_common/util.rs b/library/std/src/sys_common/util.rs
new file mode 100644
index 00000000000..9f7c3bd8795
--- /dev/null
+++ b/library/std/src/sys_common/util.rs
@@ -0,0 +1,28 @@
+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));
+    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/library/std/src/sys_common/wtf8.rs b/library/std/src/sys_common/wtf8.rs
new file mode 100644
index 00000000000..bdb6a05464e
--- /dev/null
+++ b/library/std/src/sys_common/wtf8.rs
@@ -0,0 +1,1285 @@
+//! 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 `capacity` bytes.
+    #[inline]
+    pub fn with_capacity(capacity: usize) -> Wtf8Buf {
+        Wtf8Buf { bytes: Vec::with_capacity(capacity) }
+    }
+
+    /// 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 mut bytes = [0; 4];
+        let bytes = char::encode_utf8_raw(code_point.value, &mut 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));
+    }
+
+    #[inline]
+    fn extend_one(&mut self, code_point: CodePoint) {
+        self.push(code_point);
+    }
+
+    #[inline]
+    fn extend_reserve(&mut self, additional: usize) {
+        // Lower bound of one byte per code point (ASCII only)
+        self.bytes.reserve(additional);
+    }
+}
+
+/// 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> {
+        match self.bytes {
+            [.., 0xED, b2 @ 0xA0..=0xAF, b3] => Some(decode_surrogate(b2, b3)),
+            _ => None,
+        }
+    }
+
+    #[inline]
+    fn initial_trail_surrogate(&self) -> Option<u16> {
+        match self.bytes {
+            [0xED, b2 @ 0xB0..=0xBF, b3, ..] => Some(decode_surrogate(b2, b3)),
+            _ => None,
+        }
+    }
+
+    pub fn clone_into(&self, buf: &mut Wtf8Buf) {
+        self.bytes.clone_into(&mut buf.bytes)
+    }
+
+    /// 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) }
+    }
+
+    #[inline]
+    pub fn make_ascii_lowercase(&mut self) {
+        self.bytes.make_ascii_lowercase()
+    }
+
+    #[inline]
+    pub fn make_ascii_uppercase(&mut self) {
+        self.bytes.make_ascii_uppercase()
+    }
+
+    #[inline]
+    pub fn to_ascii_lowercase(&self) -> Wtf8Buf {
+        Wtf8Buf { bytes: self.bytes.to_ascii_lowercase() }
+    }
+
+    #[inline]
+    pub fn to_ascii_uppercase(&self) -> Wtf8Buf {
+        Wtf8Buf { bytes: self.bytes.to_ascii_uppercase() }
+    }
+
+    #[inline]
+    pub fn is_ascii(&self) -> bool {
+        self.bytes.is_ascii()
+    }
+
+    #[inline]
+    pub fn eq_ignore_ascii_case(&self, other: &Self) -> bool {
+        self.bytes.eq_ignore_ascii_case(&other.bytes)
+    }
+}
+
+/// 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 n = char::encode_utf16_raw(code_point.value, &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)
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use crate::borrow::Cow;
+
+    #[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]
+        );
+    }
+}