From 0090e01f08f7ed564a62fb3cd2e3b652317d39d7 Mon Sep 17 00:00:00 2001 From: Anders Kaseorg Date: Mon, 23 Mar 2015 00:58:19 -0400 Subject: Get __pthread_get_minstack at runtime with dlsym MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Linking __pthread_get_minstack, even weakly, was causing Debian’s dpkg-shlibdeps to detect an unnecessarily strict versioned dependency on libc6. Closes #23628. Signed-off-by: Anders Kaseorg --- src/libstd/sys/unix/thread.rs | 35 +++++++++++++++++++++++------------ 1 file changed, 23 insertions(+), 12 deletions(-) (limited to 'src/libstd/sys') diff --git a/src/libstd/sys/unix/thread.rs b/src/libstd/sys/unix/thread.rs index c5f07c6c75a..1d3cb43465b 100644 --- a/src/libstd/sys/unix/thread.rs +++ b/src/libstd/sys/unix/thread.rs @@ -13,12 +13,14 @@ use core::prelude::*; use cmp; +use dynamic_lib::DynamicLibrary; use ffi::CString; use io; use libc::consts::os::posix01::PTHREAD_STACK_MIN; use libc; use mem; use ptr; +use sync::{Once, ONCE_INIT}; use sys::os; use thunk::Thunk; use time::Duration; @@ -314,21 +316,30 @@ pub fn sleep(dur: Duration) { // is created in an application with big thread-local storage requirements. // See #6233 for rationale and details. // -// Link weakly to the symbol for compatibility with older versions of glibc. -// Assumes that we've been dynamically linked to libpthread but that is -// currently always the case. Note that you need to check that the symbol -// is non-null before calling it! +// Use dlsym to get the symbol value at runtime, for compatibility +// with older versions of glibc. Assumes that we've been dynamically +// linked to libpthread but that is currently always the case. We +// previously used weak linkage (under the same assumption), but that +// caused Debian to detect an unnecessarily strict versioned +// dependency on libc6 (#23628). #[cfg(target_os = "linux")] fn min_stack_size(attr: *const libc::pthread_attr_t) -> libc::size_t { type F = unsafe extern "C" fn(*const libc::pthread_attr_t) -> libc::size_t; - extern { - #[linkage = "extern_weak"] - static __pthread_get_minstack: *const (); - } - if __pthread_get_minstack.is_null() { - PTHREAD_STACK_MIN - } else { - unsafe { mem::transmute::<*const (), F>(__pthread_get_minstack)(attr) } + static INIT: Once = ONCE_INIT; + static mut __pthread_get_minstack: Option = None; + + INIT.call_once(|| { + let lib = DynamicLibrary::open(None).unwrap(); + unsafe { + if let Ok(f) = lib.symbol("__pthread_get_minstack") { + __pthread_get_minstack = Some(mem::transmute::<*const (), F>(f)); + } + } + }); + + match unsafe { __pthread_get_minstack } { + None => PTHREAD_STACK_MIN, + Some(f) => unsafe { f(attr) }, } } -- cgit 1.4.1-3-g733a5 From b6641c1595687a6c7c8ba381b46b931a58a3ada4 Mon Sep 17 00:00:00 2001 From: Anders Kaseorg Date: Mon, 23 Mar 2015 03:48:06 -0400 Subject: min_stack_size: update non-Linux implementation comment Signed-off-by: Anders Kaseorg --- src/libstd/sys/unix/thread.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/libstd/sys') diff --git a/src/libstd/sys/unix/thread.rs b/src/libstd/sys/unix/thread.rs index 1d3cb43465b..b3594dcaa75 100644 --- a/src/libstd/sys/unix/thread.rs +++ b/src/libstd/sys/unix/thread.rs @@ -343,8 +343,8 @@ fn min_stack_size(attr: *const libc::pthread_attr_t) -> libc::size_t { } } -// __pthread_get_minstack() is marked as weak but extern_weak linkage is -// not supported on OS X, hence this kludge... +// No point in looking up __pthread_get_minstack() on non-glibc +// platforms. #[cfg(not(target_os = "linux"))] fn min_stack_size(_: *const libc::pthread_attr_t) -> libc::size_t { PTHREAD_STACK_MIN -- cgit 1.4.1-3-g733a5 From 737bb30f0af5b27785a006a91a8792a06478de87 Mon Sep 17 00:00:00 2001 From: Anders Kaseorg Date: Mon, 23 Mar 2015 04:02:02 -0400 Subject: min_stack_size: clarify both reasons to use dlsym Signed-off-by: Anders Kaseorg --- src/libstd/sys/unix/thread.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'src/libstd/sys') diff --git a/src/libstd/sys/unix/thread.rs b/src/libstd/sys/unix/thread.rs index b3594dcaa75..c66d86b7625 100644 --- a/src/libstd/sys/unix/thread.rs +++ b/src/libstd/sys/unix/thread.rs @@ -316,11 +316,12 @@ pub fn sleep(dur: Duration) { // is created in an application with big thread-local storage requirements. // See #6233 for rationale and details. // -// Use dlsym to get the symbol value at runtime, for compatibility -// with older versions of glibc. Assumes that we've been dynamically -// linked to libpthread but that is currently always the case. We -// previously used weak linkage (under the same assumption), but that -// caused Debian to detect an unnecessarily strict versioned +// Use dlsym to get the symbol value at runtime, both for +// compatibility with older versions of glibc, and to avoid creating +// dependencies on GLIBC_PRIVATE symbols. Assumes that we've been +// dynamically linked to libpthread but that is currently always the +// case. We previously used weak linkage (under the same assumption), +// but that caused Debian to detect an unnecessarily strict versioned // dependency on libc6 (#23628). #[cfg(target_os = "linux")] fn min_stack_size(attr: *const libc::pthread_attr_t) -> libc::size_t { -- cgit 1.4.1-3-g733a5 From d29d5545b6a5485bb1a51e035889e20330b2e4f7 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Mon, 23 Mar 2015 19:06:09 +0200 Subject: prctl instead of pthread on linux for name setup This is more portable as far as linux is concerned. --- src/libstd/sys/unix/thread.rs | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) (limited to 'src/libstd/sys') diff --git a/src/libstd/sys/unix/thread.rs b/src/libstd/sys/unix/thread.rs index c5f07c6c75a..4ba0d6472b6 100644 --- a/src/libstd/sys/unix/thread.rs +++ b/src/libstd/sys/unix/thread.rs @@ -227,19 +227,16 @@ pub unsafe fn create(stack: usize, p: Thunk) -> io::Result { #[cfg(any(target_os = "linux", target_os = "android"))] pub unsafe fn set_name(name: &str) { - // pthread_setname_np() since glibc 2.12 - // availability autodetected via weak linkage - type F = unsafe extern fn(libc::pthread_t, *const libc::c_char) - -> libc::c_int; + // pthread wrapper only appeared in glibc 2.12, so we use syscall directly. extern { - #[linkage = "extern_weak"] - static pthread_setname_np: *const (); - } - if !pthread_setname_np.is_null() { - let cname = CString::new(name).unwrap(); - mem::transmute::<*const (), F>(pthread_setname_np)(pthread_self(), - cname.as_ptr()); + fn prctl(option: libc::c_int, arg2: libc::c_ulong, arg3: libc::c_ulong, + arg4: libc::c_ulong, arg5: libc::c_ulong) -> libc::c_int; } + const PR_SET_NAME: libc::c_int = 15; + let cname = CString::new(name).unwrap_or_else(|_| { + panic!("thread name may not contain interior null bytes") + }); + prctl(PR_SET_NAME, cname.as_ptr() as libc::c_ulong, 0, 0, 0); } #[cfg(any(target_os = "freebsd", -- cgit 1.4.1-3-g733a5 From 6bd3ab0d8140053475a901ad4e2e80e98955bcb0 Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Fri, 20 Mar 2015 00:46:13 -0700 Subject: Implement RFC 909: move thread_local into thread This commit implements [RFC 909](https://github.com/rust-lang/rfcs/pull/909): The `std::thread_local` module is now deprecated, and its contents are available directly in `std::thread` as `LocalKey`, `LocalKeyState`, and `ScopedKey`. The macros remain exactly as they were, which means little if any code should break. Nevertheless, this is technically a: [breaking-change] Closes #23547 --- src/libstd/lib.rs | 23 +- src/libstd/sys/common/thread_info.rs | 4 +- src/libstd/thread.rs | 960 ------------------------------- src/libstd/thread/local.rs | 735 ++++++++++++++++++++++++ src/libstd/thread/mod.rs | 1026 ++++++++++++++++++++++++++++++++++ src/libstd/thread/scoped.rs | 317 +++++++++++ src/libstd/thread_local/mod.rs | 762 ------------------------- src/libstd/thread_local/scoped.rs | 313 ----------- 8 files changed, 2088 insertions(+), 2052 deletions(-) delete mode 100644 src/libstd/thread.rs create mode 100644 src/libstd/thread/local.rs create mode 100644 src/libstd/thread/mod.rs create mode 100644 src/libstd/thread/scoped.rs delete mode 100644 src/libstd/thread_local/mod.rs delete mode 100644 src/libstd/thread_local/scoped.rs (limited to 'src/libstd/sys') diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index b055796ba54..970074f7930 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -249,30 +249,23 @@ pub mod num; /* Runtime and platform support */ #[macro_use] -pub mod thread_local; +pub mod thread; +pub mod collections; pub mod dynamic_lib; +pub mod env; pub mod ffi; -pub mod old_io; -pub mod io; pub mod fs; +pub mod io; pub mod net; +pub mod old_io; +pub mod old_path; pub mod os; -pub mod env; pub mod path; -pub mod old_path; pub mod process; pub mod rand; -pub mod time; - -/* Common data structures */ - -pub mod collections; - -/* Threads and communication */ - -pub mod thread; pub mod sync; +pub mod time; #[macro_use] #[path = "sys/common/mod.rs"] mod sys_common; @@ -305,7 +298,7 @@ mod std { pub use rt; // used for panic!() pub use vec; // used for vec![] pub use cell; // used for tls! - pub use thread_local; // used for thread_local! + pub use thread; // used for thread_local! pub use marker; // used for tls! pub use ops; // used for bitflags! diff --git a/src/libstd/sys/common/thread_info.rs b/src/libstd/sys/common/thread_info.rs index e4985e703ba..90526b8f4f3 100644 --- a/src/libstd/sys/common/thread_info.rs +++ b/src/libstd/sys/common/thread_info.rs @@ -15,7 +15,7 @@ use core::prelude::*; use cell::RefCell; use string::String; use thread::Thread; -use thread_local::State; +use thread::LocalKeyState; struct ThreadInfo { stack_guard: uint, @@ -26,7 +26,7 @@ thread_local! { static THREAD_INFO: RefCell> = RefCell::new(N impl ThreadInfo { fn with(f: F) -> R where F: FnOnce(&mut ThreadInfo) -> R { - if THREAD_INFO.state() == State::Destroyed { + if THREAD_INFO.state() == LocalKeyState::Destroyed { panic!("Use of std::thread::current() is not possible after \ the thread's local data has been destroyed"); } diff --git a/src/libstd/thread.rs b/src/libstd/thread.rs deleted file mode 100644 index ab74442cac9..00000000000 --- a/src/libstd/thread.rs +++ /dev/null @@ -1,960 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Native threads -//! -//! ## The threading model -//! -//! An executing Rust program consists of a collection of native OS threads, -//! each with their own stack and local state. -//! -//! Communication between threads can be done through -//! [channels](../../std/sync/mpsc/index.html), Rust's message-passing -//! types, along with [other forms of thread -//! synchronization](../../std/sync/index.html) and shared-memory data -//! structures. In particular, types that are guaranteed to be -//! threadsafe are easily shared between threads using the -//! atomically-reference-counted container, -//! [`Arc`](../../std/sync/struct.Arc.html). -//! -//! Fatal logic errors in Rust cause *thread panic*, during which -//! a thread will unwind the stack, running destructors and freeing -//! owned resources. Thread panic is unrecoverable from within -//! the panicking thread (i.e. there is no 'try/catch' in Rust), but -//! the panic may optionally be detected from a different thread. If -//! the main thread panics, the application will exit with a non-zero -//! exit code. -//! -//! When the main thread of a Rust program terminates, the entire program shuts -//! down, even if other threads are still running. However, this module provides -//! convenient facilities for automatically waiting for the termination of a -//! child thread (i.e., join). -//! -//! ## The `Thread` type -//! -//! Threads are represented via the `Thread` type, which you can -//! get in one of two ways: -//! -//! * By spawning a new thread, e.g. using the `thread::spawn` function. -//! * By requesting the current thread, using the `thread::current` function. -//! -//! Threads can be named, and provide some built-in support for low-level -//! synchronization (described below). -//! -//! The `thread::current()` function is available even for threads not spawned -//! by the APIs of this module. -//! -//! ## Spawning a thread -//! -//! A new thread can be spawned using the `thread::spawn` function: -//! -//! ```rust -//! use std::thread; -//! -//! thread::spawn(move || { -//! // some work here -//! }); -//! ``` -//! -//! In this example, the spawned thread is "detached" from the current -//! thread. This means that it can outlive its parent (the thread that spawned -//! it), unless this parent is the main thread. -//! -//! ## Scoped threads -//! -//! Often a parent thread uses a child thread to perform some particular task, -//! and at some point must wait for the child to complete before continuing. -//! For this scenario, use the `thread::scoped` function: -//! -//! ```rust -//! use std::thread; -//! -//! let guard = thread::scoped(move || { -//! // some work here -//! }); -//! -//! // do some other work in the meantime -//! let output = guard.join(); -//! ``` -//! -//! The `scoped` function doesn't return a `Thread` directly; instead, -//! it returns a *join guard*. The join guard is an RAII-style guard -//! that will automatically join the child thread (block until it -//! terminates) when it is dropped. You can join the child thread in -//! advance by calling the `join` method on the guard, which will also -//! return the result produced by the thread. A handle to the thread -//! itself is available via the `thread` method of the join guard. -//! -//! ## Configuring threads -//! -//! A new thread can be configured before it is spawned via the `Builder` type, -//! which currently allows you to set the name, stack size, and writers for -//! `println!` and `panic!` for the child thread: -//! -//! ```rust -//! use std::thread; -//! -//! thread::Builder::new().name("child1".to_string()).spawn(move || { -//! println!("Hello, world!"); -//! }); -//! ``` -//! -//! ## Blocking support: park and unpark -//! -//! Every thread is equipped with some basic low-level blocking support, via the -//! `park` and `unpark` functions. -//! -//! Conceptually, each `Thread` handle has an associated token, which is -//! initially not present: -//! -//! * The `thread::park()` function blocks the current thread unless or until -//! the token is available for its thread handle, at which point it atomically -//! consumes the token. It may also return *spuriously*, without consuming the -//! token. `thread::park_timeout()` does the same, but allows specifying a -//! maximum time to block the thread for. -//! -//! * The `unpark()` method on a `Thread` atomically makes the token available -//! if it wasn't already. -//! -//! In other words, each `Thread` acts a bit like a semaphore with initial count -//! 0, except that the semaphore is *saturating* (the count cannot go above 1), -//! and can return spuriously. -//! -//! The API is typically used by acquiring a handle to the current thread, -//! placing that handle in a shared data structure so that other threads can -//! find it, and then `park`ing. When some desired condition is met, another -//! thread calls `unpark` on the handle. -//! -//! The motivation for this design is twofold: -//! -//! * It avoids the need to allocate mutexes and condvars when building new -//! synchronization primitives; the threads already provide basic blocking/signaling. -//! -//! * It can be implemented very efficiently on many platforms. - -#![stable(feature = "rust1", since = "1.0.0")] - -use prelude::v1::*; - -use any::Any; -use cell::UnsafeCell; -use fmt; -use io; -use marker::PhantomData; -use rt::{self, unwind}; -use sync::{Mutex, Condvar, Arc}; -use sys::thread as imp; -use sys_common::{stack, thread_info}; -use thunk::Thunk; -use time::Duration; - -#[allow(deprecated)] use old_io::Writer; - -/// Thread configuration. Provides detailed control over the properties -/// and behavior of new threads. -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Builder { - // A name for the thread-to-be, for identification in panic messages - name: Option, - // The size of the stack for the spawned thread - stack_size: Option, -} - -impl Builder { - /// Generate the base configuration for spawning a thread, from which - /// configuration methods can be chained. - #[stable(feature = "rust1", since = "1.0.0")] - pub fn new() -> Builder { - Builder { - name: None, - stack_size: None, - } - } - - /// Name the thread-to-be. Currently the name is used for identification - /// only in panic messages. - #[stable(feature = "rust1", since = "1.0.0")] - pub fn name(mut self, name: String) -> Builder { - self.name = Some(name); - self - } - - /// Set the size of the stack for the new thread. - #[stable(feature = "rust1", since = "1.0.0")] - pub fn stack_size(mut self, size: usize) -> Builder { - self.stack_size = Some(size); - self - } - - /// Redirect thread-local stdout. - #[unstable(feature = "std_misc", - reason = "Will likely go away after proc removal")] - #[deprecated(since = "1.0.0", - reason = "the old I/O module is deprecated and this function \ - will be removed with no replacement")] - #[allow(deprecated)] - pub fn stdout(self, _stdout: Box) -> Builder { - self - } - - /// Redirect thread-local stderr. - #[unstable(feature = "std_misc", - reason = "Will likely go away after proc removal")] - #[deprecated(since = "1.0.0", - reason = "the old I/O module is deprecated and this function \ - will be removed with no replacement")] - #[allow(deprecated)] - pub fn stderr(self, _stderr: Box) -> Builder { - self - } - - /// Spawn a new thread, and return a join handle for it. - /// - /// The child thread may outlive the parent (unless the parent thread - /// is the main thread; the whole process is terminated when the main - /// thread finishes.) The join handle can be used to block on - /// termination of the child thread, including recovering its panics. - /// - /// # Errors - /// - /// Unlike the `spawn` free function, this method yields an - /// `io::Result` to capture any failure to create the thread at - /// the OS level. - #[stable(feature = "rust1", since = "1.0.0")] - pub fn spawn(self, f: F) -> io::Result where - F: FnOnce(), F: Send + 'static - { - self.spawn_inner(Thunk::new(f)).map(|i| JoinHandle(i)) - } - - /// Spawn a new child thread that must be joined within a given - /// scope, and return a `JoinGuard`. - /// - /// The join guard can be used to explicitly join the child thread (via - /// `join`), returning `Result`, or it will implicitly join the child - /// upon being dropped. Because the child thread may refer to data on the - /// current thread's stack (hence the "scoped" name), it cannot be detached; - /// it *must* be joined before the relevant stack frame is popped. See the - /// module documentation for additional details. - /// - /// # Errors - /// - /// Unlike the `scoped` free function, this method yields an - /// `io::Result` to capture any failure to create the thread at - /// the OS level. - #[stable(feature = "rust1", since = "1.0.0")] - pub fn scoped<'a, T, F>(self, f: F) -> io::Result> where - T: Send + 'a, F: FnOnce() -> T, F: Send + 'a - { - self.spawn_inner(Thunk::new(f)).map(|inner| { - JoinGuard { inner: inner, _marker: PhantomData } - }) - } - - fn spawn_inner(self, f: Thunk<(), T>) -> io::Result> { - let Builder { name, stack_size } = self; - - let stack_size = stack_size.unwrap_or(rt::min_stack()); - - let my_thread = Thread::new(name); - let their_thread = my_thread.clone(); - - let my_packet = Packet(Arc::new(UnsafeCell::new(None))); - let their_packet = Packet(my_packet.0.clone()); - - // Spawning a new OS thread guarantees that __morestack will never get - // triggered, but we must manually set up the actual stack bounds once - // this function starts executing. This raises the lower limit by a bit - // because by the time that this function is executing we've already - // consumed at least a little bit of stack (we don't know the exact byte - // address at which our stack started). - let main = move || { - let something_around_the_top_of_the_stack = 1; - let addr = &something_around_the_top_of_the_stack as *const i32; - let my_stack_top = addr as usize; - let my_stack_bottom = my_stack_top - stack_size + 1024; - unsafe { - if let Some(name) = their_thread.name() { - imp::set_name(name); - } - stack::record_os_managed_stack_bounds(my_stack_bottom, - my_stack_top); - thread_info::set(imp::guard::current(), their_thread); - } - - let mut output = None; - let try_result = { - let ptr = &mut output; - - // There are two primary reasons that general try/catch is - // unsafe. The first is that we do not support nested - // try/catch. The fact that this is happening in a newly-spawned - // thread suffices. The second is that unwinding while unwinding - // is not defined. We take care of that by having an - // 'unwinding' flag in the thread itself. For these reasons, - // this unsafety should be ok. - unsafe { - unwind::try(move || *ptr = Some(f.invoke(()))) - } - }; - unsafe { - *their_packet.0.get() = Some(match (output, try_result) { - (Some(data), Ok(_)) => Ok(data), - (None, Err(cause)) => Err(cause), - _ => unreachable!() - }); - } - }; - - Ok(JoinInner { - native: try!(unsafe { imp::create(stack_size, Thunk::new(main)) }), - thread: my_thread, - packet: my_packet, - joined: false, - }) - } -} - -/// Spawn a new thread, returning a `JoinHandle` for it. -/// -/// The join handle will implicitly *detach* the child thread upon being -/// dropped. In this case, the child thread may outlive the parent (unless -/// the parent thread is the main thread; the whole process is terminated when -/// the main thread finishes.) Additionally, the join handle provides a `join` -/// method that can be used to join the child thread. If the child thread -/// panics, `join` will return an `Err` containing the argument given to -/// `panic`. -/// -/// # Panics -/// -/// Panicks if the OS fails to create a thread; use `Builder::spawn` -/// to recover from such errors. -#[stable(feature = "rust1", since = "1.0.0")] -pub fn spawn(f: F) -> JoinHandle where F: FnOnce(), F: Send + 'static { - Builder::new().spawn(f).unwrap() -} - -/// Spawn a new *scoped* thread, returning a `JoinGuard` for it. -/// -/// The join guard can be used to explicitly join the child thread (via -/// `join`), returning `Result`, or it will implicitly join the child -/// upon being dropped. Because the child thread may refer to data on the -/// current thread's stack (hence the "scoped" name), it cannot be detached; -/// it *must* be joined before the relevant stack frame is popped. See the -/// module documentation for additional details. -/// -/// # Panics -/// -/// Panicks if the OS fails to create a thread; use `Builder::scoped` -/// to recover from such errors. -#[stable(feature = "rust1", since = "1.0.0")] -pub fn scoped<'a, T, F>(f: F) -> JoinGuard<'a, T> where - T: Send + 'a, F: FnOnce() -> T, F: Send + 'a -{ - Builder::new().scoped(f).unwrap() -} - -/// Gets a handle to the thread that invokes it. -#[stable(feature = "rust1", since = "1.0.0")] -pub fn current() -> Thread { - thread_info::current_thread() -} - -/// Cooperatively give up a timeslice to the OS scheduler. -#[stable(feature = "rust1", since = "1.0.0")] -pub fn yield_now() { - unsafe { imp::yield_now() } -} - -/// Determines whether the current thread is unwinding because of panic. -#[inline] -#[stable(feature = "rust1", since = "1.0.0")] -pub fn panicking() -> bool { - unwind::panicking() -} - -/// Put the current thread to sleep for the specified amount of time. -/// -/// The thread may sleep longer than the duration specified due to scheduling -/// specifics or platform-dependent functionality. Note that on unix platforms -/// this function will not return early due to a signal being received or a -/// spurious wakeup. -#[unstable(feature = "thread_sleep", - reason = "recently added, needs an RFC, and `Duration` itself is \ - unstable")] -pub fn sleep(dur: Duration) { - imp::sleep(dur) -} - -/// Block unless or until the current thread's token is made available (may wake spuriously). -/// -/// See the module doc for more detail. -// -// The implementation currently uses the trivial strategy of a Mutex+Condvar -// with wakeup flag, which does not actually allow spurious wakeups. In the -// future, this will be implemented in a more efficient way, perhaps along the lines of -// http://cr.openjdk.java.net/~stefank/6989984.1/raw_files/new/src/os/linux/vm/os_linux.cpp -// or futuxes, and in either case may allow spurious wakeups. -#[stable(feature = "rust1", since = "1.0.0")] -pub fn park() { - let thread = current(); - let mut guard = thread.inner.lock.lock().unwrap(); - while !*guard { - guard = thread.inner.cvar.wait(guard).unwrap(); - } - *guard = false; -} - -/// Block unless or until the current thread's token is made available or -/// the specified duration has been reached (may wake spuriously). -/// -/// The semantics of this function are equivalent to `park()` except that the -/// thread will be blocked for roughly no longer than *duration*. This method -/// should not be used for precise timing due to anomalies such as -/// preemption or platform differences that may not cause the maximum -/// amount of time waited to be precisely *duration* long. -/// -/// See the module doc for more detail. -#[unstable(feature = "std_misc", reason = "recently introduced, depends on Duration")] -pub fn park_timeout(duration: Duration) { - let thread = current(); - let mut guard = thread.inner.lock.lock().unwrap(); - if !*guard { - let (g, _) = thread.inner.cvar.wait_timeout(guard, duration).unwrap(); - guard = g; - } - *guard = false; -} - -/// The internal representation of a `Thread` handle -struct Inner { - name: Option, - lock: Mutex, // true when there is a buffered unpark - cvar: Condvar, -} - -unsafe impl Sync for Inner {} - -#[derive(Clone)] -#[stable(feature = "rust1", since = "1.0.0")] -/// A handle to a thread. -pub struct Thread { - inner: Arc, -} - -impl Thread { - // Used only internally to construct a thread object without spawning - fn new(name: Option) -> Thread { - Thread { - inner: Arc::new(Inner { - name: name, - lock: Mutex::new(false), - cvar: Condvar::new(), - }) - } - } - - /// Deprecated: use module-level free function. - #[deprecated(since = "1.0.0", reason = "use module-level free function")] - #[unstable(feature = "std_misc", - reason = "may change with specifics of new Send semantics")] - pub fn spawn(f: F) -> Thread where F: FnOnce(), F: Send + 'static { - Builder::new().spawn(f).unwrap().thread().clone() - } - - /// Deprecated: use module-level free function. - #[deprecated(since = "1.0.0", reason = "use module-level free function")] - #[unstable(feature = "std_misc", - reason = "may change with specifics of new Send semantics")] - pub fn scoped<'a, T, F>(f: F) -> JoinGuard<'a, T> where - T: Send + 'a, F: FnOnce() -> T, F: Send + 'a - { - Builder::new().scoped(f).unwrap() - } - - /// Deprecated: use module-level free function. - #[deprecated(since = "1.0.0", reason = "use module-level free function")] - #[stable(feature = "rust1", since = "1.0.0")] - pub fn current() -> Thread { - thread_info::current_thread() - } - - /// Deprecated: use module-level free function. - #[deprecated(since = "1.0.0", reason = "use module-level free function")] - #[unstable(feature = "std_misc", reason = "name may change")] - pub fn yield_now() { - unsafe { imp::yield_now() } - } - - /// Deprecated: use module-level free function. - #[deprecated(since = "1.0.0", reason = "use module-level free function")] - #[inline] - #[stable(feature = "rust1", since = "1.0.0")] - pub fn panicking() -> bool { - unwind::panicking() - } - - /// Deprecated: use module-level free function. - #[deprecated(since = "1.0.0", reason = "use module-level free function")] - #[unstable(feature = "std_misc", reason = "recently introduced")] - pub fn park() { - let thread = current(); - let mut guard = thread.inner.lock.lock().unwrap(); - while !*guard { - guard = thread.inner.cvar.wait(guard).unwrap(); - } - *guard = false; - } - - /// Deprecated: use module-level free function. - #[deprecated(since = "1.0.0", reason = "use module-level free function")] - #[unstable(feature = "std_misc", reason = "recently introduced")] - pub fn park_timeout(duration: Duration) { - let thread = current(); - let mut guard = thread.inner.lock.lock().unwrap(); - if !*guard { - let (g, _) = thread.inner.cvar.wait_timeout(guard, duration).unwrap(); - guard = g; - } - *guard = false; - } - - /// Atomically makes the handle's token available if it is not already. - /// - /// See the module doc for more detail. - #[stable(feature = "rust1", since = "1.0.0")] - pub fn unpark(&self) { - let mut guard = self.inner.lock.lock().unwrap(); - if !*guard { - *guard = true; - self.inner.cvar.notify_one(); - } - } - - /// Get the thread's name. - #[stable(feature = "rust1", since = "1.0.0")] - pub fn name(&self) -> Option<&str> { - self.inner.name.as_ref().map(|s| &**s) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for Thread { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Debug::fmt(&self.name(), f) - } -} - -// a hack to get around privacy restrictions -impl thread_info::NewThread for Thread { - fn new(name: Option) -> Thread { Thread::new(name) } -} - -/// Indicates the manner in which a thread exited. -/// -/// A thread that completes without panicking is considered to exit successfully. -#[stable(feature = "rust1", since = "1.0.0")] -pub type Result = ::result::Result>; - -struct Packet(Arc>>>); - -unsafe impl Send for Packet {} -unsafe impl Sync for Packet {} - -/// Inner representation for JoinHandle and JoinGuard -struct JoinInner { - native: imp::rust_thread, - thread: Thread, - packet: Packet, - joined: bool, -} - -impl JoinInner { - fn join(&mut self) -> Result { - assert!(!self.joined); - unsafe { imp::join(self.native) }; - self.joined = true; - unsafe { - (*self.packet.0.get()).take().unwrap() - } - } -} - -/// An owned permission to join on a thread (block on its termination). -/// -/// Unlike a `JoinGuard`, a `JoinHandle` *detaches* the child thread -/// when it is dropped, rather than automatically joining on drop. -/// -/// Due to platform restrictions, it is not possible to `Clone` this -/// handle: the ability to join a child thread is a uniquely-owned -/// permission. -#[stable(feature = "rust1", since = "1.0.0")] -pub struct JoinHandle(JoinInner<()>); - -impl JoinHandle { - /// Extract a handle to the underlying thread - #[stable(feature = "rust1", since = "1.0.0")] - pub fn thread(&self) -> &Thread { - &self.0.thread - } - - /// Wait for the associated thread to finish. - /// - /// If the child thread panics, `Err` is returned with the parameter given - /// to `panic`. - #[stable(feature = "rust1", since = "1.0.0")] - pub fn join(mut self) -> Result<()> { - self.0.join() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Drop for JoinHandle { - fn drop(&mut self) { - if !self.0.joined { - unsafe { imp::detach(self.0.native) } - } - } -} - -/// An RAII-style guard that will block until thread termination when dropped. -/// -/// The type `T` is the return type for the thread's main function. -/// -/// Joining on drop is necessary to ensure memory safety when stack -/// data is shared between a parent and child thread. -/// -/// Due to platform restrictions, it is not possible to `Clone` this -/// handle: the ability to join a child thread is a uniquely-owned -/// permission. -#[must_use = "thread will be immediately joined if `JoinGuard` is not used"] -#[stable(feature = "rust1", since = "1.0.0")] -pub struct JoinGuard<'a, T: 'a> { - inner: JoinInner, - _marker: PhantomData<&'a T>, -} - -#[stable(feature = "rust1", since = "1.0.0")] -unsafe impl<'a, T: Send + 'a> Sync for JoinGuard<'a, T> {} - -impl<'a, T: Send + 'a> JoinGuard<'a, T> { - /// Extract a handle to the thread this guard will join on. - #[stable(feature = "rust1", since = "1.0.0")] - pub fn thread(&self) -> &Thread { - &self.inner.thread - } - - /// Wait for the associated thread to finish, returning the result of the thread's - /// calculation. - /// - /// # Panics - /// - /// Panics on the child thread are propagated by panicking the parent. - #[stable(feature = "rust1", since = "1.0.0")] - pub fn join(mut self) -> T { - match self.inner.join() { - Ok(res) => res, - Err(_) => panic!("child thread {:?} panicked", self.thread()), - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl JoinGuard<'static, T> { - /// Detaches the child thread, allowing it to outlive its parent. - #[deprecated(since = "1.0.0", reason = "use spawn instead")] - #[unstable(feature = "std_misc")] - pub fn detach(mut self) { - unsafe { imp::detach(self.inner.native) }; - self.inner.joined = true; // avoid joining in the destructor - } -} - -#[unsafe_destructor] -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T: Send + 'a> Drop for JoinGuard<'a, T> { - fn drop(&mut self) { - if !self.inner.joined { - if self.inner.join().is_err() { - panic!("child thread {:?} panicked", self.thread()); - } - } - } -} - -#[cfg(test)] -mod test { - use prelude::v1::*; - - use any::Any; - use sync::mpsc::{channel, Sender}; - use boxed::BoxAny; - use result; - use std::old_io::{ChanReader, ChanWriter}; - use super::{Builder}; - use thread; - use thunk::Thunk; - use time::Duration; - - // !!! These tests are dangerous. If something is buggy, they will hang, !!! - // !!! instead of exiting cleanly. This might wedge the buildbots. !!! - - #[test] - fn test_unnamed_thread() { - thread::spawn(move|| { - assert!(thread::current().name().is_none()); - }).join().ok().unwrap(); - } - - #[test] - fn test_named_thread() { - Builder::new().name("ada lovelace".to_string()).scoped(move|| { - assert!(thread::current().name().unwrap() == "ada lovelace".to_string()); - }).unwrap().join(); - } - - #[test] - fn test_run_basic() { - let (tx, rx) = channel(); - thread::spawn(move|| { - tx.send(()).unwrap(); - }); - rx.recv().unwrap(); - } - - #[test] - fn test_join_success() { - assert!(thread::scoped(move|| -> String { - "Success!".to_string() - }).join() == "Success!"); - } - - #[test] - fn test_join_panic() { - match thread::spawn(move|| { - panic!() - }).join() { - result::Result::Err(_) => (), - result::Result::Ok(()) => panic!() - } - } - - #[test] - fn test_scoped_success() { - let res = thread::scoped(move|| -> String { - "Success!".to_string() - }).join(); - assert!(res == "Success!"); - } - - #[test] - #[should_fail] - fn test_scoped_panic() { - thread::scoped(|| panic!()).join(); - } - - #[test] - #[should_fail] - fn test_scoped_implicit_panic() { - let _ = thread::scoped(|| panic!()); - } - - #[test] - fn test_spawn_sched() { - use clone::Clone; - - let (tx, rx) = channel(); - - fn f(i: i32, tx: Sender<()>) { - let tx = tx.clone(); - thread::spawn(move|| { - if i == 0 { - tx.send(()).unwrap(); - } else { - f(i - 1, tx); - } - }); - - } - f(10, tx); - rx.recv().unwrap(); - } - - #[test] - fn test_spawn_sched_childs_on_default_sched() { - let (tx, rx) = channel(); - - thread::spawn(move|| { - thread::spawn(move|| { - tx.send(()).unwrap(); - }); - }); - - rx.recv().unwrap(); - } - - fn avoid_copying_the_body(spawnfn: F) where F: FnOnce(Thunk<'static>) { - let (tx, rx) = channel(); - - let x: Box<_> = box 1; - let x_in_parent = (&*x) as *const i32 as usize; - - spawnfn(Thunk::new(move|| { - let x_in_child = (&*x) as *const i32 as usize; - tx.send(x_in_child).unwrap(); - })); - - let x_in_child = rx.recv().unwrap(); - assert_eq!(x_in_parent, x_in_child); - } - - #[test] - fn test_avoid_copying_the_body_spawn() { - avoid_copying_the_body(|v| { - thread::spawn(move || v.invoke(())); - }); - } - - #[test] - fn test_avoid_copying_the_body_thread_spawn() { - avoid_copying_the_body(|f| { - thread::spawn(move|| { - f.invoke(()); - }); - }) - } - - #[test] - fn test_avoid_copying_the_body_join() { - avoid_copying_the_body(|f| { - let _ = thread::spawn(move|| { - f.invoke(()) - }).join(); - }) - } - - #[test] - fn test_child_doesnt_ref_parent() { - // If the child refcounts the parent task, this will stack overflow when - // climbing the task tree to dereference each ancestor. (See #1789) - // (well, it would if the constant were 8000+ - I lowered it to be more - // valgrind-friendly. try this at home, instead..!) - const GENERATIONS: u32 = 16; - fn child_no(x: u32) -> Thunk<'static> { - return Thunk::new(move|| { - if x < GENERATIONS { - thread::spawn(move|| child_no(x+1).invoke(())); - } - }); - } - thread::spawn(|| child_no(0).invoke(())); - } - - #[test] - fn test_simple_newsched_spawn() { - thread::spawn(move || {}); - } - - #[test] - fn test_try_panic_message_static_str() { - match thread::spawn(move|| { - panic!("static string"); - }).join() { - Err(e) => { - type T = &'static str; - assert!(e.is::()); - assert_eq!(*e.downcast::().unwrap(), "static string"); - } - Ok(()) => panic!() - } - } - - #[test] - fn test_try_panic_message_owned_str() { - match thread::spawn(move|| { - panic!("owned string".to_string()); - }).join() { - Err(e) => { - type T = String; - assert!(e.is::()); - assert_eq!(*e.downcast::().unwrap(), "owned string".to_string()); - } - Ok(()) => panic!() - } - } - - #[test] - fn test_try_panic_message_any() { - match thread::spawn(move|| { - panic!(box 413u16 as Box); - }).join() { - Err(e) => { - type T = Box; - assert!(e.is::()); - let any = e.downcast::().unwrap(); - assert!(any.is::()); - assert_eq!(*any.downcast::().unwrap(), 413); - } - Ok(()) => panic!() - } - } - - #[test] - fn test_try_panic_message_unit_struct() { - struct Juju; - - match thread::spawn(move|| { - panic!(Juju) - }).join() { - Err(ref e) if e.is::() => {} - Err(_) | Ok(()) => panic!() - } - } - - #[test] - fn test_park_timeout_unpark_before() { - for _ in 0..10 { - thread::current().unpark(); - thread::park_timeout(Duration::seconds(10_000_000)); - } - } - - #[test] - fn test_park_timeout_unpark_not_called() { - for _ in 0..10 { - thread::park_timeout(Duration::milliseconds(10)); - } - } - - #[test] - fn test_park_timeout_unpark_called_other_thread() { - use std::old_io; - - for _ in 0..10 { - let th = thread::current(); - - let _guard = thread::spawn(move || { - old_io::timer::sleep(Duration::milliseconds(50)); - th.unpark(); - }); - - thread::park_timeout(Duration::seconds(10_000_000)); - } - } - - #[test] - fn sleep_smoke() { - thread::sleep(Duration::milliseconds(2)); - thread::sleep(Duration::milliseconds(-2)); - } - - // NOTE: the corresponding test for stderr is in run-pass/task-stderr, due - // to the test harness apparently interfering with stderr configuration. -} diff --git a/src/libstd/thread/local.rs b/src/libstd/thread/local.rs new file mode 100644 index 00000000000..43142d2e5bc --- /dev/null +++ b/src/libstd/thread/local.rs @@ -0,0 +1,735 @@ +// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Thread local storage + +#![unstable(feature = "thread_local_internals")] + +use prelude::v1::*; + +use cell::UnsafeCell; + +// Sure wish we had macro hygiene, no? +#[doc(hidden)] +#[unstable(feature = "thread_local_internals")] +pub mod __impl { + pub use super::imp::Key as KeyInner; + pub use super::imp::destroy_value; + pub use sys_common::thread_local::INIT_INNER as OS_INIT_INNER; + pub use sys_common::thread_local::StaticKey as OsStaticKey; +} + +/// A thread local storage key which owns its contents. +/// +/// This key uses the fastest possible implementation available to it for the +/// target platform. It is instantiated with the `thread_local!` macro and the +/// primary method is the `with` method. +/// +/// The `with` method yields a reference to the contained value which cannot be +/// sent across tasks or escape the given closure. +/// +/// # Initialization and Destruction +/// +/// Initialization is dynamically performed on the first call to `with()` +/// within a thread, and values support destructors which will be run when a +/// thread exits. +/// +/// # Examples +/// +/// ``` +/// use std::cell::RefCell; +/// use std::thread; +/// +/// thread_local!(static FOO: RefCell = RefCell::new(1)); +/// +/// FOO.with(|f| { +/// assert_eq!(*f.borrow(), 1); +/// *f.borrow_mut() = 2; +/// }); +/// +/// // each thread starts out with the initial value of 1 +/// thread::spawn(move|| { +/// FOO.with(|f| { +/// assert_eq!(*f.borrow(), 1); +/// *f.borrow_mut() = 3; +/// }); +/// }); +/// +/// // we retain our original value of 2 despite the child thread +/// FOO.with(|f| { +/// assert_eq!(*f.borrow(), 2); +/// }); +/// ``` +#[stable(feature = "rust1", since = "1.0.0")] +pub struct LocalKey { + // The key itself may be tagged with #[thread_local], and this `Key` is + // stored as a `static`, and it's not valid for a static to reference the + // address of another thread_local static. For this reason we kinda wonkily + // work around this by generating a shim function which will give us the + // address of the inner TLS key at runtime. + // + // This is trivially devirtualizable by LLVM because we never store anything + // to this field and rustc can declare the `static` as constant as well. + #[doc(hidden)] + #[unstable(feature = "thread_local_internals")] + pub inner: fn() -> &'static __impl::KeyInner>>, + + // initialization routine to invoke to create a value + #[doc(hidden)] + #[unstable(feature = "thread_local_internals")] + pub init: fn() -> T, +} + +/// Declare a new thread local storage key of type `std::thread::LocalKey`. +#[macro_export] +#[stable(feature = "rust1", since = "1.0.0")] +#[allow_internal_unstable] +macro_rules! thread_local { + (static $name:ident: $t:ty = $init:expr) => ( + static $name: ::std::thread::LocalKey<$t> = { + use std::cell::UnsafeCell as __UnsafeCell; + use std::thread::__local::__impl::KeyInner as __KeyInner; + use std::option::Option as __Option; + use std::option::Option::None as __None; + + __thread_local_inner!(static __KEY: __UnsafeCell<__Option<$t>> = { + __UnsafeCell { value: __None } + }); + fn __init() -> $t { $init } + fn __getit() -> &'static __KeyInner<__UnsafeCell<__Option<$t>>> { + &__KEY + } + ::std::thread::LocalKey { inner: __getit, init: __init } + }; + ); + (pub static $name:ident: $t:ty = $init:expr) => ( + pub static $name: ::std::thread::LocalKey<$t> = { + use std::cell::UnsafeCell as __UnsafeCell; + use std::thread::__local::__impl::KeyInner as __KeyInner; + use std::option::Option as __Option; + use std::option::Option::None as __None; + + __thread_local_inner!(static __KEY: __UnsafeCell<__Option<$t>> = { + __UnsafeCell { value: __None } + }); + fn __init() -> $t { $init } + fn __getit() -> &'static __KeyInner<__UnsafeCell<__Option<$t>>> { + &__KEY + } + ::std::thread::LocalKey { inner: __getit, init: __init } + }; + ); +} + +// Macro pain #4586: +// +// When cross compiling, rustc will load plugins and macros from the *host* +// platform before search for macros from the target platform. This is primarily +// done to detect, for example, plugins. Ideally the macro below would be +// defined once per module below, but unfortunately this means we have the +// following situation: +// +// 1. We compile libstd for x86_64-unknown-linux-gnu, this thread_local!() macro +// will inject #[thread_local] statics. +// 2. We then try to compile a program for arm-linux-androideabi +// 3. The compiler has a host of linux and a target of android, so it loads +// macros from the *linux* libstd. +// 4. The macro generates a #[thread_local] field, but the android libstd does +// not use #[thread_local] +// 5. Compile error about structs with wrong fields. +// +// To get around this, we're forced to inject the #[cfg] logic into the macro +// itself. Woohoo. + +#[macro_export] +#[doc(hidden)] +#[allow_internal_unstable] +macro_rules! __thread_local_inner { + (static $name:ident: $t:ty = $init:expr) => ( + #[cfg_attr(all(any(target_os = "macos", target_os = "linux"), + not(target_arch = "aarch64")), + thread_local)] + static $name: ::std::thread::__local::__impl::KeyInner<$t> = + __thread_local_inner!($init, $t); + ); + (pub static $name:ident: $t:ty = $init:expr) => ( + #[cfg_attr(all(any(target_os = "macos", target_os = "linux"), + not(target_arch = "aarch64")), + thread_local)] + pub static $name: ::std::thread::__local::__impl::KeyInner<$t> = + __thread_local_inner!($init, $t); + ); + ($init:expr, $t:ty) => ({ + #[cfg(all(any(target_os = "macos", target_os = "linux"), not(target_arch = "aarch64")))] + const _INIT: ::std::thread::__local::__impl::KeyInner<$t> = { + ::std::thread::__local::__impl::KeyInner { + inner: ::std::cell::UnsafeCell { value: $init }, + dtor_registered: ::std::cell::UnsafeCell { value: false }, + dtor_running: ::std::cell::UnsafeCell { value: false }, + } + }; + + #[cfg(any(not(any(target_os = "macos", target_os = "linux")), target_arch = "aarch64"))] + const _INIT: ::std::thread::__local::__impl::KeyInner<$t> = { + unsafe extern fn __destroy(ptr: *mut u8) { + ::std::thread::__local::__impl::destroy_value::<$t>(ptr); + } + + ::std::thread::__local::__impl::KeyInner { + inner: ::std::cell::UnsafeCell { value: $init }, + os: ::std::thread::__local::__impl::OsStaticKey { + inner: ::std::thread::__local::__impl::OS_INIT_INNER, + dtor: ::std::option::Option::Some(__destroy as unsafe extern fn(*mut u8)), + }, + } + }; + + _INIT + }); +} + +/// Indicator of the state of a thread local storage key. +#[unstable(feature = "std_misc", + reason = "state querying was recently added")] +#[derive(Eq, PartialEq, Copy)] +pub enum LocalKeyState { + /// All keys are in this state whenever a thread starts. Keys will + /// transition to the `Valid` state once the first call to `with` happens + /// and the initialization expression succeeds. + /// + /// Keys in the `Uninitialized` state will yield a reference to the closure + /// passed to `with` so long as the initialization routine does not panic. + Uninitialized, + + /// Once a key has been accessed successfully, it will enter the `Valid` + /// state. Keys in the `Valid` state will remain so until the thread exits, + /// at which point the destructor will be run and the key will enter the + /// `Destroyed` state. + /// + /// Keys in the `Valid` state will be guaranteed to yield a reference to the + /// closure passed to `with`. + Valid, + + /// When a thread exits, the destructors for keys will be run (if + /// necessary). While a destructor is running, and possibly after a + /// destructor has run, a key is in the `Destroyed` state. + /// + /// Keys in the `Destroyed` states will trigger a panic when accessed via + /// `with`. + Destroyed, +} + +impl LocalKey { + /// Acquire a reference to the value in this TLS key. + /// + /// This will lazily initialize the value if this thread has not referenced + /// this key yet. + /// + /// # Panics + /// + /// This function will `panic!()` if the key currently has its + /// destructor running, and it **may** panic if the destructor has + /// previously been run for this thread. + #[stable(feature = "rust1", since = "1.0.0")] + pub fn with(&'static self, f: F) -> R + where F: FnOnce(&T) -> R { + let slot = (self.inner)(); + unsafe { + let slot = slot.get().expect("cannot access a TLS value during or \ + after it is destroyed"); + f(match *slot.get() { + Some(ref inner) => inner, + None => self.init(slot), + }) + } + } + + unsafe fn init(&self, slot: &UnsafeCell>) -> &T { + // Execute the initialization up front, *then* move it into our slot, + // just in case initialization fails. + let value = (self.init)(); + let ptr = slot.get(); + *ptr = Some(value); + (*ptr).as_ref().unwrap() + } + + /// Query the current state of this key. + /// + /// A key is initially in the `Uninitialized` state whenever a thread + /// starts. It will remain in this state up until the first call to `with` + /// within a thread has run the initialization expression successfully. + /// + /// Once the initialization expression succeeds, the key transitions to the + /// `Valid` state which will guarantee that future calls to `with` will + /// succeed within the thread. + /// + /// When a thread exits, each key will be destroyed in turn, and as keys are + /// destroyed they will enter the `Destroyed` state just before the + /// destructor starts to run. Keys may remain in the `Destroyed` state after + /// destruction has completed. Keys without destructors (e.g. with types + /// that are `Copy`), may never enter the `Destroyed` state. + /// + /// Keys in the `Uninitialized` can be accessed so long as the + /// initialization does not panic. Keys in the `Valid` state are guaranteed + /// to be able to be accessed. Keys in the `Destroyed` state will panic on + /// any call to `with`. + #[unstable(feature = "std_misc", + reason = "state querying was recently added")] + pub fn state(&'static self) -> LocalKeyState { + unsafe { + match (self.inner)().get() { + Some(cell) => { + match *cell.get() { + Some(..) => LocalKeyState::Valid, + None => LocalKeyState::Uninitialized, + } + } + None => LocalKeyState::Destroyed, + } + } + } + + /// Deprecated + #[unstable(feature = "std_misc")] + #[deprecated(since = "1.0.0", + reason = "function renamed to state() and returns more info")] + pub fn destroyed(&'static self) -> bool { self.state() == LocalKeyState::Destroyed } +} + +#[cfg(all(any(target_os = "macos", target_os = "linux"), not(target_arch = "aarch64")))] +mod imp { + use prelude::v1::*; + + use cell::UnsafeCell; + use intrinsics; + use ptr; + + #[doc(hidden)] + #[unstable(feature = "thread_local_internals")] + pub struct Key { + // Place the inner bits in an `UnsafeCell` to currently get around the + // "only Sync statics" restriction. This allows any type to be placed in + // the cell. + // + // Note that all access requires `T: 'static` so it can't be a type with + // any borrowed pointers still. + #[unstable(feature = "thread_local_internals")] + pub inner: UnsafeCell, + + // Metadata to keep track of the state of the destructor. Remember that + // these variables are thread-local, not global. + #[unstable(feature = "thread_local_internals")] + pub dtor_registered: UnsafeCell, // should be Cell + #[unstable(feature = "thread_local_internals")] + pub dtor_running: UnsafeCell, // should be Cell + } + + unsafe impl ::marker::Sync for Key { } + + #[doc(hidden)] + impl Key { + pub unsafe fn get(&'static self) -> Option<&'static T> { + if intrinsics::needs_drop::() && *self.dtor_running.get() { + return None + } + self.register_dtor(); + Some(&*self.inner.get()) + } + + unsafe fn register_dtor(&self) { + if !intrinsics::needs_drop::() || *self.dtor_registered.get() { + return + } + + register_dtor(self as *const _ as *mut u8, + destroy_value::); + *self.dtor_registered.get() = true; + } + } + + // Since what appears to be glibc 2.18 this symbol has been shipped which + // GCC and clang both use to invoke destructors in thread_local globals, so + // let's do the same! + // + // Note, however, that we run on lots older linuxes, as well as cross + // compiling from a newer linux to an older linux, so we also have a + // fallback implementation to use as well. + // + // Due to rust-lang/rust#18804, make sure this is not generic! + #[cfg(target_os = "linux")] + unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) { + use boxed; + use mem; + use libc; + use sys_common::thread_local as os; + + extern { + static __dso_handle: *mut u8; + #[linkage = "extern_weak"] + static __cxa_thread_atexit_impl: *const (); + } + if !__cxa_thread_atexit_impl.is_null() { + type F = unsafe extern fn(dtor: unsafe extern fn(*mut u8), + arg: *mut u8, + dso_handle: *mut u8) -> libc::c_int; + mem::transmute::<*const (), F>(__cxa_thread_atexit_impl) + (dtor, t, __dso_handle); + return + } + + // 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: os::StaticKey = os::StaticKey { + inner: os::INIT_INNER, + dtor: Some(run_dtors as unsafe extern "C" fn(*mut u8)), + }; + type List = Vec<(*mut u8, unsafe extern fn(*mut u8))>; + if DTORS.get().is_null() { + let v: Box = box Vec::new(); + DTORS.set(boxed::into_raw(v) as *mut u8); + } + let list: &mut List = &mut *(DTORS.get() as *mut List); + list.push((t, dtor)); + + unsafe extern fn run_dtors(mut ptr: *mut u8) { + while !ptr.is_null() { + let list: Box = Box::from_raw(ptr as *mut List); + for &(ptr, dtor) in &*list { + dtor(ptr); + } + ptr = DTORS.get(); + DTORS.set(ptr::null_mut()); + } + } + } + + // OSX's analog of the above linux function is this _tlv_atexit function. + // The disassembly of thread_local globals in C++ (at least produced by + // clang) will have this show up in the output. + #[cfg(target_os = "macos")] + unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) { + extern { + fn _tlv_atexit(dtor: unsafe extern fn(*mut u8), + arg: *mut u8); + } + _tlv_atexit(dtor, t); + } + + #[doc(hidden)] + #[unstable(feature = "thread_local_internals")] + pub unsafe extern fn destroy_value(ptr: *mut u8) { + let ptr = ptr as *mut Key; + // Right before we run the user destructor be sure to flag the + // destructor as running for this thread so calls to `get` will return + // `None`. + *(*ptr).dtor_running.get() = true; + ptr::read((*ptr).inner.get()); + } +} + +#[cfg(any(not(any(target_os = "macos", target_os = "linux")), target_arch = "aarch64"))] +mod imp { + use prelude::v1::*; + + use alloc::boxed; + use cell::UnsafeCell; + use mem; + use ptr; + use sys_common::thread_local::StaticKey as OsStaticKey; + + #[doc(hidden)] + #[unstable(feature = "thread_local_internals")] + pub struct Key { + // Statically allocated initialization expression, using an `UnsafeCell` + // for the same reasons as above. + #[unstable(feature = "thread_local_internals")] + pub inner: UnsafeCell, + + // OS-TLS key that we'll use to key off. + #[unstable(feature = "thread_local_internals")] + pub os: OsStaticKey, + } + + unsafe impl ::marker::Sync for Key { } + + struct Value { + key: &'static Key, + value: T, + } + + #[doc(hidden)] + impl Key { + pub unsafe fn get(&'static self) -> Option<&'static T> { + self.ptr().map(|p| &*p) + } + + unsafe fn ptr(&'static self) -> Option<*mut T> { + let ptr = self.os.get() as *mut Value; + if !ptr.is_null() { + if ptr as usize == 1 { + return None + } + return Some(&mut (*ptr).value as *mut T); + } + + // If the lookup returned null, we haven't initialized our own local + // copy, so do that now. + // + // Also note that this transmute_copy should be ok because the value + // `inner` is already validated to be a valid `static` value, so we + // should be able to freely copy the bits. + let ptr: Box> = box Value { + key: self, + value: mem::transmute_copy(&self.inner), + }; + let ptr: *mut Value = boxed::into_raw(ptr); + self.os.set(ptr as *mut u8); + Some(&mut (*ptr).value as *mut T) + } + } + + #[doc(hidden)] + #[unstable(feature = "thread_local_internals")] + pub unsafe extern fn destroy_value(ptr: *mut u8) { + // The OS TLS ensures that this key contains a NULL value when this + // destructor starts to run. We set it back to a sentinel value of 1 to + // ensure that any future calls to `get` for this thread will return + // `None`. + // + // Note that to prevent an infinite loop we reset it back to null right + // before we return from the destructor ourselves. + let ptr: Box> = Box::from_raw(ptr as *mut Value); + let key = ptr.key; + key.os.set(1 as *mut u8); + drop(ptr); + key.os.set(ptr::null_mut()); + } +} + +#[cfg(test)] +mod tests { + use prelude::v1::*; + + use sync::mpsc::{channel, Sender}; + use cell::UnsafeCell; + use super::LocalKeyState; + use thread; + + struct Foo(Sender<()>); + + impl Drop for Foo { + fn drop(&mut self) { + let Foo(ref s) = *self; + s.send(()).unwrap(); + } + } + + #[test] + fn smoke_no_dtor() { + thread_local!(static FOO: UnsafeCell = UnsafeCell { value: 1 }); + + FOO.with(|f| unsafe { + assert_eq!(*f.get(), 1); + *f.get() = 2; + }); + let (tx, rx) = channel(); + let _t = thread::spawn(move|| { + FOO.with(|f| unsafe { + assert_eq!(*f.get(), 1); + }); + tx.send(()).unwrap(); + }); + rx.recv().unwrap(); + + FOO.with(|f| unsafe { + assert_eq!(*f.get(), 2); + }); + } + + #[test] + fn states() { + struct Foo; + impl Drop for Foo { + fn drop(&mut self) { + assert!(FOO.state() == LocalKeyState::Destroyed); + } + } + fn foo() -> Foo { + assert!(FOO.state() == LocalKeyState::Uninitialized); + Foo + } + thread_local!(static FOO: Foo = foo()); + + thread::spawn(|| { + assert!(FOO.state() == LocalKeyState::Uninitialized); + FOO.with(|_| { + assert!(FOO.state() == LocalKeyState::Valid); + }); + assert!(FOO.state() == LocalKeyState::Valid); + }).join().ok().unwrap(); + } + + #[test] + fn smoke_dtor() { + thread_local!(static FOO: UnsafeCell> = UnsafeCell { + value: None + }); + + let (tx, rx) = channel(); + let _t = thread::spawn(move|| unsafe { + let mut tx = Some(tx); + FOO.with(|f| { + *f.get() = Some(Foo(tx.take().unwrap())); + }); + }); + rx.recv().unwrap(); + } + + #[test] + fn circular() { + struct S1; + struct S2; + thread_local!(static K1: UnsafeCell> = UnsafeCell { + value: None + }); + thread_local!(static K2: UnsafeCell> = UnsafeCell { + value: None + }); + static mut HITS: u32 = 0; + + impl Drop for S1 { + fn drop(&mut self) { + unsafe { + HITS += 1; + if K2.state() == LocalKeyState::Destroyed { + assert_eq!(HITS, 3); + } else { + if HITS == 1 { + K2.with(|s| *s.get() = Some(S2)); + } else { + assert_eq!(HITS, 3); + } + } + } + } + } + impl Drop for S2 { + fn drop(&mut self) { + unsafe { + HITS += 1; + assert!(K1.state() != LocalKeyState::Destroyed); + assert_eq!(HITS, 2); + K1.with(|s| *s.get() = Some(S1)); + } + } + } + + thread::spawn(move|| { + drop(S1); + }).join().ok().unwrap(); + } + + #[test] + fn self_referential() { + struct S1; + thread_local!(static K1: UnsafeCell> = UnsafeCell { + value: None + }); + + impl Drop for S1 { + fn drop(&mut self) { + assert!(K1.state() == LocalKeyState::Destroyed); + } + } + + thread::spawn(move|| unsafe { + K1.with(|s| *s.get() = Some(S1)); + }).join().ok().unwrap(); + } + + #[test] + fn dtors_in_dtors_in_dtors() { + struct S1(Sender<()>); + thread_local!(static K1: UnsafeCell> = UnsafeCell { + value: None + }); + thread_local!(static K2: UnsafeCell> = UnsafeCell { + value: None + }); + + impl Drop for S1 { + fn drop(&mut self) { + let S1(ref tx) = *self; + unsafe { + if K2.state() != LocalKeyState::Destroyed { + K2.with(|s| *s.get() = Some(Foo(tx.clone()))); + } + } + } + } + + let (tx, rx) = channel(); + let _t = thread::spawn(move|| unsafe { + let mut tx = Some(tx); + K1.with(|s| *s.get() = Some(S1(tx.take().unwrap()))); + }); + rx.recv().unwrap(); + } +} + +#[cfg(test)] +mod dynamic_tests { + use prelude::v1::*; + + use cell::RefCell; + use collections::HashMap; + + #[test] + fn smoke() { + fn square(i: i32) -> i32 { i * i } + thread_local!(static FOO: i32 = square(3)); + + FOO.with(|f| { + assert_eq!(*f, 9); + }); + } + + #[test] + fn hashmap() { + fn map() -> RefCell> { + let mut m = HashMap::new(); + m.insert(1, 2); + RefCell::new(m) + } + thread_local!(static FOO: RefCell> = map()); + + FOO.with(|map| { + assert_eq!(map.borrow()[1], 2); + }); + } + + #[test] + fn refcell_vec() { + thread_local!(static FOO: RefCell> = RefCell::new(vec![1, 2, 3])); + + FOO.with(|vec| { + assert_eq!(vec.borrow().len(), 3); + vec.borrow_mut().push(4); + assert_eq!(vec.borrow()[3], 4); + }); + } +} diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs new file mode 100644 index 00000000000..57baeb1fb74 --- /dev/null +++ b/src/libstd/thread/mod.rs @@ -0,0 +1,1026 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Native threads +//! +//! ## The threading model +//! +//! An executing Rust program consists of a collection of native OS threads, +//! each with their own stack and local state. +//! +//! Communication between threads can be done through +//! [channels](../../std/sync/mpsc/index.html), Rust's message-passing +//! types, along with [other forms of thread +//! synchronization](../../std/sync/index.html) and shared-memory data +//! structures. In particular, types that are guaranteed to be +//! threadsafe are easily shared between threads using the +//! atomically-reference-counted container, +//! [`Arc`](../../std/sync/struct.Arc.html). +//! +//! Fatal logic errors in Rust cause *thread panic*, during which +//! a thread will unwind the stack, running destructors and freeing +//! owned resources. Thread panic is unrecoverable from within +//! the panicking thread (i.e. there is no 'try/catch' in Rust), but +//! the panic may optionally be detected from a different thread. If +//! the main thread panics, the application will exit with a non-zero +//! exit code. +//! +//! When the main thread of a Rust program terminates, the entire program shuts +//! down, even if other threads are still running. However, this module provides +//! convenient facilities for automatically waiting for the termination of a +//! child thread (i.e., join). +//! +//! ## The `Thread` type +//! +//! Threads are represented via the `Thread` type, which you can +//! get in one of two ways: +//! +//! * By spawning a new thread, e.g. using the `thread::spawn` function. +//! * By requesting the current thread, using the `thread::current` function. +//! +//! Threads can be named, and provide some built-in support for low-level +//! synchronization (described below). +//! +//! The `thread::current()` function is available even for threads not spawned +//! by the APIs of this module. +//! +//! ## Spawning a thread +//! +//! A new thread can be spawned using the `thread::spawn` function: +//! +//! ```rust +//! use std::thread; +//! +//! thread::spawn(move || { +//! // some work here +//! }); +//! ``` +//! +//! In this example, the spawned thread is "detached" from the current +//! thread. This means that it can outlive its parent (the thread that spawned +//! it), unless this parent is the main thread. +//! +//! ## Scoped threads +//! +//! Often a parent thread uses a child thread to perform some particular task, +//! and at some point must wait for the child to complete before continuing. +//! For this scenario, use the `thread::scoped` function: +//! +//! ```rust +//! use std::thread; +//! +//! let guard = thread::scoped(move || { +//! // some work here +//! }); +//! +//! // do some other work in the meantime +//! let output = guard.join(); +//! ``` +//! +//! The `scoped` function doesn't return a `Thread` directly; instead, +//! it returns a *join guard*. The join guard is an RAII-style guard +//! that will automatically join the child thread (block until it +//! terminates) when it is dropped. You can join the child thread in +//! advance by calling the `join` method on the guard, which will also +//! return the result produced by the thread. A handle to the thread +//! itself is available via the `thread` method of the join guard. +//! +//! ## Configuring threads +//! +//! A new thread can be configured before it is spawned via the `Builder` type, +//! which currently allows you to set the name, stack size, and writers for +//! `println!` and `panic!` for the child thread: +//! +//! ```rust +//! use std::thread; +//! +//! thread::Builder::new().name("child1".to_string()).spawn(move || { +//! println!("Hello, world!"); +//! }); +//! ``` +//! +//! ## Blocking support: park and unpark +//! +//! Every thread is equipped with some basic low-level blocking support, via the +//! `park` and `unpark` functions. +//! +//! Conceptually, each `Thread` handle has an associated token, which is +//! initially not present: +//! +//! * The `thread::park()` function blocks the current thread unless or until +//! the token is available for its thread handle, at which point it atomically +//! consumes the token. It may also return *spuriously*, without consuming the +//! token. `thread::park_timeout()` does the same, but allows specifying a +//! maximum time to block the thread for. +//! +//! * The `unpark()` method on a `Thread` atomically makes the token available +//! if it wasn't already. +//! +//! In other words, each `Thread` acts a bit like a semaphore with initial count +//! 0, except that the semaphore is *saturating* (the count cannot go above 1), +//! and can return spuriously. +//! +//! The API is typically used by acquiring a handle to the current thread, +//! placing that handle in a shared data structure so that other threads can +//! find it, and then `park`ing. When some desired condition is met, another +//! thread calls `unpark` on the handle. +//! +//! The motivation for this design is twofold: +//! +//! * It avoids the need to allocate mutexes and condvars when building new +//! synchronization primitives; the threads already provide basic blocking/signaling. +//! +//! * It can be implemented very efficiently on many platforms. +//! +//! ## Thread-local storage +//! +//! This module also provides an implementation of thread local storage for Rust +//! programs. Thread local storage is a method of storing data into a global +//! variable which each thread in the program will have its own copy of. +//! Threads do not share this data, so accesses do not need to be synchronized. +//! +//! At a high level, this module provides two variants of storage: +//! +//! * Owned thread-local storage. This is a type of thread local key which +//! owns the value that it contains, and will destroy the value when the +//! thread exits. This variant is created with the `thread_local!` macro and +//! can contain any value which is `'static` (no borrowed pointers). +//! +//! * Scoped thread-local storage. This type of key is used to store a reference +//! to a value into local storage temporarily for the scope of a function +//! call. There are no restrictions on what types of values can be placed +//! into this key. +//! +//! Both forms of thread local storage provide an accessor function, `with`, +//! which will yield a shared reference to the value to the specified +//! closure. Thread-local keys only allow shared access to values as there is no +//! way to guarantee uniqueness if a mutable borrow was allowed. Most values +//! will want to make use of some form of **interior mutability** through the +//! `Cell` or `RefCell` types. + +#![stable(feature = "rust1", since = "1.0.0")] + +#[stable(feature = "rust1", since = "1.0.0")] +pub use self::__local::{LocalKey, LocalKeyState}; + +#[unstable(feature = "scoped_tls", + reason = "scoped TLS has yet to have wide enough use to fully consider \ + stabilizing its interface")] +pub use self::__scoped::ScopedKey; + +use prelude::v1::*; + +use any::Any; +use cell::UnsafeCell; +use fmt; +use io; +use marker::PhantomData; +use rt::{self, unwind}; +use sync::{Mutex, Condvar, Arc}; +use sys::thread as imp; +use sys_common::{stack, thread_info}; +use thunk::Thunk; +use time::Duration; + +#[allow(deprecated)] use old_io::Writer; + +//////////////////////////////////////////////////////////////////////////////// +// Thread-local storage +//////////////////////////////////////////////////////////////////////////////// + +#[macro_use] +#[doc(hidden)] +#[path = "local.rs"] pub mod __local; + +#[macro_use] +#[doc(hidden)] +#[path = "scoped.rs"] pub mod __scoped; + +//////////////////////////////////////////////////////////////////////////////// +// Builder +//////////////////////////////////////////////////////////////////////////////// + +/// Thread configuration. Provides detailed control over the properties +/// and behavior of new threads. +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Builder { + // A name for the thread-to-be, for identification in panic messages + name: Option, + // The size of the stack for the spawned thread + stack_size: Option, +} + +impl Builder { + /// Generate the base configuration for spawning a thread, from which + /// configuration methods can be chained. + #[stable(feature = "rust1", since = "1.0.0")] + pub fn new() -> Builder { + Builder { + name: None, + stack_size: None, + } + } + + /// Name the thread-to-be. Currently the name is used for identification + /// only in panic messages. + #[stable(feature = "rust1", since = "1.0.0")] + pub fn name(mut self, name: String) -> Builder { + self.name = Some(name); + self + } + + /// Set the size of the stack for the new thread. + #[stable(feature = "rust1", since = "1.0.0")] + pub fn stack_size(mut self, size: usize) -> Builder { + self.stack_size = Some(size); + self + } + + /// Redirect thread-local stdout. + #[unstable(feature = "std_misc", + reason = "Will likely go away after proc removal")] + #[deprecated(since = "1.0.0", + reason = "the old I/O module is deprecated and this function \ + will be removed with no replacement")] + #[allow(deprecated)] + pub fn stdout(self, _stdout: Box) -> Builder { + self + } + + /// Redirect thread-local stderr. + #[unstable(feature = "std_misc", + reason = "Will likely go away after proc removal")] + #[deprecated(since = "1.0.0", + reason = "the old I/O module is deprecated and this function \ + will be removed with no replacement")] + #[allow(deprecated)] + pub fn stderr(self, _stderr: Box) -> Builder { + self + } + + /// Spawn a new thread, and return a join handle for it. + /// + /// The child thread may outlive the parent (unless the parent thread + /// is the main thread; the whole process is terminated when the main + /// thread finishes.) The join handle can be used to block on + /// termination of the child thread, including recovering its panics. + /// + /// # Errors + /// + /// Unlike the `spawn` free function, this method yields an + /// `io::Result` to capture any failure to create the thread at + /// the OS level. + #[stable(feature = "rust1", since = "1.0.0")] + pub fn spawn(self, f: F) -> io::Result where + F: FnOnce(), F: Send + 'static + { + self.spawn_inner(Thunk::new(f)).map(|i| JoinHandle(i)) + } + + /// Spawn a new child thread that must be joined within a given + /// scope, and return a `JoinGuard`. + /// + /// The join guard can be used to explicitly join the child thread (via + /// `join`), returning `Result`, or it will implicitly join the child + /// upon being dropped. Because the child thread may refer to data on the + /// current thread's stack (hence the "scoped" name), it cannot be detached; + /// it *must* be joined before the relevant stack frame is popped. See the + /// module documentation for additional details. + /// + /// # Errors + /// + /// Unlike the `scoped` free function, this method yields an + /// `io::Result` to capture any failure to create the thread at + /// the OS level. + #[stable(feature = "rust1", since = "1.0.0")] + pub fn scoped<'a, T, F>(self, f: F) -> io::Result> where + T: Send + 'a, F: FnOnce() -> T, F: Send + 'a + { + self.spawn_inner(Thunk::new(f)).map(|inner| { + JoinGuard { inner: inner, _marker: PhantomData } + }) + } + + fn spawn_inner(self, f: Thunk<(), T>) -> io::Result> { + let Builder { name, stack_size } = self; + + let stack_size = stack_size.unwrap_or(rt::min_stack()); + + let my_thread = Thread::new(name); + let their_thread = my_thread.clone(); + + let my_packet = Packet(Arc::new(UnsafeCell::new(None))); + let their_packet = Packet(my_packet.0.clone()); + + // Spawning a new OS thread guarantees that __morestack will never get + // triggered, but we must manually set up the actual stack bounds once + // this function starts executing. This raises the lower limit by a bit + // because by the time that this function is executing we've already + // consumed at least a little bit of stack (we don't know the exact byte + // address at which our stack started). + let main = move || { + let something_around_the_top_of_the_stack = 1; + let addr = &something_around_the_top_of_the_stack as *const i32; + let my_stack_top = addr as usize; + let my_stack_bottom = my_stack_top - stack_size + 1024; + unsafe { + if let Some(name) = their_thread.name() { + imp::set_name(name); + } + stack::record_os_managed_stack_bounds(my_stack_bottom, + my_stack_top); + thread_info::set(imp::guard::current(), their_thread); + } + + let mut output = None; + let try_result = { + let ptr = &mut output; + + // There are two primary reasons that general try/catch is + // unsafe. The first is that we do not support nested + // try/catch. The fact that this is happening in a newly-spawned + // thread suffices. The second is that unwinding while unwinding + // is not defined. We take care of that by having an + // 'unwinding' flag in the thread itself. For these reasons, + // this unsafety should be ok. + unsafe { + unwind::try(move || *ptr = Some(f.invoke(()))) + } + }; + unsafe { + *their_packet.0.get() = Some(match (output, try_result) { + (Some(data), Ok(_)) => Ok(data), + (None, Err(cause)) => Err(cause), + _ => unreachable!() + }); + } + }; + + Ok(JoinInner { + native: try!(unsafe { imp::create(stack_size, Thunk::new(main)) }), + thread: my_thread, + packet: my_packet, + joined: false, + }) + } +} + +//////////////////////////////////////////////////////////////////////////////// +// Free functions +//////////////////////////////////////////////////////////////////////////////// + +/// Spawn a new thread, returning a `JoinHandle` for it. +/// +/// The join handle will implicitly *detach* the child thread upon being +/// dropped. In this case, the child thread may outlive the parent (unless +/// the parent thread is the main thread; the whole process is terminated when +/// the main thread finishes.) Additionally, the join handle provides a `join` +/// method that can be used to join the child thread. If the child thread +/// panics, `join` will return an `Err` containing the argument given to +/// `panic`. +/// +/// # Panics +/// +/// Panicks if the OS fails to create a thread; use `Builder::spawn` +/// to recover from such errors. +#[stable(feature = "rust1", since = "1.0.0")] +pub fn spawn(f: F) -> JoinHandle where F: FnOnce(), F: Send + 'static { + Builder::new().spawn(f).unwrap() +} + +/// Spawn a new *scoped* thread, returning a `JoinGuard` for it. +/// +/// The join guard can be used to explicitly join the child thread (via +/// `join`), returning `Result`, or it will implicitly join the child +/// upon being dropped. Because the child thread may refer to data on the +/// current thread's stack (hence the "scoped" name), it cannot be detached; +/// it *must* be joined before the relevant stack frame is popped. See the +/// module documentation for additional details. +/// +/// # Panics +/// +/// Panicks if the OS fails to create a thread; use `Builder::scoped` +/// to recover from such errors. +#[stable(feature = "rust1", since = "1.0.0")] +pub fn scoped<'a, T, F>(f: F) -> JoinGuard<'a, T> where + T: Send + 'a, F: FnOnce() -> T, F: Send + 'a +{ + Builder::new().scoped(f).unwrap() +} + +/// Gets a handle to the thread that invokes it. +#[stable(feature = "rust1", since = "1.0.0")] +pub fn current() -> Thread { + thread_info::current_thread() +} + +/// Cooperatively give up a timeslice to the OS scheduler. +#[stable(feature = "rust1", since = "1.0.0")] +pub fn yield_now() { + unsafe { imp::yield_now() } +} + +/// Determines whether the current thread is unwinding because of panic. +#[inline] +#[stable(feature = "rust1", since = "1.0.0")] +pub fn panicking() -> bool { + unwind::panicking() +} + +/// Put the current thread to sleep for the specified amount of time. +/// +/// The thread may sleep longer than the duration specified due to scheduling +/// specifics or platform-dependent functionality. Note that on unix platforms +/// this function will not return early due to a signal being received or a +/// spurious wakeup. +#[unstable(feature = "thread_sleep", + reason = "recently added, needs an RFC, and `Duration` itself is \ + unstable")] +pub fn sleep(dur: Duration) { + imp::sleep(dur) +} + +/// Block unless or until the current thread's token is made available (may wake spuriously). +/// +/// See the module doc for more detail. +// +// The implementation currently uses the trivial strategy of a Mutex+Condvar +// with wakeup flag, which does not actually allow spurious wakeups. In the +// future, this will be implemented in a more efficient way, perhaps along the lines of +// http://cr.openjdk.java.net/~stefank/6989984.1/raw_files/new/src/os/linux/vm/os_linux.cpp +// or futuxes, and in either case may allow spurious wakeups. +#[stable(feature = "rust1", since = "1.0.0")] +pub fn park() { + let thread = current(); + let mut guard = thread.inner.lock.lock().unwrap(); + while !*guard { + guard = thread.inner.cvar.wait(guard).unwrap(); + } + *guard = false; +} + +/// Block unless or until the current thread's token is made available or +/// the specified duration has been reached (may wake spuriously). +/// +/// The semantics of this function are equivalent to `park()` except that the +/// thread will be blocked for roughly no longer than *duration*. This method +/// should not be used for precise timing due to anomalies such as +/// preemption or platform differences that may not cause the maximum +/// amount of time waited to be precisely *duration* long. +/// +/// See the module doc for more detail. +#[unstable(feature = "std_misc", reason = "recently introduced, depends on Duration")] +pub fn park_timeout(duration: Duration) { + let thread = current(); + let mut guard = thread.inner.lock.lock().unwrap(); + if !*guard { + let (g, _) = thread.inner.cvar.wait_timeout(guard, duration).unwrap(); + guard = g; + } + *guard = false; +} + +//////////////////////////////////////////////////////////////////////////////// +// Thread +//////////////////////////////////////////////////////////////////////////////// + +/// The internal representation of a `Thread` handle +struct Inner { + name: Option, + lock: Mutex, // true when there is a buffered unpark + cvar: Condvar, +} + +unsafe impl Sync for Inner {} + +#[derive(Clone)] +#[stable(feature = "rust1", since = "1.0.0")] +/// A handle to a thread. +pub struct Thread { + inner: Arc, +} + +impl Thread { + // Used only internally to construct a thread object without spawning + fn new(name: Option) -> Thread { + Thread { + inner: Arc::new(Inner { + name: name, + lock: Mutex::new(false), + cvar: Condvar::new(), + }) + } + } + + /// Deprecated: use module-level free function. + #[deprecated(since = "1.0.0", reason = "use module-level free function")] + #[unstable(feature = "std_misc", + reason = "may change with specifics of new Send semantics")] + pub fn spawn(f: F) -> Thread where F: FnOnce(), F: Send + 'static { + Builder::new().spawn(f).unwrap().thread().clone() + } + + /// Deprecated: use module-level free function. + #[deprecated(since = "1.0.0", reason = "use module-level free function")] + #[unstable(feature = "std_misc", + reason = "may change with specifics of new Send semantics")] + pub fn scoped<'a, T, F>(f: F) -> JoinGuard<'a, T> where + T: Send + 'a, F: FnOnce() -> T, F: Send + 'a + { + Builder::new().scoped(f).unwrap() + } + + /// Deprecated: use module-level free function. + #[deprecated(since = "1.0.0", reason = "use module-level free function")] + #[stable(feature = "rust1", since = "1.0.0")] + pub fn current() -> Thread { + thread_info::current_thread() + } + + /// Deprecated: use module-level free function. + #[deprecated(since = "1.0.0", reason = "use module-level free function")] + #[unstable(feature = "std_misc", reason = "name may change")] + pub fn yield_now() { + unsafe { imp::yield_now() } + } + + /// Deprecated: use module-level free function. + #[deprecated(since = "1.0.0", reason = "use module-level free function")] + #[inline] + #[stable(feature = "rust1", since = "1.0.0")] + pub fn panicking() -> bool { + unwind::panicking() + } + + /// Deprecated: use module-level free function. + #[deprecated(since = "1.0.0", reason = "use module-level free function")] + #[unstable(feature = "std_misc", reason = "recently introduced")] + pub fn park() { + let thread = current(); + let mut guard = thread.inner.lock.lock().unwrap(); + while !*guard { + guard = thread.inner.cvar.wait(guard).unwrap(); + } + *guard = false; + } + + /// Deprecated: use module-level free function. + #[deprecated(since = "1.0.0", reason = "use module-level free function")] + #[unstable(feature = "std_misc", reason = "recently introduced")] + pub fn park_timeout(duration: Duration) { + let thread = current(); + let mut guard = thread.inner.lock.lock().unwrap(); + if !*guard { + let (g, _) = thread.inner.cvar.wait_timeout(guard, duration).unwrap(); + guard = g; + } + *guard = false; + } + + /// Atomically makes the handle's token available if it is not already. + /// + /// See the module doc for more detail. + #[stable(feature = "rust1", since = "1.0.0")] + pub fn unpark(&self) { + let mut guard = self.inner.lock.lock().unwrap(); + if !*guard { + *guard = true; + self.inner.cvar.notify_one(); + } + } + + /// Get the thread's name. + #[stable(feature = "rust1", since = "1.0.0")] + pub fn name(&self) -> Option<&str> { + self.inner.name.as_ref().map(|s| &**s) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Debug for Thread { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(&self.name(), f) + } +} + +// a hack to get around privacy restrictions +impl thread_info::NewThread for Thread { + fn new(name: Option) -> Thread { Thread::new(name) } +} + +//////////////////////////////////////////////////////////////////////////////// +// JoinHandle and JoinGuard +//////////////////////////////////////////////////////////////////////////////// + +/// Indicates the manner in which a thread exited. +/// +/// A thread that completes without panicking is considered to exit successfully. +#[stable(feature = "rust1", since = "1.0.0")] +pub type Result = ::result::Result>; + +struct Packet(Arc>>>); + +unsafe impl Send for Packet {} +unsafe impl Sync for Packet {} + +/// Inner representation for JoinHandle and JoinGuard +struct JoinInner { + native: imp::rust_thread, + thread: Thread, + packet: Packet, + joined: bool, +} + +impl JoinInner { + fn join(&mut self) -> Result { + assert!(!self.joined); + unsafe { imp::join(self.native) }; + self.joined = true; + unsafe { + (*self.packet.0.get()).take().unwrap() + } + } +} + +/// An owned permission to join on a thread (block on its termination). +/// +/// Unlike a `JoinGuard`, a `JoinHandle` *detaches* the child thread +/// when it is dropped, rather than automatically joining on drop. +/// +/// Due to platform restrictions, it is not possible to `Clone` this +/// handle: the ability to join a child thread is a uniquely-owned +/// permission. +#[stable(feature = "rust1", since = "1.0.0")] +pub struct JoinHandle(JoinInner<()>); + +impl JoinHandle { + /// Extract a handle to the underlying thread + #[stable(feature = "rust1", since = "1.0.0")] + pub fn thread(&self) -> &Thread { + &self.0.thread + } + + /// Wait for the associated thread to finish. + /// + /// If the child thread panics, `Err` is returned with the parameter given + /// to `panic`. + #[stable(feature = "rust1", since = "1.0.0")] + pub fn join(mut self) -> Result<()> { + self.0.join() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Drop for JoinHandle { + fn drop(&mut self) { + if !self.0.joined { + unsafe { imp::detach(self.0.native) } + } + } +} + +/// An RAII-style guard that will block until thread termination when dropped. +/// +/// The type `T` is the return type for the thread's main function. +/// +/// Joining on drop is necessary to ensure memory safety when stack +/// data is shared between a parent and child thread. +/// +/// Due to platform restrictions, it is not possible to `Clone` this +/// handle: the ability to join a child thread is a uniquely-owned +/// permission. +#[must_use = "thread will be immediately joined if `JoinGuard` is not used"] +#[stable(feature = "rust1", since = "1.0.0")] +pub struct JoinGuard<'a, T: 'a> { + inner: JoinInner, + _marker: PhantomData<&'a T>, +} + +#[stable(feature = "rust1", since = "1.0.0")] +unsafe impl<'a, T: Send + 'a> Sync for JoinGuard<'a, T> {} + +impl<'a, T: Send + 'a> JoinGuard<'a, T> { + /// Extract a handle to the thread this guard will join on. + #[stable(feature = "rust1", since = "1.0.0")] + pub fn thread(&self) -> &Thread { + &self.inner.thread + } + + /// Wait for the associated thread to finish, returning the result of the thread's + /// calculation. + /// + /// # Panics + /// + /// Panics on the child thread are propagated by panicking the parent. + #[stable(feature = "rust1", since = "1.0.0")] + pub fn join(mut self) -> T { + match self.inner.join() { + Ok(res) => res, + Err(_) => panic!("child thread {:?} panicked", self.thread()), + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl JoinGuard<'static, T> { + /// Detaches the child thread, allowing it to outlive its parent. + #[deprecated(since = "1.0.0", reason = "use spawn instead")] + #[unstable(feature = "std_misc")] + pub fn detach(mut self) { + unsafe { imp::detach(self.inner.native) }; + self.inner.joined = true; // avoid joining in the destructor + } +} + +#[unsafe_destructor] +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T: Send + 'a> Drop for JoinGuard<'a, T> { + fn drop(&mut self) { + if !self.inner.joined { + if self.inner.join().is_err() { + panic!("child thread {:?} panicked", self.thread()); + } + } + } +} + +//////////////////////////////////////////////////////////////////////////////// +// Tests +//////////////////////////////////////////////////////////////////////////////// + +#[cfg(test)] +mod test { + use prelude::v1::*; + + use any::Any; + use sync::mpsc::{channel, Sender}; + use boxed::BoxAny; + use result; + use std::old_io::{ChanReader, ChanWriter}; + use super::{Builder}; + use thread; + use thunk::Thunk; + use time::Duration; + + // !!! These tests are dangerous. If something is buggy, they will hang, !!! + // !!! instead of exiting cleanly. This might wedge the buildbots. !!! + + #[test] + fn test_unnamed_thread() { + thread::spawn(move|| { + assert!(thread::current().name().is_none()); + }).join().ok().unwrap(); + } + + #[test] + fn test_named_thread() { + Builder::new().name("ada lovelace".to_string()).scoped(move|| { + assert!(thread::current().name().unwrap() == "ada lovelace".to_string()); + }).unwrap().join(); + } + + #[test] + fn test_run_basic() { + let (tx, rx) = channel(); + thread::spawn(move|| { + tx.send(()).unwrap(); + }); + rx.recv().unwrap(); + } + + #[test] + fn test_join_success() { + assert!(thread::scoped(move|| -> String { + "Success!".to_string() + }).join() == "Success!"); + } + + #[test] + fn test_join_panic() { + match thread::spawn(move|| { + panic!() + }).join() { + result::Result::Err(_) => (), + result::Result::Ok(()) => panic!() + } + } + + #[test] + fn test_scoped_success() { + let res = thread::scoped(move|| -> String { + "Success!".to_string() + }).join(); + assert!(res == "Success!"); + } + + #[test] + #[should_fail] + fn test_scoped_panic() { + thread::scoped(|| panic!()).join(); + } + + #[test] + #[should_fail] + fn test_scoped_implicit_panic() { + let _ = thread::scoped(|| panic!()); + } + + #[test] + fn test_spawn_sched() { + use clone::Clone; + + let (tx, rx) = channel(); + + fn f(i: i32, tx: Sender<()>) { + let tx = tx.clone(); + thread::spawn(move|| { + if i == 0 { + tx.send(()).unwrap(); + } else { + f(i - 1, tx); + } + }); + + } + f(10, tx); + rx.recv().unwrap(); + } + + #[test] + fn test_spawn_sched_childs_on_default_sched() { + let (tx, rx) = channel(); + + thread::spawn(move|| { + thread::spawn(move|| { + tx.send(()).unwrap(); + }); + }); + + rx.recv().unwrap(); + } + + fn avoid_copying_the_body(spawnfn: F) where F: FnOnce(Thunk<'static>) { + let (tx, rx) = channel(); + + let x: Box<_> = box 1; + let x_in_parent = (&*x) as *const i32 as usize; + + spawnfn(Thunk::new(move|| { + let x_in_child = (&*x) as *const i32 as usize; + tx.send(x_in_child).unwrap(); + })); + + let x_in_child = rx.recv().unwrap(); + assert_eq!(x_in_parent, x_in_child); + } + + #[test] + fn test_avoid_copying_the_body_spawn() { + avoid_copying_the_body(|v| { + thread::spawn(move || v.invoke(())); + }); + } + + #[test] + fn test_avoid_copying_the_body_thread_spawn() { + avoid_copying_the_body(|f| { + thread::spawn(move|| { + f.invoke(()); + }); + }) + } + + #[test] + fn test_avoid_copying_the_body_join() { + avoid_copying_the_body(|f| { + let _ = thread::spawn(move|| { + f.invoke(()) + }).join(); + }) + } + + #[test] + fn test_child_doesnt_ref_parent() { + // If the child refcounts the parent task, this will stack overflow when + // climbing the task tree to dereference each ancestor. (See #1789) + // (well, it would if the constant were 8000+ - I lowered it to be more + // valgrind-friendly. try this at home, instead..!) + const GENERATIONS: u32 = 16; + fn child_no(x: u32) -> Thunk<'static> { + return Thunk::new(move|| { + if x < GENERATIONS { + thread::spawn(move|| child_no(x+1).invoke(())); + } + }); + } + thread::spawn(|| child_no(0).invoke(())); + } + + #[test] + fn test_simple_newsched_spawn() { + thread::spawn(move || {}); + } + + #[test] + fn test_try_panic_message_static_str() { + match thread::spawn(move|| { + panic!("static string"); + }).join() { + Err(e) => { + type T = &'static str; + assert!(e.is::()); + assert_eq!(*e.downcast::().unwrap(), "static string"); + } + Ok(()) => panic!() + } + } + + #[test] + fn test_try_panic_message_owned_str() { + match thread::spawn(move|| { + panic!("owned string".to_string()); + }).join() { + Err(e) => { + type T = String; + assert!(e.is::()); + assert_eq!(*e.downcast::().unwrap(), "owned string".to_string()); + } + Ok(()) => panic!() + } + } + + #[test] + fn test_try_panic_message_any() { + match thread::spawn(move|| { + panic!(box 413u16 as Box); + }).join() { + Err(e) => { + type T = Box; + assert!(e.is::()); + let any = e.downcast::().unwrap(); + assert!(any.is::()); + assert_eq!(*any.downcast::().unwrap(), 413); + } + Ok(()) => panic!() + } + } + + #[test] + fn test_try_panic_message_unit_struct() { + struct Juju; + + match thread::spawn(move|| { + panic!(Juju) + }).join() { + Err(ref e) if e.is::() => {} + Err(_) | Ok(()) => panic!() + } + } + + #[test] + fn test_park_timeout_unpark_before() { + for _ in 0..10 { + thread::current().unpark(); + thread::park_timeout(Duration::seconds(10_000_000)); + } + } + + #[test] + fn test_park_timeout_unpark_not_called() { + for _ in 0..10 { + thread::park_timeout(Duration::milliseconds(10)); + } + } + + #[test] + fn test_park_timeout_unpark_called_other_thread() { + use std::old_io; + + for _ in 0..10 { + let th = thread::current(); + + let _guard = thread::spawn(move || { + old_io::timer::sleep(Duration::milliseconds(50)); + th.unpark(); + }); + + thread::park_timeout(Duration::seconds(10_000_000)); + } + } + + #[test] + fn sleep_smoke() { + thread::sleep(Duration::milliseconds(2)); + thread::sleep(Duration::milliseconds(-2)); + } + + // NOTE: the corresponding test for stderr is in run-pass/task-stderr, due + // to the test harness apparently interfering with stderr configuration. +} diff --git a/src/libstd/thread/scoped.rs b/src/libstd/thread/scoped.rs new file mode 100644 index 00000000000..2a8be2ad82c --- /dev/null +++ b/src/libstd/thread/scoped.rs @@ -0,0 +1,317 @@ +// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Scoped thread-local storage +//! +//! This module provides the ability to generate *scoped* thread-local +//! variables. In this sense, scoped indicates that thread local storage +//! actually stores a reference to a value, and this reference is only placed +//! in storage for a scoped amount of time. +//! +//! There are no restrictions on what types can be placed into a scoped +//! variable, but all scoped variables are initialized to the equivalent of +//! null. Scoped thread local storage is useful when a value is present for a known +//! period of time and it is not required to relinquish ownership of the +//! contents. +//! +//! # Examples +//! +//! ``` +//! scoped_thread_local!(static FOO: u32); +//! +//! // Initially each scoped slot is empty. +//! assert!(!FOO.is_set()); +//! +//! // When inserting a value, the value is only in place for the duration +//! // of the closure specified. +//! FOO.set(&1, || { +//! FOO.with(|slot| { +//! assert_eq!(*slot, 1); +//! }); +//! }); +//! ``` + +#![unstable(feature = "thread_local_internals")] + +use prelude::v1::*; + +// macro hygiene sure would be nice, wouldn't it? +#[doc(hidden)] +pub mod __impl { + pub use super::imp::KeyInner; + pub use sys_common::thread_local::INIT as OS_INIT; +} + +/// Type representing a thread local storage key corresponding to a reference +/// to the type parameter `T`. +/// +/// Keys are statically allocated and can contain a reference to an instance of +/// type `T` scoped to a particular lifetime. Keys provides two methods, `set` +/// and `with`, both of which currently use closures to control the scope of +/// their contents. +#[unstable(feature = "scoped_tls", + reason = "scoped TLS has yet to have wide enough use to fully consider \ + stabilizing its interface")] +pub struct ScopedKey { #[doc(hidden)] pub inner: __impl::KeyInner } + +/// Declare a new scoped thread local storage key. +/// +/// This macro declares a `static` item on which methods are used to get and +/// set the value stored within. +#[macro_export] +#[allow_internal_unstable] +macro_rules! scoped_thread_local { + (static $name:ident: $t:ty) => ( + __scoped_thread_local_inner!(static $name: $t); + ); + (pub static $name:ident: $t:ty) => ( + __scoped_thread_local_inner!(pub static $name: $t); + ); +} + +#[macro_export] +#[doc(hidden)] +#[allow_internal_unstable] +macro_rules! __scoped_thread_local_inner { + (static $name:ident: $t:ty) => ( + #[cfg_attr(not(any(windows, + target_os = "android", + target_os = "ios", + target_os = "openbsd", + target_arch = "aarch64")), + thread_local)] + static $name: ::std::thread::ScopedKey<$t> = + __scoped_thread_local_inner!($t); + ); + (pub static $name:ident: $t:ty) => ( + #[cfg_attr(not(any(windows, + target_os = "android", + target_os = "ios", + target_os = "openbsd", + target_arch = "aarch64")), + thread_local)] + pub static $name: ::std::thread::ScopedKey<$t> = + __scoped_thread_local_inner!($t); + ); + ($t:ty) => ({ + use std::thread::ScopedKey as __Key; + + #[cfg(not(any(windows, + target_os = "android", + target_os = "ios", + target_os = "openbsd", + target_arch = "aarch64")))] + const _INIT: __Key<$t> = __Key { + inner: ::std::thread::__scoped::__impl::KeyInner { + inner: ::std::cell::UnsafeCell { value: 0 as *mut _ }, + } + }; + + #[cfg(any(windows, + target_os = "android", + target_os = "ios", + target_os = "openbsd", + target_arch = "aarch64"))] + const _INIT: __Key<$t> = __Key { + inner: ::std::thread::__scoped::__impl::KeyInner { + inner: ::std::thread::__scoped::__impl::OS_INIT, + marker: ::std::marker::PhantomData::<::std::cell::Cell<$t>>, + } + }; + + _INIT + }) +} + +#[unstable(feature = "scoped_tls", + reason = "scoped TLS has yet to have wide enough use to fully consider \ + stabilizing its interface")] +impl ScopedKey { + /// Insert a value into this scoped thread local storage slot for a + /// duration of a closure. + /// + /// While `cb` is running, the value `t` will be returned by `get` unless + /// this function is called recursively inside of `cb`. + /// + /// Upon return, this function will restore the previous value, if any + /// was available. + /// + /// # Examples + /// + /// ``` + /// scoped_thread_local!(static FOO: u32); + /// + /// FOO.set(&100, || { + /// let val = FOO.with(|v| *v); + /// assert_eq!(val, 100); + /// + /// // set can be called recursively + /// FOO.set(&101, || { + /// // ... + /// }); + /// + /// // Recursive calls restore the previous value. + /// let val = FOO.with(|v| *v); + /// assert_eq!(val, 100); + /// }); + /// ``` + pub fn set(&'static self, t: &T, cb: F) -> R where + F: FnOnce() -> R, + { + struct Reset<'a, T: 'a> { + key: &'a __impl::KeyInner, + val: *mut T, + } + #[unsafe_destructor] + impl<'a, T> Drop for Reset<'a, T> { + fn drop(&mut self) { + unsafe { self.key.set(self.val) } + } + } + + let prev = unsafe { + let prev = self.inner.get(); + self.inner.set(t as *const T as *mut T); + prev + }; + + let _reset = Reset { key: &self.inner, val: prev }; + cb() + } + + /// Get a value out of this scoped variable. + /// + /// This function takes a closure which receives the value of this + /// variable. + /// + /// # Panics + /// + /// This function will panic if `set` has not previously been called. + /// + /// # Examples + /// + /// ```no_run + /// scoped_thread_local!(static FOO: u32); + /// + /// FOO.with(|slot| { + /// // work with `slot` + /// }); + /// ``` + pub fn with(&'static self, cb: F) -> R where + F: FnOnce(&T) -> R + { + unsafe { + let ptr = self.inner.get(); + assert!(!ptr.is_null(), "cannot access a scoped thread local \ + variable without calling `set` first"); + cb(&*ptr) + } + } + + /// Test whether this TLS key has been `set` for the current thread. + pub fn is_set(&'static self) -> bool { + unsafe { !self.inner.get().is_null() } + } +} + +#[cfg(not(any(windows, + target_os = "android", + target_os = "ios", + target_os = "openbsd", + target_arch = "aarch64")))] +mod imp { + use std::cell::UnsafeCell; + + #[doc(hidden)] + pub struct KeyInner { pub inner: UnsafeCell<*mut T> } + + unsafe impl ::marker::Sync for KeyInner { } + + #[doc(hidden)] + impl KeyInner { + #[doc(hidden)] + pub unsafe fn set(&self, ptr: *mut T) { *self.inner.get() = ptr; } + #[doc(hidden)] + pub unsafe fn get(&self) -> *mut T { *self.inner.get() } + } +} + +#[cfg(any(windows, + target_os = "android", + target_os = "ios", + target_os = "openbsd", + target_arch = "aarch64"))] +mod imp { + use marker; + use std::cell::Cell; + use sys_common::thread_local::StaticKey as OsStaticKey; + + #[doc(hidden)] + pub struct KeyInner { + pub inner: OsStaticKey, + pub marker: marker::PhantomData>, + } + + unsafe impl ::marker::Sync for KeyInner { } + + #[doc(hidden)] + impl KeyInner { + #[doc(hidden)] + pub unsafe fn set(&self, ptr: *mut T) { self.inner.set(ptr as *mut _) } + #[doc(hidden)] + pub unsafe fn get(&self) -> *mut T { self.inner.get() as *mut _ } + } +} + + +#[cfg(test)] +mod tests { + use cell::Cell; + use prelude::v1::*; + + scoped_thread_local!(static FOO: u32); + + #[test] + fn smoke() { + scoped_thread_local!(static BAR: u32); + + assert!(!BAR.is_set()); + BAR.set(&1, || { + assert!(BAR.is_set()); + BAR.with(|slot| { + assert_eq!(*slot, 1); + }); + }); + assert!(!BAR.is_set()); + } + + #[test] + fn cell_allowed() { + scoped_thread_local!(static BAR: Cell); + + BAR.set(&Cell::new(1), || { + BAR.with(|slot| { + assert_eq!(slot.get(), 1); + }); + }); + } + + #[test] + fn scope_item_allowed() { + assert!(!FOO.is_set()); + FOO.set(&1, || { + assert!(FOO.is_set()); + FOO.with(|slot| { + assert_eq!(*slot, 1); + }); + }); + assert!(!FOO.is_set()); + } +} diff --git a/src/libstd/thread_local/mod.rs b/src/libstd/thread_local/mod.rs deleted file mode 100644 index 08780292c88..00000000000 --- a/src/libstd/thread_local/mod.rs +++ /dev/null @@ -1,762 +0,0 @@ -// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Thread local storage -//! -//! This module provides an implementation of thread local storage for Rust -//! programs. Thread local storage is a method of storing data into a global -//! variable which each thread in the program will have its own copy of. -//! Threads do not share this data, so accesses do not need to be synchronized. -//! -//! At a high level, this module provides two variants of storage: -//! -//! * Owning thread local storage. This is a type of thread local key which -//! owns the value that it contains, and will destroy the value when the -//! thread exits. This variant is created with the `thread_local!` macro and -//! can contain any value which is `'static` (no borrowed pointers. -//! -//! * Scoped thread local storage. This type of key is used to store a reference -//! to a value into local storage temporarily for the scope of a function -//! call. There are no restrictions on what types of values can be placed -//! into this key. -//! -//! Both forms of thread local storage provide an accessor function, `with`, -//! which will yield a shared reference to the value to the specified -//! closure. Thread local keys only allow shared access to values as there is no -//! way to guarantee uniqueness if a mutable borrow was allowed. Most values -//! will want to make use of some form of **interior mutability** through the -//! `Cell` or `RefCell` types. - -#![stable(feature = "rust1", since = "1.0.0")] - -use prelude::v1::*; - -use cell::UnsafeCell; - -#[macro_use] -pub mod scoped; - -// Sure wish we had macro hygiene, no? -#[doc(hidden)] -#[unstable(feature = "thread_local_internals")] -pub mod __impl { - pub use super::imp::Key as KeyInner; - pub use super::imp::destroy_value; - pub use sys_common::thread_local::INIT_INNER as OS_INIT_INNER; - pub use sys_common::thread_local::StaticKey as OsStaticKey; -} - -/// A thread local storage key which owns its contents. -/// -/// This key uses the fastest possible implementation available to it for the -/// target platform. It is instantiated with the `thread_local!` macro and the -/// primary method is the `with` method. -/// -/// The `with` method yields a reference to the contained value which cannot be -/// sent across tasks or escape the given closure. -/// -/// # Initialization and Destruction -/// -/// Initialization is dynamically performed on the first call to `with()` -/// within a thread, and values support destructors which will be run when a -/// thread exits. -/// -/// # Examples -/// -/// ``` -/// use std::cell::RefCell; -/// use std::thread; -/// -/// thread_local!(static FOO: RefCell = RefCell::new(1)); -/// -/// FOO.with(|f| { -/// assert_eq!(*f.borrow(), 1); -/// *f.borrow_mut() = 2; -/// }); -/// -/// // each thread starts out with the initial value of 1 -/// thread::spawn(move|| { -/// FOO.with(|f| { -/// assert_eq!(*f.borrow(), 1); -/// *f.borrow_mut() = 3; -/// }); -/// }); -/// -/// // we retain our original value of 2 despite the child thread -/// FOO.with(|f| { -/// assert_eq!(*f.borrow(), 2); -/// }); -/// ``` -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Key { - // The key itself may be tagged with #[thread_local], and this `Key` is - // stored as a `static`, and it's not valid for a static to reference the - // address of another thread_local static. For this reason we kinda wonkily - // work around this by generating a shim function which will give us the - // address of the inner TLS key at runtime. - // - // This is trivially devirtualizable by LLVM because we never store anything - // to this field and rustc can declare the `static` as constant as well. - #[doc(hidden)] - #[unstable(feature = "thread_local_internals")] - pub inner: fn() -> &'static __impl::KeyInner>>, - - // initialization routine to invoke to create a value - #[doc(hidden)] - #[unstable(feature = "thread_local_internals")] - pub init: fn() -> T, -} - -/// Declare a new thread local storage key of type `std::thread_local::Key`. -#[macro_export] -#[stable(feature = "rust1", since = "1.0.0")] -#[allow_internal_unstable] -macro_rules! thread_local { - (static $name:ident: $t:ty = $init:expr) => ( - static $name: ::std::thread_local::Key<$t> = { - use std::cell::UnsafeCell as __UnsafeCell; - use std::thread_local::__impl::KeyInner as __KeyInner; - use std::option::Option as __Option; - use std::option::Option::None as __None; - - __thread_local_inner!(static __KEY: __UnsafeCell<__Option<$t>> = { - __UnsafeCell { value: __None } - }); - fn __init() -> $t { $init } - fn __getit() -> &'static __KeyInner<__UnsafeCell<__Option<$t>>> { - &__KEY - } - ::std::thread_local::Key { inner: __getit, init: __init } - }; - ); - (pub static $name:ident: $t:ty = $init:expr) => ( - pub static $name: ::std::thread_local::Key<$t> = { - use std::cell::UnsafeCell as __UnsafeCell; - use std::thread_local::__impl::KeyInner as __KeyInner; - use std::option::Option as __Option; - use std::option::Option::None as __None; - - __thread_local_inner!(static __KEY: __UnsafeCell<__Option<$t>> = { - __UnsafeCell { value: __None } - }); - fn __init() -> $t { $init } - fn __getit() -> &'static __KeyInner<__UnsafeCell<__Option<$t>>> { - &__KEY - } - ::std::thread_local::Key { inner: __getit, init: __init } - }; - ); -} - -// Macro pain #4586: -// -// When cross compiling, rustc will load plugins and macros from the *host* -// platform before search for macros from the target platform. This is primarily -// done to detect, for example, plugins. Ideally the macro below would be -// defined once per module below, but unfortunately this means we have the -// following situation: -// -// 1. We compile libstd for x86_64-unknown-linux-gnu, this thread_local!() macro -// will inject #[thread_local] statics. -// 2. We then try to compile a program for arm-linux-androideabi -// 3. The compiler has a host of linux and a target of android, so it loads -// macros from the *linux* libstd. -// 4. The macro generates a #[thread_local] field, but the android libstd does -// not use #[thread_local] -// 5. Compile error about structs with wrong fields. -// -// To get around this, we're forced to inject the #[cfg] logic into the macro -// itself. Woohoo. - -#[macro_export] -#[doc(hidden)] -#[allow_internal_unstable] -macro_rules! __thread_local_inner { - (static $name:ident: $t:ty = $init:expr) => ( - #[cfg_attr(all(any(target_os = "macos", target_os = "linux"), - not(target_arch = "aarch64")), - thread_local)] - static $name: ::std::thread_local::__impl::KeyInner<$t> = - __thread_local_inner!($init, $t); - ); - (pub static $name:ident: $t:ty = $init:expr) => ( - #[cfg_attr(all(any(target_os = "macos", target_os = "linux"), - not(target_arch = "aarch64")), - thread_local)] - pub static $name: ::std::thread_local::__impl::KeyInner<$t> = - __thread_local_inner!($init, $t); - ); - ($init:expr, $t:ty) => ({ - #[cfg(all(any(target_os = "macos", target_os = "linux"), not(target_arch = "aarch64")))] - const _INIT: ::std::thread_local::__impl::KeyInner<$t> = { - ::std::thread_local::__impl::KeyInner { - inner: ::std::cell::UnsafeCell { value: $init }, - dtor_registered: ::std::cell::UnsafeCell { value: false }, - dtor_running: ::std::cell::UnsafeCell { value: false }, - } - }; - - #[cfg(any(not(any(target_os = "macos", target_os = "linux")), target_arch = "aarch64"))] - const _INIT: ::std::thread_local::__impl::KeyInner<$t> = { - unsafe extern fn __destroy(ptr: *mut u8) { - ::std::thread_local::__impl::destroy_value::<$t>(ptr); - } - - ::std::thread_local::__impl::KeyInner { - inner: ::std::cell::UnsafeCell { value: $init }, - os: ::std::thread_local::__impl::OsStaticKey { - inner: ::std::thread_local::__impl::OS_INIT_INNER, - dtor: ::std::option::Option::Some(__destroy as unsafe extern fn(*mut u8)), - }, - } - }; - - _INIT - }); -} - -/// Indicator of the state of a thread local storage key. -#[unstable(feature = "std_misc", - reason = "state querying was recently added")] -#[derive(Eq, PartialEq, Copy)] -pub enum State { - /// All keys are in this state whenever a thread starts. Keys will - /// transition to the `Valid` state once the first call to `with` happens - /// and the initialization expression succeeds. - /// - /// Keys in the `Uninitialized` state will yield a reference to the closure - /// passed to `with` so long as the initialization routine does not panic. - Uninitialized, - - /// Once a key has been accessed successfully, it will enter the `Valid` - /// state. Keys in the `Valid` state will remain so until the thread exits, - /// at which point the destructor will be run and the key will enter the - /// `Destroyed` state. - /// - /// Keys in the `Valid` state will be guaranteed to yield a reference to the - /// closure passed to `with`. - Valid, - - /// When a thread exits, the destructors for keys will be run (if - /// necessary). While a destructor is running, and possibly after a - /// destructor has run, a key is in the `Destroyed` state. - /// - /// Keys in the `Destroyed` states will trigger a panic when accessed via - /// `with`. - Destroyed, -} - -impl Key { - /// Acquire a reference to the value in this TLS key. - /// - /// This will lazily initialize the value if this thread has not referenced - /// this key yet. - /// - /// # Panics - /// - /// This function will `panic!()` if the key currently has its - /// destructor running, and it **may** panic if the destructor has - /// previously been run for this thread. - #[stable(feature = "rust1", since = "1.0.0")] - pub fn with(&'static self, f: F) -> R - where F: FnOnce(&T) -> R { - let slot = (self.inner)(); - unsafe { - let slot = slot.get().expect("cannot access a TLS value during or \ - after it is destroyed"); - f(match *slot.get() { - Some(ref inner) => inner, - None => self.init(slot), - }) - } - } - - unsafe fn init(&self, slot: &UnsafeCell>) -> &T { - // Execute the initialization up front, *then* move it into our slot, - // just in case initialization fails. - let value = (self.init)(); - let ptr = slot.get(); - *ptr = Some(value); - (*ptr).as_ref().unwrap() - } - - /// Query the current state of this key. - /// - /// A key is initially in the `Uninitialized` state whenever a thread - /// starts. It will remain in this state up until the first call to `with` - /// within a thread has run the initialization expression successfully. - /// - /// Once the initialization expression succeeds, the key transitions to the - /// `Valid` state which will guarantee that future calls to `with` will - /// succeed within the thread. - /// - /// When a thread exits, each key will be destroyed in turn, and as keys are - /// destroyed they will enter the `Destroyed` state just before the - /// destructor starts to run. Keys may remain in the `Destroyed` state after - /// destruction has completed. Keys without destructors (e.g. with types - /// that are `Copy`), may never enter the `Destroyed` state. - /// - /// Keys in the `Uninitialized` can be accessed so long as the - /// initialization does not panic. Keys in the `Valid` state are guaranteed - /// to be able to be accessed. Keys in the `Destroyed` state will panic on - /// any call to `with`. - #[unstable(feature = "std_misc", - reason = "state querying was recently added")] - pub fn state(&'static self) -> State { - unsafe { - match (self.inner)().get() { - Some(cell) => { - match *cell.get() { - Some(..) => State::Valid, - None => State::Uninitialized, - } - } - None => State::Destroyed, - } - } - } - - /// Deprecated - #[unstable(feature = "std_misc")] - #[deprecated(since = "1.0.0", - reason = "function renamed to state() and returns more info")] - pub fn destroyed(&'static self) -> bool { self.state() == State::Destroyed } -} - -#[cfg(all(any(target_os = "macos", target_os = "linux"), not(target_arch = "aarch64")))] -mod imp { - use prelude::v1::*; - - use cell::UnsafeCell; - use intrinsics; - use ptr; - - #[doc(hidden)] - #[unstable(feature = "thread_local_internals")] - pub struct Key { - // Place the inner bits in an `UnsafeCell` to currently get around the - // "only Sync statics" restriction. This allows any type to be placed in - // the cell. - // - // Note that all access requires `T: 'static` so it can't be a type with - // any borrowed pointers still. - #[unstable(feature = "thread_local_internals")] - pub inner: UnsafeCell, - - // Metadata to keep track of the state of the destructor. Remember that - // these variables are thread-local, not global. - #[unstable(feature = "thread_local_internals")] - pub dtor_registered: UnsafeCell, // should be Cell - #[unstable(feature = "thread_local_internals")] - pub dtor_running: UnsafeCell, // should be Cell - } - - unsafe impl ::marker::Sync for Key { } - - #[doc(hidden)] - impl Key { - pub unsafe fn get(&'static self) -> Option<&'static T> { - if intrinsics::needs_drop::() && *self.dtor_running.get() { - return None - } - self.register_dtor(); - Some(&*self.inner.get()) - } - - unsafe fn register_dtor(&self) { - if !intrinsics::needs_drop::() || *self.dtor_registered.get() { - return - } - - register_dtor(self as *const _ as *mut u8, - destroy_value::); - *self.dtor_registered.get() = true; - } - } - - // Since what appears to be glibc 2.18 this symbol has been shipped which - // GCC and clang both use to invoke destructors in thread_local globals, so - // let's do the same! - // - // Note, however, that we run on lots older linuxes, as well as cross - // compiling from a newer linux to an older linux, so we also have a - // fallback implementation to use as well. - // - // Due to rust-lang/rust#18804, make sure this is not generic! - #[cfg(target_os = "linux")] - unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) { - use boxed; - use mem; - use libc; - use sys_common::thread_local as os; - - extern { - static __dso_handle: *mut u8; - #[linkage = "extern_weak"] - static __cxa_thread_atexit_impl: *const (); - } - if !__cxa_thread_atexit_impl.is_null() { - type F = unsafe extern fn(dtor: unsafe extern fn(*mut u8), - arg: *mut u8, - dso_handle: *mut u8) -> libc::c_int; - mem::transmute::<*const (), F>(__cxa_thread_atexit_impl) - (dtor, t, __dso_handle); - return - } - - // 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: os::StaticKey = os::StaticKey { - inner: os::INIT_INNER, - dtor: Some(run_dtors as unsafe extern "C" fn(*mut u8)), - }; - type List = Vec<(*mut u8, unsafe extern fn(*mut u8))>; - if DTORS.get().is_null() { - let v: Box = box Vec::new(); - DTORS.set(boxed::into_raw(v) as *mut u8); - } - let list: &mut List = &mut *(DTORS.get() as *mut List); - list.push((t, dtor)); - - unsafe extern fn run_dtors(mut ptr: *mut u8) { - while !ptr.is_null() { - let list: Box = Box::from_raw(ptr as *mut List); - for &(ptr, dtor) in &*list { - dtor(ptr); - } - ptr = DTORS.get(); - DTORS.set(ptr::null_mut()); - } - } - } - - // OSX's analog of the above linux function is this _tlv_atexit function. - // The disassembly of thread_local globals in C++ (at least produced by - // clang) will have this show up in the output. - #[cfg(target_os = "macos")] - unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) { - extern { - fn _tlv_atexit(dtor: unsafe extern fn(*mut u8), - arg: *mut u8); - } - _tlv_atexit(dtor, t); - } - - #[doc(hidden)] - #[unstable(feature = "thread_local_internals")] - pub unsafe extern fn destroy_value(ptr: *mut u8) { - let ptr = ptr as *mut Key; - // Right before we run the user destructor be sure to flag the - // destructor as running for this thread so calls to `get` will return - // `None`. - *(*ptr).dtor_running.get() = true; - ptr::read((*ptr).inner.get()); - } -} - -#[cfg(any(not(any(target_os = "macos", target_os = "linux")), target_arch = "aarch64"))] -mod imp { - use prelude::v1::*; - - use alloc::boxed; - use cell::UnsafeCell; - use mem; - use ptr; - use sys_common::thread_local::StaticKey as OsStaticKey; - - #[doc(hidden)] - #[unstable(feature = "thread_local_internals")] - pub struct Key { - // Statically allocated initialization expression, using an `UnsafeCell` - // for the same reasons as above. - #[unstable(feature = "thread_local_internals")] - pub inner: UnsafeCell, - - // OS-TLS key that we'll use to key off. - #[unstable(feature = "thread_local_internals")] - pub os: OsStaticKey, - } - - unsafe impl ::marker::Sync for Key { } - - struct Value { - key: &'static Key, - value: T, - } - - #[doc(hidden)] - impl Key { - pub unsafe fn get(&'static self) -> Option<&'static T> { - self.ptr().map(|p| &*p) - } - - unsafe fn ptr(&'static self) -> Option<*mut T> { - let ptr = self.os.get() as *mut Value; - if !ptr.is_null() { - if ptr as usize == 1 { - return None - } - return Some(&mut (*ptr).value as *mut T); - } - - // If the lookup returned null, we haven't initialized our own local - // copy, so do that now. - // - // Also note that this transmute_copy should be ok because the value - // `inner` is already validated to be a valid `static` value, so we - // should be able to freely copy the bits. - let ptr: Box> = box Value { - key: self, - value: mem::transmute_copy(&self.inner), - }; - let ptr: *mut Value = boxed::into_raw(ptr); - self.os.set(ptr as *mut u8); - Some(&mut (*ptr).value as *mut T) - } - } - - #[doc(hidden)] - #[unstable(feature = "thread_local_internals")] - pub unsafe extern fn destroy_value(ptr: *mut u8) { - // The OS TLS ensures that this key contains a NULL value when this - // destructor starts to run. We set it back to a sentinel value of 1 to - // ensure that any future calls to `get` for this thread will return - // `None`. - // - // Note that to prevent an infinite loop we reset it back to null right - // before we return from the destructor ourselves. - let ptr: Box> = Box::from_raw(ptr as *mut Value); - let key = ptr.key; - key.os.set(1 as *mut u8); - drop(ptr); - key.os.set(ptr::null_mut()); - } -} - -#[cfg(test)] -mod tests { - use prelude::v1::*; - - use sync::mpsc::{channel, Sender}; - use cell::UnsafeCell; - use super::State; - use thread; - - struct Foo(Sender<()>); - - impl Drop for Foo { - fn drop(&mut self) { - let Foo(ref s) = *self; - s.send(()).unwrap(); - } - } - - #[test] - fn smoke_no_dtor() { - thread_local!(static FOO: UnsafeCell = UnsafeCell { value: 1 }); - - FOO.with(|f| unsafe { - assert_eq!(*f.get(), 1); - *f.get() = 2; - }); - let (tx, rx) = channel(); - let _t = thread::spawn(move|| { - FOO.with(|f| unsafe { - assert_eq!(*f.get(), 1); - }); - tx.send(()).unwrap(); - }); - rx.recv().unwrap(); - - FOO.with(|f| unsafe { - assert_eq!(*f.get(), 2); - }); - } - - #[test] - fn states() { - struct Foo; - impl Drop for Foo { - fn drop(&mut self) { - assert!(FOO.state() == State::Destroyed); - } - } - fn foo() -> Foo { - assert!(FOO.state() == State::Uninitialized); - Foo - } - thread_local!(static FOO: Foo = foo()); - - thread::spawn(|| { - assert!(FOO.state() == State::Uninitialized); - FOO.with(|_| { - assert!(FOO.state() == State::Valid); - }); - assert!(FOO.state() == State::Valid); - }).join().ok().unwrap(); - } - - #[test] - fn smoke_dtor() { - thread_local!(static FOO: UnsafeCell> = UnsafeCell { - value: None - }); - - let (tx, rx) = channel(); - let _t = thread::spawn(move|| unsafe { - let mut tx = Some(tx); - FOO.with(|f| { - *f.get() = Some(Foo(tx.take().unwrap())); - }); - }); - rx.recv().unwrap(); - } - - #[test] - fn circular() { - struct S1; - struct S2; - thread_local!(static K1: UnsafeCell> = UnsafeCell { - value: None - }); - thread_local!(static K2: UnsafeCell> = UnsafeCell { - value: None - }); - static mut HITS: u32 = 0; - - impl Drop for S1 { - fn drop(&mut self) { - unsafe { - HITS += 1; - if K2.state() == State::Destroyed { - assert_eq!(HITS, 3); - } else { - if HITS == 1 { - K2.with(|s| *s.get() = Some(S2)); - } else { - assert_eq!(HITS, 3); - } - } - } - } - } - impl Drop for S2 { - fn drop(&mut self) { - unsafe { - HITS += 1; - assert!(K1.state() != State::Destroyed); - assert_eq!(HITS, 2); - K1.with(|s| *s.get() = Some(S1)); - } - } - } - - thread::spawn(move|| { - drop(S1); - }).join().ok().unwrap(); - } - - #[test] - fn self_referential() { - struct S1; - thread_local!(static K1: UnsafeCell> = UnsafeCell { - value: None - }); - - impl Drop for S1 { - fn drop(&mut self) { - assert!(K1.state() == State::Destroyed); - } - } - - thread::spawn(move|| unsafe { - K1.with(|s| *s.get() = Some(S1)); - }).join().ok().unwrap(); - } - - #[test] - fn dtors_in_dtors_in_dtors() { - struct S1(Sender<()>); - thread_local!(static K1: UnsafeCell> = UnsafeCell { - value: None - }); - thread_local!(static K2: UnsafeCell> = UnsafeCell { - value: None - }); - - impl Drop for S1 { - fn drop(&mut self) { - let S1(ref tx) = *self; - unsafe { - if K2.state() != State::Destroyed { - K2.with(|s| *s.get() = Some(Foo(tx.clone()))); - } - } - } - } - - let (tx, rx) = channel(); - let _t = thread::spawn(move|| unsafe { - let mut tx = Some(tx); - K1.with(|s| *s.get() = Some(S1(tx.take().unwrap()))); - }); - rx.recv().unwrap(); - } -} - -#[cfg(test)] -mod dynamic_tests { - use prelude::v1::*; - - use cell::RefCell; - use collections::HashMap; - - #[test] - fn smoke() { - fn square(i: i32) -> i32 { i * i } - thread_local!(static FOO: i32 = square(3)); - - FOO.with(|f| { - assert_eq!(*f, 9); - }); - } - - #[test] - fn hashmap() { - fn map() -> RefCell> { - let mut m = HashMap::new(); - m.insert(1, 2); - RefCell::new(m) - } - thread_local!(static FOO: RefCell> = map()); - - FOO.with(|map| { - assert_eq!(map.borrow()[1], 2); - }); - } - - #[test] - fn refcell_vec() { - thread_local!(static FOO: RefCell> = RefCell::new(vec![1, 2, 3])); - - FOO.with(|vec| { - assert_eq!(vec.borrow().len(), 3); - vec.borrow_mut().push(4); - assert_eq!(vec.borrow()[3], 4); - }); - } -} diff --git a/src/libstd/thread_local/scoped.rs b/src/libstd/thread_local/scoped.rs deleted file mode 100644 index 86e6c059a70..00000000000 --- a/src/libstd/thread_local/scoped.rs +++ /dev/null @@ -1,313 +0,0 @@ -// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Scoped thread-local storage -//! -//! This module provides the ability to generate *scoped* thread-local -//! variables. In this sense, scoped indicates that thread local storage -//! actually stores a reference to a value, and this reference is only placed -//! in storage for a scoped amount of time. -//! -//! There are no restrictions on what types can be placed into a scoped -//! variable, but all scoped variables are initialized to the equivalent of -//! null. Scoped thread local storage is useful when a value is present for a known -//! period of time and it is not required to relinquish ownership of the -//! contents. -//! -//! # Examples -//! -//! ``` -//! scoped_thread_local!(static FOO: u32); -//! -//! // Initially each scoped slot is empty. -//! assert!(!FOO.is_set()); -//! -//! // When inserting a value, the value is only in place for the duration -//! // of the closure specified. -//! FOO.set(&1, || { -//! FOO.with(|slot| { -//! assert_eq!(*slot, 1); -//! }); -//! }); -//! ``` - -#![unstable(feature = "std_misc", - reason = "scoped TLS has yet to have wide enough use to fully consider \ - stabilizing its interface")] - -use prelude::v1::*; - -// macro hygiene sure would be nice, wouldn't it? -#[doc(hidden)] -pub mod __impl { - pub use super::imp::KeyInner; - pub use sys_common::thread_local::INIT as OS_INIT; -} - -/// Type representing a thread local storage key corresponding to a reference -/// to the type parameter `T`. -/// -/// Keys are statically allocated and can contain a reference to an instance of -/// type `T` scoped to a particular lifetime. Keys provides two methods, `set` -/// and `with`, both of which currently use closures to control the scope of -/// their contents. -pub struct Key { #[doc(hidden)] pub inner: __impl::KeyInner } - -/// Declare a new scoped thread local storage key. -/// -/// This macro declares a `static` item on which methods are used to get and -/// set the value stored within. -#[macro_export] -#[allow_internal_unstable] -macro_rules! scoped_thread_local { - (static $name:ident: $t:ty) => ( - __scoped_thread_local_inner!(static $name: $t); - ); - (pub static $name:ident: $t:ty) => ( - __scoped_thread_local_inner!(pub static $name: $t); - ); -} - -#[macro_export] -#[doc(hidden)] -#[allow_internal_unstable] -macro_rules! __scoped_thread_local_inner { - (static $name:ident: $t:ty) => ( - #[cfg_attr(not(any(windows, - target_os = "android", - target_os = "ios", - target_os = "openbsd", - target_arch = "aarch64")), - thread_local)] - static $name: ::std::thread_local::scoped::Key<$t> = - __scoped_thread_local_inner!($t); - ); - (pub static $name:ident: $t:ty) => ( - #[cfg_attr(not(any(windows, - target_os = "android", - target_os = "ios", - target_os = "openbsd", - target_arch = "aarch64")), - thread_local)] - pub static $name: ::std::thread_local::scoped::Key<$t> = - __scoped_thread_local_inner!($t); - ); - ($t:ty) => ({ - use std::thread_local::scoped::Key as __Key; - - #[cfg(not(any(windows, - target_os = "android", - target_os = "ios", - target_os = "openbsd", - target_arch = "aarch64")))] - const _INIT: __Key<$t> = __Key { - inner: ::std::thread_local::scoped::__impl::KeyInner { - inner: ::std::cell::UnsafeCell { value: 0 as *mut _ }, - } - }; - - #[cfg(any(windows, - target_os = "android", - target_os = "ios", - target_os = "openbsd", - target_arch = "aarch64"))] - const _INIT: __Key<$t> = __Key { - inner: ::std::thread_local::scoped::__impl::KeyInner { - inner: ::std::thread_local::scoped::__impl::OS_INIT, - marker: ::std::marker::PhantomData::<::std::cell::Cell<$t>>, - } - }; - - _INIT - }) -} - -impl Key { - /// Insert a value into this scoped thread local storage slot for a - /// duration of a closure. - /// - /// While `cb` is running, the value `t` will be returned by `get` unless - /// this function is called recursively inside of `cb`. - /// - /// Upon return, this function will restore the previous value, if any - /// was available. - /// - /// # Examples - /// - /// ``` - /// scoped_thread_local!(static FOO: u32); - /// - /// FOO.set(&100, || { - /// let val = FOO.with(|v| *v); - /// assert_eq!(val, 100); - /// - /// // set can be called recursively - /// FOO.set(&101, || { - /// // ... - /// }); - /// - /// // Recursive calls restore the previous value. - /// let val = FOO.with(|v| *v); - /// assert_eq!(val, 100); - /// }); - /// ``` - pub fn set(&'static self, t: &T, cb: F) -> R where - F: FnOnce() -> R, - { - struct Reset<'a, T: 'a> { - key: &'a __impl::KeyInner, - val: *mut T, - } - #[unsafe_destructor] - impl<'a, T> Drop for Reset<'a, T> { - fn drop(&mut self) { - unsafe { self.key.set(self.val) } - } - } - - let prev = unsafe { - let prev = self.inner.get(); - self.inner.set(t as *const T as *mut T); - prev - }; - - let _reset = Reset { key: &self.inner, val: prev }; - cb() - } - - /// Get a value out of this scoped variable. - /// - /// This function takes a closure which receives the value of this - /// variable. - /// - /// # Panics - /// - /// This function will panic if `set` has not previously been called. - /// - /// # Examples - /// - /// ```no_run - /// scoped_thread_local!(static FOO: u32); - /// - /// FOO.with(|slot| { - /// // work with `slot` - /// }); - /// ``` - pub fn with(&'static self, cb: F) -> R where - F: FnOnce(&T) -> R - { - unsafe { - let ptr = self.inner.get(); - assert!(!ptr.is_null(), "cannot access a scoped thread local \ - variable without calling `set` first"); - cb(&*ptr) - } - } - - /// Test whether this TLS key has been `set` for the current thread. - pub fn is_set(&'static self) -> bool { - unsafe { !self.inner.get().is_null() } - } -} - -#[cfg(not(any(windows, - target_os = "android", - target_os = "ios", - target_os = "openbsd", - target_arch = "aarch64")))] -mod imp { - use std::cell::UnsafeCell; - - #[doc(hidden)] - pub struct KeyInner { pub inner: UnsafeCell<*mut T> } - - unsafe impl ::marker::Sync for KeyInner { } - - #[doc(hidden)] - impl KeyInner { - #[doc(hidden)] - pub unsafe fn set(&self, ptr: *mut T) { *self.inner.get() = ptr; } - #[doc(hidden)] - pub unsafe fn get(&self) -> *mut T { *self.inner.get() } - } -} - -#[cfg(any(windows, - target_os = "android", - target_os = "ios", - target_os = "openbsd", - target_arch = "aarch64"))] -mod imp { - use marker; - use std::cell::Cell; - use sys_common::thread_local::StaticKey as OsStaticKey; - - #[doc(hidden)] - pub struct KeyInner { - pub inner: OsStaticKey, - pub marker: marker::PhantomData>, - } - - unsafe impl ::marker::Sync for KeyInner { } - - #[doc(hidden)] - impl KeyInner { - #[doc(hidden)] - pub unsafe fn set(&self, ptr: *mut T) { self.inner.set(ptr as *mut _) } - #[doc(hidden)] - pub unsafe fn get(&self) -> *mut T { self.inner.get() as *mut _ } - } -} - - -#[cfg(test)] -mod tests { - use cell::Cell; - use prelude::v1::*; - - scoped_thread_local!(static FOO: u32); - - #[test] - fn smoke() { - scoped_thread_local!(static BAR: u32); - - assert!(!BAR.is_set()); - BAR.set(&1, || { - assert!(BAR.is_set()); - BAR.with(|slot| { - assert_eq!(*slot, 1); - }); - }); - assert!(!BAR.is_set()); - } - - #[test] - fn cell_allowed() { - scoped_thread_local!(static BAR: Cell); - - BAR.set(&Cell::new(1), || { - BAR.with(|slot| { - assert_eq!(slot.get(), 1); - }); - }); - } - - #[test] - fn scope_item_allowed() { - assert!(!FOO.is_set()); - FOO.set(&1, || { - assert!(FOO.is_set()); - FOO.with(|slot| { - assert_eq!(*slot, 1); - }); - }); - assert!(!FOO.is_set()); - } -} -- cgit 1.4.1-3-g733a5 From b4d4daf007753dfb04d87b1ffe1c2ad2d8811d5a Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sat, 21 Mar 2015 19:33:27 -0400 Subject: Adjust Index/IndexMut impls. For generic collections, we take references. For collections whose keys are integers, we take both references and by-value. --- src/libcollections/btree/map.rs | 15 +++ src/libcollections/string.rs | 32 ++++++ src/libcollections/vec.rs | 82 +++++++++++++++ src/libcollections/vec_deque.rs | 14 +++ src/libcollections/vec_map.rs | 42 +++++++- src/libcore/ops.rs | 6 +- src/libcore/slice.rs | 201 +++++++++++++++++++++++++++++++++++++ src/libcore/str/mod.rs | 78 ++++++++++++++ src/libserialize/json.rs | 23 +++++ src/libstd/collections/hash/map.rs | 24 ++++- src/libstd/ffi/os_str.rs | 12 +++ src/libstd/sys/common/wtf8.rs | 79 +++++++++++++++ 12 files changed, 600 insertions(+), 8 deletions(-) (limited to 'src/libstd/sys') diff --git a/src/libcollections/btree/map.rs b/src/libcollections/btree/map.rs index a9e1ce8d7ce..0a72f24b437 100644 --- a/src/libcollections/btree/map.rs +++ b/src/libcollections/btree/map.rs @@ -914,12 +914,27 @@ impl Debug for BTreeMap { } } +#[cfg(stage0)] #[stable(feature = "rust1", since = "1.0.0")] impl Index for BTreeMap where K: Borrow, Q: Ord { type Output = V; + #[inline] + fn index(&self, key: &Q) -> &V { + self.get(key).expect("no entry found for key") + } +} + +#[cfg(not(stage0))] +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, K: Ord, Q: ?Sized, V> Index<&'a Q> for BTreeMap + where K: Borrow, Q: Ord +{ + type Output = V; + + #[inline] fn index(&self, key: &Q) -> &V { self.get(key).expect("no entry found for key") } diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index cd6f27bf65f..3f869d0b8ae 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -870,34 +870,66 @@ impl<'a> Add<&'a str> for String { #[stable(feature = "rust1", since = "1.0.0")] impl ops::Index> for String { type Output = str; + + #[cfg(stage0)] #[inline] fn index(&self, index: &ops::Range) -> &str { &self[..][*index] } + + #[cfg(not(stage0))] + #[inline] + fn index(&self, index: ops::Range) -> &str { + &self[..][index] + } } #[stable(feature = "rust1", since = "1.0.0")] impl ops::Index> for String { type Output = str; + + #[cfg(stage0)] #[inline] fn index(&self, index: &ops::RangeTo) -> &str { &self[..][*index] } + + #[cfg(not(stage0))] + #[inline] + fn index(&self, index: ops::RangeTo) -> &str { + &self[..][index] + } } #[stable(feature = "rust1", since = "1.0.0")] impl ops::Index> for String { type Output = str; + + #[cfg(stage0)] #[inline] fn index(&self, index: &ops::RangeFrom) -> &str { &self[..][*index] } + + #[cfg(not(stage0))] + #[inline] + fn index(&self, index: ops::RangeFrom) -> &str { + &self[..][index] + } } #[stable(feature = "rust1", since = "1.0.0")] impl ops::Index for String { type Output = str; + + #[cfg(stage0)] #[inline] fn index(&self, _index: &ops::RangeFull) -> &str { unsafe { mem::transmute(&*self.vec) } } + + #[cfg(not(stage0))] + #[inline] + fn index(&self, _index: ops::RangeFull) -> &str { + unsafe { mem::transmute(&*self.vec) } + } } #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index b0e8dc7d0b6..3e46ebfc446 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -1323,83 +1323,165 @@ impl Hash for Vec { impl Index for Vec { type Output = T; + + #[cfg(stage0)] #[inline] fn index(&self, index: &usize) -> &T { // NB built-in indexing via `&[T]` &(**self)[*index] } + + #[cfg(not(stage0))] + #[inline] + fn index(&self, index: usize) -> &T { + // NB built-in indexing via `&[T]` + &(**self)[index] + } } #[stable(feature = "rust1", since = "1.0.0")] impl IndexMut for Vec { + + #[cfg(stage0)] #[inline] fn index_mut(&mut self, index: &usize) -> &mut T { // NB built-in indexing via `&mut [T]` &mut (**self)[*index] } + + #[cfg(not(stage0))] + #[inline] + fn index_mut(&mut self, index: usize) -> &mut T { + // NB built-in indexing via `&mut [T]` + &mut (**self)[index] + } } #[stable(feature = "rust1", since = "1.0.0")] impl ops::Index> for Vec { type Output = [T]; + + #[cfg(stage0)] #[inline] fn index(&self, index: &ops::Range) -> &[T] { Index::index(&**self, index) } + + #[cfg(not(stage0))] + #[inline] + fn index(&self, index: ops::Range) -> &[T] { + Index::index(&**self, index) + } } #[stable(feature = "rust1", since = "1.0.0")] impl ops::Index> for Vec { type Output = [T]; + + #[cfg(stage0)] #[inline] fn index(&self, index: &ops::RangeTo) -> &[T] { Index::index(&**self, index) } + + #[cfg(not(stage0))] + #[inline] + fn index(&self, index: ops::RangeTo) -> &[T] { + Index::index(&**self, index) + } } #[stable(feature = "rust1", since = "1.0.0")] impl ops::Index> for Vec { type Output = [T]; + + #[cfg(stage0)] #[inline] fn index(&self, index: &ops::RangeFrom) -> &[T] { Index::index(&**self, index) } + + #[cfg(not(stage0))] + #[inline] + fn index(&self, index: ops::RangeFrom) -> &[T] { + Index::index(&**self, index) + } } #[stable(feature = "rust1", since = "1.0.0")] impl ops::Index for Vec { type Output = [T]; + + #[cfg(stage0)] #[inline] fn index(&self, _index: &ops::RangeFull) -> &[T] { self.as_slice() } + + #[cfg(not(stage0))] + #[inline] + fn index(&self, _index: ops::RangeFull) -> &[T] { + self.as_slice() + } } #[stable(feature = "rust1", since = "1.0.0")] impl ops::IndexMut> for Vec { + + #[cfg(stage0)] #[inline] fn index_mut(&mut self, index: &ops::Range) -> &mut [T] { IndexMut::index_mut(&mut **self, index) } + + #[cfg(not(stage0))] + #[inline] + fn index_mut(&mut self, index: ops::Range) -> &mut [T] { + IndexMut::index_mut(&mut **self, index) + } } #[stable(feature = "rust1", since = "1.0.0")] impl ops::IndexMut> for Vec { + + #[cfg(stage0)] #[inline] fn index_mut(&mut self, index: &ops::RangeTo) -> &mut [T] { IndexMut::index_mut(&mut **self, index) } + + #[cfg(not(stage0))] + #[inline] + fn index_mut(&mut self, index: ops::RangeTo) -> &mut [T] { + IndexMut::index_mut(&mut **self, index) + } } #[stable(feature = "rust1", since = "1.0.0")] impl ops::IndexMut> for Vec { + + #[cfg(stage0)] #[inline] fn index_mut(&mut self, index: &ops::RangeFrom) -> &mut [T] { IndexMut::index_mut(&mut **self, index) } + + #[cfg(not(stage0))] + #[inline] + fn index_mut(&mut self, index: ops::RangeFrom) -> &mut [T] { + IndexMut::index_mut(&mut **self, index) + } } #[stable(feature = "rust1", since = "1.0.0")] impl ops::IndexMut for Vec { + + #[cfg(stage0)] #[inline] fn index_mut(&mut self, _index: &ops::RangeFull) -> &mut [T] { self.as_mut_slice() } + + #[cfg(not(stage0))] + #[inline] + fn index_mut(&mut self, _index: ops::RangeFull) -> &mut [T] { + self.as_mut_slice() + } } #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libcollections/vec_deque.rs b/src/libcollections/vec_deque.rs index 56ca74dab1f..591ad48f579 100644 --- a/src/libcollections/vec_deque.rs +++ b/src/libcollections/vec_deque.rs @@ -1689,18 +1689,32 @@ impl Hash for VecDeque { impl Index for VecDeque { type Output = A; + #[cfg(stage0)] #[inline] fn index(&self, i: &usize) -> &A { self.get(*i).expect("Out of bounds access") } + + #[cfg(not(stage0))] + #[inline] + fn index(&self, i: usize) -> &A { + self.get(i).expect("Out of bounds access") + } } #[stable(feature = "rust1", since = "1.0.0")] impl IndexMut for VecDeque { + #[cfg(stage0)] #[inline] fn index_mut(&mut self, i: &usize) -> &mut A { self.get_mut(*i).expect("Out of bounds access") } + + #[cfg(not(stage0))] + #[inline] + fn index_mut(&mut self, i: usize) -> &mut A { + self.get_mut(i).expect("Out of bounds access") + } } #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libcollections/vec_map.rs b/src/libcollections/vec_map.rs index 6e67d876327..05693ec5275 100644 --- a/src/libcollections/vec_map.rs +++ b/src/libcollections/vec_map.rs @@ -798,6 +798,7 @@ impl Extend<(usize, V)> for VecMap { } } +#[cfg(stage0)] impl Index for VecMap { type Output = V; @@ -807,10 +808,49 @@ impl Index for VecMap { } } +#[cfg(not(stage0))] +impl Index for VecMap { + type Output = V; + + #[inline] + fn index<'a>(&'a self, i: usize) -> &'a V { + self.get(&i).expect("key not present") + } +} + +#[cfg(not(stage0))] +impl<'a,V> Index<&'a usize> for VecMap { + type Output = V; + + #[inline] + fn index(&self, i: &usize) -> &V { + self.get(i).expect("key not present") + } +} + +#[cfg(stage0)] +#[stable(feature = "rust1", since = "1.0.0")] +impl IndexMut for VecMap { + #[inline] + fn index_mut(&mut self, i: &usize) -> &mut V { + self.get_mut(&i).expect("key not present") + } +} + +#[cfg(not(stage0))] #[stable(feature = "rust1", since = "1.0.0")] impl IndexMut for VecMap { #[inline] - fn index_mut<'a>(&'a mut self, i: &usize) -> &'a mut V { + fn index_mut(&mut self, i: usize) -> &mut V { + self.get_mut(&i).expect("key not present") + } +} + +#[cfg(not(stage0))] +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, V> IndexMut<&'a usize> for VecMap { + #[inline] + fn index_mut(&mut self, i: &usize) -> &mut V { self.get_mut(i).expect("key not present") } } diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index e1e352b5b64..6e6f97a7af7 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -898,7 +898,7 @@ shr_impl_all! { u8 u16 u32 u64 usize i8 i16 i32 i64 isize } /// impl Index for Foo { /// type Output = Foo; /// -/// fn index<'a>(&'a self, _index: &Bar) -> &'a Foo { +/// fn index<'a>(&'a self, _index: Bar) -> &'a Foo { /// println!("Indexing!"); /// self /// } @@ -945,13 +945,13 @@ pub trait Index { /// impl Index for Foo { /// type Output = Foo; /// -/// fn index<'a>(&'a self, _index: &Bar) -> &'a Foo { +/// fn index<'a>(&'a self, _index: Bar) -> &'a Foo { /// self /// } /// } /// /// impl IndexMut for Foo { -/// fn index_mut<'a>(&'a mut self, _index: &Bar) -> &'a mut Foo { +/// fn index_mut<'a>(&'a mut self, _index: Bar) -> &'a mut Foo { /// println!("Indexing!"); /// self /// } diff --git a/src/libcore/slice.rs b/src/libcore/slice.rs index 907b2eba80c..04b425416f3 100644 --- a/src/libcore/slice.rs +++ b/src/libcore/slice.rs @@ -263,6 +263,7 @@ impl SliceExt for [T] { #[inline] fn as_mut_slice(&mut self) -> &mut [T] { self } + #[cfg(stage0)] #[inline] fn split_at_mut(&mut self, mid: usize) -> (&mut [T], &mut [T]) { unsafe { @@ -273,6 +274,17 @@ impl SliceExt for [T] { } } + #[cfg(not(stage0))] + #[inline] + fn split_at_mut(&mut self, mid: usize) -> (&mut [T], &mut [T]) { + unsafe { + let self2: &mut [T] = mem::transmute_copy(&self); + + (ops::IndexMut::index_mut(self, ops::RangeTo { end: mid } ), + ops::IndexMut::index_mut(self2, ops::RangeFrom { start: mid } )) + } + } + #[inline] fn iter_mut<'a>(&'a mut self) -> IterMut<'a, T> { unsafe { @@ -495,25 +507,45 @@ impl SliceExt for [T] { impl ops::Index for [T] { type Output = T; + #[cfg(stage0)] fn index(&self, &index: &usize) -> &T { assert!(index < self.len()); unsafe { mem::transmute(self.repr().data.offset(index as isize)) } } + + #[cfg(not(stage0))] + fn index(&self, index: usize) -> &T { + assert!(index < self.len()); + + unsafe { mem::transmute(self.repr().data.offset(index as isize)) } + } } #[stable(feature = "rust1", since = "1.0.0")] impl ops::IndexMut for [T] { + #[cfg(stage0)] + #[inline] fn index_mut(&mut self, &index: &usize) -> &mut T { assert!(index < self.len()); unsafe { mem::transmute(self.repr().data.offset(index as isize)) } } + + #[cfg(not(stage0))] + #[inline] + fn index_mut(&mut self, index: usize) -> &mut T { + assert!(index < self.len()); + + unsafe { mem::transmute(self.repr().data.offset(index as isize)) } + } } #[stable(feature = "rust1", since = "1.0.0")] impl ops::Index> for [T] { type Output = [T]; + + #[cfg(stage0)] #[inline] fn index(&self, index: &ops::Range) -> &[T] { assert!(index.start <= index.end); @@ -525,34 +557,72 @@ impl ops::Index> for [T] { ) } } + + #[cfg(not(stage0))] + #[inline] + fn index(&self, index: ops::Range) -> &[T] { + assert!(index.start <= index.end); + assert!(index.end <= self.len()); + unsafe { + from_raw_parts ( + self.as_ptr().offset(index.start as isize), + index.end - index.start + ) + } + } } #[stable(feature = "rust1", since = "1.0.0")] impl ops::Index> for [T] { type Output = [T]; + + #[cfg(stage0)] #[inline] fn index(&self, index: &ops::RangeTo) -> &[T] { self.index(&ops::Range{ start: 0, end: index.end }) } + + #[cfg(not(stage0))] + #[inline] + fn index(&self, index: ops::RangeTo) -> &[T] { + self.index(ops::Range{ start: 0, end: index.end }) + } } #[stable(feature = "rust1", since = "1.0.0")] impl ops::Index> for [T] { type Output = [T]; + + #[cfg(stage0)] #[inline] fn index(&self, index: &ops::RangeFrom) -> &[T] { self.index(&ops::Range{ start: index.start, end: self.len() }) } + + #[cfg(not(stage0))] + #[inline] + fn index(&self, index: ops::RangeFrom) -> &[T] { + self.index(ops::Range{ start: index.start, end: self.len() }) + } } #[stable(feature = "rust1", since = "1.0.0")] impl ops::Index for [T] { type Output = [T]; + + #[cfg(stage0)] #[inline] fn index(&self, _index: &RangeFull) -> &[T] { self } + + #[cfg(not(stage0))] + #[inline] + fn index(&self, _index: RangeFull) -> &[T] { + self + } } #[stable(feature = "rust1", since = "1.0.0")] impl ops::IndexMut> for [T] { + #[cfg(stage0)] #[inline] fn index_mut(&mut self, index: &ops::Range) -> &mut [T] { assert!(index.start <= index.end); @@ -564,28 +634,64 @@ impl ops::IndexMut> for [T] { ) } } + + #[cfg(not(stage0))] + #[inline] + fn index_mut(&mut self, index: ops::Range) -> &mut [T] { + assert!(index.start <= index.end); + assert!(index.end <= self.len()); + unsafe { + from_raw_parts_mut( + self.as_mut_ptr().offset(index.start as isize), + index.end - index.start + ) + } + } } #[stable(feature = "rust1", since = "1.0.0")] impl ops::IndexMut> for [T] { + #[cfg(stage0)] #[inline] fn index_mut(&mut self, index: &ops::RangeTo) -> &mut [T] { self.index_mut(&ops::Range{ start: 0, end: index.end }) } + + #[cfg(not(stage0))] + #[inline] + fn index_mut(&mut self, index: ops::RangeTo) -> &mut [T] { + self.index_mut(ops::Range{ start: 0, end: index.end }) + } } #[stable(feature = "rust1", since = "1.0.0")] impl ops::IndexMut> for [T] { + #[cfg(stage0)] #[inline] fn index_mut(&mut self, index: &ops::RangeFrom) -> &mut [T] { let len = self.len(); self.index_mut(&ops::Range{ start: index.start, end: len }) } + + #[cfg(not(stage0))] + #[inline] + fn index_mut(&mut self, index: ops::RangeFrom) -> &mut [T] { + let len = self.len(); + self.index_mut(ops::Range{ start: index.start, end: len }) + } } #[stable(feature = "rust1", since = "1.0.0")] impl ops::IndexMut for [T] { + + #[cfg(stage0)] #[inline] fn index_mut(&mut self, _index: &RangeFull) -> &mut [T] { self } + + #[cfg(not(stage0))] + #[inline] + fn index_mut(&mut self, _index: RangeFull) -> &mut [T] { + self + } } @@ -763,37 +869,69 @@ unsafe impl<'a, T: Sync> Send for Iter<'a, T> {} #[unstable(feature = "core")] impl<'a, T> ops::Index> for Iter<'a, T> { type Output = [T]; + + #[cfg(stage0)] #[inline] fn index(&self, index: &ops::Range) -> &[T] { self.as_slice().index(index) } + + #[cfg(not(stage0))] + #[inline] + fn index(&self, index: ops::Range) -> &[T] { + self.as_slice().index(index) + } } #[unstable(feature = "core")] impl<'a, T> ops::Index> for Iter<'a, T> { type Output = [T]; + + #[cfg(stage0)] #[inline] fn index(&self, index: &ops::RangeTo) -> &[T] { self.as_slice().index(index) } + + #[cfg(not(stage0))] + #[inline] + fn index(&self, index: ops::RangeTo) -> &[T] { + self.as_slice().index(index) + } } #[unstable(feature = "core")] impl<'a, T> ops::Index> for Iter<'a, T> { type Output = [T]; + + #[cfg(stage0)] #[inline] fn index(&self, index: &ops::RangeFrom) -> &[T] { self.as_slice().index(index) } + + #[cfg(not(stage0))] + #[inline] + fn index(&self, index: ops::RangeFrom) -> &[T] { + self.as_slice().index(index) + } } #[unstable(feature = "core")] impl<'a, T> ops::Index for Iter<'a, T> { type Output = [T]; + + #[cfg(stage0)] #[inline] fn index(&self, _index: &RangeFull) -> &[T] { self.as_slice() } + + #[cfg(not(stage0))] + #[inline] + fn index(&self, _index: RangeFull) -> &[T] { + self.as_slice() + } } impl<'a, T> Iter<'a, T> { @@ -856,63 +994,126 @@ unsafe impl<'a, T: Send> Send for IterMut<'a, T> {} #[unstable(feature = "core")] impl<'a, T> ops::Index> for IterMut<'a, T> { type Output = [T]; + + #[cfg(stage0)] #[inline] fn index(&self, index: &ops::Range) -> &[T] { self.index(&RangeFull).index(index) } + + #[cfg(not(stage0))] + #[inline] + fn index(&self, index: ops::Range) -> &[T] { + self.index(RangeFull).index(index) + } } #[unstable(feature = "core")] impl<'a, T> ops::Index> for IterMut<'a, T> { type Output = [T]; + + #[cfg(stage0)] #[inline] fn index(&self, index: &ops::RangeTo) -> &[T] { self.index(&RangeFull).index(index) } + + #[cfg(not(stage0))] + #[inline] + fn index(&self, index: ops::RangeTo) -> &[T] { + self.index(RangeFull).index(index) + } } #[unstable(feature = "core")] impl<'a, T> ops::Index> for IterMut<'a, T> { type Output = [T]; + + #[cfg(stage0)] #[inline] fn index(&self, index: &ops::RangeFrom) -> &[T] { self.index(&RangeFull).index(index) } + + #[cfg(not(stage0))] + #[inline] + fn index(&self, index: ops::RangeFrom) -> &[T] { + self.index(RangeFull).index(index) + } } #[unstable(feature = "core")] impl<'a, T> ops::Index for IterMut<'a, T> { type Output = [T]; + + #[cfg(stage0)] #[inline] fn index(&self, _index: &RangeFull) -> &[T] { make_slice!(T => &[T]: self.ptr, self.end) } + + #[cfg(not(stage0))] + #[inline] + fn index(&self, _index: RangeFull) -> &[T] { + make_slice!(T => &[T]: self.ptr, self.end) + } } #[unstable(feature = "core")] impl<'a, T> ops::IndexMut> for IterMut<'a, T> { + #[cfg(stage0)] #[inline] fn index_mut(&mut self, index: &ops::Range) -> &mut [T] { self.index_mut(&RangeFull).index_mut(index) } + + #[cfg(not(stage0))] + #[inline] + fn index_mut(&mut self, index: ops::Range) -> &mut [T] { + self.index_mut(RangeFull).index_mut(index) + } } #[unstable(feature = "core")] impl<'a, T> ops::IndexMut> for IterMut<'a, T> { + + #[cfg(stage0)] #[inline] fn index_mut(&mut self, index: &ops::RangeTo) -> &mut [T] { self.index_mut(&RangeFull).index_mut(index) } + + #[cfg(not(stage0))] + #[inline] + fn index_mut(&mut self, index: ops::RangeTo) -> &mut [T] { + self.index_mut(RangeFull).index_mut(index) + } } #[unstable(feature = "core")] impl<'a, T> ops::IndexMut> for IterMut<'a, T> { + + #[cfg(stage0)] #[inline] fn index_mut(&mut self, index: &ops::RangeFrom) -> &mut [T] { self.index_mut(&RangeFull).index_mut(index) } + + #[cfg(not(stage0))] + #[inline] + fn index_mut(&mut self, index: ops::RangeFrom) -> &mut [T] { + self.index_mut(RangeFull).index_mut(index) + } } #[unstable(feature = "core")] impl<'a, T> ops::IndexMut for IterMut<'a, T> { + + #[cfg(stage0)] #[inline] fn index_mut(&mut self, _index: &RangeFull) -> &mut [T] { make_mut_slice!(T => &mut [T]: self.ptr, self.end) } + + #[cfg(not(stage0))] + #[inline] + fn index_mut(&mut self, _index: RangeFull) -> &mut [T] { + make_mut_slice!(T => &mut [T]: self.ptr, self.end) + } } diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index e8181395b5c..b9a655c6d4e 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -1203,6 +1203,7 @@ mod traits { /// // byte 100 is outside the string /// // &s[3 .. 100]; /// ``` + #[cfg(stage0)] #[stable(feature = "rust1", since = "1.0.0")] impl ops::Index> for str { type Output = str; @@ -1219,6 +1220,49 @@ mod traits { } } + /// Returns a slice of the given string from the byte range + /// [`begin`..`end`). + /// + /// This operation is `O(1)`. + /// + /// Panics when `begin` and `end` do not point to valid characters + /// or point beyond the last character of the string. + /// + /// # Examples + /// + /// ``` + /// let s = "Löwe 老虎 Léopard"; + /// assert_eq!(&s[0 .. 1], "L"); + /// + /// assert_eq!(&s[1 .. 9], "öwe 老"); + /// + /// // these will panic: + /// // byte 2 lies within `ö`: + /// // &s[2 ..3]; + /// + /// // byte 8 lies within `老` + /// // &s[1 .. 8]; + /// + /// // byte 100 is outside the string + /// // &s[3 .. 100]; + /// ``` + #[cfg(not(stage0))] + #[stable(feature = "rust1", since = "1.0.0")] + impl ops::Index> for str { + type Output = str; + #[inline] + fn index(&self, index: ops::Range) -> &str { + // is_char_boundary checks that the index is in [0, .len()] + if index.start <= index.end && + self.is_char_boundary(index.start) && + self.is_char_boundary(index.end) { + unsafe { self.slice_unchecked(index.start, index.end) } + } else { + super::slice_error_fail(self, index.start, index.end) + } + } + } + /// Returns a slice of the string from the beginning to byte /// `end`. /// @@ -1229,6 +1273,8 @@ mod traits { #[stable(feature = "rust1", since = "1.0.0")] impl ops::Index> for str { type Output = str; + + #[cfg(stage0)] #[inline] fn index(&self, index: &ops::RangeTo) -> &str { // is_char_boundary checks that the index is in [0, .len()] @@ -1238,6 +1284,17 @@ mod traits { super::slice_error_fail(self, 0, index.end) } } + + #[cfg(not(stage0))] + #[inline] + fn index(&self, index: ops::RangeTo) -> &str { + // is_char_boundary checks that the index is in [0, .len()] + if self.is_char_boundary(index.end) { + unsafe { self.slice_unchecked(0, index.end) } + } else { + super::slice_error_fail(self, 0, index.end) + } + } } /// Returns a slice of the string from `begin` to its end. @@ -1249,6 +1306,8 @@ mod traits { #[stable(feature = "rust1", since = "1.0.0")] impl ops::Index> for str { type Output = str; + + #[cfg(stage0)] #[inline] fn index(&self, index: &ops::RangeFrom) -> &str { // is_char_boundary checks that the index is in [0, .len()] @@ -1258,15 +1317,34 @@ mod traits { super::slice_error_fail(self, index.start, self.len()) } } + + #[cfg(not(stage0))] + #[inline] + fn index(&self, index: ops::RangeFrom) -> &str { + // is_char_boundary checks that the index is in [0, .len()] + if self.is_char_boundary(index.start) { + unsafe { self.slice_unchecked(index.start, self.len()) } + } else { + super::slice_error_fail(self, index.start, self.len()) + } + } } #[stable(feature = "rust1", since = "1.0.0")] impl ops::Index for str { type Output = str; + + #[cfg(stage0)] #[inline] fn index(&self, _index: &ops::RangeFull) -> &str { self } + + #[cfg(not(stage0))] + #[inline] + fn index(&self, _index: ops::RangeFull) -> &str { + self + } } } diff --git a/src/libserialize/json.rs b/src/libserialize/json.rs index 096c72e6af2..abbfc82319f 100644 --- a/src/libserialize/json.rs +++ b/src/libserialize/json.rs @@ -1218,6 +1218,7 @@ impl Json { } } +#[cfg(stage0)] impl<'a> Index<&'a str> for Json { type Output = Json; @@ -1226,6 +1227,16 @@ impl<'a> Index<&'a str> for Json { } } +#[cfg(not(stage0))] +impl<'a> Index<&'a str> for Json { + type Output = Json; + + fn index(&self, idx: &'a str) -> &Json { + self.find(idx).unwrap() + } +} + +#[cfg(stage0)] impl Index for Json { type Output = Json; @@ -1237,6 +1248,18 @@ impl Index for Json { } } +#[cfg(not(stage0))] +impl Index for Json { + type Output = Json; + + fn index<'a>(&'a self, idx: uint) -> &'a Json { + match self { + &Json::Array(ref v) => &v[idx], + _ => panic!("can only index Json with uint if it is an array") + } + } +} + /// The output of the streaming parser. #[derive(PartialEq, Clone, Debug)] pub enum JsonEvent { diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 9139e182ce4..86664d7eb0c 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -1088,7 +1088,7 @@ impl HashMap /// Some(x) => *x = "b", /// None => (), /// } - /// assert_eq!(map[1], "b"); + /// assert_eq!(map[&1], "b"); /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn get_mut(&mut self, k: &Q) -> Option<&mut V> @@ -1111,7 +1111,7 @@ impl HashMap /// /// map.insert(37, "b"); /// assert_eq!(map.insert(37, "c"), Some("b")); - /// assert_eq!(map[37], "c"); + /// assert_eq!(map[&37], "c"); /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn insert(&mut self, k: K, v: V) -> Option { @@ -1244,6 +1244,7 @@ impl Default for HashMap } } +#[cfg(stage0)] #[stable(feature = "rust1", since = "1.0.0")] impl Index for HashMap where K: Eq + Hash + Borrow, @@ -1258,6 +1259,21 @@ impl Index for HashMap } } +#[cfg(not(stage0))] +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, K, Q: ?Sized, V, S> Index<&'a Q> for HashMap + where K: Eq + Hash + Borrow, + Q: Eq + Hash, + S: HashState, +{ + type Output = V; + + #[inline] + fn index(&self, index: &Q) -> &V { + self.get(index).expect("no entry found for key") + } +} + /// HashMap iterator. #[stable(feature = "rust1", since = "1.0.0")] pub struct Iter<'a, K: 'a, V: 'a> { @@ -2185,7 +2201,7 @@ mod test_map { map.insert(2, 1); map.insert(3, 4); - assert_eq!(map[2], 1); + assert_eq!(map[&2], 1); } #[test] @@ -2197,7 +2213,7 @@ mod test_map { map.insert(2, 1); map.insert(3, 4); - map[4]; + map[&4]; } #[test] diff --git a/src/libstd/ffi/os_str.rs b/src/libstd/ffi/os_str.rs index feacbf1e98b..290c48b1310 100644 --- a/src/libstd/ffi/os_str.rs +++ b/src/libstd/ffi/os_str.rs @@ -103,6 +103,7 @@ impl OsString { } } +#[cfg(stage0)] #[stable(feature = "rust1", since = "1.0.0")] impl ops::Index for OsString { type Output = OsStr; @@ -113,6 +114,17 @@ impl ops::Index for OsString { } } +#[cfg(not(stage0))] +#[stable(feature = "rust1", since = "1.0.0")] +impl ops::Index for OsString { + type Output = OsStr; + + #[inline] + fn index(&self, _index: ops::RangeFull) -> &OsStr { + unsafe { mem::transmute(self.inner.as_slice()) } + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl ops::Deref for OsString { type Target = OsStr; diff --git a/src/libstd/sys/common/wtf8.rs b/src/libstd/sys/common/wtf8.rs index 3cc91bf54b4..9f3dae34c7a 100644 --- a/src/libstd/sys/common/wtf8.rs +++ b/src/libstd/sys/common/wtf8.rs @@ -634,6 +634,7 @@ impl Wtf8 { /// /// Panics when `begin` and `end` do not point to code point boundaries, /// or point beyond the end of the string. +#[cfg(stage0)] impl ops::Index> for Wtf8 { type Output = Wtf8; @@ -650,12 +651,36 @@ impl ops::Index> for Wtf8 { } } +/// Return 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. +#[cfg(not(stage0))] +impl ops::Index> for Wtf8 { + type Output = Wtf8; + + #[inline] + fn index(&self, range: ops::Range) -> &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) + } + } +} + /// Return 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. +#[cfg(stage0)] impl ops::Index> for Wtf8 { type Output = Wtf8; @@ -670,12 +695,34 @@ impl ops::Index> for Wtf8 { } } +/// Return 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. +#[cfg(not(stage0))] +impl ops::Index> for Wtf8 { + type Output = Wtf8; + + #[inline] + fn index(&self, range: ops::RangeFrom) -> &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()) + } + } +} + /// Return 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. +#[cfg(stage0)] impl ops::Index> for Wtf8 { type Output = Wtf8; @@ -690,6 +737,28 @@ impl ops::Index> for Wtf8 { } } +/// Return 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. +#[cfg(not(stage0))] +impl ops::Index> for Wtf8 { + type Output = Wtf8; + + #[inline] + fn index(&self, range: ops::RangeTo) -> &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) + } + } +} + +#[cfg(stage0)] impl ops::Index for Wtf8 { type Output = Wtf8; @@ -699,6 +768,16 @@ impl ops::Index for Wtf8 { } } +#[cfg(not(stage0))] +impl ops::Index 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 -- cgit 1.4.1-3-g733a5 From 8389253df0431e58bfe0a8e0e3949d58ebe7400f Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Wed, 18 Mar 2015 09:14:54 -0700 Subject: Add generic conversion traits This commit: * Introduces `std::convert`, providing an implementation of RFC 529. * Deprecates the `AsPath`, `AsOsStr`, and `IntoBytes` traits, all in favor of the corresponding generic conversion traits. Consequently, various IO APIs now take `AsRef` rather than `AsPath`, and so on. Since the types provided by `std` implement both traits, this should cause relatively little breakage. * Deprecates many `from_foo` constructors in favor of `from`. * Changes `PathBuf::new` to take no argument (creating an empty buffer, as per convention). The previous behavior is now available as `PathBuf::from`. * De-stabilizes `IntoCow`. It's not clear whether we need this separate trait. Closes #22751 Closes #14433 [breaking-change] --- src/compiletest/compiletest.rs | 10 +- src/compiletest/header.rs | 4 +- src/compiletest/runtest.rs | 2 +- src/libcollections/borrow.rs | 11 +- src/libcollections/lib.rs | 1 + src/libcollections/slice.rs | 11 +- src/libcollections/str.rs | 28 ++--- src/libcollections/string.rs | 23 ++++ src/libcollections/vec.rs | 52 +++++++-- src/libcore/convert.rs | 113 +++++++++++++++++++ src/libcore/lib.rs | 1 + src/libcore/option.rs | 17 +++ src/libcore/prelude.rs | 1 + src/libcore/result.rs | 21 +++- src/libcore/slice.rs | 5 + src/libcore/str/mod.rs | 4 + src/libgraphviz/lib.rs | 1 + src/librustc/lib.rs | 2 + src/librustc/metadata/cstore.rs | 2 +- src/librustc/metadata/filesearch.rs | 6 +- src/librustc/metadata/loader.rs | 2 +- src/librustc/middle/traits/select.rs | 2 +- src/librustc/session/config.rs | 2 +- src/librustc/session/search_paths.rs | 2 +- src/librustc_back/archive.rs | 2 +- src/librustc_back/fs.rs | 2 +- src/librustc_back/lib.rs | 1 + src/librustc_back/rpath.rs | 2 +- src/librustc_back/target/mod.rs | 4 +- src/librustc_borrowck/lib.rs | 1 + src/librustc_driver/driver.rs | 6 +- src/librustc_driver/lib.rs | 13 ++- src/librustc_lint/builtin.rs | 4 +- src/librustc_trans/back/link.rs | 8 +- src/librustc_trans/lib.rs | 1 + src/librustc_trans/save/mod.rs | 4 +- src/librustc_trans/trans/debuginfo.rs | 2 +- src/librustc_typeck/collect.rs | 8 +- src/librustdoc/clean/mod.rs | 2 +- src/librustdoc/externalfiles.rs | 2 +- src/librustdoc/html/render.rs | 6 +- src/librustdoc/lib.rs | 11 +- src/librustdoc/test.rs | 2 +- src/libserialize/lib.rs | 1 + src/libserialize/serialize.rs | 2 +- src/libstd/env.rs | 6 +- src/libstd/ffi/c_str.rs | 11 +- src/libstd/ffi/os_str.rs | 77 ++++++++++++- src/libstd/fs/mod.rs | 70 ++++++------ src/libstd/fs/tempdir.rs | 7 +- src/libstd/lib.rs | 3 + src/libstd/net/ip.rs | 1 - src/libstd/os.rs | 5 +- src/libstd/path.rs | 200 +++++++++++++++++++++++++++++----- src/libstd/prelude/v1.rs | 4 + src/libstd/process.rs | 6 +- src/libstd/sys/unix/fs2.rs | 3 +- src/libstd/sys/unix/os.rs | 8 +- src/libsyntax/codemap.rs | 3 +- src/libsyntax/ext/source_util.rs | 2 +- src/libsyntax/lib.rs | 2 + src/libsyntax/parse/parser.rs | 4 +- src/libterm/lib.rs | 1 + src/libterm/terminfo/searcher.rs | 12 +- src/libtest/lib.rs | 5 +- src/rustbook/book.rs | 8 +- src/rustbook/build.rs | 6 +- src/rustbook/main.rs | 1 + src/test/run-pass/env-home-dir.rs | 10 +- 69 files changed, 666 insertions(+), 196 deletions(-) create mode 100644 src/libcore/convert.rs (limited to 'src/libstd/sys') diff --git a/src/compiletest/compiletest.rs b/src/compiletest/compiletest.rs index 01c4e99b77c..1ee5917ac9c 100644 --- a/src/compiletest/compiletest.rs +++ b/src/compiletest/compiletest.rs @@ -20,6 +20,8 @@ #![feature(std_misc)] #![feature(test)] #![feature(path_ext)] +#![feature(convert)] +#![feature(str_char)] #![deny(warnings)] @@ -115,7 +117,7 @@ pub fn parse_config(args: Vec ) -> Config { fn opt_path(m: &getopts::Matches, nm: &str) -> PathBuf { match m.opt_str(nm) { - Some(s) => PathBuf::new(&s), + Some(s) => PathBuf::from(&s), None => panic!("no option (=path) found for {}", nm), } } @@ -130,10 +132,10 @@ pub fn parse_config(args: Vec ) -> Config { compile_lib_path: matches.opt_str("compile-lib-path").unwrap(), run_lib_path: matches.opt_str("run-lib-path").unwrap(), rustc_path: opt_path(matches, "rustc-path"), - clang_path: matches.opt_str("clang-path").map(|s| PathBuf::new(&s)), + clang_path: matches.opt_str("clang-path").map(|s| PathBuf::from(&s)), valgrind_path: matches.opt_str("valgrind-path"), force_valgrind: matches.opt_present("force-valgrind"), - llvm_bin_path: matches.opt_str("llvm-bin-path").map(|s| PathBuf::new(&s)), + llvm_bin_path: matches.opt_str("llvm-bin-path").map(|s| PathBuf::from(&s)), src_base: opt_path(matches, "src-base"), build_base: opt_path(matches, "build-base"), aux_base: opt_path(matches, "aux-base"), @@ -141,7 +143,7 @@ pub fn parse_config(args: Vec ) -> Config { mode: matches.opt_str("mode").unwrap().parse().ok().expect("invalid mode"), run_ignored: matches.opt_present("ignored"), filter: filter, - logfile: matches.opt_str("logfile").map(|s| PathBuf::new(&s)), + logfile: matches.opt_str("logfile").map(|s| PathBuf::from(&s)), runtool: matches.opt_str("runtool"), host_rustcflags: matches.opt_str("host-rustcflags"), target_rustcflags: matches.opt_str("target-rustcflags"), diff --git a/src/compiletest/header.rs b/src/compiletest/header.rs index 29123173f5b..e1ad66c69e4 100644 --- a/src/compiletest/header.rs +++ b/src/compiletest/header.rs @@ -328,10 +328,10 @@ fn parse_exec_env(line: &str) -> Option<(String, String)> { fn parse_pp_exact(line: &str, testfile: &Path) -> Option { match parse_name_value_directive(line, "pp-exact") { - Some(s) => Some(PathBuf::new(&s)), + Some(s) => Some(PathBuf::from(&s)), None => { if parse_name_directive(line, "pp-exact") { - testfile.file_name().map(|s| PathBuf::new(s)) + testfile.file_name().map(|s| PathBuf::from(s)) } else { None } diff --git a/src/compiletest/runtest.rs b/src/compiletest/runtest.rs index a754bd950f7..319248cb810 100644 --- a/src/compiletest/runtest.rs +++ b/src/compiletest/runtest.rs @@ -1440,7 +1440,7 @@ fn aux_output_dir_name(config: &Config, testfile: &Path) -> PathBuf { } fn output_testname(testfile: &Path) -> PathBuf { - PathBuf::new(testfile.file_stem().unwrap()) + PathBuf::from(testfile.file_stem().unwrap()) } fn output_base_name(config: &Config, testfile: &Path) -> PathBuf { diff --git a/src/libcollections/borrow.rs b/src/libcollections/borrow.rs index 4bedbdeb368..88d59f699d1 100644 --- a/src/libcollections/borrow.rs +++ b/src/libcollections/borrow.rs @@ -14,6 +14,7 @@ use core::clone::Clone; use core::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd}; +use core::convert::AsRef; use core::hash::{Hash, Hasher}; use core::marker::Sized; use core::ops::Deref; @@ -291,10 +292,9 @@ impl<'a, B: ?Sized> Hash for Cow<'a, B> where B: Hash + ToOwned } /// Trait for moving into a `Cow` -#[stable(feature = "rust1", since = "1.0.0")] +#[unstable(feature = "into_cow", reason = "may be replaced by `convert::Into`")] pub trait IntoCow<'a, B: ?Sized> where B: ToOwned { /// Moves `self` into `Cow` - #[stable(feature = "rust1", since = "1.0.0")] fn into_cow(self) -> Cow<'a, B>; } @@ -304,3 +304,10 @@ impl<'a, B: ?Sized> IntoCow<'a, B> for Cow<'a, B> where B: ToOwned { self } } + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T: Clone> AsRef for Cow<'a, T> { + fn as_ref(&self) -> &T { + self + } +} diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs index c4a01496763..156c90f1e84 100644 --- a/src/libcollections/lib.rs +++ b/src/libcollections/lib.rs @@ -36,6 +36,7 @@ #![feature(unsafe_no_drop_flag)] #![feature(step_by)] #![feature(str_char)] +#![feature(convert)] #![cfg_attr(test, feature(rand, rustc_private, test))] #![cfg_attr(test, allow(deprecated))] // rand diff --git a/src/libcollections/slice.rs b/src/libcollections/slice.rs index 45864153dd7..0a0307aef32 100644 --- a/src/libcollections/slice.rs +++ b/src/libcollections/slice.rs @@ -88,6 +88,7 @@ #![stable(feature = "rust1", since = "1.0.0")] use alloc::boxed::Box; +use core::convert::AsRef; use core::clone::Clone; use core::cmp::Ordering::{self, Greater, Less}; use core::cmp::{self, Ord, PartialEq}; @@ -1088,23 +1089,23 @@ pub trait SliceConcatExt { fn connect(&self, sep: &T) -> U; } -impl> SliceConcatExt> for [V] { +impl> SliceConcatExt> for [V] { fn concat(&self) -> Vec { - let size = self.iter().fold(0, |acc, v| acc + v.as_slice().len()); + let size = self.iter().fold(0, |acc, v| acc + v.as_ref().len()); let mut result = Vec::with_capacity(size); for v in self { - result.push_all(v.as_slice()) + result.push_all(v.as_ref()) } result } fn connect(&self, sep: &T) -> Vec { - let size = self.iter().fold(0, |acc, v| acc + v.as_slice().len()); + let size = self.iter().fold(0, |acc, v| acc + v.as_ref().len()); let mut result = Vec::with_capacity(size + self.len()); let mut first = true; for v in self { if first { first = false } else { result.push(sep.clone()) } - result.push_all(v.as_slice()) + result.push_all(v.as_ref()) } result } diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs index 3a289e4ef37..c014ddc069d 100644 --- a/src/libcollections/str.rs +++ b/src/libcollections/str.rs @@ -61,10 +61,10 @@ use core::iter::AdditiveIterator; use core::iter::{Iterator, IteratorExt, Extend}; use core::option::Option::{self, Some, None}; use core::result::Result; -use core::slice::AsSlice; use core::str as core_str; use unicode::str::{UnicodeStr, Utf16Encoder}; +use core::convert::AsRef; use vec_deque::VecDeque; use borrow::{Borrow, ToOwned}; use string::String; @@ -86,51 +86,47 @@ pub use core::str::{Searcher, ReverseSearcher, DoubleEndedSearcher, SearchStep}; Section: Creating a string */ -impl SliceConcatExt for [S] { +impl> SliceConcatExt for [S] { fn concat(&self) -> String { - let s = self.as_slice(); - - if s.is_empty() { + if self.is_empty() { return String::new(); } // `len` calculation may overflow but push_str will check boundaries - let len = s.iter().map(|s| s.as_slice().len()).sum(); + let len = self.iter().map(|s| s.as_ref().len()).sum(); let mut result = String::with_capacity(len); - for s in s { - result.push_str(s.as_slice()) + for s in self { + result.push_str(s.as_ref()) } result } fn connect(&self, sep: &str) -> String { - let s = self.as_slice(); - - if s.is_empty() { + if self.is_empty() { return String::new(); } // concat is faster if sep.is_empty() { - return s.concat(); + return self.concat(); } // this is wrong without the guarantee that `self` is non-empty // `len` calculation may overflow but push_str but will check boundaries - let len = sep.len() * (s.len() - 1) - + s.iter().map(|s| s.as_slice().len()).sum(); + let len = sep.len() * (self.len() - 1) + + self.iter().map(|s| s.as_ref().len()).sum(); let mut result = String::with_capacity(len); let mut first = true; - for s in s { + for s in self { if first { first = false; } else { result.push_str(sep); } - result.push_str(s.as_slice()); + result.push_str(s.as_ref()); } result } diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index cd6f27bf65f..6463949ac8a 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -814,6 +814,7 @@ impl<'a, 'b> PartialEq> for &'b str { } #[unstable(feature = "collections", reason = "waiting on Str stabilization")] +#[allow(deprecated)] impl Str for String { #[inline] #[stable(feature = "rust1", since = "1.0.0")] @@ -973,6 +974,27 @@ impl ToString for T { } } +#[stable(feature = "rust1", since = "1.0.0")] +impl AsRef for String { + fn as_ref(&self) -> &str { + self + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a> From<&'a str> for String { + fn from(s: &'a str) -> String { + s.to_string() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Into> for String { + fn into(self) -> Vec { + self.into_bytes() + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl IntoCow<'static, str> for String { #[inline] @@ -989,6 +1011,7 @@ impl<'a> IntoCow<'a, str> for &'a str { } } +#[allow(deprecated)] impl<'a> Str for Cow<'a, str> { #[inline] fn as_slice<'b>(&'b self) -> &'b str { diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index b0e8dc7d0b6..85833c34049 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -1369,7 +1369,7 @@ impl ops::Index for Vec { type Output = [T]; #[inline] fn index(&self, _index: &ops::RangeFull) -> &[T] { - self.as_slice() + self } } @@ -1406,7 +1406,13 @@ impl ops::IndexMut for Vec { impl ops::Deref for Vec { type Target = [T]; - fn deref(&self) -> &[T] { self.as_slice() } + fn deref(&self) -> &[T] { + unsafe { + let p = *self.ptr; + assume(p != 0 as *mut T); + slice::from_raw_parts(p, self.len) + } + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -1548,6 +1554,7 @@ impl Ord for Vec { } } +#[allow(deprecated)] impl AsSlice for Vec { /// Returns a slice into `self`. /// @@ -1562,11 +1569,7 @@ impl AsSlice for Vec { #[inline] #[stable(feature = "rust1", since = "1.0.0")] fn as_slice(&self) -> &[T] { - unsafe { - let p = *self.ptr; - assume(p != 0 as *mut T); - slice::from_raw_parts(p, self.len) - } + self } } @@ -1614,6 +1617,41 @@ impl fmt::Debug for Vec { } } +#[stable(feature = "rust1", since = "1.0.0")] +impl AsRef> for Vec { + fn as_ref(&self) -> &Vec { + self + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Into> for Vec { + fn into(self) -> Vec { + self + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl AsRef<[T]> for Vec { + fn as_ref(&self) -> &[T] { + self + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T: Clone> From<&'a [T]> for Vec { + fn from(s: &'a [T]) -> Vec { + s.to_vec() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a> From<&'a str> for Vec { + fn from(s: &'a str) -> Vec { + s.as_bytes().to_vec() + } +} + //////////////////////////////////////////////////////////////////////////////// // Clone-on-write //////////////////////////////////////////////////////////////////////////////// diff --git a/src/libcore/convert.rs b/src/libcore/convert.rs new file mode 100644 index 00000000000..65a226d37cb --- /dev/null +++ b/src/libcore/convert.rs @@ -0,0 +1,113 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Traits for conversions between types. +//! +//! The traits in this module provide a general way to talk about +//! conversions from one type to another. They follow the standard +//! Rust conventions of `as`/`to`/`into`/`from`. + +#![unstable(feature = "convert", + reason = "recently added, experimental traits")] + +use marker::Sized; + +/// A cheap, reference-to-reference conversion. +pub trait AsRef { + /// Perform the conversion. + fn as_ref(&self) -> &T; +} + +/// A cheap, mutable reference-to-mutable reference conversion. +pub trait AsMut { + /// Perform the conversion. + fn as_mut(&mut self) -> &mut T; +} + +/// A conversion that consumes `self`, which may or may not be +/// expensive. +pub trait Into: Sized { + /// Perform the conversion. + fn into(self) -> T; +} + +/// Construct `Self` via a conversion. +pub trait From { + /// Perform the conversion. + fn from(T) -> Self; +} + +//////////////////////////////////////////////////////////////////////////////// +// GENERIC IMPLS +//////////////////////////////////////////////////////////////////////////////// + +// As implies Into +impl<'a, T: ?Sized, U: ?Sized> Into<&'a U> for &'a T where T: AsRef { + fn into(self) -> &'a U { + self.as_ref() + } +} + +// As lifts over & +impl<'a, T: ?Sized, U: ?Sized> AsRef for &'a T where T: AsRef { + fn as_ref(&self) -> &U { + >::as_ref(*self) + } +} + +// As lifts over &mut +impl<'a, T: ?Sized, U: ?Sized> AsRef for &'a mut T where T: AsRef { + fn as_ref(&self) -> &U { + >::as_ref(*self) + } +} + +// AsMut implies Into +impl<'a, T: ?Sized, U: ?Sized> Into<&'a mut U> for &'a mut T where T: AsMut { + fn into(self) -> &'a mut U { + (*self).as_mut() + } +} + +// AsMut lifts over &mut +impl<'a, T: ?Sized, U: ?Sized> AsMut for &'a mut T where T: AsMut { + fn as_mut(&mut self) -> &mut U { + (*self).as_mut() + } +} + +// From implies Into +impl Into for T where U: From { + fn into(self) -> U { + U::from(self) + } +} + +//////////////////////////////////////////////////////////////////////////////// +// CONCRETE IMPLS +//////////////////////////////////////////////////////////////////////////////// + +impl AsRef<[T]> for [T] { + fn as_ref(&self) -> &[T] { + self + } +} + +impl AsMut<[T]> for [T] { + fn as_mut(&mut self) -> &mut [T] { + self + } +} + +impl AsRef for str { + fn as_ref(&self) -> &str { + self + } +} diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 29cc11d5a60..e31542c183a 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -125,6 +125,7 @@ pub mod ops; pub mod cmp; pub mod clone; pub mod default; +pub mod convert; /* Core types and methods on primitives */ diff --git a/src/libcore/option.rs b/src/libcore/option.rs index 455c68d4319..4a1e24c1f40 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -154,6 +154,7 @@ use mem; use ops::{Deref, FnOnce}; use result::Result::{Ok, Err}; use result::Result; +#[allow(deprecated)] use slice::AsSlice; use slice; @@ -701,6 +702,19 @@ impl Option { pub fn take(&mut self) -> Option { mem::replace(self, None) } + + /// Convert from `Option` to `&[T]` (without copying) + #[inline] + #[unstable(feature = "as_slice", since = "unsure of the utility here")] + pub fn as_slice<'a>(&'a self) -> &'a [T] { + match *self { + Some(ref x) => slice::ref_slice(x), + None => { + let result: &[_] = &[]; + result + } + } + } } impl<'a, T: Clone, D: Deref> Option { @@ -752,6 +766,9 @@ impl Option { #[unstable(feature = "core", reason = "waiting on the stability of the trait itself")] +#[deprecated(since = "1.0.0", + reason = "use the inherent method instead")] +#[allow(deprecated)] impl AsSlice for Option { /// Convert from `Option` to `&[T]` (without copying) #[inline] diff --git a/src/libcore/prelude.rs b/src/libcore/prelude.rs index 4bf7f85284c..424829939b9 100644 --- a/src/libcore/prelude.rs +++ b/src/libcore/prelude.rs @@ -36,6 +36,7 @@ pub use mem::drop; pub use char::CharExt; pub use clone::Clone; pub use cmp::{PartialEq, PartialOrd, Eq, Ord}; +pub use convert::{AsRef, AsMut, Into, From}; pub use iter::{Extend, IteratorExt}; pub use iter::{Iterator, DoubleEndedIterator}; pub use iter::{ExactSizeIterator}; diff --git a/src/libcore/result.rs b/src/libcore/result.rs index bc8d53e2a57..4b3cda46c1d 100644 --- a/src/libcore/result.rs +++ b/src/libcore/result.rs @@ -240,6 +240,7 @@ use iter::{Iterator, IteratorExt, DoubleEndedIterator, FromIterator, ExactSizeIterator, IntoIterator}; use ops::{FnMut, FnOnce}; use option::Option::{self, None, Some}; +#[allow(deprecated)] use slice::AsSlice; use slice; @@ -408,6 +409,20 @@ impl Result { } } + /// Convert from `Result` to `&[T]` (without copying) + #[inline] + #[unstable(feature = "as_slice", since = "unsure of the utility here")] + pub fn as_slice(&self) -> &[T] { + match *self { + Ok(ref x) => slice::ref_slice(x), + Err(_) => { + // work around lack of implicit coercion from fixed-size array to slice + let emp: &[_] = &[]; + emp + } + } + } + /// Convert from `Result` to `&mut [T]` (without copying) /// /// ``` @@ -788,10 +803,14 @@ impl Result { // Trait implementations ///////////////////////////////////////////////////////////////////////////// +#[unstable(feature = "core", + reason = "waiting on the stability of the trait itself")] +#[deprecated(since = "1.0.0", + reason = "use inherent method instead")] +#[allow(deprecated)] impl AsSlice for Result { /// Convert from `Result` to `&[T]` (without copying) #[inline] - #[stable(feature = "rust1", since = "1.0.0")] fn as_slice<'a>(&'a self) -> &'a [T] { match *self { Ok(ref x) => slice::ref_slice(x), diff --git a/src/libcore/slice.rs b/src/libcore/slice.rs index 907b2eba80c..e7535ae1d17 100644 --- a/src/libcore/slice.rs +++ b/src/libcore/slice.rs @@ -596,24 +596,29 @@ impl ops::IndexMut for [T] { /// Data that is viewable as a slice. #[unstable(feature = "core", reason = "will be replaced by slice syntax")] +#[deprecated(since = "1.0.0", + reason = "use std::convert::AsRef<[T]> instead")] pub trait AsSlice { /// Work with `self` as a slice. fn as_slice<'a>(&'a self) -> &'a [T]; } #[unstable(feature = "core", reason = "trait is experimental")] +#[allow(deprecated)] impl AsSlice for [T] { #[inline(always)] fn as_slice<'a>(&'a self) -> &'a [T] { self } } #[unstable(feature = "core", reason = "trait is experimental")] +#[allow(deprecated)] impl<'a, T, U: ?Sized + AsSlice> AsSlice for &'a U { #[inline(always)] fn as_slice(&self) -> &[T] { AsSlice::as_slice(*self) } } #[unstable(feature = "core", reason = "trait is experimental")] +#[allow(deprecated)] impl<'a, T, U: ?Sized + AsSlice> AsSlice for &'a mut U { #[inline(always)] fn as_slice(&self) -> &[T] { AsSlice::as_slice(*self) } diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index e8181395b5c..e31aebbd74e 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -1275,16 +1275,20 @@ mod traits { reason = "Instead of taking this bound generically, this trait will be \ replaced with one of slicing syntax (&foo[..]), deref coercions, or \ a more generic conversion trait")] +#[deprecated(since = "1.0.0", + reason = "use std::convert::AsRef instead")] pub trait Str { /// Work with `self` as a slice. fn as_slice<'a>(&'a self) -> &'a str; } +#[allow(deprecated)] impl Str for str { #[inline] fn as_slice<'a>(&'a self) -> &'a str { self } } +#[allow(deprecated)] impl<'a, S: ?Sized> Str for &'a S where S: Str { #[inline] fn as_slice(&self) -> &str { Str::as_slice(*self) } diff --git a/src/libgraphviz/lib.rs b/src/libgraphviz/lib.rs index 0e080459344..6d95d5e0724 100644 --- a/src/libgraphviz/lib.rs +++ b/src/libgraphviz/lib.rs @@ -280,6 +280,7 @@ html_root_url = "http://doc.rust-lang.org/nightly/")] #![feature(int_uint)] #![feature(collections)] +#![feature(into_cow)] use self::LabelText::*; diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 97ed391fdfc..793eff6a9da 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -43,6 +43,8 @@ #![feature(path_ext)] #![feature(str_words)] #![feature(str_char)] +#![feature(convert)] +#![feature(into_cow)] #![cfg_attr(test, feature(test))] extern crate arena; diff --git a/src/librustc/metadata/cstore.rs b/src/librustc/metadata/cstore.rs index 47ec31c0f1a..dc9d1e11e8e 100644 --- a/src/librustc/metadata/cstore.rs +++ b/src/librustc/metadata/cstore.rs @@ -243,7 +243,7 @@ impl crate_metadata { impl MetadataBlob { pub fn as_slice<'a>(&'a self) -> &'a [u8] { let slice = match *self { - MetadataVec(ref vec) => vec.as_slice(), + MetadataVec(ref vec) => &vec[..], MetadataArchive(ref ar) => ar.as_slice(), }; if slice.len() < 4 { diff --git a/src/librustc/metadata/filesearch.rs b/src/librustc/metadata/filesearch.rs index 22a4a6fc978..284e76b328a 100644 --- a/src/librustc/metadata/filesearch.rs +++ b/src/librustc/metadata/filesearch.rs @@ -156,7 +156,7 @@ impl<'a> FileSearch<'a> { // Returns a list of directories where target-specific tool binaries are located. pub fn get_tools_search_paths(&self) -> Vec { - let mut p = PathBuf::new(self.sysroot); + let mut p = PathBuf::from(self.sysroot); p.push(&find_libdir(self.sysroot)); p.push(&rustlibdir()); p.push(&self.triple); @@ -166,7 +166,7 @@ impl<'a> FileSearch<'a> { } pub fn relative_target_lib_path(sysroot: &Path, target_triple: &str) -> PathBuf { - let mut p = PathBuf::new(&find_libdir(sysroot)); + let mut p = PathBuf::from(&find_libdir(sysroot)); assert!(p.is_relative()); p.push(&rustlibdir()); p.push(target_triple); @@ -224,7 +224,7 @@ pub fn rust_path() -> Vec { Some(env_path) => { let env_path_components = env_path.split(PATH_ENTRY_SEPARATOR); - env_path_components.map(|s| PathBuf::new(s)).collect() + env_path_components.map(|s| PathBuf::from(s)).collect() } None => Vec::new() }; diff --git a/src/librustc/metadata/loader.rs b/src/librustc/metadata/loader.rs index e466dc8a3a0..7854db81146 100644 --- a/src/librustc/metadata/loader.rs +++ b/src/librustc/metadata/loader.rs @@ -628,7 +628,7 @@ impl<'a> Context<'a> { let mut rlibs = HashMap::new(); let mut dylibs = HashMap::new(); { - let locs = locs.iter().map(|l| PathBuf::new(&l[..])).filter(|loc| { + let locs = locs.iter().map(|l| PathBuf::from(l)).filter(|loc| { if !loc.exists() { sess.err(&format!("extern location for {} does not exist: {}", self.crate_name, loc.display())); diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs index 7dfbccea0dc..882caecb382 100644 --- a/src/librustc/middle/traits/select.rs +++ b/src/librustc/middle/traits/select.rs @@ -1762,7 +1762,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { match obligations { Ok(mut obls) => { - obls.push_all(normalized.obligations.as_slice()); + obls.push_all(&normalized.obligations); obls }, Err(ErrorReported) => Vec::new() diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index e368a669133..a7c67a08631 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -907,7 +907,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { let cg = build_codegen_options(matches); - let sysroot_opt = matches.opt_str("sysroot").map(|m| PathBuf::new(&m)); + let sysroot_opt = matches.opt_str("sysroot").map(|m| PathBuf::from(&m)); let target = matches.opt_str("target").unwrap_or( host_triple().to_string()); let opt_level = { diff --git a/src/librustc/session/search_paths.rs b/src/librustc/session/search_paths.rs index 3c5d9744505..3dc31f9524e 100644 --- a/src/librustc/session/search_paths.rs +++ b/src/librustc/session/search_paths.rs @@ -54,7 +54,7 @@ impl SearchPaths { if path.is_empty() { early_error("empty search path given via `-L`"); } - self.paths.push((kind, PathBuf::new(path))); + self.paths.push((kind, PathBuf::from(path))); } pub fn iter(&self, kind: PathKind) -> Iter { diff --git a/src/librustc_back/archive.rs b/src/librustc_back/archive.rs index aec8ac38a5a..2cc51a723f2 100644 --- a/src/librustc_back/archive.rs +++ b/src/librustc_back/archive.rs @@ -319,7 +319,7 @@ impl<'a> ArchiveBuilder<'a> { }; let new_filename = self.work_dir.path().join(&filename[..]); try!(fs::rename(&file, &new_filename)); - self.members.push(PathBuf::new(&filename)); + self.members.push(PathBuf::from(filename)); } Ok(()) } diff --git a/src/librustc_back/fs.rs b/src/librustc_back/fs.rs index c29cbb352a3..6d8891dd4fe 100644 --- a/src/librustc_back/fs.rs +++ b/src/librustc_back/fs.rs @@ -19,7 +19,7 @@ use std::path::{Path, PathBuf}; pub fn realpath(original: &Path) -> io::Result { let old = old_path::Path::new(original.to_str().unwrap()); match old_realpath(&old) { - Ok(p) => Ok(PathBuf::new(p.as_str().unwrap())), + Ok(p) => Ok(PathBuf::from(p.as_str().unwrap())), Err(e) => Err(io::Error::new(io::ErrorKind::Other, "realpath error", Some(e.to_string()))) diff --git a/src/librustc_back/lib.rs b/src/librustc_back/lib.rs index 99d24a60130..086742f740c 100644 --- a/src/librustc_back/lib.rs +++ b/src/librustc_back/lib.rs @@ -49,6 +49,7 @@ #![feature(std_misc)] #![feature(path_relative_from)] #![feature(step_by)] +#![feature(convert)] extern crate syntax; extern crate serialize; diff --git a/src/librustc_back/rpath.rs b/src/librustc_back/rpath.rs index 4f9f1447d8a..8dd65c5b893 100644 --- a/src/librustc_back/rpath.rs +++ b/src/librustc_back/rpath.rs @@ -106,7 +106,7 @@ fn get_rpath_relative_to_output(config: &mut RPathConfig, lib: &Path) -> String } fn relativize(path: &Path, rel: &Path) -> PathBuf { - let mut res = PathBuf::new(""); + let mut res = PathBuf::new(); let mut cur = rel; while !path.starts_with(cur) { res.push(".."); diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs index 4663901a7b4..c464658f447 100644 --- a/src/librustc_back/target/mod.rs +++ b/src/librustc_back/target/mod.rs @@ -393,11 +393,11 @@ impl Target { let path = { let mut target = target.to_string(); target.push_str(".json"); - PathBuf::new(&target) + PathBuf::from(target) }; let target_path = env::var_os("RUST_TARGET_PATH") - .unwrap_or(OsString::from_str("")); + .unwrap_or(OsString::new()); // FIXME 16351: add a sane default search path? diff --git a/src/librustc_borrowck/lib.rs b/src/librustc_borrowck/lib.rs index e09457970e1..e927ea5b86c 100644 --- a/src/librustc_borrowck/lib.rs +++ b/src/librustc_borrowck/lib.rs @@ -28,6 +28,7 @@ #![feature(rustc_private)] #![feature(staged_api)] #![feature(unsafe_destructor)] +#![feature(into_cow)] #[macro_use] extern crate log; #[macro_use] extern crate syntax; diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index dc27a301109..4c654cbf27d 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -468,7 +468,7 @@ pub fn phase_2_configure_and_expand(sess: &Session, // dependent dlls. Note that this uses cfg!(windows) as opposed to // targ_cfg because syntax extensions are always loaded for the host // compiler, not for the target. - let mut _old_path = OsString::from_str(""); + let mut _old_path = OsString::new(); if cfg!(windows) { _old_path = env::var_os("PATH").unwrap_or(_old_path); let mut new_path = sess.host_filesearch(PathKind::All).get_dylib_search_paths(); @@ -752,7 +752,7 @@ pub fn phase_5_run_llvm_passes(sess: &Session, pub fn phase_6_link_output(sess: &Session, trans: &trans::CrateTranslation, outputs: &OutputFilenames) { - let old_path = env::var_os("PATH").unwrap_or(OsString::from_str("")); + let old_path = env::var_os("PATH").unwrap_or(OsString::new()); let mut new_path = sess.host_filesearch(PathKind::All).get_tools_search_paths(); new_path.extend(env::split_paths(&old_path)); env::set_var("PATH", &env::join_paths(new_path.iter()).unwrap()); @@ -927,7 +927,7 @@ pub fn build_output_filenames(input: &Input, // We want to toss everything after the final '.' let dirpath = match *odir { Some(ref d) => d.clone(), - None => PathBuf::new("") + None => PathBuf::new() }; // If a crate name is present, we use it as the link name diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 0071e4434ef..5e6f2fb835b 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -39,6 +39,7 @@ #![feature(io)] #![feature(set_stdio)] #![feature(unicode)] +#![feature(convert)] extern crate arena; extern crate flate; @@ -163,8 +164,8 @@ pub fn run_compiler<'a>(args: &[String], // Extract output directory and file from matches. fn make_output(matches: &getopts::Matches) -> (Option, Option) { - let odir = matches.opt_str("out-dir").map(|o| PathBuf::new(&o)); - let ofile = matches.opt_str("o").map(|o| PathBuf::new(&o)); + let odir = matches.opt_str("out-dir").map(|o| PathBuf::from(&o)); + let ofile = matches.opt_str("o").map(|o| PathBuf::from(&o)); (odir, ofile) } @@ -177,7 +178,7 @@ fn make_input(free_matches: &[String]) -> Option<(Input, Option)> { io::stdin().read_to_string(&mut src).unwrap(); Some((Input::Str(src), None)) } else { - Some((Input::File(PathBuf::new(ifile)), Some(PathBuf::new(ifile)))) + Some((Input::File(PathBuf::from(ifile)), Some(PathBuf::from(ifile)))) } } else { None @@ -858,9 +859,9 @@ pub fn diagnostics_registry() -> diagnostics::registry::Registry { use syntax::diagnostics::registry::Registry; let all_errors = Vec::new() + - rustc::diagnostics::DIAGNOSTICS.as_slice() + - rustc_typeck::diagnostics::DIAGNOSTICS.as_slice() + - rustc_resolve::diagnostics::DIAGNOSTICS.as_slice(); + &rustc::diagnostics::DIAGNOSTICS[..] + + &rustc_typeck::diagnostics::DIAGNOSTICS[..] + + &rustc_resolve::diagnostics::DIAGNOSTICS[..]; Registry::new(&*all_errors) } diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index f6f82c65374..7958dabe74e 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -2056,7 +2056,7 @@ impl LintPass for InvalidNoMangleItems { } }, ast::ItemStatic(..) => { - if attr::contains_name(it.attrs.as_slice(), "no_mangle") && + if attr::contains_name(&it.attrs, "no_mangle") && !cx.exported_items.contains(&it.id) { let msg = format!("static {} is marked #[no_mangle], but not exported", it.ident); @@ -2064,7 +2064,7 @@ impl LintPass for InvalidNoMangleItems { } }, ast::ItemConst(..) => { - if attr::contains_name(it.attrs.as_slice(), "no_mangle") { + if attr::contains_name(&it.attrs, "no_mangle") { // Const items do not refer to a particular location in memory, and therefore // don't have anything to attach a symbol to let msg = "const items should never be #[no_mangle], consider instead using \ diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index 34a23f3efac..c0a2e24d6f5 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -877,7 +877,7 @@ fn link_args(cmd: &mut Command, if t.options.is_like_osx { let morestack = lib_path.join("libmorestack.a"); - let mut v = OsString::from_str("-Wl,-force_load,"); + let mut v = OsString::from("-Wl,-force_load,"); v.push(&morestack); cmd.arg(&v); } else { @@ -1002,7 +1002,7 @@ fn link_args(cmd: &mut Command, cmd.args(&["-dynamiclib", "-Wl,-dylib"]); if sess.opts.cg.rpath { - let mut v = OsString::from_str("-Wl,-install_name,@rpath/"); + let mut v = OsString::from("-Wl,-install_name,@rpath/"); v.push(out_filename.file_name().unwrap()); cmd.arg(&v); } @@ -1020,7 +1020,7 @@ fn link_args(cmd: &mut Command, let mut get_install_prefix_lib_path = || { let install_prefix = option_env!("CFG_PREFIX").expect("CFG_PREFIX"); let tlib = filesearch::relative_target_lib_path(sysroot, target_triple); - let mut path = PathBuf::new(install_prefix); + let mut path = PathBuf::from(install_prefix); path.push(&tlib); path @@ -1102,7 +1102,7 @@ fn add_local_native_libraries(cmd: &mut Command, sess: &Session) { &sess.target.target.options.staticlib_suffix, &search_path[..], &sess.diagnostic().handler); - let mut v = OsString::from_str("-Wl,-force_load,"); + let mut v = OsString::from("-Wl,-force_load,"); v.push(&lib); cmd.arg(&v); } diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index efc81da560b..176e3805a31 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -41,6 +41,7 @@ #![feature(path_ext)] #![feature(fs)] #![feature(hash)] +#![feature(convert)] #![feature(path_relative_from)] extern crate arena; diff --git a/src/librustc_trans/save/mod.rs b/src/librustc_trans/save/mod.rs index 83bb5efb425..765e93f5b82 100644 --- a/src/librustc_trans/save/mod.rs +++ b/src/librustc_trans/save/mod.rs @@ -1509,10 +1509,10 @@ pub fn process_crate(sess: &Session, // find a path to dump our data to let mut root_path = match env::var_os("DXR_RUST_TEMP_FOLDER") { - Some(val) => PathBuf::new(&val), + Some(val) => PathBuf::from(val), None => match odir { Some(val) => val.join("dxr"), - None => PathBuf::new("dxr-temp"), + None => PathBuf::from("dxr-temp"), }, }; diff --git a/src/librustc_trans/trans/debuginfo.rs b/src/librustc_trans/trans/debuginfo.rs index 3e8cc46e255..b9c59a0bc78 100644 --- a/src/librustc_trans/trans/debuginfo.rs +++ b/src/librustc_trans/trans/debuginfo.rs @@ -1695,7 +1695,7 @@ fn declare_local<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, }; let name = CString::new(name.as_bytes()).unwrap(); - match (variable_access, [].as_slice()) { + match (variable_access, &[][..]) { (DirectVariable { alloca }, address_operations) | (IndirectVariable {alloca, address_operations}, _) => { let metadata = unsafe { diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 97cc3ac7c48..f1352cacae4 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -690,7 +690,7 @@ fn convert_field<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } } -fn convert_associated_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, +fn as_refsociated_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, container: ImplOrTraitItemContainer, ident: ast::Ident, id: ast::NodeId, @@ -835,7 +835,7 @@ fn convert_item(ccx: &CrateCtxt, it: &ast::Item) { "associated items are not allowed in inherent impls"); } - convert_associated_type(ccx, ImplContainer(local_def(it.id)), + as_refsociated_type(ccx, ImplContainer(local_def(it.id)), impl_item.ident, impl_item.id, impl_item.vis); let typ = ccx.icx(&ty_predicates).to_ty(&ExplicitRscope, ty); @@ -917,7 +917,7 @@ fn convert_item(ccx: &CrateCtxt, it: &ast::Item) { match trait_item.node { ast::MethodTraitItem(..) => {} ast::TypeTraitItem(..) => { - convert_associated_type(ccx, TraitContainer(local_def(it.id)), + as_refsociated_type(ccx, TraitContainer(local_def(it.id)), trait_item.ident, trait_item.id, ast::Public); } } @@ -1987,7 +1987,7 @@ fn conv_param_bounds<'a,'tcx>(astconv: &AstConv<'tcx>, builtin_bounds, trait_bounds, region_bounds - } = astconv::partition_bounds(tcx, span, ast_bounds.as_slice()); + } = astconv::partition_bounds(tcx, span, &ast_bounds); let mut projection_bounds = Vec::new(); diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 421549f8b7e..8e9408c9ebc 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -188,7 +188,7 @@ impl<'a, 'tcx> Clean for visit_ast::RustdocVisitor<'a, 'tcx> { let src = match cx.input { Input::File(ref path) => path.clone(), - Input::Str(_) => PathBuf::new("") // FIXME: this is wrong + Input::Str(_) => PathBuf::new() // FIXME: this is wrong }; Crate { diff --git a/src/librustdoc/externalfiles.rs b/src/librustdoc/externalfiles.rs index c2b6c940cae..57cb87e1b2d 100644 --- a/src/librustdoc/externalfiles.rs +++ b/src/librustdoc/externalfiles.rs @@ -47,7 +47,7 @@ pub fn load_string(input: &Path) -> io::Result> { macro_rules! load_or_return { ($input: expr, $cant_read: expr, $not_utf8: expr) => { { - let input = PathBuf::new($input); + let input = PathBuf::from(&$input[..]); match ::externalfiles::load_string(&input) { Err(e) => { let _ = writeln!(&mut io::stderr(), diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 81daac7b90f..d9b40fb6ba6 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -300,7 +300,7 @@ pub fn run(mut krate: clean::Crate, passes: HashSet) -> io::Result<()> { let src_root = match krate.src.parent() { Some(p) => p.to_path_buf(), - None => PathBuf::new(""), + None => PathBuf::new(), }; let mut cx = Context { dst: dst, @@ -784,7 +784,7 @@ impl<'a> DocFolder for SourceCollector<'a> { impl<'a> SourceCollector<'a> { /// Renders the given filename into its corresponding HTML source file. fn emit_source(&mut self, filename: &str) -> io::Result<()> { - let p = PathBuf::new(filename); + let p = PathBuf::from(filename); // If we couldn't open this file, then just returns because it // probably means that it's some standard library macro thing and we @@ -819,7 +819,7 @@ impl<'a> SourceCollector<'a> { let mut fname = p.file_name().expect("source has no filename") .to_os_string(); fname.push(".html"); - cur.push(&fname); + cur.push(&fname[..]); let mut w = BufWriter::new(try!(File::create(&cur))); let title = format!("{} -- source", cur.file_name().unwrap() diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index d747ed3f119..12baa849cc9 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -38,6 +38,7 @@ #![feature(file_path)] #![feature(path_ext)] #![feature(path_relative_from)] +#![feature(convert)] extern crate arena; extern crate getopts; @@ -251,7 +252,7 @@ pub fn main_args(args: &[String]) -> int { let should_test = matches.opt_present("test"); let markdown_input = input.ends_with(".md") || input.ends_with(".markdown"); - let output = matches.opt_str("o").map(|s| PathBuf::new(&s)); + let output = matches.opt_str("o").map(|s| PathBuf::from(&s)); let cfgs = matches.opt_strs("cfg"); let external_html = match ExternalHtml::load( @@ -271,7 +272,7 @@ pub fn main_args(args: &[String]) -> int { return test::run(input, cfgs, libs, externs, test_args, crate_name) } (false, true) => return markdown::render(input, - output.unwrap_or(PathBuf::new("doc")), + output.unwrap_or(PathBuf::from("doc")), &matches, &external_html, !matches.opt_present("markdown-no-toc")), (false, false) => {} @@ -289,7 +290,7 @@ pub fn main_args(args: &[String]) -> int { match matches.opt_str("w").as_ref().map(|s| &**s) { Some("html") | None => { match html::render::run(krate, &external_html, - output.unwrap_or(PathBuf::new("doc")), + output.unwrap_or(PathBuf::from("doc")), passes.into_iter().collect()) { Ok(()) => {} Err(e) => panic!("failed to generate documentation: {}", e), @@ -297,7 +298,7 @@ pub fn main_args(args: &[String]) -> int { } Some("json") => { match json_output(krate, json_plugins, - output.unwrap_or(PathBuf::new("doc.json"))) { + output.unwrap_or(PathBuf::from("doc.json"))) { Ok(()) => {} Err(e) => panic!("failed to write json: {}", e), } @@ -376,7 +377,7 @@ fn rust_input(cratefile: &str, externs: core::Externs, matches: &getopts::Matche let cfgs = matches.opt_strs("cfg"); let triple = matches.opt_str("target"); - let cr = PathBuf::new(cratefile); + let cr = PathBuf::from(cratefile); info!("starting to run rustc"); let (tx, rx) = channel(); diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index e2f8a6f82c6..0b79fa7970d 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -46,7 +46,7 @@ pub fn run(input: &str, mut test_args: Vec, crate_name: Option) -> int { - let input_path = PathBuf::new(input); + let input_path = PathBuf::from(input); let input = config::Input::File(input_path.clone()); let sessopts = config::Options { diff --git a/src/libserialize/lib.rs b/src/libserialize/lib.rs index 90cb88046e5..f320f723c2e 100644 --- a/src/libserialize/lib.rs +++ b/src/libserialize/lib.rs @@ -37,6 +37,7 @@ Core encoding and decoding interfaces. #![feature(std_misc)] #![feature(unicode)] #![feature(str_char)] +#![feature(convert)] #![cfg_attr(test, feature(test))] // test harness access diff --git a/src/libserialize/serialize.rs b/src/libserialize/serialize.rs index 71f9e01706d..5e9baa9b9e9 100644 --- a/src/libserialize/serialize.rs +++ b/src/libserialize/serialize.rs @@ -579,7 +579,7 @@ impl Encodable for path::PathBuf { impl Decodable for path::PathBuf { fn decode(d: &mut D) -> Result { let bytes: String = try!(Decodable::decode(d)); - Ok(path::PathBuf::new(&bytes)) + Ok(path::PathBuf::from(bytes)) } } diff --git a/src/libstd/env.rs b/src/libstd/env.rs index 24882c7f7ab..9d6933ce9c8 100644 --- a/src/libstd/env.rs +++ b/src/libstd/env.rs @@ -23,7 +23,7 @@ use error::Error; use ffi::{OsString, AsOsStr}; use fmt; use io; -use path::{AsPath, PathBuf}; +use path::{self, Path, PathBuf}; use sync::atomic::{AtomicIsize, ATOMIC_ISIZE_INIT, Ordering}; use sync::{StaticMutex, MUTEX_INIT}; use sys::os as os_imp; @@ -67,8 +67,8 @@ pub fn current_dir() -> io::Result { /// println!("Successfully changed working directory to {}!", root.display()); /// ``` #[stable(feature = "env", since = "1.0.0")] -pub fn set_current_dir(p: &P) -> io::Result<()> { - os_imp::chdir(p.as_path()) +pub fn set_current_dir + ?Sized>(p: &P) -> io::Result<()> { + os_imp::chdir(p.as_ref()) } static ENV_LOCK: StaticMutex = MUTEX_INIT; diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs index fc4f03ff3a5..1760445a0fc 100644 --- a/src/libstd/ffi/c_str.rs +++ b/src/libstd/ffi/c_str.rs @@ -10,6 +10,7 @@ #![unstable(feature = "std_misc")] +use convert::Into; use cmp::{PartialEq, Eq, PartialOrd, Ord, Ordering}; use error::{Error, FromError}; use fmt; @@ -130,6 +131,8 @@ pub struct NulError(usize, Vec); /// A conversion trait used by the constructor of `CString` for types that can /// be converted to a vector of bytes. +#[deprecated(since = "1.0.0", reason = "use std::convert::Into> instead")] +#[unstable(feature = "std_misc")] pub trait IntoBytes { /// Consumes this container, returning a vector of bytes. fn into_bytes(self) -> Vec; @@ -163,8 +166,8 @@ impl CString { /// internal 0 byte. The error returned will contain the bytes as well as /// the position of the nul byte. #[stable(feature = "rust1", since = "1.0.0")] - pub fn new(t: T) -> Result { - let bytes = t.into_bytes(); + pub fn new>>(t: T) -> Result { + let bytes = t.into(); match bytes.iter().position(|x| *x == 0) { Some(i) => Err(NulError(i, bytes)), None => Ok(unsafe { CString::from_vec_unchecked(bytes) }), @@ -433,15 +436,19 @@ pub unsafe fn c_str_to_bytes_with_nul<'a>(raw: &'a *const libc::c_char) slice::from_raw_parts(*(raw as *const _ as *const *const u8), len as usize) } +#[allow(deprecated)] impl<'a> IntoBytes for &'a str { fn into_bytes(self) -> Vec { self.as_bytes().to_vec() } } +#[allow(deprecated)] impl<'a> IntoBytes for &'a [u8] { fn into_bytes(self) -> Vec { self.to_vec() } } +#[allow(deprecated)] impl IntoBytes for String { fn into_bytes(self) -> Vec { self.into_bytes() } } +#[allow(deprecated)] impl IntoBytes for Vec { fn into_bytes(self) -> Vec { self } } diff --git a/src/libstd/ffi/os_str.rs b/src/libstd/ffi/os_str.rs index feacbf1e98b..4d411046632 100644 --- a/src/libstd/ffi/os_str.rs +++ b/src/libstd/ffi/os_str.rs @@ -63,16 +63,18 @@ pub struct OsStr { impl OsString { /// Constructs an `OsString` at no cost by consuming a `String`. #[stable(feature = "rust1", since = "1.0.0")] + #[deprecated(since = "1.0.0", reason = "use `from` instead")] pub fn from_string(s: String) -> OsString { - OsString { inner: Buf::from_string(s) } + OsString::from(s) } /// Constructs an `OsString` by copying from a `&str` slice. /// /// Equivalent to: `OsString::from_string(String::from_str(s))`. #[stable(feature = "rust1", since = "1.0.0")] + #[deprecated(since = "1.0.0", reason = "use `from` instead")] pub fn from_str(s: &str) -> OsString { - OsString { inner: Buf::from_str(s) } + OsString::from(s) } /// Constructs a new empty `OsString`. @@ -98,8 +100,36 @@ impl OsString { /// Extend the string with the given `&OsStr` slice. #[stable(feature = "rust1", since = "1.0.0")] - pub fn push(&mut self, s: &T) { - self.inner.push_slice(&s.as_os_str().inner) + pub fn push>(&mut self, s: T) { + self.inner.push_slice(&s.as_ref().inner) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl From for OsString { + fn from(s: String) -> OsString { + OsString { inner: Buf::from_string(s) } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a> From<&'a String> for OsString { + fn from(s: &'a String) -> OsString { + OsString { inner: Buf::from_str(s) } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a> From<&'a str> for OsString { + fn from(s: &'a str) -> OsString { + OsString { inner: Buf::from_str(s) } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a> From<&'a OsStr> for OsString { + fn from(s: &'a OsStr) -> OsString { + OsString { inner: s.inner.to_owned() } } } @@ -316,37 +346,76 @@ impl ToOwned for OsStr { } #[stable(feature = "rust1", since = "1.0.0")] +#[deprecated(since = "1.0.0", reason = "trait is deprecated")] impl<'a, T: AsOsStr + ?Sized> AsOsStr for &'a T { fn as_os_str(&self) -> &OsStr { (*self).as_os_str() } } +#[stable(feature = "rust1", since = "1.0.0")] +#[deprecated(since = "1.0.0", reason = "trait is deprecated")] impl AsOsStr for OsStr { fn as_os_str(&self) -> &OsStr { self } } +#[stable(feature = "rust1", since = "1.0.0")] +#[deprecated(since = "1.0.0", reason = "trait is deprecated")] impl AsOsStr for OsString { fn as_os_str(&self) -> &OsStr { &self[..] } } +#[stable(feature = "rust1", since = "1.0.0")] +#[deprecated(since = "1.0.0", reason = "trait is deprecated")] impl AsOsStr for str { fn as_os_str(&self) -> &OsStr { OsStr::from_str(self) } } +#[stable(feature = "rust1", since = "1.0.0")] +#[deprecated(since = "1.0.0", reason = "trait is deprecated")] impl AsOsStr for String { fn as_os_str(&self) -> &OsStr { OsStr::from_str(&self[..]) } } +#[stable(feature = "rust1", since = "1.0.0")] +impl AsRef for OsStr { + fn as_ref(&self) -> &OsStr { + self + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl AsRef for OsString { + fn as_ref(&self) -> &OsStr { + self + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl AsRef for str { + fn as_ref(&self) -> &OsStr { + OsStr::from_str(self) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl AsRef for String { + fn as_ref(&self) -> &OsStr { + OsStr::from_str(&self[..]) + } +} + #[allow(deprecated)] +#[stable(feature = "rust1", since = "1.0.0")] +#[deprecated(since = "1.0.0", reason = "trait is deprecated")] impl AsOsStr for Path { #[cfg(unix)] fn as_os_str(&self) -> &OsStr { diff --git a/src/libstd/fs/mod.rs b/src/libstd/fs/mod.rs index 7df6d6887a2..ab65004f5d1 100644 --- a/src/libstd/fs/mod.rs +++ b/src/libstd/fs/mod.rs @@ -20,7 +20,7 @@ use core::prelude::*; use io::{self, Error, ErrorKind, SeekFrom, Seek, Read, Write}; -use path::{AsPath, Path, PathBuf}; +use path::{Path, PathBuf}; use sys::fs2 as fs_imp; use sys_common::{AsInnerMut, FromInner, AsInner}; use vec::Vec; @@ -129,7 +129,7 @@ impl File { /// This function will return an error if `path` does not already exist. /// Other errors may also be returned according to `OpenOptions::open`. #[stable(feature = "rust1", since = "1.0.0")] - pub fn open(path: P) -> io::Result { + pub fn open>(path: P) -> io::Result { OpenOptions::new().read(true).open(path) } @@ -140,7 +140,7 @@ impl File { /// /// See the `OpenOptions::open` function for more details. #[stable(feature = "rust1", since = "1.0.0")] - pub fn create(path: P) -> io::Result { + pub fn create>(path: P) -> io::Result { OpenOptions::new().write(true).create(true).truncate(true).open(path) } @@ -302,8 +302,8 @@ impl OpenOptions { /// permissions for /// * Filesystem-level errors (full disk, etc) #[stable(feature = "rust1", since = "1.0.0")] - pub fn open(&self, path: P) -> io::Result { - let path = path.as_path(); + pub fn open>(&self, path: P) -> io::Result { + let path = path.as_ref(); let inner = try!(fs_imp::File::open(path, &self.0)); Ok(File { path: path.to_path_buf(), inner: inner }) } @@ -415,8 +415,8 @@ impl DirEntry { /// user lacks permissions to remove the file, or if some other filesystem-level /// error occurs. #[stable(feature = "rust1", since = "1.0.0")] -pub fn remove_file(path: P) -> io::Result<()> { - fs_imp::unlink(path.as_path()) +pub fn remove_file>(path: P) -> io::Result<()> { + fs_imp::unlink(path.as_ref()) } /// Given a path, query the file system to get information about a file, @@ -443,8 +443,8 @@ pub fn remove_file(path: P) -> io::Result<()> { /// permissions to perform a `metadata` call on the given `path` or if there /// is no entry in the filesystem at the provided path. #[stable(feature = "rust1", since = "1.0.0")] -pub fn metadata(path: P) -> io::Result { - fs_imp::stat(path.as_path()).map(Metadata) +pub fn metadata>(path: P) -> io::Result { + fs_imp::stat(path.as_ref()).map(Metadata) } /// Rename a file or directory to a new name. @@ -464,8 +464,8 @@ pub fn metadata(path: P) -> io::Result { /// reside on separate filesystems, or if some other intermittent I/O error /// occurs. #[stable(feature = "rust1", since = "1.0.0")] -pub fn rename(from: P, to: Q) -> io::Result<()> { - fs_imp::rename(from.as_path(), to.as_path()) +pub fn rename, Q: AsRef>(from: P, to: Q) -> io::Result<()> { + fs_imp::rename(from.as_ref(), to.as_ref()) } /// Copies the contents of one file to another. This function will also @@ -494,9 +494,9 @@ pub fn rename(from: P, to: Q) -> io::Result<()> { /// * The current process does not have the permission rights to access /// `from` or write `to` #[stable(feature = "rust1", since = "1.0.0")] -pub fn copy(from: P, to: Q) -> io::Result { - let from = from.as_path(); - let to = to.as_path(); +pub fn copy, Q: AsRef>(from: P, to: Q) -> io::Result { + let from = from.as_ref(); + let to = to.as_ref(); if !from.is_file() { return Err(Error::new(ErrorKind::InvalidInput, "the source path is not an existing file", @@ -517,16 +517,16 @@ pub fn copy(from: P, to: Q) -> io::Result { /// The `dst` path will be a link pointing to the `src` path. Note that systems /// often require these two paths to both be located on the same filesystem. #[stable(feature = "rust1", since = "1.0.0")] -pub fn hard_link(src: P, dst: Q) -> io::Result<()> { - fs_imp::link(src.as_path(), dst.as_path()) +pub fn hard_link, Q: AsRef>(src: P, dst: Q) -> io::Result<()> { + fs_imp::link(src.as_ref(), dst.as_ref()) } /// Creates a new soft link on the filesystem. /// /// The `dst` path will be a soft link pointing to the `src` path. #[stable(feature = "rust1", since = "1.0.0")] -pub fn soft_link(src: P, dst: Q) -> io::Result<()> { - fs_imp::symlink(src.as_path(), dst.as_path()) +pub fn soft_link, Q: AsRef>(src: P, dst: Q) -> io::Result<()> { + fs_imp::symlink(src.as_ref(), dst.as_ref()) } /// Reads a soft link, returning the file that the link points to. @@ -537,8 +537,8 @@ pub fn soft_link(src: P, dst: Q) -> io::Result<()> { /// reading a file that does not exist or reading a file that is not a soft /// link. #[stable(feature = "rust1", since = "1.0.0")] -pub fn read_link(path: P) -> io::Result { - fs_imp::readlink(path.as_path()) +pub fn read_link>(path: P) -> io::Result { + fs_imp::readlink(path.as_ref()) } /// Create a new, empty directory at the provided path @@ -556,8 +556,8 @@ pub fn read_link(path: P) -> io::Result { /// This function will return an error if the user lacks permissions to make a /// new directory at the provided `path`, or if the directory already exists. #[stable(feature = "rust1", since = "1.0.0")] -pub fn create_dir(path: P) -> io::Result<()> { - fs_imp::mkdir(path.as_path()) +pub fn create_dir>(path: P) -> io::Result<()> { + fs_imp::mkdir(path.as_ref()) } /// Recursively create a directory and all of its parent components if they @@ -570,8 +570,8 @@ pub fn create_dir(path: P) -> io::Result<()> { /// error conditions for when a directory is being created (after it is /// determined to not exist) are outlined by `fs::create_dir`. #[stable(feature = "rust1", since = "1.0.0")] -pub fn create_dir_all(path: P) -> io::Result<()> { - let path = path.as_path(); +pub fn create_dir_all>(path: P) -> io::Result<()> { + let path = path.as_ref(); if path.is_dir() { return Ok(()) } if let Some(p) = path.parent() { try!(create_dir_all(p)) } create_dir(path) @@ -592,8 +592,8 @@ pub fn create_dir_all(path: P) -> io::Result<()> { /// This function will return an error if the user lacks permissions to remove /// the directory at the provided `path`, or if the directory isn't empty. #[stable(feature = "rust1", since = "1.0.0")] -pub fn remove_dir(path: P) -> io::Result<()> { - fs_imp::rmdir(path.as_path()) +pub fn remove_dir>(path: P) -> io::Result<()> { + fs_imp::rmdir(path.as_ref()) } /// Removes a directory at this path, after removing all its contents. Use @@ -606,8 +606,8 @@ pub fn remove_dir(path: P) -> io::Result<()> { /// /// See `file::remove_file` and `fs::remove_dir` #[stable(feature = "rust1", since = "1.0.0")] -pub fn remove_dir_all(path: P) -> io::Result<()> { - let path = path.as_path(); +pub fn remove_dir_all>(path: P) -> io::Result<()> { + let path = path.as_ref(); for child in try!(read_dir(path)) { let child = try!(child).path(); let stat = try!(lstat(&*child)); @@ -659,8 +659,8 @@ pub fn remove_dir_all(path: P) -> io::Result<()> { /// the process lacks permissions to view the contents or if the `path` points /// at a non-directory file #[stable(feature = "rust1", since = "1.0.0")] -pub fn read_dir(path: P) -> io::Result { - fs_imp::readdir(path.as_path()).map(ReadDir) +pub fn read_dir>(path: P) -> io::Result { + fs_imp::readdir(path.as_ref()).map(ReadDir) } /// Returns an iterator that will recursively walk the directory structure @@ -675,7 +675,7 @@ pub fn read_dir(path: P) -> io::Result { reason = "the precise semantics and defaults for a recursive walk \ may change and this may end up accounting for files such \ as symlinks differently")] -pub fn walk_dir(path: P) -> io::Result { +pub fn walk_dir>(path: P) -> io::Result { let start = try!(read_dir(path)); Ok(WalkDir { cur: Some(start), stack: Vec::new() }) } @@ -761,9 +761,9 @@ impl PathExt for Path { reason = "the argument type of u64 is not quite appropriate for \ this function and may change if the standard library \ gains a type to represent a moment in time")] -pub fn set_file_times(path: P, accessed: u64, +pub fn set_file_times>(path: P, accessed: u64, modified: u64) -> io::Result<()> { - fs_imp::utimes(path.as_path(), accessed, modified) + fs_imp::utimes(path.as_ref(), accessed, modified) } /// Changes the permissions found on a file or a directory. @@ -790,8 +790,8 @@ pub fn set_file_times(path: P, accessed: u64, reason = "a more granual ability to set specific permissions may \ be exposed on the Permissions structure itself and this \ method may not always exist")] -pub fn set_permissions(path: P, perm: Permissions) -> io::Result<()> { - fs_imp::set_perm(path.as_path(), perm.0) +pub fn set_permissions>(path: P, perm: Permissions) -> io::Result<()> { + fs_imp::set_perm(path.as_ref(), perm.0) } #[cfg(test)] diff --git a/src/libstd/fs/tempdir.rs b/src/libstd/fs/tempdir.rs index 8f32d7a5864..a9717e36323 100644 --- a/src/libstd/fs/tempdir.rs +++ b/src/libstd/fs/tempdir.rs @@ -18,7 +18,7 @@ use prelude::v1::*; use env; use io::{self, Error, ErrorKind}; use fs; -use path::{self, PathBuf, AsPath}; +use path::{self, PathBuf}; use rand::{thread_rng, Rng}; /// A wrapper for a path to temporary directory implementing automatic @@ -43,10 +43,9 @@ impl TempDir { /// /// If no directory can be created, `Err` is returned. #[allow(deprecated)] // rand usage - pub fn new_in(tmpdir: &P, prefix: &str) - -> io::Result { + pub fn new_in>(tmpdir: P, prefix: &str) -> io::Result { let storage; - let mut tmpdir = tmpdir.as_path(); + let mut tmpdir = tmpdir.as_ref(); if !tmpdir.is_absolute() { let cur_dir = try!(env::current_dir()); storage = cur_dir.join(tmpdir); diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index b055796ba54..1488c7969f6 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -126,8 +126,10 @@ #![feature(hash)] #![feature(int_uint)] #![feature(unique)] +#![feature(convert)] #![feature(allow_internal_unstable)] #![feature(str_char)] +#![feature(into_cow)] #![cfg_attr(test, feature(test, rustc_private))] // Don't link to std. We are std. @@ -169,6 +171,7 @@ pub use core::any; pub use core::cell; pub use core::clone; #[cfg(not(test))] pub use core::cmp; +pub use core::convert; pub use core::default; #[allow(deprecated)] pub use core::finally; diff --git a/src/libstd/net/ip.rs b/src/libstd/net/ip.rs index 73c2464a6b2..d737ad17ff8 100644 --- a/src/libstd/net/ip.rs +++ b/src/libstd/net/ip.rs @@ -374,7 +374,6 @@ impl fmt::Display for Ipv6Addr { .iter() .map(|&seg| format!("{:x}", seg)) .collect::>() - .as_slice() .connect(":") } diff --git a/src/libstd/os.rs b/src/libstd/os.rs index 3870b8614ff..72f9338b456 100644 --- a/src/libstd/os.rs +++ b/src/libstd/os.rs @@ -38,6 +38,7 @@ use self::MapError::*; use boxed::Box; use clone::Clone; +use convert::From; use env; use error::{FromError, Error}; use ffi::{OsString, OsStr}; @@ -79,12 +80,12 @@ fn err2old(new: ::io::Error) -> IoError { #[cfg(windows)] fn path2new(path: &Path) -> PathBuf { - PathBuf::new(path.as_str().unwrap()) + PathBuf::from(path.as_str().unwrap()) } #[cfg(unix)] fn path2new(path: &Path) -> PathBuf { use os::unix::prelude::*; - PathBuf::new(::from_bytes(path.as_vec())) + PathBuf::from(::from_bytes(path.as_vec())) } #[cfg(unix)] diff --git a/src/libstd/path.rs b/src/libstd/path.rs index ddceed14cc6..25372c1cb7c 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -106,6 +106,7 @@ use cmp; use iter::{self, IntoIterator}; use mem; use ops::{self, Deref}; +use string::String; use vec::Vec; use fmt; @@ -527,6 +528,13 @@ impl<'a> Component<'a> { } } +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a> AsRef for Component<'a> { + fn as_ref(&self) -> &OsStr { + self.as_os_str() + } +} + /// The core iterator giving the components of a path. /// /// See the module documentation for an in-depth explanation of components and @@ -601,6 +609,7 @@ impl<'a> Components<'a> { } /// Extract a slice corresponding to the portion of the path remaining for iteration. + #[stable(feature = "rust1", since = "1.0.0")] pub fn as_path(&self) -> &'a Path { let mut comps = self.clone(); if comps.front == State::Body { comps.trim_left(); } @@ -695,6 +704,20 @@ impl<'a> Components<'a> { } } +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a> AsRef for Components<'a> { + fn as_ref(&self) -> &Path { + self.as_path() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a> AsRef for Components<'a> { + fn as_ref(&self) -> &OsStr { + self.as_path().as_os_str() + } +} + impl<'a> Iter<'a> { /// Extract a slice corresponding to the portion of the path remaining for iteration. #[stable(feature = "rust1", since = "1.0.0")] @@ -703,6 +726,20 @@ impl<'a> Iter<'a> { } } +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a> AsRef for Iter<'a> { + fn as_ref(&self) -> &Path { + self.as_path() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a> AsRef for Iter<'a> { + fn as_ref(&self) -> &OsStr { + self.as_path().as_os_str() + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl<'a> Iterator for Iter<'a> { type Item = &'a OsStr; @@ -873,11 +910,10 @@ impl PathBuf { unsafe { mem::transmute(self) } } - /// Allocate a `PathBuf` with initial contents given by the - /// argument. + /// Allocate an empty `PathBuf`. #[stable(feature = "rust1", since = "1.0.0")] - pub fn new(s: S) -> PathBuf { - PathBuf { inner: s.as_os_str().to_os_string() } + pub fn new() -> PathBuf { + PathBuf { inner: OsString::new() } } /// Extend `self` with `path`. @@ -890,8 +926,8 @@ impl PathBuf { /// replaces everything except for the prefix (if any) of `self`. /// * if `path` has a prefix but no root, it replaces `self. #[stable(feature = "rust1", since = "1.0.0")] - pub fn push(&mut self, path: P) { - let path = path.as_path(); + pub fn push>(&mut self, path: P) { + let path = path.as_ref(); // in general, a separator is needed if the rightmost byte is not a separator let mut need_sep = self.as_mut_vec().last().map(|c| !is_sep_byte(*c)).unwrap_or(false); @@ -958,12 +994,12 @@ impl PathBuf { /// assert!(buf == PathBuf::new("/baz.txt")); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn set_file_name(&mut self, file_name: S) { + pub fn set_file_name>(&mut self, file_name: S) { if self.file_name().is_some() { let popped = self.pop(); debug_assert!(popped); } - self.push(file_name.as_os_str()); + self.push(file_name.as_ref()); } /// Updates `self.extension()` to `extension`. @@ -973,15 +1009,15 @@ impl PathBuf { /// Otherwise, returns `true`; if `self.extension()` is `None`, the extension /// is added; otherwise it is replaced. #[stable(feature = "rust1", since = "1.0.0")] - pub fn set_extension(&mut self, extension: S) -> bool { + pub fn set_extension>(&mut self, extension: S) -> bool { if self.file_name().is_none() { return false; } let mut stem = match self.file_stem() { Some(stem) => stem.to_os_string(), - None => OsString::from_str(""), + None => OsString::new(), }; - let extension = extension.as_os_str(); + let extension = extension.as_ref(); if os_str_as_u8_slice(extension).len() > 0 { stem.push("."); stem.push(extension); @@ -999,16 +1035,65 @@ impl PathBuf { } #[stable(feature = "rust1", since = "1.0.0")] -impl iter::FromIterator

for PathBuf { +impl<'a> From<&'a Path> for PathBuf { + fn from(s: &'a Path) -> PathBuf { + s.to_path_buf() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a> From<&'a str> for PathBuf { + fn from(s: &'a str) -> PathBuf { + PathBuf::from(OsString::from(s)) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a> From<&'a String> for PathBuf { + fn from(s: &'a String) -> PathBuf { + PathBuf::from(OsString::from(s)) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl From for PathBuf { + fn from(s: String) -> PathBuf { + PathBuf::from(OsString::from(s)) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a> From<&'a OsStr> for PathBuf { + fn from(s: &'a OsStr) -> PathBuf { + PathBuf::from(OsString::from(s)) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a> From<&'a OsString> for PathBuf { + fn from(s: &'a OsString) -> PathBuf { + PathBuf::from(s.to_os_string()) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl From for PathBuf { + fn from(s: OsString) -> PathBuf { + PathBuf { inner: s } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl> iter::FromIterator

for PathBuf { fn from_iter>(iter: I) -> PathBuf { - let mut buf = PathBuf::new(""); + let mut buf = PathBuf::new(); buf.extend(iter); buf } } #[stable(feature = "rust1", since = "1.0.0")] -impl iter::Extend

for PathBuf { +impl> iter::Extend

for PathBuf { fn extend>(&mut self, iter: I) { for p in iter { self.push(p) @@ -1084,12 +1169,27 @@ impl cmp::Ord for PathBuf { } #[stable(feature = "rust1", since = "1.0.0")] +impl AsRef for PathBuf { + fn as_ref(&self) -> &OsStr { + &self.inner[..] + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +#[deprecated(since = "1.0.0", reason = "trait is deprecated")] impl AsOsStr for PathBuf { fn as_os_str(&self) -> &OsStr { &self.inner[..] } } +#[stable(feature = "rust1", since = "1.0.0")] +impl Into for PathBuf { + fn into(self) -> OsString { + self.inner + } +} + /// A slice of a path (akin to `str`). /// /// This type supports a number of operations for inspecting a path, including @@ -1133,8 +1233,14 @@ impl Path { /// /// This is a cost-free conversion. #[stable(feature = "rust1", since = "1.0.0")] - pub fn new(s: &S) -> &Path { - unsafe { mem::transmute(s.as_os_str()) } + pub fn new + ?Sized>(s: &S) -> &Path { + unsafe { mem::transmute(s.as_ref()) } + } + + /// Yield the underlying `OsStr` slice. + #[stable(feature = "rust1", since = "1.0.0")] + pub fn as_os_str(&self) -> &OsStr { + &self.inner } /// Yield a `&str` slice if the `Path` is valid unicode. @@ -1156,7 +1262,7 @@ impl Path { /// Convert a `Path` to an owned `PathBuf`. #[stable(feature = "rust1", since = "1.0.0")] pub fn to_path_buf(&self) -> PathBuf { - PathBuf::new(self) + PathBuf::from(self.inner.to_os_string()) } /// A path is *absolute* if it is independent of the current directory. @@ -1244,22 +1350,21 @@ impl Path { /// Returns a path that, when joined onto `base`, yields `self`. #[unstable(feature = "path_relative_from", reason = "see #23284")] - pub fn relative_from<'a, P: ?Sized>(&'a self, base: &'a P) -> Option<&Path> where - P: AsPath + pub fn relative_from<'a, P: ?Sized + AsRef>(&'a self, base: &'a P) -> Option<&Path> { - iter_after(self.components(), base.as_path().components()).map(|c| c.as_path()) + iter_after(self.components(), base.as_ref().components()).map(|c| c.as_path()) } /// Determines whether `base` is a prefix of `self`. #[stable(feature = "rust1", since = "1.0.0")] - pub fn starts_with(&self, base: P) -> bool { - iter_after(self.components(), base.as_path().components()).is_some() + pub fn starts_with>(&self, base: P) -> bool { + iter_after(self.components(), base.as_ref().components()).is_some() } /// Determines whether `child` is a suffix of `self`. #[stable(feature = "rust1", since = "1.0.0")] - pub fn ends_with(&self, child: P) -> bool { - iter_after(self.components().rev(), child.as_path().components().rev()).is_some() + pub fn ends_with>(&self, child: P) -> bool { + iter_after(self.components().rev(), child.as_ref().components().rev()).is_some() } /// Extract the stem (non-extension) portion of `self.file()`. @@ -1292,7 +1397,7 @@ impl Path { /// /// See `PathBuf::push` for more details on what it means to adjoin a path. #[stable(feature = "rust1", since = "1.0.0")] - pub fn join(&self, path: P) -> PathBuf { + pub fn join>(&self, path: P) -> PathBuf { let mut buf = self.to_path_buf(); buf.push(path); buf @@ -1302,7 +1407,7 @@ impl Path { /// /// See `PathBuf::set_file_name` for more details. #[stable(feature = "rust1", since = "1.0.0")] - pub fn with_file_name(&self, file_name: S) -> PathBuf { + pub fn with_file_name>(&self, file_name: S) -> PathBuf { let mut buf = self.to_path_buf(); buf.set_file_name(file_name); buf @@ -1312,7 +1417,7 @@ impl Path { /// /// See `PathBuf::set_extension` for more details. #[stable(feature = "rust1", since = "1.0.0")] - pub fn with_extension(&self, extension: S) -> PathBuf { + pub fn with_extension>(&self, extension: S) -> PathBuf { let mut buf = self.to_path_buf(); buf.set_extension(extension); buf @@ -1346,6 +1451,14 @@ impl Path { } #[stable(feature = "rust1", since = "1.0.0")] +impl AsRef for Path { + fn as_ref(&self) -> &OsStr { + &self.inner + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +#[deprecated(since = "1.0.0", reason = "trait is deprecated")] impl AsOsStr for Path { fn as_os_str(&self) -> &OsStr { &self.inner @@ -1405,6 +1518,7 @@ impl cmp::Ord for Path { /// Freely convertible to a `Path`. #[unstable(feature = "std_misc")] +#[deprecated(since = "1.0.0", reason = "use std::convert::AsRef instead")] pub trait AsPath { /// Convert to a `Path`. #[unstable(feature = "std_misc")] @@ -1412,10 +1526,42 @@ pub trait AsPath { } #[unstable(feature = "std_misc")] +#[deprecated(since = "1.0.0", reason = "use std::convert::AsRef instead")] +#[allow(deprecated)] impl AsPath for T { fn as_path(&self) -> &Path { Path::new(self.as_os_str()) } } +#[stable(feature = "rust1", since = "1.0.0")] +impl AsRef for Path { + fn as_ref(&self) -> &Path { self } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl AsRef for OsStr { + fn as_ref(&self) -> &Path { Path::new(self) } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl AsRef for OsString { + fn as_ref(&self) -> &Path { Path::new(self) } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl AsRef for str { + fn as_ref(&self) -> &Path { Path::new(self) } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl AsRef for String { + fn as_ref(&self) -> &Path { Path::new(self) } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl AsRef for PathBuf { + fn as_ref(&self) -> &Path { self } +} + #[cfg(test)] mod tests { use super::*; diff --git a/src/libstd/prelude/v1.rs b/src/libstd/prelude/v1.rs index a0b4c80e9f3..6e12ac1a226 100644 --- a/src/libstd/prelude/v1.rs +++ b/src/libstd/prelude/v1.rs @@ -29,6 +29,8 @@ #[doc(no_inline)] pub use clone::Clone; #[stable(feature = "rust1", since = "1.0.0")] #[doc(no_inline)] pub use cmp::{PartialEq, PartialOrd, Eq, Ord}; +#[unstable(feature = "convert")] +#[doc(no_inline)] pub use convert::{AsRef, AsMut, Into, From}; #[stable(feature = "rust1", since = "1.0.0")] #[doc(no_inline)] pub use iter::DoubleEndedIterator; #[stable(feature = "rust1", since = "1.0.0")] @@ -40,8 +42,10 @@ #[stable(feature = "rust1", since = "1.0.0")] #[doc(no_inline)] pub use result::Result::{self, Ok, Err}; #[stable(feature = "rust1", since = "1.0.0")] +#[allow(deprecated)] #[doc(no_inline)] pub use slice::{SliceConcatExt, AsSlice}; #[stable(feature = "rust1", since = "1.0.0")] +#[allow(deprecated)] #[doc(no_inline)] pub use str::Str; #[stable(feature = "rust1", since = "1.0.0")] #[doc(no_inline)] pub use string::{String, ToString}; diff --git a/src/libstd/process.rs b/src/libstd/process.rs index 6b09636c1df..d11c3d22144 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -19,8 +19,8 @@ use io::prelude::*; use ffi::AsOsStr; use fmt; use io::{self, Error, ErrorKind}; -use path::AsPath; use libc; +use path; use sync::mpsc::{channel, Receiver}; use sys::pipe2::{self, AnonPipe}; use sys::process2::Process as ProcessImp; @@ -198,8 +198,8 @@ impl Command { /// Set the working directory for the child process. #[stable(feature = "process", since = "1.0.0")] - pub fn current_dir(&mut self, dir: P) -> &mut Command { - self.inner.cwd(dir.as_path().as_os_str()); + pub fn current_dir>(&mut self, dir: P) -> &mut Command { + self.inner.cwd(dir.as_ref().as_os_str()); self } diff --git a/src/libstd/sys/unix/fs2.rs b/src/libstd/sys/unix/fs2.rs index ea74aab3331..202e5ddaec4 100644 --- a/src/libstd/sys/unix/fs2.rs +++ b/src/libstd/sys/unix/fs2.rs @@ -338,8 +338,7 @@ pub fn readlink(p: &Path) -> io::Result { })); buf.set_len(n as usize); } - let s: OsString = OsStringExt::from_vec(buf); - Ok(PathBuf::new(&s)) + Ok(PathBuf::from(OsString::from_vec(buf))) } pub fn symlink(src: &Path, dst: &Path) -> io::Result<()> { diff --git a/src/libstd/sys/unix/os.rs b/src/libstd/sys/unix/os.rs index a5a2f71acb7..6c191689255 100644 --- a/src/libstd/sys/unix/os.rs +++ b/src/libstd/sys/unix/os.rs @@ -36,7 +36,7 @@ const BUF_BYTES: usize = 2048; const TMPBUF_SZ: usize = 128; fn bytes2path(b: &[u8]) -> PathBuf { - PathBuf::new(::from_bytes(b)) + PathBuf::from(::from_bytes(b)) } fn os2path(os: OsString) -> PathBuf { @@ -253,7 +253,7 @@ pub fn current_exe() -> io::Result { let err = _NSGetExecutablePath(v.as_mut_ptr() as *mut i8, &mut sz); if err != 0 { return Err(io::Error::last_os_error()); } v.set_len(sz as uint - 1); // chop off trailing NUL - Ok(PathBuf::new(OsString::from_vec(v))) + Ok(PathBuf::from(OsString::from_vec(v))) } } @@ -466,9 +466,9 @@ pub fn page_size() -> usize { pub fn temp_dir() -> PathBuf { getenv("TMPDIR".as_os_str()).map(os2path).unwrap_or_else(|| { if cfg!(target_os = "android") { - PathBuf::new("/data/local/tmp") + PathBuf::from("/data/local/tmp") } else { - PathBuf::new("/tmp") + PathBuf::from("/tmp") } }) } diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index 70aab26092c..1abe8d0a3c1 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -351,8 +351,7 @@ impl Encodable for FileMap { let max_line_length = if lines.len() == 1 { 0 } else { - lines.as_slice() - .windows(2) + lines.windows(2) .map(|w| w[1] - w[0]) .map(|bp| bp.to_usize()) .max() diff --git a/src/libsyntax/ext/source_util.rs b/src/libsyntax/ext/source_util.rs index c61aec0069d..31d8b207bb9 100644 --- a/src/libsyntax/ext/source_util.rs +++ b/src/libsyntax/ext/source_util.rs @@ -194,7 +194,7 @@ pub fn expand_include_bytes(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) fn res_rel_file(cx: &mut ExtCtxt, sp: codemap::Span, arg: &Path) -> PathBuf { // NB: relative paths are resolved relative to the compilation unit if !arg.is_absolute() { - let mut cu = PathBuf::new(&cx.codemap().span_to_filename(sp)); + let mut cu = PathBuf::from(&cx.codemap().span_to_filename(sp)); cu.pop(); cu.push(arg); cu diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index 9f217bba00a..9af7b9ab633 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -39,6 +39,8 @@ #![feature(unicode)] #![feature(path_ext)] #![feature(str_char)] +#![feature(convert)] +#![feature(into_cow)] extern crate arena; extern crate fmt_macros; diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 667af642744..e77786c1347 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -5064,8 +5064,8 @@ impl<'a> Parser<'a> { outer_attrs: &[ast::Attribute], id_sp: Span) -> (ast::Item_, Vec ) { - let mut prefix = PathBuf::new(&self.sess.span_diagnostic.cm - .span_to_filename(self.span)); + let mut prefix = PathBuf::from(&self.sess.span_diagnostic.cm + .span_to_filename(self.span)); prefix.pop(); let mut dir_path = prefix; for part in &self.mod_path_stack { diff --git a/src/libterm/lib.rs b/src/libterm/lib.rs index f517dca53cd..8e3c00bb805 100644 --- a/src/libterm/lib.rs +++ b/src/libterm/lib.rs @@ -62,6 +62,7 @@ #![feature(std_misc)] #![feature(str_char)] #![feature(path_ext)] +#![feature(convert)] #![cfg_attr(windows, feature(libc))] #[macro_use] extern crate log; diff --git a/src/libterm/terminfo/searcher.rs b/src/libterm/terminfo/searcher.rs index f47921cbf5e..66ee2b1ba87 100644 --- a/src/libterm/terminfo/searcher.rs +++ b/src/libterm/terminfo/searcher.rs @@ -31,7 +31,7 @@ pub fn get_dbpath_for_term(term: &str) -> Option> { // Find search directory match env::var_os("TERMINFO") { - Some(dir) => dirs_to_search.push(PathBuf::new(&dir)), + Some(dir) => dirs_to_search.push(PathBuf::from(dir)), None => { if homedir.is_some() { // ncurses compatibility; @@ -40,9 +40,9 @@ pub fn get_dbpath_for_term(term: &str) -> Option> { match env::var("TERMINFO_DIRS") { Ok(dirs) => for i in dirs.split(':') { if i == "" { - dirs_to_search.push(PathBuf::new("/usr/share/terminfo")); + dirs_to_search.push(PathBuf::from("/usr/share/terminfo")); } else { - dirs_to_search.push(PathBuf::new(i)); + dirs_to_search.push(PathBuf::from(i)); } }, // Found nothing in TERMINFO_DIRS, use the default paths: @@ -50,9 +50,9 @@ pub fn get_dbpath_for_term(term: &str) -> Option> { // ~/.terminfo, ncurses will search /etc/terminfo, then // /lib/terminfo, and eventually /usr/share/terminfo. Err(..) => { - dirs_to_search.push(PathBuf::new("/etc/terminfo")); - dirs_to_search.push(PathBuf::new("/lib/terminfo")); - dirs_to_search.push(PathBuf::new("/usr/share/terminfo")); + dirs_to_search.push(PathBuf::from("/etc/terminfo")); + dirs_to_search.push(PathBuf::from("/lib/terminfo")); + dirs_to_search.push(PathBuf::from("/usr/share/terminfo")); } } } diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs index 51decbab858..94944453eda 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -45,6 +45,7 @@ #![feature(libc)] #![feature(set_stdio)] #![feature(os)] +#![feature(convert)] extern crate getopts; extern crate serialize; @@ -382,7 +383,7 @@ pub fn parse_opts(args: &[String]) -> Option { let run_ignored = matches.opt_present("ignored"); let logfile = matches.opt_str("logfile"); - let logfile = logfile.map(|s| PathBuf::new(&s)); + let logfile = logfile.map(|s| PathBuf::from(&s)); let run_benchmarks = matches.opt_present("bench"); let run_tests = ! run_benchmarks || @@ -696,7 +697,7 @@ pub fn run_tests_console(opts: &TestOpts, tests: Vec ) -> io::Res match tests.iter().max_by(|t|len_if_padded(*t)) { Some(t) => { let n = t.desc.name.as_slice(); - st.max_name_len = n.as_slice().len(); + st.max_name_len = n.len(); }, None => {} } diff --git a/src/rustbook/book.rs b/src/rustbook/book.rs index ac7f2f824cb..a08481f8be9 100644 --- a/src/rustbook/book.rs +++ b/src/rustbook/book.rs @@ -102,8 +102,8 @@ pub fn parse_summary(input: &mut Read, src: &Path) -> Result> // always include the introduction top_items.push(BookItem { title: "Introduction".to_string(), - path: PathBuf::new("README.md"), - path_to_root: PathBuf::new("."), + path: PathBuf::from("README.md"), + path_to_root: PathBuf::from("."), children: vec!(), }); @@ -133,10 +133,10 @@ pub fn parse_summary(input: &mut Read, src: &Path) -> Result> errors.push(format!("paths in SUMMARY.md must be relative, \ but path '{}' for section '{}' is not.", given_path, title)); - PathBuf::new("") + PathBuf::new() } }; - let path_to_root = PathBuf::new(&iter::repeat("../") + let path_to_root = PathBuf::from(&iter::repeat("../") .take(path_from_root.components().count() - 1) .collect::()); let item = BookItem { diff --git a/src/rustbook/build.rs b/src/rustbook/build.rs index 731773917e0..f06290b27cb 100644 --- a/src/rustbook/build.rs +++ b/src/rustbook/build.rs @@ -87,7 +87,7 @@ fn render(book: &Book, tgt: &Path) -> CliResult<()> { if env::args().len() < 3 { src = env::current_dir().unwrap().clone(); } else { - src = PathBuf::new(&env::args().nth(2).unwrap()); + src = PathBuf::from(&env::args().nth(2).unwrap()); } // preprocess the markdown, rerouting markdown references to html references let mut markdown_data = String::new(); @@ -164,13 +164,13 @@ impl Subcommand for Build { if env::args().len() < 3 { src = cwd.clone(); } else { - src = PathBuf::new(&env::args().nth(2).unwrap()); + src = PathBuf::from(&env::args().nth(2).unwrap()); } if env::args().len() < 4 { tgt = cwd.join("_book"); } else { - tgt = PathBuf::new(&env::args().nth(3).unwrap()); + tgt = PathBuf::from(&env::args().nth(3).unwrap()); } try!(fs::create_dir(&tgt)); diff --git a/src/rustbook/main.rs b/src/rustbook/main.rs index 09fcd518c1e..4a652f846ed 100644 --- a/src/rustbook/main.rs +++ b/src/rustbook/main.rs @@ -15,6 +15,7 @@ #![feature(rustdoc)] #![feature(rustc_private)] #![feature(path_relative_from)] +#![feature(convert)] extern crate rustdoc; extern crate rustc_back; diff --git a/src/test/run-pass/env-home-dir.rs b/src/test/run-pass/env-home-dir.rs index 5d68a25a14a..cd614750451 100644 --- a/src/test/run-pass/env-home-dir.rs +++ b/src/test/run-pass/env-home-dir.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(convert)] + use std::env::*; use std::path::PathBuf; @@ -16,7 +18,7 @@ fn main() { let oldhome = var("HOME"); set_var("HOME", "/home/MountainView"); - assert!(home_dir() == Some(PathBuf::new("/home/MountainView"))); + assert!(home_dir() == Some(PathBuf::from("/home/MountainView"))); remove_var("HOME"); if cfg!(target_os = "android") { @@ -37,14 +39,14 @@ fn main() { assert!(home_dir().is_some()); set_var("HOME", "/home/MountainView"); - assert!(home_dir() == Some(PathBuf::new("/home/MountainView"))); + assert!(home_dir() == Some(PathBuf::from("/home/MountainView"))); remove_var("HOME"); set_var("USERPROFILE", "/home/MountainView"); - assert!(home_dir() == Some(PathBuf::new("/home/MountainView"))); + assert!(home_dir() == Some(PathBuf::from("/home/MountainView"))); set_var("HOME", "/home/MountainView"); set_var("USERPROFILE", "/home/PaloAlto"); - assert!(home_dir() == Some(PathBuf::new("/home/MountainView"))); + assert!(home_dir() == Some(PathBuf::from("/home/MountainView"))); } -- cgit 1.4.1-3-g733a5 From 29b54387b88bdf43c00849e3483c2297723f5a73 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 23 Mar 2015 15:54:39 -0700 Subject: Test fixes and rebase conflicts, round 2 --- src/doc/trpl/documentation.md | 3 +- src/liballoc/arc.rs | 76 +++++++++++++----------- src/liballoc/rc.rs | 90 ++++++++++++++++------------- src/libcollections/vec.rs | 32 ++++++---- src/libcollectionstest/lib.rs | 1 + src/libgraphviz/lib.rs | 40 ++++++------- src/librustc_back/lib.rs | 1 - src/librustc_back/rpath.rs | 4 +- src/librustc_lint/lib.rs | 1 - src/librustc_trans/trans/asm.rs | 2 +- src/librustc_typeck/lib.rs | 1 - src/libstd/env.rs | 5 +- src/libstd/path.rs | 23 ++++---- src/libstd/process.rs | 2 +- src/libstd/sys/unix/thread.rs | 5 +- src/libstd/sys/windows/fs2.rs | 2 +- src/libstd/sys/windows/mod.rs | 4 +- src/libstd/sys/windows/os.rs | 5 +- src/libstd/thread/scoped.rs | 6 +- src/test/run-make/issue-19371/foo.rs | 6 +- src/test/run-pass/create-dir-all-bare.rs | 2 + src/test/run-pass/issue-20797.rs | 8 +-- src/test/run-pass/send_str_hashmap.rs | 2 +- src/test/run-pass/send_str_treemap.rs | 2 +- src/test/run-pass/tcp-stress.rs | 3 + src/test/run-pass/ufcs-polymorphic-paths.rs | 2 +- 26 files changed, 179 insertions(+), 149 deletions(-) (limited to 'src/libstd/sys') diff --git a/src/doc/trpl/documentation.md b/src/doc/trpl/documentation.md index 7a459ad354d..54821e3ce30 100644 --- a/src/doc/trpl/documentation.md +++ b/src/doc/trpl/documentation.md @@ -361,7 +361,8 @@ Here’s an example of documenting a macro: #[macro_export] macro_rules! panic_unless { ($condition:expr, $($rest:expr),+) => ({ if ! $condition { panic!($($rest),+); } }); -} +} +# fn main() {} ``` You’ll note three things: we need to add our own `extern crate` line, so that diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs index 97d3f78f67c..c9bbc0d74cd 100644 --- a/src/liballoc/arc.rs +++ b/src/liballoc/arc.rs @@ -128,8 +128,8 @@ unsafe impl Sync for Arc { } /// A weak pointer to an `Arc`. /// -/// Weak pointers will not keep the data inside of the `Arc` alive, and can be used to break cycles -/// between `Arc` pointers. +/// Weak pointers will not keep the data inside of the `Arc` alive, and can be +/// used to break cycles between `Arc` pointers. #[unsafe_no_drop_flag] #[unstable(feature = "alloc", reason = "Weak pointers may not belong in this module.")] @@ -218,8 +218,8 @@ impl Arc { unsafe fn drop_slow(&mut self) { let ptr = *self._ptr; - // Destroy the data at this time, even though we may not free the box allocation itself - // (there may still be weak pointers lying around). + // Destroy the data at this time, even though we may not free the box + // allocation itself (there may still be weak pointers lying around). drop(ptr::read(&self.inner().data)); if self.inner().weak.fetch_sub(1, Release) == 1 { @@ -286,8 +286,8 @@ impl Deref for Arc { impl Arc { /// Make a mutable reference from the given `Arc`. /// - /// This is also referred to as a copy-on-write operation because the inner data is cloned if - /// the reference count is greater than one. + /// This is also referred to as a copy-on-write operation because the inner + /// data is cloned if the reference count is greater than one. /// /// # Examples /// @@ -302,16 +302,18 @@ impl Arc { #[inline] #[unstable(feature = "alloc")] pub fn make_unique(&mut self) -> &mut T { - // Note that we hold a strong reference, which also counts as a weak reference, so we only - // clone if there is an additional reference of either kind. + // Note that we hold a strong reference, which also counts as a weak + // reference, so we only clone if there is an additional reference of + // either kind. if self.inner().strong.load(SeqCst) != 1 || self.inner().weak.load(SeqCst) != 1 { *self = Arc::new((**self).clone()) } - // This unsafety is ok because we're guaranteed that the pointer returned is the *only* - // pointer that will ever be returned to T. Our reference count is guaranteed to be 1 at - // this point, and we required the Arc itself to be `mut`, so we're returning the only - // possible reference to the inner data. + // This unsafety is ok because we're guaranteed that the pointer + // returned is the *only* pointer that will ever be returned to T. Our + // reference count is guaranteed to be 1 at this point, and we required + // the Arc itself to be `mut`, so we're returning the only possible + // reference to the inner data. let inner = unsafe { &mut **self._ptr }; &mut inner.data } @@ -322,8 +324,9 @@ impl Arc { impl Drop for Arc { /// Drops the `Arc`. /// - /// This will decrement the strong reference count. If the strong reference count becomes zero - /// and the only other references are `Weak` ones, `drop`s the inner value. + /// This will decrement the strong reference count. If the strong reference + /// count becomes zero and the only other references are `Weak` ones, + /// `drop`s the inner value. /// /// # Examples /// @@ -347,29 +350,32 @@ impl Drop for Arc { /// ``` #[inline] fn drop(&mut self) { - // This structure has #[unsafe_no_drop_flag], so this drop glue may run more than once (but - // it is guaranteed to be zeroed after the first if it's run more than once) + // This structure has #[unsafe_no_drop_flag], so this drop glue may run + // more than once (but it is guaranteed to be zeroed after the first if + // it's run more than once) let ptr = *self._ptr; if ptr.is_null() { return } - // Because `fetch_sub` is already atomic, we do not need to synchronize with other threads - // unless we are going to delete the object. This same logic applies to the below - // `fetch_sub` to the `weak` count. + // Because `fetch_sub` is already atomic, we do not need to synchronize + // with other threads unless we are going to delete the object. This + // same logic applies to the below `fetch_sub` to the `weak` count. if self.inner().strong.fetch_sub(1, Release) != 1 { return } - // This fence is needed to prevent reordering of use of the data and deletion of the data. - // Because it is marked `Release`, the decreasing of the reference count synchronizes with - // this `Acquire` fence. This means that use of the data happens before decreasing the - // reference count, which happens before this fence, which happens before the deletion of - // the data. + // This fence is needed to prevent reordering of use of the data and + // deletion of the data. Because it is marked `Release`, the decreasing + // of the reference count synchronizes with this `Acquire` fence. This + // means that use of the data happens before decreasing the reference + // count, which happens before this fence, which happens before the + // deletion of the data. // // As explained in the [Boost documentation][1], // - // > It is important to enforce any possible access to the object in one thread (through an - // > existing reference) to *happen before* deleting the object in a different thread. This - // > is achieved by a "release" operation after dropping a reference (any access to the - // > object through this reference must obviously happened before), and an "acquire" - // > operation before deleting the object. + // > It is important to enforce any possible access to the object in one + // > thread (through an existing reference) to *happen before* deleting + // > the object in a different thread. This is achieved by a "release" + // > operation after dropping a reference (any access to the object + // > through this reference must obviously happened before), and an + // > "acquire" operation before deleting the object. // // [1]: (www.boost.org/doc/libs/1_55_0/doc/html/atomic/usage_examples.html) atomic::fence(Acquire); @@ -387,7 +393,8 @@ impl Weak { /// /// Upgrades the `Weak` reference to an `Arc`, if possible. /// - /// Returns `None` if there were no strong references and the data was destroyed. + /// Returns `None` if there were no strong references and the data was + /// destroyed. /// /// # Examples /// @@ -402,8 +409,8 @@ impl Weak { /// let strong_five: Option> = weak_five.upgrade(); /// ``` pub fn upgrade(&self) -> Option> { - // We use a CAS loop to increment the strong count instead of a fetch_add because once the - // count hits 0 is must never be above 0. + // We use a CAS loop to increment the strong count instead of a + // fetch_add because once the count hits 0 is must never be above 0. let inner = self.inner(); loop { let n = inner.strong.load(SeqCst); @@ -480,8 +487,9 @@ impl Drop for Weak { // see comments above for why this check is here if ptr.is_null() { return } - // If we find out that we were the last weak pointer, then its time to deallocate the data - // entirely. See the discussion in Arc::drop() about the memory orderings + // If we find out that we were the last weak pointer, then its time to + // deallocate the data entirely. See the discussion in Arc::drop() about + // the memory orderings if self.inner().weak.fetch_sub(1, Release) == 1 { atomic::fence(Acquire); unsafe { deallocate(ptr as *mut u8, size_of::>(), diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index e4b09bba529..eb3c5c16726 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -59,12 +59,12 @@ //! //! drop(gadget_owner); //! -//! // Despite dropping gadget_owner, we're still able to print out the name of -//! // the Owner of the Gadgets. This is because we've only dropped the +//! // Despite dropping gadget_owner, we're still able to print out the name +//! // of the Owner of the Gadgets. This is because we've only dropped the //! // reference count object, not the Owner it wraps. As long as there are -//! // other `Rc` objects pointing at the same Owner, it will remain allocated. Notice -//! // that the `Rc` wrapper around Gadget.owner gets automatically dereferenced -//! // for us. +//! // other `Rc` objects pointing at the same Owner, it will remain +//! // allocated. Notice that the `Rc` wrapper around Gadget.owner gets +//! // automatically dereferenced for us. //! println!("Gadget {} owned by {}", gadget1.id, gadget1.owner.name); //! println!("Gadget {} owned by {}", gadget2.id, gadget2.owner.name); //! @@ -74,19 +74,22 @@ //! } //! ``` //! -//! If our requirements change, and we also need to be able to traverse from Owner → Gadget, we -//! will run into problems: an `Rc` pointer from Owner → Gadget introduces a cycle between the -//! objects. This means that their reference counts can never reach 0, and the objects will remain -//! allocated: a memory leak. In order to get around this, we can use `Weak` pointers. These -//! pointers don't contribute to the total count. +//! If our requirements change, and we also need to be able to traverse from +//! Owner → Gadget, we will run into problems: an `Rc` pointer from Owner +//! → Gadget introduces a cycle between the objects. This means that their +//! reference counts can never reach 0, and the objects will remain allocated: a +//! memory leak. In order to get around this, we can use `Weak` pointers. +//! These pointers don't contribute to the total count. //! -//! Rust actually makes it somewhat difficult to produce this loop in the first place: in order to -//! end up with two objects that point at each other, one of them needs to be mutable. This is -//! problematic because `Rc` enforces memory safety by only giving out shared references to the -//! object it wraps, and these don't allow direct mutation. We need to wrap the part of the object -//! we wish to mutate in a `RefCell`, which provides *interior mutability*: a method to achieve -//! mutability through a shared reference. `RefCell` enforces Rust's borrowing rules at runtime. -//! Read the `Cell` documentation for more details on interior mutability. +//! Rust actually makes it somewhat difficult to produce this loop in the first +//! place: in order to end up with two objects that point at each other, one of +//! them needs to be mutable. This is problematic because `Rc` enforces +//! memory safety by only giving out shared references to the object it wraps, +//! and these don't allow direct mutation. We need to wrap the part of the +//! object we wish to mutate in a `RefCell`, which provides *interior +//! mutability*: a method to achieve mutability through a shared reference. +//! `RefCell` enforces Rust's borrowing rules at runtime. Read the `Cell` +//! documentation for more details on interior mutability. //! //! ```rust //! # #![feature(alloc)] @@ -130,9 +133,10 @@ //! for gadget_opt in gadget_owner.gadgets.borrow().iter() { //! //! // gadget_opt is a Weak. Since weak pointers can't guarantee -//! // that their object is still allocated, we need to call upgrade() on them -//! // to turn them into a strong reference. This returns an Option, which -//! // contains a reference to our object if it still exists. +//! // that their object is still allocated, we need to call upgrade() +//! // on them to turn them into a strong reference. This returns an +//! // Option, which contains a reference to our object if it still +//! // exists. //! let gadget = gadget_opt.upgrade().unwrap(); //! println!("Gadget {} owned by {}", gadget.id, gadget.owner.name); //! } @@ -180,8 +184,8 @@ struct RcBox { #[unsafe_no_drop_flag] #[stable(feature = "rust1", since = "1.0.0")] pub struct Rc { - // FIXME #12808: strange names to try to avoid interfering with field accesses of the contained - // type via Deref + // FIXME #12808: strange names to try to avoid interfering with field + // accesses of the contained type via Deref _ptr: NonZero<*mut RcBox>, } @@ -203,9 +207,10 @@ impl Rc { pub fn new(value: T) -> Rc { unsafe { Rc { - // there is an implicit weak pointer owned by all the strong pointers, which - // ensures that the weak destructor never frees the allocation while the strong - // destructor is running, even if the weak pointer is stored inside the strong one. + // there is an implicit weak pointer owned by all the strong + // pointers, which ensures that the weak destructor never frees + // the allocation while the strong destructor is running, even + // if the weak pointer is stored inside the strong one. _ptr: NonZero::new(boxed::into_raw(box RcBox { value: value, strong: Cell::new(1), @@ -245,7 +250,8 @@ pub fn weak_count(this: &Rc) -> usize { this.weak() - 1 } #[unstable(feature = "alloc")] pub fn strong_count(this: &Rc) -> usize { this.strong() } -/// Returns true if there are no other `Rc` or `Weak` values that share the same inner value. +/// Returns true if there are no other `Rc` or `Weak` values that share the +/// same inner value. /// /// # Examples /// @@ -330,8 +336,8 @@ pub fn get_mut<'a, T>(rc: &'a mut Rc) -> Option<&'a mut T> { impl Rc { /// Make a mutable reference from the given `Rc`. /// - /// This is also referred to as a copy-on-write operation because the inner data is cloned if - /// the reference count is greater than one. + /// This is also referred to as a copy-on-write operation because the inner + /// data is cloned if the reference count is greater than one. /// /// # Examples /// @@ -349,10 +355,11 @@ impl Rc { if !is_unique(self) { *self = Rc::new((**self).clone()) } - // This unsafety is ok because we're guaranteed that the pointer returned is the *only* - // pointer that will ever be returned to T. Our reference count is guaranteed to be 1 at - // this point, and we required the `Rc` itself to be `mut`, so we're returning the only - // possible reference to the inner value. + // This unsafety is ok because we're guaranteed that the pointer + // returned is the *only* pointer that will ever be returned to T. Our + // reference count is guaranteed to be 1 at this point, and we required + // the `Rc` itself to be `mut`, so we're returning the only possible + // reference to the inner value. let inner = unsafe { &mut **self._ptr }; &mut inner.value } @@ -373,8 +380,9 @@ impl Deref for Rc { impl Drop for Rc { /// Drops the `Rc`. /// - /// This will decrement the strong reference count. If the strong reference count becomes zero - /// and the only other references are `Weak` ones, `drop`s the inner value. + /// This will decrement the strong reference count. If the strong reference + /// count becomes zero and the only other references are `Weak` ones, + /// `drop`s the inner value. /// /// # Examples /// @@ -404,8 +412,8 @@ impl Drop for Rc { if self.strong() == 0 { ptr::read(&**self); // destroy the contained object - // remove the implicit "strong weak" pointer now that we've destroyed the - // contents. + // remove the implicit "strong weak" pointer now that we've + // destroyed the contents. self.dec_weak(); if self.weak() == 0 { @@ -627,7 +635,8 @@ impl fmt::Debug for Rc { /// A weak version of `Rc`. /// -/// Weak references do not count when determining if the inner value should be dropped. +/// Weak references do not count when determining if the inner value should be +/// dropped. /// /// See the [module level documentation](./index.html) for more. #[unsafe_no_drop_flag] @@ -652,7 +661,8 @@ impl Weak { /// /// Upgrades the `Weak` reference to an `Rc`, if possible. /// - /// Returns `None` if there were no strong references and the data was destroyed. + /// Returns `None` if there were no strong references and the data was + /// destroyed. /// /// # Examples /// @@ -710,8 +720,8 @@ impl Drop for Weak { let ptr = *self._ptr; if !ptr.is_null() { self.dec_weak(); - // the weak count starts at 1, and will only go to zero if all the strong pointers - // have disappeared. + // the weak count starts at 1, and will only go to zero if all + // the strong pointers have disappeared. if self.weak() == 0 { deallocate(ptr as *mut u8, size_of::>(), min_align_of::>()) diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index e360c0b840b..59819d01bc6 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -8,7 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! A growable list type with heap-allocated contents, written `Vec` but pronounced 'vector.' +//! A growable list type with heap-allocated contents, written `Vec` but +//! pronounced 'vector.' //! //! Vectors have `O(1)` indexing, push (to the end) and pop (from the end). //! @@ -124,17 +125,19 @@ use borrow::{Cow, IntoCow}; /// /// # Capacity and reallocation /// -/// The capacity of a vector is the amount of space allocated for any future elements that will be -/// added onto the vector. This is not to be confused with the *length* of a vector, which -/// specifies the number of actual elements within the vector. If a vector's length exceeds its -/// capacity, its capacity will automatically be increased, but its elements will have to be +/// The capacity of a vector is the amount of space allocated for any future +/// elements that will be added onto the vector. This is not to be confused with +/// the *length* of a vector, which specifies the number of actual elements +/// within the vector. If a vector's length exceeds its capacity, its capacity +/// will automatically be increased, but its elements will have to be /// reallocated. /// -/// For example, a vector with capacity 10 and length 0 would be an empty vector with space for 10 -/// more elements. Pushing 10 or fewer elements onto the vector will not change its capacity or -/// cause reallocation to occur. However, if the vector's length is increased to 11, it will have -/// to reallocate, which can be slow. For this reason, it is recommended to use -/// `Vec::with_capacity` whenever possible to specify how big the vector is expected to get. +/// For example, a vector with capacity 10 and length 0 would be an empty vector +/// with space for 10 more elements. Pushing 10 or fewer elements onto the +/// vector will not change its capacity or cause reallocation to occur. However, +/// if the vector's length is increased to 11, it will have to reallocate, which +/// can be slow. For this reason, it is recommended to use `Vec::with_capacity` +/// whenever possible to specify how big the vector is expected to get. #[unsafe_no_drop_flag] #[stable(feature = "rust1", since = "1.0.0")] pub struct Vec { @@ -1429,7 +1432,7 @@ impl ops::Index for Vec { #[cfg(not(stage0))] #[inline] fn index(&self, _index: ops::RangeFull) -> &[T] { - self.as_slice() + self } } @@ -1733,15 +1736,20 @@ impl AsRef<[T]> for Vec { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T: Clone> From<&'a [T]> for Vec { + #[cfg(not(test))] fn from(s: &'a [T]) -> Vec { s.to_vec() } + #[cfg(test)] + fn from(s: &'a [T]) -> Vec { + ::slice::to_vec(s) + } } #[stable(feature = "rust1", since = "1.0.0")] impl<'a> From<&'a str> for Vec { fn from(s: &'a str) -> Vec { - s.as_bytes().to_vec() + From::from(s.as_bytes()) } } diff --git a/src/libcollectionstest/lib.rs b/src/libcollectionstest/lib.rs index 365ef637a4c..f03a073e274 100644 --- a/src/libcollectionstest/lib.rs +++ b/src/libcollectionstest/lib.rs @@ -20,6 +20,7 @@ #![feature(unboxed_closures)] #![feature(unicode)] #![feature(unsafe_destructor)] +#![feature(into_cow)] #![cfg_attr(test, feature(str_char))] #[macro_use] extern crate log; diff --git a/src/libgraphviz/lib.rs b/src/libgraphviz/lib.rs index 9a6e77af28e..ccf4a3f48d9 100644 --- a/src/libgraphviz/lib.rs +++ b/src/libgraphviz/lib.rs @@ -47,13 +47,13 @@ //! which is cyclic. //! //! ```rust -//! # #![feature(rustc_private, core)] +//! # #![feature(rustc_private, core, into_cow)] //! use std::borrow::IntoCow; //! use std::io::Write; //! use graphviz as dot; //! -//! type Nd = int; -//! type Ed = (int,int); +//! type Nd = isize; +//! type Ed = (isize,isize); //! struct Edges(Vec); //! //! pub fn render_to(output: &mut W) { @@ -133,7 +133,7 @@ //! direct reference to the `(source,target)` pair stored in the graph's //! internal vector (rather than passing around a copy of the pair //! itself). Note that this implies that `fn edges(&'a self)` must -//! construct a fresh `Vec<&'a (uint,uint)>` from the `Vec<(uint,uint)>` +//! construct a fresh `Vec<&'a (usize,usize)>` from the `Vec<(usize,usize)>` //! edges stored in `self`. //! //! Since both the set of nodes and the set of edges are always @@ -149,14 +149,14 @@ //! entity `&sube`). //! //! ```rust -//! # #![feature(rustc_private, core)] +//! # #![feature(rustc_private, core, into_cow)] //! use std::borrow::IntoCow; //! use std::io::Write; //! use graphviz as dot; //! -//! type Nd = uint; -//! type Ed<'a> = &'a (uint, uint); -//! struct Graph { nodes: Vec<&'static str>, edges: Vec<(uint,uint)> } +//! type Nd = usize; +//! type Ed<'a> = &'a (usize, usize); +//! struct Graph { nodes: Vec<&'static str>, edges: Vec<(usize,usize)> } //! //! pub fn render_to(output: &mut W) { //! let nodes = vec!("{x,y}","{x}","{y}","{}"); @@ -207,14 +207,14 @@ //! Hasse-diagram for the subsets of the set `{x, y}`. //! //! ```rust -//! # #![feature(rustc_private, core)] +//! # #![feature(rustc_private, core, into_cow)] //! use std::borrow::IntoCow; //! use std::io::Write; //! use graphviz as dot; //! -//! type Nd<'a> = (uint, &'a str); +//! type Nd<'a> = (usize, &'a str); //! type Ed<'a> = (Nd<'a>, Nd<'a>); -//! struct Graph { nodes: Vec<&'static str>, edges: Vec<(uint,uint)> } +//! struct Graph { nodes: Vec<&'static str>, edges: Vec<(usize,usize)> } //! //! pub fn render_to(output: &mut W) { //! let nodes = vec!("{x,y}","{x}","{y}","{}"); @@ -231,7 +231,7 @@ //! } //! fn node_label<'b>(&'b self, n: &Nd<'b>) -> dot::LabelText<'b> { //! let &(i, _) = n; -//! dot::LabelText::LabelStr(self.nodes[i].as_slice().into_cow()) +//! dot::LabelText::LabelStr(self.nodes[i].into_cow()) //! } //! fn edge_label<'b>(&'b self, _: &Ed<'b>) -> dot::LabelText<'b> { //! dot::LabelText::LabelStr("⊆".into_cow()) @@ -240,12 +240,12 @@ //! //! impl<'a> dot::GraphWalk<'a, Nd<'a>, Ed<'a>> for Graph { //! fn nodes(&'a self) -> dot::Nodes<'a,Nd<'a>> { -//! self.nodes.iter().map(|s|s.as_slice()).enumerate().collect() +//! self.nodes.iter().map(|s| &s[..]).enumerate().collect() //! } //! fn edges(&'a self) -> dot::Edges<'a,Ed<'a>> { //! self.edges.iter() -//! .map(|&(i,j)|((i, self.nodes[i].as_slice()), -//! (j, self.nodes[j].as_slice()))) +//! .map(|&(i,j)|((i, &self.nodes[i][..]), +//! (j, &self.nodes[j][..]))) //! .collect() //! } //! fn source(&self, e: &Ed<'a>) -> Nd<'a> { let &(s,_) = e; s } @@ -385,7 +385,7 @@ impl<'a> Id<'a> { is_letter_or_underscore(c) || in_range('0', c, '9') } fn in_range(low: char, c: char, high: char) -> bool { - low as uint <= c as uint && c as uint <= high as uint + low as usize <= c as usize && c as usize <= high as usize } } @@ -602,12 +602,12 @@ mod tests { use std::iter::repeat; /// each node is an index in a vector in the graph. - type Node = uint; + type Node = usize; struct Edge { - from: uint, to: uint, label: &'static str + from: usize, to: usize, label: &'static str } - fn edge(from: uint, to: uint, label: &'static str) -> Edge { + fn edge(from: usize, to: usize, label: &'static str) -> Edge { Edge { from: from, to: to, label: label } } @@ -637,7 +637,7 @@ mod tests { enum NodeLabels { AllNodesLabelled(Vec), - UnlabelledNodes(uint), + UnlabelledNodes(usize), SomeNodesLabelled(Vec>), } diff --git a/src/librustc_back/lib.rs b/src/librustc_back/lib.rs index b2e12a91ec8..63727a573a3 100644 --- a/src/librustc_back/lib.rs +++ b/src/librustc_back/lib.rs @@ -47,7 +47,6 @@ #![feature(rand)] #![feature(path_ext)] #![feature(std_misc)] -#![feature(path_relative_from)] #![feature(step_by)] #![feature(convert)] #![cfg_attr(test, feature(test, rand))] diff --git a/src/librustc_back/rpath.rs b/src/librustc_back/rpath.rs index 10d17e266ed..ff3f0b78f91 100644 --- a/src/librustc_back/rpath.rs +++ b/src/librustc_back/rpath.rs @@ -228,7 +228,7 @@ mod test { used_crates: Vec::new(), has_rpath: true, is_like_osx: true, - out_filename: PathBuf::new("bin/rustc"), + out_filename: PathBuf::from("bin/rustc"), get_install_prefix_lib_path: &mut || panic!(), realpath: &mut |p| Ok(p.to_path_buf()), }; @@ -238,7 +238,7 @@ mod test { } else { let config = &mut RPathConfig { used_crates: Vec::new(), - out_filename: PathBuf::new("bin/rustc"), + out_filename: PathBuf::from("bin/rustc"), get_install_prefix_lib_path: &mut || panic!(), has_rpath: true, is_like_osx: false, diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index 99b3393c003..ef65acf8b13 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -40,7 +40,6 @@ #![feature(rustc_private)] #![feature(unsafe_destructor)] #![feature(staged_api)] -#![feature(std_misc)] #![feature(str_char)] #![cfg_attr(test, feature(test))] diff --git a/src/librustc_trans/trans/asm.rs b/src/librustc_trans/trans/asm.rs index 33817bb952e..d6c85e8b173 100644 --- a/src/librustc_trans/trans/asm.rs +++ b/src/librustc_trans/trans/asm.rs @@ -81,7 +81,7 @@ pub fn trans_inline_asm<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ia: &ast::InlineAsm) // Default per-arch clobbers // Basically what clang does - let arch_clobbers = match bcx.sess().target.target.arch.as_slice() { + let arch_clobbers = match &bcx.sess().target.target.arch[..] { "x86" | "x86_64" => vec!("~{dirflag}", "~{fpsr}", "~{flags}"), _ => Vec::new() }; diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 6bdfb17ec1c..4e7e63a5d77 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -80,7 +80,6 @@ This API is completely unstable and subject to change. #![feature(collections)] #![feature(core)] #![feature(int_uint)] -#![feature(std_misc)] #![feature(quote)] #![feature(rustc_diagnostic_macros)] #![feature(rustc_private)] diff --git a/src/libstd/env.rs b/src/libstd/env.rs index 00ce6917835..fd7532ea4a7 100644 --- a/src/libstd/env.rs +++ b/src/libstd/env.rs @@ -327,12 +327,13 @@ pub struct JoinPathsError { /// # Examples /// /// ``` +/// # #![feature(convert)] /// use std::env; /// use std::path::PathBuf; /// /// if let Some(path) = env::var_os("PATH") { /// let mut paths = env::split_paths(&path).collect::>(); -/// paths.push(PathBuf::new("/home/xyz/bin")); +/// paths.push(PathBuf::from("/home/xyz/bin")); /// let new_path = env::join_paths(paths.iter()).unwrap(); /// env::set_var("PATH", &new_path); /// } @@ -853,7 +854,7 @@ mod tests { fn split_paths_unix() { fn check_parse(unparsed: &str, parsed: &[&str]) -> bool { split_paths(unparsed).collect::>() == - parsed.iter().map(|s| PathBuf::new(*s)).collect::>() + parsed.iter().map(|s| PathBuf::from(*s)).collect::>() } assert!(check_parse("", &mut [""])); diff --git a/src/libstd/path.rs b/src/libstd/path.rs index 8ee33e94fe7..50f79967f55 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -35,9 +35,10 @@ //! To build or modify paths, use `PathBuf`: //! //! ```rust +//! # #![feature(convert)] //! use std::path::PathBuf; //! -//! let mut path = PathBuf::new("c:\\"); +//! let mut path = PathBuf::from("c:\\"); //! path.push("windows"); //! path.push("system32"); //! path.set_extension("dll"); @@ -892,9 +893,10 @@ impl<'a> cmp::Ord for Components<'a> { /// # Examples /// /// ``` +/// # #![feature(convert)] /// use std::path::PathBuf; /// -/// let mut path = PathBuf::new("c:\\"); +/// let mut path = PathBuf::from("c:\\"); /// path.push("windows"); /// path.push("system32"); /// path.set_extension("dll"); @@ -983,15 +985,16 @@ impl PathBuf { /// # Examples /// /// ``` + /// # #![feature(convert)] /// use std::path::PathBuf; /// - /// let mut buf = PathBuf::new("/"); + /// let mut buf = PathBuf::from("/"); /// assert!(buf.file_name() == None); /// buf.set_file_name("bar"); - /// assert!(buf == PathBuf::new("/bar")); + /// assert!(buf == PathBuf::from("/bar")); /// assert!(buf.file_name().is_some()); /// buf.set_file_name("baz.txt"); - /// assert!(buf == PathBuf::new("/baz.txt")); + /// assert!(buf == PathBuf::from("/baz.txt")); /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn set_file_name>(&mut self, file_name: S) { @@ -1661,7 +1664,7 @@ mod tests { let static_path = Path::new("/home/foo"); let static_cow_path: Cow<'static, Path> = static_path.into_cow(); - let pathbuf = PathBuf::new("/home/foo"); + let pathbuf = PathBuf::from("/home/foo"); { let path: &Path = &pathbuf; @@ -2543,7 +2546,7 @@ mod tests { pub fn test_push() { macro_rules! tp( ($path:expr, $push:expr, $expected:expr) => ( { - let mut actual = PathBuf::new($path); + let mut actual = PathBuf::from($path); actual.push($push); assert!(actual.to_str() == Some($expected), "pushing {:?} onto {:?}: Expected {:?}, got {:?}", @@ -2631,7 +2634,7 @@ mod tests { pub fn test_pop() { macro_rules! tp( ($path:expr, $expected:expr, $output:expr) => ( { - let mut actual = PathBuf::new($path); + let mut actual = PathBuf::from($path); let output = actual.pop(); assert!(actual.to_str() == Some($expected) && output == $output, "popping from {:?}: Expected {:?}/{:?}, got {:?}/{:?}", @@ -2685,7 +2688,7 @@ mod tests { pub fn test_set_file_name() { macro_rules! tfn( ($path:expr, $file:expr, $expected:expr) => ( { - let mut p = PathBuf::new($path); + let mut p = PathBuf::from($path); p.set_file_name($file); assert!(p.to_str() == Some($expected), "setting file name of {:?} to {:?}: Expected {:?}, got {:?}", @@ -2719,7 +2722,7 @@ mod tests { pub fn test_set_extension() { macro_rules! tfe( ($path:expr, $ext:expr, $expected:expr, $output:expr) => ( { - let mut p = PathBuf::new($path); + let mut p = PathBuf::from($path); let output = p.set_extension($ext); assert!(p.to_str() == Some($expected) && output == $output, "setting extension of {:?} to {:?}: Expected {:?}/{:?}, got {:?}/{:?}", diff --git a/src/libstd/process.rs b/src/libstd/process.rs index d11c3d22144..553412c8371 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -770,7 +770,7 @@ mod tests { // test changing to the parent of os::getcwd() because we know // the path exists (and os::getcwd() is not expected to be root) let parent_dir = os::getcwd().unwrap().dir_path(); - let result = pwd_cmd().current_dir(&parent_dir).output().unwrap(); + let result = pwd_cmd().current_dir(parent_dir.as_str().unwrap()).output().unwrap(); let output = String::from_utf8(result.stdout).unwrap(); let child_dir = old_path::Path::new(output.trim()); diff --git a/src/libstd/sys/unix/thread.rs b/src/libstd/sys/unix/thread.rs index eb2a6dc08bf..eb61f21aacd 100644 --- a/src/libstd/sys/unix/thread.rs +++ b/src/libstd/sys/unix/thread.rs @@ -13,14 +13,12 @@ use core::prelude::*; use cmp; -use dynamic_lib::DynamicLibrary; use ffi::CString; use io; use libc::consts::os::posix01::PTHREAD_STACK_MIN; use libc; use mem; use ptr; -use sync::{Once, ONCE_INIT}; use sys::os; use thunk::Thunk; use time::Duration; @@ -322,6 +320,9 @@ pub fn sleep(dur: Duration) { // dependency on libc6 (#23628). #[cfg(target_os = "linux")] fn min_stack_size(attr: *const libc::pthread_attr_t) -> libc::size_t { + use dynamic_lib::DynamicLibrary; + use sync::{Once, ONCE_INIT}; + type F = unsafe extern "C" fn(*const libc::pthread_attr_t) -> libc::size_t; static INIT: Once = ONCE_INIT; static mut __pthread_get_minstack: Option = None; diff --git a/src/libstd/sys/windows/fs2.rs b/src/libstd/sys/windows/fs2.rs index 117f819eeeb..99835265111 100644 --- a/src/libstd/sys/windows/fs2.rs +++ b/src/libstd/sys/windows/fs2.rs @@ -372,7 +372,7 @@ pub fn readlink(p: &Path) -> io::Result { sz - 1, libc::VOLUME_NAME_DOS) }, |s| OsStringExt::from_wide(s))); - Ok(PathBuf::new(&ret)) + Ok(PathBuf::from(&ret)) } pub fn symlink(src: &Path, dst: &Path) -> io::Result<()> { diff --git a/src/libstd/sys/windows/mod.rs b/src/libstd/sys/windows/mod.rs index eeaf4ced072..b1ceac9b902 100644 --- a/src/libstd/sys/windows/mod.rs +++ b/src/libstd/sys/windows/mod.rs @@ -304,9 +304,7 @@ fn fill_utf16_buf_new(f1: F1, f2: F2) -> io::Result } fn os2path(s: &[u16]) -> PathBuf { - let os = ::from_wide(s); - // FIXME(#22751) should consume `os` - PathBuf::new(&os) + PathBuf::from(OsString::from_wide(s)) } pub fn truncate_utf16_at_nul<'a>(v: &'a [u16]) -> &'a [u16] { diff --git a/src/libstd/sys/windows/os.rs b/src/libstd/sys/windows/os.rs index 4f6c4c9aab3..83d06371734 100644 --- a/src/libstd/sys/windows/os.rs +++ b/src/libstd/sys/windows/os.rs @@ -363,10 +363,7 @@ pub fn temp_dir() -> PathBuf { pub fn home_dir() -> Option { getenv("HOME".as_os_str()).or_else(|| { getenv("USERPROFILE".as_os_str()) - }).map(|os| { - // FIXME(#22751) should consume `os` - PathBuf::new(&os) - }).or_else(|| unsafe { + }).map(PathBuf::from).or_else(|| unsafe { let me = c::GetCurrentProcess(); let mut token = ptr::null_mut(); if c::OpenProcessToken(me, c::TOKEN_READ, &mut token) == 0 { diff --git a/src/libstd/thread/scoped.rs b/src/libstd/thread/scoped.rs index d57535391fd..b384879d7a9 100644 --- a/src/libstd/thread/scoped.rs +++ b/src/libstd/thread/scoped.rs @@ -24,7 +24,7 @@ //! # Examples //! //! ``` -//! # #![feature(std_misc)] +//! # #![feature(scoped_tls)] //! scoped_thread_local!(static FOO: u32); //! //! // Initially each scoped slot is empty. @@ -147,7 +147,7 @@ impl ScopedKey { /// # Examples /// /// ``` - /// # #![feature(std_misc)] + /// # #![feature(scoped_tls)] /// scoped_thread_local!(static FOO: u32); /// /// FOO.set(&100, || { @@ -200,7 +200,7 @@ impl ScopedKey { /// # Examples /// /// ```no_run - /// # #![feature(std_misc)] + /// # #![feature(scoped_tls)] /// scoped_thread_local!(static FOO: u32); /// /// FOO.with(|slot| { diff --git a/src/test/run-make/issue-19371/foo.rs b/src/test/run-make/issue-19371/foo.rs index b089b9269a2..0d42e0be58d 100644 --- a/src/test/run-make/issue-19371/foo.rs +++ b/src/test/run-make/issue-19371/foo.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(rustc_private, path)] +#![feature(rustc_private, path, convert)] extern crate rustc; extern crate rustc_driver; @@ -33,9 +33,9 @@ fn main() { panic!("expected rustc path"); } - let tmpdir = PathBuf::new(&args[1]); + let tmpdir = PathBuf::from(&args[1]); - let mut sysroot = PathBuf::new(&args[3]); + let mut sysroot = PathBuf::from(&args[3]); sysroot.pop(); sysroot.pop(); diff --git a/src/test/run-pass/create-dir-all-bare.rs b/src/test/run-pass/create-dir-all-bare.rs index 3a4286c2927..475df629f63 100644 --- a/src/test/run-pass/create-dir-all-bare.rs +++ b/src/test/run-pass/create-dir-all-bare.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(tempdir)] + use std::env; use std::fs::{self, TempDir}; diff --git a/src/test/run-pass/issue-20797.rs b/src/test/run-pass/issue-20797.rs index 4dbe7c968a7..d0720ec593f 100644 --- a/src/test/run-pass/issue-20797.rs +++ b/src/test/run-pass/issue-20797.rs @@ -12,12 +12,12 @@ // pretty-expanded FIXME #23616 -#![feature(old_io, old_path)] +#![feature(convert)] use std::default::Default; use std::io; use std::fs; -use std::path::{PathBuf, Path}; +use std::path::PathBuf; pub trait PathExtensions { fn is_dir(&self) -> bool { false } @@ -98,8 +98,8 @@ impl Iterator for Subpaths { } } -fn foo() { - let mut walker: Subpaths = Subpaths::walk(&PathBuf::new("/home")).unwrap(); +fn _foo() { + let _walker: Subpaths = Subpaths::walk(&PathBuf::from("/home")).unwrap(); } fn main() {} diff --git a/src/test/run-pass/send_str_hashmap.rs b/src/test/run-pass/send_str_hashmap.rs index 7bef36d0656..d109f7abde4 100644 --- a/src/test/run-pass/send_str_hashmap.rs +++ b/src/test/run-pass/send_str_hashmap.rs @@ -10,7 +10,7 @@ // pretty-expanded FIXME #23616 -#![feature(collections)] +#![feature(collections, into_cow)] extern crate collections; diff --git a/src/test/run-pass/send_str_treemap.rs b/src/test/run-pass/send_str_treemap.rs index 04a4a239b0f..07dd5443348 100644 --- a/src/test/run-pass/send_str_treemap.rs +++ b/src/test/run-pass/send_str_treemap.rs @@ -10,7 +10,7 @@ // pretty-expanded FIXME #23616 -#![feature(collections)] +#![feature(collections, into_cow)] extern crate collections; diff --git a/src/test/run-pass/tcp-stress.rs b/src/test/run-pass/tcp-stress.rs index e06e6883a75..489abf163c0 100644 --- a/src/test/run-pass/tcp-stress.rs +++ b/src/test/run-pass/tcp-stress.rs @@ -13,6 +13,9 @@ // ignore-openbsd system ulimit (Too many open files) // exec-env:RUST_LOG=debug +#![feature(rustc_private, libc, old_io, io, std_misc)] +#![allow(deprecated, unused_must_use)] + #[macro_use] extern crate log; extern crate libc; diff --git a/src/test/run-pass/ufcs-polymorphic-paths.rs b/src/test/run-pass/ufcs-polymorphic-paths.rs index e05a60dbc7f..a6ea0f76dc2 100644 --- a/src/test/run-pass/ufcs-polymorphic-paths.rs +++ b/src/test/run-pass/ufcs-polymorphic-paths.rs @@ -10,7 +10,7 @@ // pretty-expanded FIXME #23616 -#![feature(collections, rand)] +#![feature(collections, rand, into_cow)] use std::borrow::{Cow, IntoCow}; use std::collections::BitVec; -- cgit 1.4.1-3-g733a5