\fBopt\-level\fR=\fIVAL\fR
Optimize with possible levels 0\[en]3
-.SH ENVIRONMENT VARIABLES
+.SH ENVIRONMENT
Some of these affect the output of the compiler, while others affect programs
which link to the standard library.
#![feature(std_misc)]
#![feature(test)]
#![feature(path_ext)]
+#![feature(convert)]
+#![feature(str_char)]
#![deny(warnings)]
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),
}
}
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"),
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"),
fn parse_pp_exact(line: &str, testfile: &Path) -> Option<PathBuf> {
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
}
#![allow(deprecated)] // for old path, for dynamic_lib
-use std::process::{ExitStatus, Command, Child, Output, Stdio};
-use std::io::prelude::*;
use std::dynamic_lib::DynamicLibrary;
+use std::io::prelude::*;
+use std::old_path::Path;
+use std::process::{ExitStatus, Command, Child, Output, Stdio};
fn add_target_env(cmd: &mut Command, lib_path: &str, aux_path: Option<&str>) {
// Need to be sure to put both the lib_path and the aux path in the dylib
}
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 {
## Attributes
```{.ebnf .gram}
-attribute : "#!" ? '[' meta_item ']' ;
+attribute : '#' '!' ? '[' meta_item ']' ;
meta_item : ident [ '=' literal
| '(' meta_seq ')' ] ? ;
meta_seq : meta_item [ ',' meta_seq ] ? ;
### While loops
```{.ebnf .gram}
-while_expr : "while" no_struct_literal_expr '{' block '}' ;
+while_expr : [ lifetime ':' ] "while" no_struct_literal_expr '{' block '}' ;
```
A `while` loop begins by evaluating the boolean loop conditional expression.
### For expressions
```{.ebnf .gram}
-for_expr : "for" pat "in" no_struct_literal_expr '{' block '}' ;
+for_expr : [ lifetime ':' ] "for" pat "in" no_struct_literal_expr '{' block '}' ;
```
A `for` expression is a syntactic construct for looping over elements provided
# Summary
-* [I: The Basics](basic.md)
+* [The Basics](basic.md)
* [Installing Rust](installing-rust.md)
* [Hello, world!](hello-world.md)
* [Hello, Cargo!](hello-cargo.md)
* [Strings](strings.md)
* [Arrays, Vectors, and Slices](arrays-vectors-and-slices.md)
* [Standard Input](standard-input.md)
-* [II: Intermediate Rust](intermediate.md)
+* [Intermediate Rust](intermediate.md)
* [Crates and Modules](crates-and-modules.md)
* [Testing](testing.md)
* [Pointers](pointers.md)
* [Concurrency](concurrency.md)
* [Error Handling](error-handling.md)
* [Documentation](documentation.md)
-* [III: Advanced Topics](advanced.md)
+* [Advanced Topics](advanced.md)
* [FFI](ffi.md)
* [Unsafe Code](unsafe.md)
* [Advanced Macros](advanced-macros.md)
There are also a few things you can do with a tuple as a whole, without
destructuring. You can assign one tuple into another, if they have the same
-contained types and arity. Tuples have the same arity when they have the same
+contained types and [arity]. Tuples have the same arity when they have the same
length.
```rust
and with a struct, we have actual names.
There _is_ one case when a tuple struct is very useful, though, and that's a
-tuple struct with only one element. We call this a *newtype*, because it lets
-you create a new type that's similar to another one:
+tuple struct with only one element. We call this the *newtype* pattern, because
+it allows you to create a new type, distinct from that of its contained value
+and expressing its own semantic meaning:
```{rust}
struct Inches(i32);
Finally, Rust has a "sum type", an *enum*. Enums are an incredibly useful
feature of Rust, and are used throughout the standard library. An `enum` is
-a type which ties a set of alternates to a specific name. For example, below
+a type which relates a set of alternates to a specific name. For example, below
we define `Character` to be either a `Digit` or something else. These
can be used via their fully scoped names: `Character::Other` (more about `::`
below).
}
```
-An `enum` variant can be defined as most normal types. Below are some example
-types which also would be allowed in an `enum`.
+Most normal types are allowed as the variant components of an `enum`. Here are
+some examples:
```rust
struct Empty;
struct HeightDatabase(Vec<i32>);
```
-So you see that depending on the sub-datastructure, the `enum` variant, same as
-a struct, may or may not hold data. That is, in `Character`, `Digit` is a name
-tied to an `i32` where `Other` is just a name. However, the fact that they are
-distinct makes this very useful.
+You see that, depending on its type, an `enum` variant may or may not hold data.
+In `Character`, for instance, `Digit` gives a meaningful name for an `i32`
+value, where `Other` is only a name. However, the fact that they represent
+distinct categories of `Character` is a very useful property.
-As with structures, enums don't by default have access to operators such as
-compare ( `==` and `!=`), binary operations (`*` and `+`), and order
-(`<` and `>=`). As such, using the previous `Character` type, the
-following code is invalid:
+As with structures, the variants of an enum by default are not comparable with
+equality operators (`==`, `!=`), have no ordering (`<`, `>=`, etc.), and do not
+support other binary operations such as `*` and `+`. As such, the following code
+is invalid for the example `Character` type:
```{rust,ignore}
// These assignments both succeed
```
This may seem rather limiting, but it's a limitation which we can overcome.
-There are two ways: by implementing equality ourselves, or by using the
-[`match`][match] keyword. We don't know enough about Rust to implement equality
-yet, but we can use the `Ordering` enum from the standard library, which does:
+There are two ways: by implementing equality ourselves, or by pattern matching
+variants with [`match`][match] expressions, which you'll learn in the next
+chapter. We don't know enough about Rust to implement equality yet, but we can
+use the `Ordering` enum from the standard library, which does:
```
enum Ordering {
}
```
-Because we did not define `Ordering`, we must import it (from the std
-library) with the `use` keyword. Here's an example of how `Ordering` is
-used:
+Because `Ordering` has already been defined for us, we will import it with the
+`use` keyword. Here's an example of how it is used:
```{rust}
use std::cmp::Ordering;
Okay, let's talk about the actual code in the example. `cmp` is a function that
compares two things, and returns an `Ordering`. We return either
-`Ordering::Less`, `Ordering::Greater`, or `Ordering::Equal`, depending on if
-the two values are less, greater, or equal. Note that each variant of the
-`enum` is namespaced under the `enum` itself: it's `Ordering::Greater` not
-`Greater`.
+`Ordering::Less`, `Ordering::Greater`, or `Ordering::Equal`, depending on
+whether the first value is less than, greater than, or equal to the second. Note
+that each variant of the `enum` is namespaced under the `enum` itself: it's
+`Ordering::Greater`, not `Greater`.
The `ordering` variable has the type `Ordering`, and so contains one of the
three values. We then do a bunch of `if`/`else` comparisons to check which
one it is.
-This `Ordering::Greater` notation is too long. Let's use `use` to import the
-`enum` variants instead. This will avoid full scoping:
+This `Ordering::Greater` notation is too long. Let's use another form of `use`
+to import the `enum` variants instead. This will avoid full scoping:
```{rust}
use std::cmp::Ordering::{self, Equal, Less, Greater};
```
Importing variants is convenient and compact, but can also cause name conflicts,
-so do this with caution. It's considered good style to rarely import variants
-for this reason.
+so do this with caution. For this reason, it's normally considered better style
+to `use` an enum rather than its variants directly.
-As you can see, `enum`s are quite a powerful tool for data representation, and are
-even more useful when they're [generic][generics] across types. Before we
-get to generics, though, let's talk about how to use them with pattern matching, a
-tool that will let us deconstruct this sum type (the type theory term for enums)
-in a very elegant way and avoid all these messy `if`/`else`s.
+As you can see, `enum`s are quite a powerful tool for data representation, and
+are even more useful when they're [generic][generics] across types. Before we
+get to generics, though, let's talk about how to use enums with pattern
+matching, a tool that will let us deconstruct sum types (the type theory term
+for enums) like `Ordering` in a very elegant way that avoids all these messy
+and brittle `if`/`else`s.
+[arity]: ./glossary.html#arity
[match]: ./match.html
[game]: ./guessing-game.html#comparing-guesses
[generics]: ./generics.html
### `Sync`
-The second of these two trait is called [`Sync`](../std/marker/trait.Sync.html).
+The second of these traits is called [`Sync`](../std/marker/trait.Sync.html).
When a type `T` implements `Sync`, it indicates to the compiler that something
of this type has no possibility of introducing memory unsafety when used from
multiple threads concurrently.
For example, sharing immutable data with an atomic reference count is
threadsafe. Rust provides a type like this, `Arc<T>`, and it implements `Sync`,
-so that it could be safely shared between threads.
+so it is safe to share between threads.
These two traits allow you to use the type system to make strong guarantees
about the properties of your code under concurrency. Before we demonstrate
}
```
-The `Thread::scoped()` method accepts a closure, which is executed in a new
+The `thread::scoped()` method accepts a closure, which is executed in a new
thread. It's called `scoped` because this thread returns a join guard:
```
```text
<anon>:11:9: 11:22 error: the trait `core::marker::Send` is not implemented for the type `std::sync::mutex::MutexGuard<'_, collections::vec::Vec<u32>>` [E0277]
-<anon>:11 Thread::spawn(move || {
+<anon>:11 thread::spawn(move || {
^~~~~~~~~~~~~
<anon>:11:9: 11:22 note: `std::sync::mutex::MutexGuard<'_, collections::vec::Vec<u32>>` cannot be sent between threads safely
-<anon>:11 Thread::spawn(move || {
+<anon>:11 thread::spawn(move || {
^~~~~~~~~~~~~
```
is `Send` over the channel!
```
-use std::sync::{Arc, Mutex};
use std::thread;
use std::sync::mpsc;
% Crates and Modules
-When a project starts getting large, it's considered a good software
+When a project starts getting large, it's considered good software
engineering practice to split it up into a bunch of smaller pieces, and then
fit them together. It's also important to have a well-defined interface, so
that some of your functionality is private, and some is public. To facilitate
two languages for those phrases to be in. We'll use this module layout:
```text
- +-----------+
- +---| greetings |
- | +-----------+
- +---------+ |
- | english |---+
- +---------+ | +-----------+
- | +---| farewells |
-+---------+ | +-----------+
+ +-----------+
+ +---| greetings |
+ | +-----------+
+ +---------+ |
+ +---| english |---+
+ | +---------+ | +-----------+
+ | +---| farewells |
++---------+ | +-----------+
| phrases |---+
-+---------+ | +-----------+
- | +---| greetings |
- +----------+ | +-----------+
- | japanese |---+
- +----------+ |
- | +-----------+
- +---| farewells |
- +-----------+
++---------+ | +-----------+
+ | +---| greetings |
+ | +----------+ | +-----------+
+ +---| japanese |--+
+ +----------+ |
+ | +-----------+
+ +---| farewells |
+ +-----------+
```
In this example, `phrases` is the name of our crate. All of the rest are
`src/lib.rs` look like this:
```
-// in src/lib.rs
-
mod english {
mod greetings {
-
}
mod farewells {
-
}
}
mod japanese {
mod greetings {
-
}
mod farewells {
-
}
}
```
```
If we do that, Rust will expect to find either a `english.rs` file, or a
-`english/mod.rs` file with the contents of our module:
-
-```{rust,ignore}
-// contents of our module go here
-```
+`english/mod.rs` file with the contents of our module.
Note that in these files, you don't need to re-declare the module: that's
already been done with the initial `mod` declaration.
`src/lib.rs` is our crate root, and looks like this:
```{rust,ignore}
-// in src/lib.rs
-
mod english;
-
mod japanese;
```
like this:
```{rust,ignore}
-// both src/english/mod.rs and src/japanese/mod.rs
-
mod greetings;
-
mod farewells;
```
Put this in `src/english/greetings.rs`:
```rust
-// in src/english/greetings.rs
-
fn hello() -> String {
"Hello!".to_string()
}
Put this in `src/english/farewells.rs`:
```rust
-// in src/english/farewells.rs
-
fn goodbye() -> String {
"Goodbye.".to_string()
}
Put this in `src/japanese/farewells.rs`:
```rust
-// in src/japanese/farewells.rs
-
fn goodbye() -> String {
"さようなら".to_string()
}
We have a library crate. Let's make an executable crate that imports and uses
our library.
-Make a `src/main.rs` and put this in it: (it won't quite compile yet)
+Make a `src/main.rs` and put this in it (it won't quite compile yet):
```rust,ignore
-// in src/main.rs
-
extern crate phrases;
fn main() {
to just this:
```{rust,ignore}
-// in src/main.rs
-
extern crate phrases;
fn main() {
In our `src/lib.rs`, let's add `pub` to the `english` module declaration:
```{rust,ignore}
-// in src/lib.rs
-
pub mod english;
-
mod japanese;
```
And in our `src/english/mod.rs`, let's make both `pub`:
```{rust,ignore}
-// in src/english/mod.rs
-
pub mod greetings;
-
pub mod farewells;
```
In our `src/english/greetings.rs`, let's add `pub` to our `fn` declaration:
```{rust,ignore}
-// in src/english/greetings.rs
-
pub fn hello() -> String {
"Hello!".to_string()
}
And also in `src/english/farewells.rs`:
```{rust,ignore}
-// in src/english/farewells.rs
-
pub fn goodbye() -> String {
"Goodbye.".to_string()
}
Let's change our `src/main.rs` to look like this:
```{rust,ignore}
-// in src/main.rs
-
extern crate phrases;
use phrases::english::greetings;
}
```
-But it is not idiomatic. This is significantly more likely to introducing a
+But it is not idiomatic. This is significantly more likely to introduce a
naming conflict. In our short program, it's not a big deal, but as it grows, it
becomes a problem. If we have conflicting names, Rust will give a compilation
error. For example, if we made the `japanese` functions public, and tried to do
```
If we're importing multiple names from the same module, we don't have to type it out
-twice. Rust has a shortcut syntax for writing this:
+twice. Instead of this:
```{rust,ignore}
use phrases::english::greetings;
use phrases::english::farewells;
```
-You use curly braces:
+We can use this shortcut:
```{rust,ignore}
use phrases::english::{greetings, farewells};
```
-These two declarations are equivalent, but the second is a lot less typing.
-
## Re-exporting with `pub use`
You don't just use `use` to shorten identifiers. You can also use it inside of your crate
Let's look at an example. Modify your `src/main.rs` to read like this:
```{rust,ignore}
-// in src/main.rs
-
extern crate phrases;
use phrases::english::{greetings,farewells};
Then, modify your `src/lib.rs` to make the `japanese` mod public:
```{rust,ignore}
-// in src/lib.rs
-
pub mod english;
-
pub mod japanese;
```
Next, make the two functions public, first in `src/japanese/greetings.rs`:
```{rust,ignore}
-// in src/japanese/greetings.rs
-
pub fn hello() -> String {
"こんにちは".to_string()
}
And then in `src/japanese/farewells.rs`:
```{rust,ignore}
-// in src/japanese/farewells.rs
-
pub fn goodbye() -> String {
"さようなら".to_string()
}
Finally, modify your `src/japanese/mod.rs` to read like this:
```{rust,ignore}
-// in src/japanese/mod.rs
-
pub use self::greetings::hello;
pub use self::farewells::goodbye;
mod greetings;
-
mod farewells;
```
the error case explicitly. `expect()` allows us to give an error message if
this crash happens.
-We will cover the exact details of how all of this works later in the Guide.
-For now, this gives you enough of a basic understanding to work with.
+We will cover the exact details of how all of this works later in the Guide in
+[Error Handling]. For now, this gives you enough of a basic understanding to
+work with.
Back to the code we were working on! Here's a refresher:
That's all you need to get basic input from the standard input! It's not too
complicated, but there are a number of small parts.
+
+
+[Error Handling]: ./error-handling.html
///
/// On failure, return a null pointer and leave the original allocation intact.
///
+/// If the allocation was relocated, the memory at the passed-in pointer is
+/// undefined after the call.
+///
/// Behavior is undefined if the requested size is 0 or the alignment is not a
/// power of 2. The alignment must be no larger than the largest supported page
/// size on the platform.
impl Index<usize> for BitVec {
type Output = bool;
+
+ #[cfg(stage0)]
#[inline]
fn index(&self, i: &usize) -> &bool {
if self.get(*i).expect("index out of bounds") {
&FALSE
}
}
+
+ #[cfg(not(stage0))]
+ #[inline]
+ fn index(&self, i: usize) -> &bool {
+ if self.get(i).expect("index out of bounds") {
+ &TRUE
+ } else {
+ &FALSE
+ }
+ }
}
/// Computes how many blocks are needed to store that many bits
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;
}
/// 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>;
}
self
}
}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a, T: Clone> AsRef<T> for Cow<'a, T> {
+ fn as_ref(&self) -> &T {
+ self
+ }
+}
use core::fmt::Debug;
use core::hash::{Hash, Hasher};
use core::iter::{Map, FromIterator, IntoIterator};
-use core::ops::{Index, IndexMut};
+use core::ops::{Index};
use core::{iter, fmt, mem, usize};
use Bound::{self, Included, Excluded, Unbounded};
}
/// An abstract base over-which all other BTree iterators are built.
+#[derive(Clone)]
struct AbsIter<T> {
traversals: VecDeque<T>,
size: usize,
/// Some(x) => *x = "b",
/// None => (),
/// }
- /// assert_eq!(map[1], "b");
+ /// assert_eq!(map[&1], "b");
/// ```
// See `get` for implementation notes, this is basically a copy-paste with mut's added
#[stable(feature = "rust1", since = "1.0.0")]
///
/// 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, mut key: K, mut value: V) -> Option<V> {
}
}
+#[cfg(stage0)]
#[stable(feature = "rust1", since = "1.0.0")]
impl<K: Ord, Q: ?Sized, V> Index<Q> for BTreeMap<K, V>
where K: Borrow<Q>, 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<K: Ord, Q: ?Sized, V> IndexMut<Q> for BTreeMap<K, V>
+impl<'a, K: Ord, Q: ?Sized, V> Index<&'a Q> for BTreeMap<K, V>
where K: Borrow<Q>, Q: Ord
{
- fn index_mut(&mut self, key: &Q) -> &mut V {
- self.get_mut(key).expect("no entry found for key")
+ type Output = V;
+
+ #[inline]
+ fn index(&self, key: &Q) -> &V {
+ self.get(key).expect("no entry found for key")
}
}
}
}
+impl<'a, K, V> Clone for Iter<'a, K, V> {
+ fn clone(&self) -> Iter<'a, K, V> { Iter { inner: self.inner.clone() } }
+}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, K, V> Iterator for Iter<'a, K, V> {
type Item = (&'a K, &'a V);
#[stable(feature = "rust1", since = "1.0.0")]
impl<K, V> ExactSizeIterator for IntoIter<K, V> {}
+impl<'a, K, V> Clone for Keys<'a, K, V> {
+ fn clone(&self) -> Keys<'a, K, V> { Keys { inner: self.inner.clone() } }
+}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, K, V> Iterator for Keys<'a, K, V> {
type Item = &'a K;
impl<'a, K, V> ExactSizeIterator for Keys<'a, K, V> {}
+impl<'a, K, V> Clone for Values<'a, K, V> {
+ fn clone(&self) -> Values<'a, K, V> { Values { inner: self.inner.clone() } }
+}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, K, V> Iterator for Values<'a, K, V> {
type Item = &'a V;
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, K, V> ExactSizeIterator for Values<'a, K, V> {}
+impl<'a, K, V> Clone for Range<'a, K, V> {
+ fn clone(&self) -> Range<'a, K, V> { Range { inner: self.inner.clone() } }
+}
impl<'a, K, V> Iterator for Range<'a, K, V> {
type Item = (&'a K, &'a V);
/// A `TraversalImpl` that actually is backed by two iterators. This works in the non-moving case,
/// as no deallocation needs to be done.
+#[derive(Clone)]
struct ElemsAndEdges<Elems, Edges>(Elems, Edges);
impl<K, V, E, Elems: DoubleEndedIterator, Edges: DoubleEndedIterator>
}
/// An abstraction over all the different kinds of traversals a node supports
+#[derive(Clone)]
struct AbsTraversal<Impl> {
inner: Impl,
head_is_edge: bool,
}
/// Returns a sub-slice with elements starting with `min_key`.
+ #[cfg(stage0)]
pub fn slice_from(self, min_key: &K) -> $NodeSlice<'a, K, V> {
// _______________
// |_1_|_3_|_5_|_7_|
}
}
+ /// Returns a sub-slice with elements starting with `min_key`.
+ #[cfg(not(stage0))]
+ pub fn slice_from(self, min_key: &K) -> $NodeSlice<'a, K, V> {
+ // _______________
+ // |_1_|_3_|_5_|_7_|
+ // | | | | |
+ // 0 0 1 1 2 2 3 3 4 index
+ // | | | | |
+ // \___|___|___|___/ slice_from(&0); pos = 0
+ // \___|___|___/ slice_from(&2); pos = 1
+ // |___|___|___/ slice_from(&3); pos = 1; result.head_is_edge = false
+ // \___|___/ slice_from(&4); pos = 2
+ // \___/ slice_from(&6); pos = 3
+ // \|/ slice_from(&999); pos = 4
+ let (pos, pos_is_kv) = self.search_linear(min_key);
+ $NodeSlice {
+ has_edges: self.has_edges,
+ edges: if !self.has_edges {
+ self.edges
+ } else {
+ self.edges.$index(pos ..)
+ },
+ keys: &self.keys[pos ..],
+ vals: self.vals.$index(pos ..),
+ head_is_edge: !pos_is_kv,
+ tail_is_edge: self.tail_is_edge,
+ }
+ }
+
/// Returns a sub-slice with elements up to and including `max_key`.
+ #[cfg(stage0)]
pub fn slice_to(self, max_key: &K) -> $NodeSlice<'a, K, V> {
// _______________
// |_1_|_3_|_5_|_7_|
tail_is_edge: !pos_is_kv,
}
}
+
+ /// Returns a sub-slice with elements up to and including `max_key`.
+ #[cfg(not(stage0))]
+ pub fn slice_to(self, max_key: &K) -> $NodeSlice<'a, K, V> {
+ // _______________
+ // |_1_|_3_|_5_|_7_|
+ // | | | | |
+ // 0 0 1 1 2 2 3 3 4 index
+ // | | | | |
+ //\|/ | | | | slice_to(&0); pos = 0
+ // \___/ | | | slice_to(&2); pos = 1
+ // \___|___| | | slice_to(&3); pos = 1; result.tail_is_edge = false
+ // \___|___/ | | slice_to(&4); pos = 2
+ // \___|___|___/ | slice_to(&6); pos = 3
+ // \___|___|___|___/ slice_to(&999); pos = 4
+ let (pos, pos_is_kv) = self.search_linear(max_key);
+ let pos = pos + if pos_is_kv { 1 } else { 0 };
+ $NodeSlice {
+ has_edges: self.has_edges,
+ edges: if !self.has_edges {
+ self.edges
+ } else {
+ self.edges.$index(.. (pos + 1))
+ },
+ keys: &self.keys[..pos],
+ vals: self.vals.$index(.. pos),
+ head_is_edge: self.head_is_edge,
+ tail_is_edge: !pos_is_kv,
+ }
+ }
}
impl<'a, K: 'a, V: 'a> $NodeSlice<'a, K, V> {
}
}
+impl<'a, T> Clone for Iter<'a, T> {
+ fn clone(&self) -> Iter<'a, T> { Iter { iter: self.iter.clone() } }
+}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T> Iterator for Iter<'a, T> {
type Item = &'a T;
impl<T> ExactSizeIterator for IntoIter<T> {}
+impl<'a, T> Clone for Range<'a, T> {
+ fn clone(&self) -> Range<'a, T> { Range { iter: self.iter.clone() } }
+}
impl<'a, T> Iterator for Range<'a, T> {
type Item = &'a T;
}
}
+impl<'a, T> Clone for Difference<'a, T> {
+ fn clone(&self) -> Difference<'a, T> {
+ Difference { a: self.a.clone(), b: self.b.clone() }
+ }
+}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T: Ord> Iterator for Difference<'a, T> {
type Item = &'a T;
}
}
+impl<'a, T> Clone for SymmetricDifference<'a, T> {
+ fn clone(&self) -> SymmetricDifference<'a, T> {
+ SymmetricDifference { a: self.a.clone(), b: self.b.clone() }
+ }
+}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T: Ord> Iterator for SymmetricDifference<'a, T> {
type Item = &'a T;
}
}
+impl<'a, T> Clone for Intersection<'a, T> {
+ fn clone(&self) -> Intersection<'a, T> {
+ Intersection { a: self.a.clone(), b: self.b.clone() }
+ }
+}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T: Ord> Iterator for Intersection<'a, T> {
type Item = &'a T;
}
}
+impl<'a, T> Clone for Union<'a, T> {
+ fn clone(&self) -> Union<'a, T> {
+ Union { a: self.a.clone(), b: self.b.clone() }
+ }
+}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T: Ord> Iterator for Union<'a, T> {
type Item = &'a T;
//!
//! ```
//! # #![allow(unused_must_use)]
+//! use std::io::Write;
//! let mut w = Vec::new();
//! write!(&mut w, "Hello {}!", "world");
//! ```
//!
//! ```
//! use std::fmt;
-//! use std::old_io;
+//! use std::io::{self, Write};
//!
//! fmt::format(format_args!("this returns {}", "String"));
//!
-//! let mut some_writer = old_io::stdout();
+//! let mut some_writer = io::stdout();
//! write!(&mut some_writer, "{}", format_args!("print with a {}", "macro"));
//!
//! fn my_fmt_fn(args: fmt::Arguments) {
-//! write!(&mut old_io::stdout(), "{}", args);
+//! write!(&mut io::stdout(), "{}", args);
//! }
//! my_fmt_fn(format_args!("or a {} too", "function"));
//! ```
#![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
#![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};
fn connect(&self, sep: &T) -> U;
}
-impl<T: Clone, V: AsSlice<T>> SliceConcatExt<T, Vec<T>> for [V] {
+impl<T: Clone, V: AsRef<[T]>> SliceConcatExt<T, Vec<T>> for [V] {
fn concat(&self) -> Vec<T> {
- 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<T> {
- 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
}
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;
pub use core::str::{FromStr, Utf8Error, Str};
pub use core::str::{Lines, LinesAny, MatchIndices, SplitStr, CharRange};
-pub use core::str::{Split, SplitTerminator};
-pub use core::str::{SplitN, RSplitN};
+pub use core::str::{Split, SplitTerminator, SplitN};
+pub use core::str::{RSplit, RSplitN};
pub use core::str::{from_utf8, CharEq, Chars, CharIndices, Bytes};
pub use core::str::{from_utf8_unchecked, from_c_str, ParseBoolError};
pub use unicode::str::{Words, Graphemes, GraphemeIndices};
Section: Creating a string
*/
-impl<S: Str> SliceConcatExt<str, String> for [S] {
+impl<S: AsRef<str>> SliceConcatExt<str, String> 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
}
core_str::StrExt::split_terminator(&self[..], pat)
}
- /// An iterator over substrings of `self`, separated by characters matched by a pattern,
+ /// An iterator over substrings of `self`, separated by a pattern,
/// starting from the end of the string.
///
- /// Restricted to splitting at most `count` times.
+ /// # Examples
///
- /// The pattern can be a simple `&str`, or a closure that determines the split.
+ /// Simple patterns:
+ ///
+ /// ```
+ /// let v: Vec<&str> = "Mary had a little lamb".rsplit(' ').collect();
+ /// assert_eq!(v, ["lamb", "little", "a", "had", "Mary"]);
+ ///
+ /// let v: Vec<&str> = "lion::tiger::leopard".rsplit("::").collect();
+ /// assert_eq!(v, ["leopard", "tiger", "lion"]);
+ /// ```
+ ///
+ /// More complex patterns with a lambda:
+ ///
+ /// ```
+ /// let v: Vec<&str> = "abc1def2ghi".rsplit(|c: char| c.is_numeric()).collect();
+ /// assert_eq!(v, ["ghi", "def", "abc"]);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn rsplit<'a, P: Pattern<'a>>(&'a self, pat: P) -> RSplit<'a, P>
+ where P::Searcher: ReverseSearcher<'a>
+ {
+ core_str::StrExt::rsplit(&self[..], pat)
+ }
+
+ /// An iterator over substrings of `self`, separated by a pattern,
+ /// starting from the end of the string, restricted to splitting
+ /// at most `count` times.
///
/// # Examples
///
- /// Simple `&str` patterns:
+ /// Simple patterns:
///
/// ```
/// let v: Vec<&str> = "Mary had a little lamb".rsplitn(2, ' ').collect();
/// assert_eq!(v, ["lamb", "little", "Mary had a"]);
///
- /// let v: Vec<&str> = "lionXXtigerXleopard".rsplitn(2, 'X').collect();
- /// assert_eq!(v, ["leopard", "tiger", "lionX"]);
+ /// let v: Vec<&str> = "lion::tiger::leopard".rsplitn(1, "::").collect();
+ /// assert_eq!(v, ["leopard", "lion::tiger"]);
/// ```
///
/// More complex patterns with a lambda:
/// assert_eq!(v, ["ghi", "abc1def"]);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn rsplitn<'a, P: Pattern<'a>>(&'a self, count: usize, pat: P) -> RSplitN<'a, P> {
+ pub fn rsplitn<'a, P: Pattern<'a>>(&'a self, count: usize, pat: P) -> RSplitN<'a, P>
+ where P::Searcher: ReverseSearcher<'a>
+ {
core_str::StrExt::rsplitn(&self[..], count, pat)
}
use core::ops::{self, Deref, Add, Index};
use core::ptr;
use core::slice;
+use core::str::Pattern;
use unicode::str as unicode_str;
use unicode::str::Utf16Item;
}
}
+/// A convenience impl that delegates to the impl for `&str`
+impl<'a, 'b> Pattern<'a> for &'b String {
+ type Searcher = <&'b str as Pattern<'a>>::Searcher;
+
+ fn into_searcher(self, haystack: &'a str) -> <&'b str as Pattern<'a>>::Searcher {
+ self[..].into_searcher(haystack)
+ }
+
+ #[inline]
+ fn is_contained_in(self, haystack: &'a str) -> bool {
+ self[..].is_contained_in(haystack)
+ }
+
+ #[inline]
+ fn is_prefix_of(self, haystack: &'a str) -> bool {
+ self[..].is_prefix_of(haystack)
+ }
+}
+
#[stable(feature = "rust1", since = "1.0.0")]
impl PartialEq for String {
#[inline]
}
#[unstable(feature = "collections", reason = "waiting on Str stabilization")]
+#[allow(deprecated)]
impl Str for String {
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
#[stable(feature = "rust1", since = "1.0.0")]
impl ops::Index<ops::Range<usize>> for String {
type Output = str;
+
+ #[cfg(stage0)]
#[inline]
fn index(&self, index: &ops::Range<usize>) -> &str {
&self[..][*index]
}
+
+ #[cfg(not(stage0))]
+ #[inline]
+ fn index(&self, index: ops::Range<usize>) -> &str {
+ &self[..][index]
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl ops::Index<ops::RangeTo<usize>> for String {
type Output = str;
+
+ #[cfg(stage0)]
#[inline]
fn index(&self, index: &ops::RangeTo<usize>) -> &str {
&self[..][*index]
}
+
+ #[cfg(not(stage0))]
+ #[inline]
+ fn index(&self, index: ops::RangeTo<usize>) -> &str {
+ &self[..][index]
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl ops::Index<ops::RangeFrom<usize>> for String {
type Output = str;
+
+ #[cfg(stage0)]
#[inline]
fn index(&self, index: &ops::RangeFrom<usize>) -> &str {
&self[..][*index]
}
+
+ #[cfg(not(stage0))]
+ #[inline]
+ fn index(&self, index: ops::RangeFrom<usize>) -> &str {
+ &self[..][index]
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl ops::Index<ops::RangeFull> 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")]
}
}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRef<str> 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<Vec<u8>> for String {
+ fn into(self) -> Vec<u8> {
+ self.into_bytes()
+ }
+}
+
#[stable(feature = "rust1", since = "1.0.0")]
impl IntoCow<'static, str> for String {
#[inline]
}
}
+#[allow(deprecated)]
impl<'a> Str for Cow<'a, str> {
#[inline]
fn as_slice<'b>(&'b self) -> &'b str {
impl<T> Index<usize> for Vec<T> {
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<T> IndexMut<usize> for Vec<T> {
+
+ #[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<T> ops::Index<ops::Range<usize>> for Vec<T> {
type Output = [T];
+
+ #[cfg(stage0)]
#[inline]
fn index(&self, index: &ops::Range<usize>) -> &[T] {
Index::index(&**self, index)
}
+
+ #[cfg(not(stage0))]
+ #[inline]
+ fn index(&self, index: ops::Range<usize>) -> &[T] {
+ Index::index(&**self, index)
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> ops::Index<ops::RangeTo<usize>> for Vec<T> {
type Output = [T];
+
+ #[cfg(stage0)]
#[inline]
fn index(&self, index: &ops::RangeTo<usize>) -> &[T] {
Index::index(&**self, index)
}
+
+ #[cfg(not(stage0))]
+ #[inline]
+ fn index(&self, index: ops::RangeTo<usize>) -> &[T] {
+ Index::index(&**self, index)
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> ops::Index<ops::RangeFrom<usize>> for Vec<T> {
type Output = [T];
+
+ #[cfg(stage0)]
#[inline]
fn index(&self, index: &ops::RangeFrom<usize>) -> &[T] {
Index::index(&**self, index)
}
+
+ #[cfg(not(stage0))]
+ #[inline]
+ fn index(&self, index: ops::RangeFrom<usize>) -> &[T] {
+ Index::index(&**self, index)
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> ops::Index<ops::RangeFull> for Vec<T> {
type Output = [T];
+
+ #[cfg(stage0)]
#[inline]
fn index(&self, _index: &ops::RangeFull) -> &[T] {
+ self
+ }
+
+ #[cfg(not(stage0))]
+ #[inline]
+ fn index(&self, _index: ops::RangeFull) -> &[T] {
self.as_slice()
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> ops::IndexMut<ops::Range<usize>> for Vec<T> {
+
+ #[cfg(stage0)]
#[inline]
fn index_mut(&mut self, index: &ops::Range<usize>) -> &mut [T] {
IndexMut::index_mut(&mut **self, index)
}
+
+ #[cfg(not(stage0))]
+ #[inline]
+ fn index_mut(&mut self, index: ops::Range<usize>) -> &mut [T] {
+ IndexMut::index_mut(&mut **self, index)
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> ops::IndexMut<ops::RangeTo<usize>> for Vec<T> {
+
+ #[cfg(stage0)]
#[inline]
fn index_mut(&mut self, index: &ops::RangeTo<usize>) -> &mut [T] {
IndexMut::index_mut(&mut **self, index)
}
+
+ #[cfg(not(stage0))]
+ #[inline]
+ fn index_mut(&mut self, index: ops::RangeTo<usize>) -> &mut [T] {
+ IndexMut::index_mut(&mut **self, index)
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> ops::IndexMut<ops::RangeFrom<usize>> for Vec<T> {
+
+ #[cfg(stage0)]
#[inline]
fn index_mut(&mut self, index: &ops::RangeFrom<usize>) -> &mut [T] {
IndexMut::index_mut(&mut **self, index)
}
+
+ #[cfg(not(stage0))]
+ #[inline]
+ fn index_mut(&mut self, index: ops::RangeFrom<usize>) -> &mut [T] {
+ IndexMut::index_mut(&mut **self, index)
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> ops::IndexMut<ops::RangeFull> for Vec<T> {
+
+ #[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")]
impl<T> ops::Deref for Vec<T> {
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")]
}
}
+#[allow(deprecated)]
impl<T> AsSlice<T> for Vec<T> {
/// Returns a slice into `self`.
///
#[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
}
}
}
}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T> AsRef<Vec<T>> for Vec<T> {
+ fn as_ref(&self) -> &Vec<T> {
+ self
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T> Into<Vec<T>> for Vec<T> {
+ fn into(self) -> Vec<T> {
+ self
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T> AsRef<[T]> for Vec<T> {
+ fn as_ref(&self) -> &[T] {
+ self
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a, T: Clone> From<&'a [T]> for Vec<T> {
+ fn from(s: &'a [T]) -> Vec<T> {
+ s.to_vec()
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a> From<&'a str> for Vec<u8> {
+ fn from(s: &'a str) -> Vec<u8> {
+ s.as_bytes().to_vec()
+ }
+}
+
////////////////////////////////////////////////////////////////////////////////
// Clone-on-write
////////////////////////////////////////////////////////////////////////////////
impl<A> Index<usize> for VecDeque<A> {
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<A> IndexMut<usize> for VecDeque<A> {
+ #[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")]
}
}
+#[cfg(stage0)]
impl<V> Index<usize> for VecMap<V> {
type Output = V;
}
}
+#[cfg(not(stage0))]
+impl<V> Index<usize> for VecMap<V> {
+ 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<V> {
+ 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<V> IndexMut<usize> for VecMap<V> {
+ #[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<V> IndexMut<usize> for VecMap<V> {
#[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<V> {
+ #[inline]
+ fn index_mut(&mut self, i: &usize) -> &mut V {
self.get_mut(i).expect("key not present")
}
}
assert_eq!(split, ["", "Märy häd ä little lämb", "Little lämb"]);
}
+#[test]
+fn test_rsplit() {
+ let data = "\nMäry häd ä little lämb\nLittle lämb\n";
+
+ let split: Vec<&str> = data.rsplit(' ').collect();
+ assert_eq!(split, ["lämb\n", "lämb\nLittle", "little", "ä", "häd", "\nMäry"]);
+
+ let split: Vec<&str> = data.rsplit("lämb").collect();
+ assert_eq!(split, ["\n", "\nLittle ", "\nMäry häd ä little "]);
+
+ let split: Vec<&str> = data.rsplit(|c: char| c == 'ä').collect();
+ assert_eq!(split, ["mb\n", "mb\nLittle l", " little l", "d ", "ry h", "\nM"]);
+}
+
+#[test]
+fn test_rsplitn() {
+ let data = "\nMäry häd ä little lämb\nLittle lämb\n";
+
+ let split: Vec<&str> = data.rsplitn(1, ' ').collect();
+ assert_eq!(split, ["lämb\n", "\nMäry häd ä little lämb\nLittle"]);
+
+ let split: Vec<&str> = data.rsplitn(1, "lämb").collect();
+ assert_eq!(split, ["\n", "\nMäry häd ä little lämb\nLittle "]);
+
+ let split: Vec<&str> = data.rsplitn(1, |c: char| c == 'ä').collect();
+ assert_eq!(split, ["mb\n", "\nMäry häd ä little lämb\nLittle l"]);
+}
+
#[test]
fn test_words() {
let data = "\n \tMäry häd\tä little lämb\nLittle lämb\n";
--- /dev/null
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! 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<T: ?Sized> {
+ /// Perform the conversion.
+ fn as_ref(&self) -> &T;
+}
+
+/// A cheap, mutable reference-to-mutable reference conversion.
+pub trait AsMut<T: ?Sized> {
+ /// 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<T>: Sized {
+ /// Perform the conversion.
+ fn into(self) -> T;
+}
+
+/// Construct `Self` via a conversion.
+pub trait From<T> {
+ /// 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<U> {
+ fn into(self) -> &'a U {
+ self.as_ref()
+ }
+}
+
+// As lifts over &
+impl<'a, T: ?Sized, U: ?Sized> AsRef<U> for &'a T where T: AsRef<U> {
+ fn as_ref(&self) -> &U {
+ <T as AsRef<U>>::as_ref(*self)
+ }
+}
+
+// As lifts over &mut
+impl<'a, T: ?Sized, U: ?Sized> AsRef<U> for &'a mut T where T: AsRef<U> {
+ fn as_ref(&self) -> &U {
+ <T as AsRef<U>>::as_ref(*self)
+ }
+}
+
+// AsMut implies Into
+impl<'a, T: ?Sized, U: ?Sized> Into<&'a mut U> for &'a mut T where T: AsMut<U> {
+ fn into(self) -> &'a mut U {
+ (*self).as_mut()
+ }
+}
+
+// AsMut lifts over &mut
+impl<'a, T: ?Sized, U: ?Sized> AsMut<U> for &'a mut T where T: AsMut<U> {
+ fn as_mut(&mut self) -> &mut U {
+ (*self).as_mut()
+ }
+}
+
+// From implies Into
+impl<T, U> Into<U> for T where U: From<T> {
+ fn into(self) -> U {
+ U::from(self)
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// CONCRETE IMPLS
+////////////////////////////////////////////////////////////////////////////////
+
+impl<T> AsRef<[T]> for [T] {
+ fn as_ref(&self) -> &[T] {
+ self
+ }
+}
+
+impl<T> AsMut<[T]> for [T] {
+ fn as_mut(&mut self) -> &mut [T] {
+ self
+ }
+}
+
+impl AsRef<str> for str {
+ fn as_ref(&self) -> &str {
+ self
+ }
+}
#![stable(feature = "rust1", since = "1.0.0")]
use prelude::*;
-use fmt::Display;
+use fmt::{Debug, Display};
/// Base functionality for all errors in Rust.
-#[unstable(feature = "core",
- reason = "the exact API of this trait may change")]
-pub trait Error: Display {
- /// A short description of the error; usually a static string.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub trait Error: Debug + Display + Send {
+ /// A short description of the error.
+ ///
+ /// The description should not contain newlines or sentence-ending
+ /// punctuation, to facilitate embedding in larger user-facing
+ /// strings.
+ #[stable(feature = "rust1", since = "1.0.0")]
fn description(&self) -> &str;
/// The lower-level cause of this error, if any.
+ #[stable(feature = "rust1", since = "1.0.0")]
fn cause(&self) -> Option<&Error> { None }
}
pub mod cmp;
pub mod clone;
pub mod default;
+pub mod convert;
/* Core types and methods on primitives */
///
/// ```
/// # #![allow(unused_must_use)]
+/// use std::io::Write;
///
/// let mut w = Vec::new();
/// write!(&mut w, "test");
// empty.
}
+unsafe impl Send for .. { }
+
impl<T> !Send for *const T { }
impl<T> !Send for *mut T { }
impl !Send for Managed { }
// Empty
}
+unsafe impl Sync for .. { }
+
impl<T> !Sync for *const T { }
impl<T> !Sync for *mut T { }
impl !Sync for Managed { }
/// impl Index<Bar> 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
/// }
type Output: ?Sized;
/// The method for the indexing (`Foo[Bar]`) operation
+ #[cfg(stage0)]
#[stable(feature = "rust1", since = "1.0.0")]
fn index<'a>(&'a self, index: &Idx) -> &'a Self::Output;
+
+ /// The method for the indexing (`Foo[Bar]`) operation
+ #[cfg(not(stage0))]
+ #[stable(feature = "rust1", since = "1.0.0")]
+ fn index<'a>(&'a self, index: Idx) -> &'a Self::Output;
}
/// The `IndexMut` trait is used to specify the functionality of indexing
/// impl Index<Bar> 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<Bar> 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
/// }
#[stable(feature = "rust1", since = "1.0.0")]
pub trait IndexMut<Idx: ?Sized>: Index<Idx> {
/// The method for the indexing (`Foo[Bar]`) operation
+ #[cfg(stage0)]
#[stable(feature = "rust1", since = "1.0.0")]
fn index_mut<'a>(&'a mut self, index: &Idx) -> &'a mut Self::Output;
+
+ /// The method for the indexing (`Foo[Bar]`) operation
+ #[cfg(not(stage0))]
+ #[stable(feature = "rust1", since = "1.0.0")]
+ fn index_mut<'a>(&'a mut self, index: Idx) -> &'a mut Self::Output;
}
/// An unbounded range.
use ops::{Deref, FnOnce};
use result::Result::{Ok, Err};
use result::Result;
+#[allow(deprecated)]
use slice::AsSlice;
use slice;
pub fn take(&mut self) -> Option<T> {
mem::replace(self, None)
}
+
+ /// Convert from `Option<T>` 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<Target=T>> Option<D> {
#[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<T> AsSlice<T> for Option<T> {
/// Convert from `Option<T>` to `&[T]` (without copying)
#[inline]
pub use ops::{Drop, Fn, FnMut, FnOnce};
// Reexported functions
-#[allow(deprecated)]
-pub use iter::range;
pub use mem::drop;
// Reexported types and traits
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};
//! let bad_result: Result<int, int> = bad_result.or_else(|i| Ok(11));
//!
//! // Consume the result and return the contents with `unwrap`.
-//! let final_awesome_result = good_result.ok().unwrap();
+//! let final_awesome_result = good_result.unwrap();
//! ```
//!
//! # Results must be used
//! something like this:
//!
//! ```{.ignore}
-//! use std::old_io::{File, Open, Write};
+//! use std::old_io::*;
+//! use std::old_path::Path;
//!
//! let mut file = File::open_mode(&Path::new("valuable_data.txt"), Open, Write);
//! // If `write_line` errors, then we'll never know, because the return
//! a marginally useful message indicating why:
//!
//! ```{.no_run}
-//! use std::old_io::{File, Open, Write};
+//! use std::old_io::*;
+//! use std::old_path::Path;
//!
//! let mut file = File::open_mode(&Path::new("valuable_data.txt"), Open, Write);
//! file.write_line("important message").ok().expect("failed to write message");
//! You might also simply assert success:
//!
//! ```{.no_run}
-//! # use std::old_io::{File, Open, Write};
+//! # use std::old_io::*;
+//! # use std::old_path::Path;
//!
//! # let mut file = File::open_mode(&Path::new("valuable_data.txt"), Open, Write);
//! assert!(file.write_line("important message").is_ok());
//! Or propagate the error up the call stack with `try!`:
//!
//! ```
-//! # use std::old_io::{File, Open, Write, IoError};
+//! # use std::old_io::*;
+//! # use std::old_path::Path;
//! fn write_message() -> Result<(), IoError> {
//! let mut file = File::open_mode(&Path::new("valuable_data.txt"), Open, Write);
//! try!(file.write_line("important message"));
//! It replaces this:
//!
//! ```
-//! use std::old_io::{File, Open, Write, IoError};
+//! use std::old_io::*;
+//! use std::old_path::Path;
//!
//! struct Info {
//! name: String,
//! With this:
//!
//! ```
-//! use std::old_io::{File, Open, Write, IoError};
+//! use std::old_io::*;
+//! use std::old_path::Path;
//!
//! struct Info {
//! name: String,
FromIterator, ExactSizeIterator, IntoIterator};
use ops::{FnMut, FnOnce};
use option::Option::{self, None, Some};
+#[allow(deprecated)]
use slice::AsSlice;
use slice;
}
}
+ /// Convert from `Result<T, E>` 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<T, E>` to `&mut [T]` (without copying)
///
/// ```
/// ignoring I/O and parse errors:
///
/// ```
- /// use std::old_io::IoResult;
+ /// use std::old_io::*;
///
/// let mut buffer: &[u8] = b"1\n2\n3\n4\n";
/// let mut buffer = &mut buffer;
/// line.trim_right().parse::<int>().unwrap_or(0)
/// });
/// // Add the value if there were no errors, otherwise add 0
- /// sum += val.ok().unwrap_or(0);
+ /// sum += val.unwrap_or(0);
/// }
///
/// assert!(sum == 10);
// 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<T, E> AsSlice<T> for Result<T, E> {
/// Convert from `Result<T, E>` 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),
#[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 {
}
}
+ #[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 {
impl<T> ops::Index<usize> 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<T> ops::IndexMut<usize> 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<T> ops::Index<ops::Range<usize>> for [T] {
type Output = [T];
+
+ #[cfg(stage0)]
#[inline]
fn index(&self, index: &ops::Range<usize>) -> &[T] {
assert!(index.start <= index.end);
)
}
}
+
+ #[cfg(not(stage0))]
+ #[inline]
+ fn index(&self, index: ops::Range<usize>) -> &[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<T> ops::Index<ops::RangeTo<usize>> for [T] {
type Output = [T];
+
+ #[cfg(stage0)]
#[inline]
fn index(&self, index: &ops::RangeTo<usize>) -> &[T] {
self.index(&ops::Range{ start: 0, end: index.end })
}
+
+ #[cfg(not(stage0))]
+ #[inline]
+ fn index(&self, index: ops::RangeTo<usize>) -> &[T] {
+ self.index(ops::Range{ start: 0, end: index.end })
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> ops::Index<ops::RangeFrom<usize>> for [T] {
type Output = [T];
+
+ #[cfg(stage0)]
#[inline]
fn index(&self, index: &ops::RangeFrom<usize>) -> &[T] {
self.index(&ops::Range{ start: index.start, end: self.len() })
}
+
+ #[cfg(not(stage0))]
+ #[inline]
+ fn index(&self, index: ops::RangeFrom<usize>) -> &[T] {
+ self.index(ops::Range{ start: index.start, end: self.len() })
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> ops::Index<RangeFull> 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<T> ops::IndexMut<ops::Range<usize>> for [T] {
+ #[cfg(stage0)]
#[inline]
fn index_mut(&mut self, index: &ops::Range<usize>) -> &mut [T] {
assert!(index.start <= index.end);
)
}
}
+
+ #[cfg(not(stage0))]
+ #[inline]
+ fn index_mut(&mut self, index: ops::Range<usize>) -> &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<T> ops::IndexMut<ops::RangeTo<usize>> for [T] {
+ #[cfg(stage0)]
#[inline]
fn index_mut(&mut self, index: &ops::RangeTo<usize>) -> &mut [T] {
self.index_mut(&ops::Range{ start: 0, end: index.end })
}
+
+ #[cfg(not(stage0))]
+ #[inline]
+ fn index_mut(&mut self, index: ops::RangeTo<usize>) -> &mut [T] {
+ self.index_mut(ops::Range{ start: 0, end: index.end })
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> ops::IndexMut<ops::RangeFrom<usize>> for [T] {
+ #[cfg(stage0)]
#[inline]
fn index_mut(&mut self, index: &ops::RangeFrom<usize>) -> &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<usize>) -> &mut [T] {
+ let len = self.len();
+ self.index_mut(ops::Range{ start: index.start, end: len })
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> ops::IndexMut<RangeFull> 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
+ }
}
/// 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<T> {
/// Work with `self` as a slice.
fn as_slice<'a>(&'a self) -> &'a [T];
}
#[unstable(feature = "core", reason = "trait is experimental")]
+#[allow(deprecated)]
impl<T> AsSlice<T> 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<T>> AsSlice<T> 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<T>> AsSlice<T> for &'a mut U {
#[inline(always)]
fn as_slice(&self) -> &[T] { AsSlice::as_slice(*self) }
#[unstable(feature = "core")]
impl<'a, T> ops::Index<ops::Range<usize>> for Iter<'a, T> {
type Output = [T];
+
+ #[cfg(stage0)]
#[inline]
fn index(&self, index: &ops::Range<usize>) -> &[T] {
self.as_slice().index(index)
}
+
+ #[cfg(not(stage0))]
+ #[inline]
+ fn index(&self, index: ops::Range<usize>) -> &[T] {
+ self.as_slice().index(index)
+ }
}
#[unstable(feature = "core")]
impl<'a, T> ops::Index<ops::RangeTo<usize>> for Iter<'a, T> {
type Output = [T];
+
+ #[cfg(stage0)]
#[inline]
fn index(&self, index: &ops::RangeTo<usize>) -> &[T] {
self.as_slice().index(index)
}
+
+ #[cfg(not(stage0))]
+ #[inline]
+ fn index(&self, index: ops::RangeTo<usize>) -> &[T] {
+ self.as_slice().index(index)
+ }
}
#[unstable(feature = "core")]
impl<'a, T> ops::Index<ops::RangeFrom<usize>> for Iter<'a, T> {
type Output = [T];
+
+ #[cfg(stage0)]
#[inline]
fn index(&self, index: &ops::RangeFrom<usize>) -> &[T] {
self.as_slice().index(index)
}
+
+ #[cfg(not(stage0))]
+ #[inline]
+ fn index(&self, index: ops::RangeFrom<usize>) -> &[T] {
+ self.as_slice().index(index)
+ }
}
#[unstable(feature = "core")]
impl<'a, T> ops::Index<RangeFull> 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> {
#[unstable(feature = "core")]
impl<'a, T> ops::Index<ops::Range<usize>> for IterMut<'a, T> {
type Output = [T];
+
+ #[cfg(stage0)]
#[inline]
fn index(&self, index: &ops::Range<usize>) -> &[T] {
self.index(&RangeFull).index(index)
}
+
+ #[cfg(not(stage0))]
+ #[inline]
+ fn index(&self, index: ops::Range<usize>) -> &[T] {
+ self.index(RangeFull).index(index)
+ }
}
#[unstable(feature = "core")]
impl<'a, T> ops::Index<ops::RangeTo<usize>> for IterMut<'a, T> {
type Output = [T];
+
+ #[cfg(stage0)]
#[inline]
fn index(&self, index: &ops::RangeTo<usize>) -> &[T] {
self.index(&RangeFull).index(index)
}
+
+ #[cfg(not(stage0))]
+ #[inline]
+ fn index(&self, index: ops::RangeTo<usize>) -> &[T] {
+ self.index(RangeFull).index(index)
+ }
}
#[unstable(feature = "core")]
impl<'a, T> ops::Index<ops::RangeFrom<usize>> for IterMut<'a, T> {
type Output = [T];
+
+ #[cfg(stage0)]
#[inline]
fn index(&self, index: &ops::RangeFrom<usize>) -> &[T] {
self.index(&RangeFull).index(index)
}
+
+ #[cfg(not(stage0))]
+ #[inline]
+ fn index(&self, index: ops::RangeFrom<usize>) -> &[T] {
+ self.index(RangeFull).index(index)
+ }
}
#[unstable(feature = "core")]
impl<'a, T> ops::Index<RangeFull> 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<ops::Range<usize>> for IterMut<'a, T> {
+ #[cfg(stage0)]
#[inline]
fn index_mut(&mut self, index: &ops::Range<usize>) -> &mut [T] {
self.index_mut(&RangeFull).index_mut(index)
}
+
+ #[cfg(not(stage0))]
+ #[inline]
+ fn index_mut(&mut self, index: ops::Range<usize>) -> &mut [T] {
+ self.index_mut(RangeFull).index_mut(index)
+ }
}
#[unstable(feature = "core")]
impl<'a, T> ops::IndexMut<ops::RangeTo<usize>> for IterMut<'a, T> {
+
+ #[cfg(stage0)]
#[inline]
fn index_mut(&mut self, index: &ops::RangeTo<usize>) -> &mut [T] {
self.index_mut(&RangeFull).index_mut(index)
}
+
+ #[cfg(not(stage0))]
+ #[inline]
+ fn index_mut(&mut self, index: ops::RangeTo<usize>) -> &mut [T] {
+ self.index_mut(RangeFull).index_mut(index)
+ }
}
#[unstable(feature = "core")]
impl<'a, T> ops::IndexMut<ops::RangeFrom<usize>> for IterMut<'a, T> {
+
+ #[cfg(stage0)]
#[inline]
fn index_mut(&mut self, index: &ops::RangeFrom<usize>) -> &mut [T] {
self.index_mut(&RangeFull).index_mut(index)
}
+
+ #[cfg(not(stage0))]
+ #[inline]
+ fn index_mut(&mut self, index: ops::RangeFrom<usize>) -> &mut [T] {
+ self.index_mut(RangeFull).index_mut(index)
+ }
}
#[unstable(feature = "core")]
impl<'a, T> ops::IndexMut<RangeFull> 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)
+ }
}
self.0.size_hint()
}
}
- }
+ };
+ (pattern reverse $te:ty : $ti:ty) => {
+ #[stable(feature = "rust1", since = "1.0.0")]
+ impl<'a, P: Pattern<'a>> Iterator for $ti
+ where P::Searcher: ReverseSearcher<'a>
+ {
+ type Item = $te;
+
+ #[inline]
+ fn next(&mut self) -> Option<$te> {
+ self.0.next()
+ }
+ #[inline]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ self.0.size_hint()
+ }
+ }
+ };
}
/// A trait to abstract the idea of creating a new instance of a type from a
iter: CharSplits<'a, P>,
/// The number of splits remaining
count: usize,
- invert: bool,
+}
+
+/// An iterator over the substrings of a string, separated by a
+/// pattern, in reverse order.
+struct RCharSplits<'a, P: Pattern<'a>> {
+ /// The slice remaining to be iterated
+ start: usize,
+ end: usize,
+ matcher: P::Searcher,
+ /// Whether an empty string at the end of iteration is allowed
+ allow_final_empty: bool,
+ finished: bool,
+}
+
+/// An iterator over the substrings of a string, separated by a
+/// pattern, splitting at most `count` times, in reverse order.
+struct RCharSplitsN<'a, P: Pattern<'a>> {
+ iter: RCharSplits<'a, P>,
+ /// The number of splits remaining
+ count: usize,
}
/// An iterator over the lines of a string, separated by `\n`.
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, P: Pattern<'a>> Iterator for CharSplitsN<'a, P>
-where P::Searcher: DoubleEndedSearcher<'a> {
+impl<'a, P: Pattern<'a>> Iterator for CharSplitsN<'a, P> {
type Item = &'a str;
#[inline]
fn next(&mut self) -> Option<&'a str> {
if self.count != 0 {
self.count -= 1;
- if self.invert { self.iter.next_back() } else { self.iter.next() }
+ self.iter.next()
} else {
self.iter.get_end()
}
}
}
+impl<'a, P: Pattern<'a>> RCharSplits<'a, P> {
+ #[inline]
+ fn get_remainder(&mut self) -> Option<&'a str> {
+ if !self.finished && (self.allow_final_empty || self.end - self.start > 0) {
+ self.finished = true;
+ unsafe {
+ let string = self.matcher.haystack().slice_unchecked(self.start, self.end);
+ Some(string)
+ }
+ } else {
+ None
+ }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a, P: Pattern<'a>> Iterator for RCharSplits<'a, P>
+ where P::Searcher: ReverseSearcher<'a>
+{
+ type Item = &'a str;
+
+ #[inline]
+ fn next(&mut self) -> Option<&'a str> {
+ if self.finished { return None }
+
+ let haystack = self.matcher.haystack();
+ match self.matcher.next_match_back() {
+ Some((a, b)) => unsafe {
+ let elt = haystack.slice_unchecked(b, self.end);
+ self.end = a;
+ Some(elt)
+ },
+ None => self.get_remainder(),
+ }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a, P: Pattern<'a>> Iterator for RCharSplitsN<'a, P>
+ where P::Searcher: ReverseSearcher<'a>
+{
+ type Item = &'a str;
+
+ #[inline]
+ fn next(&mut self) -> Option<&'a str> {
+ if self.count != 0 {
+ self.count -= 1;
+ self.iter.next()
+ } else {
+ self.iter.get_remainder()
+ }
+ }
+}
+
/// The internal state of an iterator that searches for matches of a substring
/// within a larger string using two-way search
#[derive(Clone)]
/// // byte 100 is outside the string
/// // &s[3 .. 100];
/// ```
+ #[cfg(stage0)]
#[stable(feature = "rust1", since = "1.0.0")]
impl ops::Index<ops::Range<usize>> for str {
type Output = str;
}
}
+ /// 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<ops::Range<usize>> for str {
+ type Output = str;
+ #[inline]
+ fn index(&self, index: ops::Range<usize>) -> &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`.
///
#[stable(feature = "rust1", since = "1.0.0")]
impl ops::Index<ops::RangeTo<usize>> for str {
type Output = str;
+
+ #[cfg(stage0)]
#[inline]
fn index(&self, index: &ops::RangeTo<usize>) -> &str {
// is_char_boundary checks that the index is in [0, .len()]
super::slice_error_fail(self, 0, index.end)
}
}
+
+ #[cfg(not(stage0))]
+ #[inline]
+ fn index(&self, index: ops::RangeTo<usize>) -> &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.
#[stable(feature = "rust1", since = "1.0.0")]
impl ops::Index<ops::RangeFrom<usize>> for str {
type Output = str;
+
+ #[cfg(stage0)]
#[inline]
fn index(&self, index: &ops::RangeFrom<usize>) -> &str {
// is_char_boundary checks that the index is in [0, .len()]
super::slice_error_fail(self, index.start, self.len())
}
}
+
+ #[cfg(not(stage0))]
+ #[inline]
+ fn index(&self, index: ops::RangeFrom<usize>) -> &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<ops::RangeFull> 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
+ }
}
}
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<str> 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) }
/// Return type of `StrExt::split`
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Split<'a, P: Pattern<'a>>(CharSplits<'a, P>);
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, P: Pattern<'a>> Iterator for Split<'a, P> {
- type Item = &'a str;
-
- #[inline]
- fn next(&mut self) -> Option<&'a str> {
- self.0.next()
- }
-}
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, P: Pattern<'a>> DoubleEndedIterator for Split<'a, P>
-where P::Searcher: DoubleEndedSearcher<'a> {
- #[inline]
- fn next_back(&mut self) -> Option<&'a str> {
- self.0.next_back()
- }
-}
+delegate_iter!{pattern &'a str : Split<'a, P>}
/// Return type of `StrExt::split_terminator`
#[stable(feature = "rust1", since = "1.0.0")]
pub struct SplitN<'a, P: Pattern<'a>>(CharSplitsN<'a, P>);
delegate_iter!{pattern forward &'a str : SplitN<'a, P>}
+/// Return type of `StrExt::rsplit`
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct RSplit<'a, P: Pattern<'a>>(RCharSplits<'a, P>);
+delegate_iter!{pattern reverse &'a str : RSplit<'a, P>}
+
/// Return type of `StrExt::rsplitn`
#[stable(feature = "rust1", since = "1.0.0")]
-pub struct RSplitN<'a, P: Pattern<'a>>(CharSplitsN<'a, P>);
-delegate_iter!{pattern forward &'a str : RSplitN<'a, P>}
+pub struct RSplitN<'a, P: Pattern<'a>>(RCharSplitsN<'a, P>);
+delegate_iter!{pattern reverse &'a str : RSplitN<'a, P>}
/// Methods for string slices
#[allow(missing_docs)]
fn split<'a, P: Pattern<'a>>(&'a self, pat: P) -> Split<'a, P>;
fn splitn<'a, P: Pattern<'a>>(&'a self, count: usize, pat: P) -> SplitN<'a, P>;
fn split_terminator<'a, P: Pattern<'a>>(&'a self, pat: P) -> SplitTerminator<'a, P>;
- fn rsplitn<'a, P: Pattern<'a>>(&'a self, count: usize, pat: P) -> RSplitN<'a, P>;
+ fn rsplit<'a, P: Pattern<'a>>(&'a self, pat: P) -> RSplit<'a, P>
+ where P::Searcher: ReverseSearcher<'a>;
+ fn rsplitn<'a, P: Pattern<'a>>(&'a self, count: usize, pat: P) -> RSplitN<'a, P>
+ where P::Searcher: ReverseSearcher<'a>;
fn match_indices<'a, P: Pattern<'a>>(&'a self, pat: P) -> MatchIndices<'a, P>;
#[allow(deprecated) /* for SplitStr */]
fn split_str<'a, P: Pattern<'a>>(&'a self, pat: P) -> SplitStr<'a, P>;
SplitN(CharSplitsN {
iter: self.split(pat).0,
count: count,
- invert: false,
})
}
}
#[inline]
- fn rsplitn<'a, P: Pattern<'a>>(&'a self, count: usize, pat: P) -> RSplitN<'a, P> {
- RSplitN(CharSplitsN {
- iter: self.split(pat).0,
+ fn rsplit<'a, P: Pattern<'a>>(&'a self, pat: P) -> RSplit<'a, P>
+ where P::Searcher: ReverseSearcher<'a>
+ {
+ RSplit(RCharSplits {
+ start: 0,
+ end: self.len(),
+ matcher: pat.into_searcher(self),
+ allow_final_empty: true,
+ finished: false,
+ })
+ }
+
+ #[inline]
+ fn rsplitn<'a, P: Pattern<'a>>(&'a self, count: usize, pat: P) -> RSplitN<'a, P>
+ where P::Searcher: ReverseSearcher<'a>
+ {
+ RSplitN(RCharSplitsN {
+ iter: self.rsplit(pat).0,
count: count,
- invert: true,
})
}
s, CharEqPattern(s));
}
+/// A convenience impl that delegates to the impl for `&str`
+impl<'a, 'b> Pattern<'a> for &'b &'b str {
+ type Searcher = <&'b str as Pattern<'a>>::Searcher;
+ associated_items!(<&'b str as Pattern<'a>>::Searcher,
+ s, (*s));
+}
+
/// Searches for chars that match the given predicate
impl<'a, F> Pattern<'a> for F where F: FnMut(char) -> bool {
type Searcher = <CharEqPattern<Self> as Pattern<'a>>::Searcher;
associated_items!(<CharEqPattern<Self> as Pattern<'a>>::Searcher,
s, CharEqPattern(s));
}
-
-// Deref-forward impl
-
-use ops::Deref;
-
-/// Delegates to the next deref coercion of `Self` that implements `Pattern`
-impl<'a, 'b, P: 'b + ?Sized, T: Deref<Target = P> + ?Sized> Pattern<'a> for &'b T
- where &'b P: Pattern<'a>
-{
- type Searcher = <&'b P as Pattern<'a>>::Searcher;
- associated_items!(<&'b P as Pattern<'a>>::Searcher,
- s, (&**s));
-}
let data = "aabcdaa";
assert!(data.contains("bcd"));
assert!(data.contains(&"bcd"));
- assert!(data.contains(&&"bcd"));
assert!(data.contains(&"bcd".to_string()));
- assert!(data.contains(&&"bcd".to_string()));
}
#[test]
fn check_contains_all_substrings(s: &str) {
assert!(s.contains(""));
for i in 0..s.len() {
- for j in range(i+1, s.len() + 1) {
+ for j in i+1..s.len() + 1 {
assert!(s.contains(&s[i..j]));
}
}
html_root_url = "http://doc.rust-lang.org/nightly/")]
#![feature(int_uint)]
#![feature(collections)]
+#![feature(into_cow)]
use self::LabelText::*;
pub const TCP_NODELAY: c_int = 0x0001;
pub const SOL_SOCKET: c_int = 0xffff;
- pub const SO_KEEPALIVE: c_int = 8;
- pub const SO_BROADCAST: c_int = 32;
- pub const SO_REUSEADDR: c_int = 4;
+
+ pub const SO_DEBUG: c_int = 0x0001;
+ pub const SO_ACCEPTCONN: c_int = 0x0002;
+ pub const SO_REUSEADDR: c_int = 0x0004;
+ pub const SO_KEEPALIVE: c_int = 0x0008;
+ pub const SO_DONTROUTE: c_int = 0x0010;
+ pub const SO_BROADCAST: c_int = 0x0020;
+ pub const SO_USELOOPBACK: c_int = 0x0040;
+ pub const SO_LINGER: c_int = 0x0080;
+ pub const SO_OOBINLINE: c_int = 0x0100;
+ pub const SO_SNDBUF: c_int = 0x1001;
+ pub const SO_RCVBUF: c_int = 0x1002;
+ pub const SO_SNDLOWAT: c_int = 0x1003;
+ pub const SO_RCVLOWAT: c_int = 0x1004;
+ pub const SO_SNDTIMEO: c_int = 0x1005;
+ pub const SO_RCVTIMEO: c_int = 0x1006;
pub const SO_ERROR: c_int = 0x1007;
+ pub const SO_TYPE: c_int = 0x1008;
pub const IFF_LOOPBACK: c_int = 4;
pub const TCP_NODELAY: c_int = 1;
pub const SOL_SOCKET: c_int = 1;
- pub const SO_KEEPALIVE: c_int = 9;
- pub const SO_BROADCAST: c_int = 6;
+
+ pub const SO_DEBUG: c_int = 1;
pub const SO_REUSEADDR: c_int = 2;
+ pub const SO_TYPE: c_int = 3;
pub const SO_ERROR: c_int = 4;
+ pub const SO_DONTROUTE: c_int = 5;
+ pub const SO_BROADCAST: c_int = 6;
+ pub const SO_SNDBUF: c_int = 7;
+ pub const SO_RCVBUF: c_int = 8;
+ pub const SO_KEEPALIVE: c_int = 9;
+ pub const SO_OOBINLINE: c_int = 10;
+ pub const SO_LINGER: c_int = 13;
+ pub const SO_REUSEPORT: c_int = 15;
+ pub const SO_RCVLOWAT: c_int = 18;
+ pub const SO_SNDLOWAT: c_int = 19;
+ pub const SO_RCVTIMEO: c_int = 20;
+ pub const SO_SNDTIMEO: c_int = 21;
+ pub const SO_ACCEPTCONN: c_int = 30;
pub const SHUT_RD: c_int = 0;
pub const SHUT_WR: c_int = 1;
pub const TCP_NODELAY: c_int = 1;
pub const SOL_SOCKET: c_int = 65535;
- pub const SO_KEEPALIVE: c_int = 8;
- pub const SO_BROADCAST: c_int = 32;
- pub const SO_REUSEADDR: c_int = 4;
- pub const SO_ERROR: c_int = 4103;
+
+ pub const SO_DEBUG: c_int = 0x0001;
+ pub const SO_REUSEADDR: c_int = 0x0004;
+ pub const SO_KEEPALIVE: c_int = 0x0008;
+ pub const SO_DONTROUTE: c_int = 0x0010;
+ pub const SO_BROADCAST: c_int = 0x0020;
+ pub const SO_LINGER: c_int = 0x0080;
+ pub const SO_OOBINLINE: c_int = 0x100;
+ pub const SO_REUSEPORT: c_int = 0x0200;
+ pub const SO_SNDBUF: c_int = 0x1001;
+ pub const SO_RCVBUF: c_int = 0x1002;
+ pub const SO_SNDLOWAT: c_int = 0x1003;
+ pub const SO_RCVLOWAT: c_int = 0x1004;
+ pub const SO_SNDTIMEO: c_int = 0x1005;
+ pub const SO_RCVTIMEO: c_int = 0x1006;
+ pub const SO_ERROR: c_int = 0x1007;
+ pub const SO_TYPE: c_int = 0x1008;
+ pub const SO_ACCEPTCONN: c_int = 0x1009;
pub const SHUT_RD: c_int = 0;
pub const SHUT_WR: c_int = 1;
pub const TCP_NODELAY: c_int = 1;
pub const TCP_KEEPIDLE: c_int = 256;
pub const SOL_SOCKET: c_int = 0xffff;
+ pub const SO_DEBUG: c_int = 0x01;
+ pub const SO_ACCEPTCONN: c_int = 0x0002;
+ pub const SO_REUSEADDR: c_int = 0x0004;
pub const SO_KEEPALIVE: c_int = 0x0008;
+ pub const SO_DONTROUTE: c_int = 0x0010;
pub const SO_BROADCAST: c_int = 0x0020;
- pub const SO_REUSEADDR: c_int = 0x0004;
+ pub const SO_USELOOPBACK: c_int = 0x0040;
+ pub const SO_LINGER: c_int = 0x0080;
+ pub const SO_OOBINLINE: c_int = 0x0100;
+ pub const SO_REUSEPORT: c_int = 0x0200;
+ pub const SO_SNDBUF: c_int = 0x1001;
+ pub const SO_RCVBUF: c_int = 0x1002;
+ pub const SO_SNDLOWAT: c_int = 0x1003;
+ pub const SO_RCVLOWAT: c_int = 0x1004;
+ pub const SO_SNDTIMEO: c_int = 0x1005;
+ pub const SO_RCVTIMEO: c_int = 0x1006;
pub const SO_ERROR: c_int = 0x1007;
+ pub const SO_TYPE: c_int = 0x1008;
pub const IFF_LOOPBACK: c_int = 0x8;
pub const TCP_NODELAY: c_int = 0x01;
pub const SOL_SOCKET: c_int = 0xffff;
+ pub const SO_DEBUG: c_int = 0x01;
+ pub const SO_ACCEPTCONN: c_int = 0x0002;
+ pub const SO_REUSEADDR: c_int = 0x0004;
pub const SO_KEEPALIVE: c_int = 0x0008;
+ pub const SO_DONTROUTE: c_int = 0x0010;
pub const SO_BROADCAST: c_int = 0x0020;
- pub const SO_REUSEADDR: c_int = 0x0004;
+ pub const SO_USELOOPBACK: c_int = 0x0040;
+ pub const SO_LINGER: c_int = 0x0080;
+ pub const SO_OOBINLINE: c_int = 0x0100;
+ pub const SO_REUSEPORT: c_int = 0x0200;
+ pub const SO_SNDBUF: c_int = 0x1001;
+ pub const SO_RCVBUF: c_int = 0x1002;
+ pub const SO_SNDLOWAT: c_int = 0x1003;
+ pub const SO_RCVLOWAT: c_int = 0x1004;
+ pub const SO_SNDTIMEO: c_int = 0x1005;
+ pub const SO_RCVTIMEO: c_int = 0x1006;
pub const SO_ERROR: c_int = 0x1007;
+ pub const SO_TYPE: c_int = 0x1008;
pub const IFF_LOOPBACK: c_int = 0x8;
pub const TCP_NODELAY: c_int = 0x01;
pub const TCP_KEEPALIVE: c_int = 0x10;
pub const SOL_SOCKET: c_int = 0xffff;
+
+ pub const SO_DEBUG: c_int = 0x01;
+ pub const SO_ACCEPTCONN: c_int = 0x0002;
+ pub const SO_REUSEADDR: c_int = 0x0004;
pub const SO_KEEPALIVE: c_int = 0x0008;
+ pub const SO_DONTROUTE: c_int = 0x0010;
pub const SO_BROADCAST: c_int = 0x0020;
- pub const SO_REUSEADDR: c_int = 0x0004;
+ pub const SO_USELOOPBACK: c_int = 0x0040;
+ pub const SO_LINGER: c_int = 0x0080;
+ pub const SO_OOBINLINE: c_int = 0x0100;
+ pub const SO_REUSEPORT: c_int = 0x0200;
+ pub const SO_SNDBUF: c_int = 0x1001;
+ pub const SO_RCVBUF: c_int = 0x1002;
+ pub const SO_SNDLOWAT: c_int = 0x1003;
+ pub const SO_RCVLOWAT: c_int = 0x1004;
+ pub const SO_SNDTIMEO: c_int = 0x1005;
+ pub const SO_RCVTIMEO: c_int = 0x1006;
pub const SO_ERROR: c_int = 0x1007;
+ pub const SO_TYPE: c_int = 0x1008;
pub const IFF_LOOPBACK: c_int = 0x8;
pub const MAP_STACK : c_int = 0;
pub const IPPROTO_RAW : c_int = 255;
+
+ pub const SO_NREAD: c_int = 0x1020;
+ pub const SO_NKE: c_int = 0x1021;
+ pub const SO_NOSIGPIPE: c_int = 0x1022;
+ pub const SO_NOADDRERR: c_int = 0x1023;
+ pub const SO_NWRITE: c_int = 0x1024;
+ pub const SO_DONTTRUNC: c_int = 0x2000;
+ pub const SO_WANTMORE: c_int = 0x4000;
+ pub const SO_WANTOOBFLAG: c_int = 0x8000;
}
pub mod sysconf {
use types::os::arch::c95::c_int;
--- /dev/null
+An informal guide to reading and working on the rustc compiler.
+==================================================================
+
+If you wish to expand on this document, or have a more experienced
+Rust contributor add anything else to it, please get in touch:
+
+* http://internals.rust-lang.org/
+* https://chat.mibbit.com/?server=irc.mozilla.org&channel=%23rust
+
+or file a bug:
+
+https://github.com/rust-lang/rust/issues
+
+Your concerns are probably the same as someone else's.
+
+The crates of rustc
+===================
+
+Rustc consists of a number of crates, including `libsyntax`,
+`librustc`, `librustc_back`, `librustc_trans`, and `librustc_driver`
+(the names and divisions are not set in stone and may change;
+in general, a finer-grained division of crates is preferable):
+
+- `libsyntax` contains those things concerned purely with syntax –
+ that is, the AST, parser, pretty-printer, lexer, macro expander, and
+ utilities for traversing ASTs – are in a separate crate called
+ "syntax", whose files are in `./../libsyntax`, where `.` is the
+ current directory (that is, the parent directory of front/, middle/,
+ back/, and so on).
+
+- `librustc` (the current directory) contains the high-level analysis
+ passes, such as the type checker, borrow checker, and so forth.
+ It is the heart of the compiler.
+
+- `librustc_back` contains some very low-level details that are
+ specific to different LLVM targets and so forth.
+
+- `librustc_trans` contains the code to convert from Rust IR into LLVM
+ IR, and then from LLVM IR into machine code, as well as the main
+ driver that orchestrates all the other passes and various other bits
+ of miscellany. In general it contains code that runs towards the
+ end of the compilation process.
+
+- `librustc_driver` invokes the compiler from `libsyntax`, then the
+ analysis phases from `librustc`, and finally the lowering and
+ codegen passes from `librustc_trans`.
+
+Roughly speaking the "order" of the three crates is as follows:
+
+ libsyntax -> librustc -> librustc_trans
+ | |
+ +-----------------+-------------------+
+ |
+ librustc_driver
+
+
+Modules in the rustc crate
+==========================
+
+The rustc crate itself consists of the following submodules
+(mostly, but not entirely, in their own directories):
+
+- session: options and data that pertain to the compilation session as
+ a whole
+- middle: middle-end: name resolution, typechecking, LLVM code
+ generation
+- metadata: encoder and decoder for data required by separate
+ compilation
+- plugin: infrastructure for compiler plugins
+- lint: infrastructure for compiler warnings
+- util: ubiquitous types and helper functions
+- lib: bindings to LLVM
+
+The entry-point for the compiler is main() in the librustc_trans
+crate.
+
+The 3 central data structures:
+------------------------------
+
+1. `./../libsyntax/ast.rs` defines the AST. The AST is treated as
+ immutable after parsing, but it depends on mutable context data
+ structures (mainly hash maps) to give it meaning.
+
+ - Many – though not all – nodes within this data structure are
+ wrapped in the type `spanned<T>`, meaning that the front-end has
+ marked the input coordinates of that node. The member `node` is
+ the data itself, the member `span` is the input location (file,
+ line, column; both low and high).
+
+ - Many other nodes within this data structure carry a
+ `def_id`. These nodes represent the 'target' of some name
+ reference elsewhere in the tree. When the AST is resolved, by
+ `middle/resolve.rs`, all names wind up acquiring a def that they
+ point to. So anything that can be pointed-to by a name winds
+ up with a `def_id`.
+
+2. `middle/ty.rs` defines the datatype `sty`. This is the type that
+ represents types after they have been resolved and normalized by
+ the middle-end. The typeck phase converts every ast type to a
+ `ty::sty`, and the latter is used to drive later phases of
+ compilation. Most variants in the `ast::ty` tag have a
+ corresponding variant in the `ty::sty` tag.
+
+3. `./../librustc_llvm/lib.rs` defines the exported types
+ `ValueRef`, `TypeRef`, `BasicBlockRef`, and several others.
+ Each of these is an opaque pointer to an LLVM type,
+ manipulated through the `lib::llvm` interface.
+
+
+Control and information flow within the compiler:
+-------------------------------------------------
+
+- main() in lib.rs assumes control on startup. Options are
+ parsed, platform is detected, etc.
+
+- `./../libsyntax/parse/parser.rs` parses the input files and produces
+ an AST that represents the input crate.
+
+- Multiple middle-end passes (`middle/resolve.rs`, `middle/typeck.rs`)
+ analyze the semantics of the resulting AST. Each pass generates new
+ information about the AST and stores it in various environment data
+ structures. The driver passes environments to each compiler pass
+ that needs to refer to them.
+
+- Finally, the `trans` module in `librustc_trans` translates the Rust
+ AST to LLVM bitcode in a type-directed way. When it's finished
+ synthesizing LLVM values, rustc asks LLVM to write them out in some
+ form (`.bc`, `.o`) and possibly run the system linker.
+++ /dev/null
-An informal guide to reading and working on the rustc compiler.
-==================================================================
-
-If you wish to expand on this document, or have a more experienced
-Rust contributor add anything else to it, please get in touch:
-
-* http://internals.rust-lang.org/
-* https://chat.mibbit.com/?server=irc.mozilla.org&channel=%23rust
-
-or file a bug:
-
-https://github.com/rust-lang/rust/issues
-
-Your concerns are probably the same as someone else's.
-
-The crates of rustc
-===================
-
-Rustc consists of four crates altogether: `libsyntax`, `librustc`,
-`librustc_back`, and `librustc_trans` (the names and divisions are not
-set in stone and may change; in general, a finer-grained division of
-crates is preferable):
-
-- `libsyntax` contains those things concerned purely with syntax --
- that is, the AST, parser, pretty-printer, lexer, macro expander, and
- utilities for traversing ASTs -- are in a separate crate called
- "syntax", whose files are in ./../libsyntax, where . is the current
- directory (that is, the parent directory of front/, middle/, back/,
- and so on).
-
-- `librustc` (the current directory) contains the high-level analysis
- passes, such as the type checker, borrow checker, and so forth.
- It is the heart of the compiler.
-
-- `librustc_back` contains some very low-level details that are
- specific to different LLVM targets and so forth.
-
-- `librustc_trans` contains the code to convert from Rust IR into LLVM
- IR, and then from LLVM IR into machine code, as well as the main
- driver that orchestrates all the other passes and various other bits
- of miscellany. In general it contains code that runs towards the
- end of the compilation process.
-
-Roughly speaking the "order" of the three crates is as follows:
-
- libsyntax -> librustc -> librustc_trans
- | |
- +-----------------+-------------------+
- |
- librustc_trans/driver
-
-Here the role of `librustc_trans/driver` is to invoke the compiler
-from libsyntax, then the analysis phases from librustc, and finally
-the lowering and codegen passes from librustc_trans.
-
-Modules in the rustc crate
-==========================
-
-The rustc crate itself consists of the following subdirectories
-(mostly, but not entirely, in their own directories):
-
-session - options and data that pertain to the compilation session as a whole
-middle - middle-end: name resolution, typechecking, LLVM code
- generation
-metadata - encoder and decoder for data required by
- separate compilation
-util - ubiquitous types and helper functions
-lib - bindings to LLVM
-
-The entry-point for the compiler is main() in the librustc_trans
-crate.
-
-The 3 central data structures:
-------------------------------
-
-#1: ./../libsyntax/ast.rs defines the AST. The AST is treated as immutable
- after parsing, but it depends on mutable context data structures
- (mainly hash maps) to give it meaning.
-
- - Many -- though not all -- nodes within this data structure are
- wrapped in the type `spanned<T>`, meaning that the front-end has
- marked the input coordinates of that node. The member .node is
- the data itself, the member .span is the input location (file,
- line, column; both low and high).
-
- - Many other nodes within this data structure carry a
- def_id. These nodes represent the 'target' of some name
- reference elsewhere in the tree. When the AST is resolved, by
- middle/resolve.rs, all names wind up acquiring a def that they
- point to. So anything that can be pointed-to by a name winds
- up with a def_id.
-
-#2: middle/ty.rs defines the datatype sty. This is the type that
- represents types after they have been resolved and normalized by
- the middle-end. The typeck phase converts every ast type to a
- ty::sty, and the latter is used to drive later phases of
- compilation. Most variants in the ast::ty tag have a
- corresponding variant in the ty::sty tag.
-
-#3: lib/llvm.rs (in librustc_trans) defines the exported types
- ValueRef, TypeRef, BasicBlockRef, and several others. Each of
- these is an opaque pointer to an LLVM type, manipulated through
- the lib::llvm interface.
-
-
-Control and information flow within the compiler:
--------------------------------------------------
-
-- main() in lib.rs assumes control on startup. Options are
- parsed, platform is detected, etc.
-
-- ./../libsyntax/parse/parser.rs parses the input files and produces an AST
- that represents the input crate.
-
-- Multiple middle-end passes (middle/resolve.rs, middle/typeck.rs)
- analyze the semantics of the resulting AST. Each pass generates new
- information about the AST and stores it in various environment data
- structures. The driver passes environments to each compiler pass
- that needs to refer to them.
-
-- Finally, the `trans` module in `librustc_trans` translates the Rust
- AST to LLVM bitcode in a type-directed way. When it's finished
- synthesizing LLVM values, rustc asks LLVM to write them out in some
- form (.bc, .o) and possibly run the system linker.
#![feature(path_ext)]
#![feature(str_words)]
#![feature(str_char)]
+#![feature(convert)]
+#![feature(into_cow)]
#![cfg_attr(test, feature(test))]
extern crate arena;
}
pub fn get_crate_data(&self, cnum: ast::CrateNum) -> Rc<crate_metadata> {
- (*self.metas.borrow())[cnum].clone()
+ self.metas.borrow().get(&cnum).unwrap().clone()
}
pub fn get_crate_hash(&self, cnum: ast::CrateNum) -> Svh {
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 {
match ecx.tcx.inherent_impls.borrow().get(&exp.def_id) {
Some(implementations) => {
for base_impl_did in &**implementations {
- for &method_did in &*(*impl_items)[*base_impl_did] {
+ for &method_did in impl_items.get(base_impl_did).unwrap() {
let impl_item = ty::impl_or_trait_item(
ecx.tcx,
method_did.def_id());
// We need to encode information about the default methods we
// have inherited, so we drive this based on the impl structure.
let impl_items = tcx.impl_items.borrow();
- let items = &(*impl_items)[def_id];
+ let items = impl_items.get(&def_id).unwrap();
add_to_index(item, rbml_w, index);
rbml_w.start_tag(tag_items_data_item);
impl<'a, 'b, 'c, 'tcx, 'v> Visitor<'v> for ImplVisitor<'a, 'b, 'c, 'tcx> {
fn visit_item(&mut self, item: &ast::Item) {
if let ast::ItemImpl(_, _, _, Some(ref trait_ref), _, _) = item.node {
- let def_id = self.ecx.tcx.def_map.borrow()[trait_ref.ref_id].def_id();
+ let def_id = self.ecx.tcx.def_map.borrow().get(&trait_ref.ref_id).unwrap().def_id();
// Load eagerly if this is an implementation of the Drop trait
// or if the trait is not defined in this crate.
// Returns a list of directories where target-specific tool binaries are located.
pub fn get_tools_search_paths(&self) -> Vec<PathBuf> {
- 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);
}
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);
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()
};
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()));
use std::io::prelude::*;
use std::num::FromPrimitive;
use std::rc::Rc;
+use std::fmt::Debug;
use rbml::reader;
use rbml::writer::Encoder;
fn emit_def_id(&mut self, did: ast::DefId);
}
-impl<S:serialize::Encoder> def_id_encoder_helpers for S {
+impl<S:serialize::Encoder> def_id_encoder_helpers for S
+ where <S as serialize::serialize::Encoder>::Error: Debug
+{
fn emit_def_id(&mut self, did: ast::DefId) {
- did.encode(self).ok().unwrap()
+ did.encode(self).unwrap()
}
}
cdata: &cstore::crate_metadata) -> ast::DefId;
}
-impl<D:serialize::Decoder> def_id_decoder_helpers for D {
+impl<D:serialize::Decoder> def_id_decoder_helpers for D
+ where <D as serialize::serialize::Decoder>::Error: Debug
+{
fn read_def_id(&mut self, dcx: &DecodeContext) -> ast::DefId {
- let did: ast::DefId = Decodable::decode(self).ok().unwrap();
+ let did: ast::DefId = Decodable::decode(self).unwrap();
did.tr(dcx)
}
fn read_def_id_nodcx(&mut self,
- cdata: &cstore::crate_metadata) -> ast::DefId {
- let did: ast::DefId = Decodable::decode(self).ok().unwrap();
+ cdata: &cstore::crate_metadata)
+ -> ast::DefId {
+ let did: ast::DefId = Decodable::decode(self).unwrap();
decoder::translate_def_id(cdata, did)
}
}
var_id: var_id,
closure_expr_id: id
};
- let upvar_capture = tcx.upvar_capture_map.borrow()[upvar_id].clone();
+ let upvar_capture = tcx.upvar_capture_map.borrow().get(&upvar_id).unwrap().clone();
var_id.encode(rbml_w);
upvar_capture.encode(rbml_w);
})
fn read_closure_kind<'b, 'c>(&mut self, _dcx: &DecodeContext<'b, 'c, 'tcx>)
-> ty::ClosureKind
{
- Decodable::decode(self).ok().unwrap()
+ Decodable::decode(self).unwrap()
}
fn read_closure_ty<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>)
}
impl<'a, 'ast> dot::Labeller<'a, Node<'a>, Edge<'a>> for LabelledCFG<'a, 'ast> {
- fn graph_id(&'a self) -> dot::Id<'a> { dot::Id::new(&self.name[..]).ok().unwrap() }
+ fn graph_id(&'a self) -> dot::Id<'a> { dot::Id::new(&self.name[..]).unwrap() }
fn node_id(&'a self, &(i,_): &Node<'a>) -> dot::Id<'a> {
- dot::Id::new(format!("N{}", i.node_id())).ok().unwrap()
+ dot::Id::new(format!("N{}", i.node_id())).unwrap()
}
fn node_label(&'a self, &(i, n): &Node<'a>) -> dot::LabelText<'a> {
}
ast::PatEnum(_, ref args) => {
- let def = cx.tcx.def_map.borrow()[pat_id].full_def();
+ let def = cx.tcx.def_map.borrow().get(&pat_id).unwrap().full_def();
match def {
DefConst(..) =>
cx.tcx.sess.span_bug(pat_span, "const pattern should've \
ast::PatStruct(_, ref pattern_fields, _) => {
// Is this a struct or an enum variant?
- let def = cx.tcx.def_map.borrow()[pat_id].full_def();
+ let def = cx.tcx.def_map.borrow().get(&pat_id).unwrap().full_def();
let class_id = match def {
DefConst(..) =>
cx.tcx.sess.span_bug(pat_span, "const pattern should've \
ast::PatTup(exprs.iter().map(|expr| const_expr_to_pat(tcx, &**expr, span)).collect()),
ast::ExprCall(ref callee, ref args) => {
- let def = tcx.def_map.borrow()[callee.id];
+ let def = *tcx.def_map.borrow().get(&callee.id).unwrap();
if let Vacant(entry) = tcx.def_map.borrow_mut().entry(expr.id) {
entry.insert(def);
}
fn handle_field_pattern_match(&mut self, lhs: &ast::Pat,
pats: &[codemap::Spanned<ast::FieldPat>]) {
- let id = match self.tcx.def_map.borrow()[lhs.id].full_def() {
+ let id = match self.tcx.def_map.borrow().get(&lhs.id).unwrap().full_def() {
def::DefVariant(_, id, _) => id,
_ => {
match ty::ty_to_def_id(ty::node_id_to_type(self.tcx,
None => (),
Some(impl_list) => {
for impl_did in &**impl_list {
- for item_did in &(*impl_items)[*impl_did] {
+ for item_did in &*impl_items.get(impl_did).unwrap() {
if self.live_symbols.contains(&item_did.def_id()
.node) {
return true;
match expr.node {
ast::ExprMethodCall(_, _, _) => {
let method_call = MethodCall::expr(expr.id);
- let base_type = (*self.tcx.method_map.borrow())[method_call].ty;
+ let base_type = self.tcx.method_map.borrow().get(&method_call).unwrap().ty;
debug!("effect: method call case, base type is {}",
ppaux::ty_to_string(self.tcx, base_type));
if type_is_unsafe_function(base_type) {
if !self.walk_overloaded_operator(expr,
&**lhs,
vec![&**rhs],
- PassArgs::ByRef) {
+ PassArgs::ByValue) {
self.select_from_expr(&**lhs);
self.consume_expr(&**rhs);
}
// Each match binding is effectively an assignment to the
// binding being produced.
- let def = def_map.borrow()[pat.id].full_def();
+ let def = def_map.borrow().get(&pat.id).unwrap().full_def();
match mc.cat_def(pat.id, pat.span, pat_ty, def) {
Ok(binding_cmt) => {
delegate.mutate(pat.id, pat.span, binding_cmt, Init);
(&ty::ty_rptr(a_r, ref a_mt), &ty::ty_rptr(b_r, ref b_mt)) => {
let r = try!(this.regions_with_variance(ty::Contravariant, *a_r, *b_r));
-
- // FIXME(14985) If we have mutable references to trait objects, we
- // used to use covariant subtyping. I have preserved this behaviour,
- // even though it is probably incorrect. So don't go down the usual
- // path which would require invariance.
- let mt = match (&a_mt.ty.sty, &b_mt.ty.sty) {
- (&ty::ty_trait(..), &ty::ty_trait(..)) if a_mt.mutbl == b_mt.mutbl => {
- let ty = try!(this.tys(a_mt.ty, b_mt.ty));
- ty::mt { ty: ty, mutbl: a_mt.mutbl }
- }
- _ => try!(this.mts(a_mt, b_mt))
- };
+ let mt = try!(this.mts(a_mt, b_mt));
Ok(ty::mk_rptr(tcx, tcx.mk_region(r), mt))
}
return;
}
- let requested_output = env::var("RUST_REGION_GRAPH").ok();
+ let requested_output = env::var("RUST_REGION_GRAPH");
debug!("requested_output: {:?} requested_node: {:?}",
requested_output, requested_node);
let output_path = {
let output_template = match requested_output {
- Some(ref s) if &**s == "help" => {
+ Ok(ref s) if &**s == "help" => {
static PRINTED_YET: AtomicBool = ATOMIC_BOOL_INIT;
if !PRINTED_YET.load(Ordering::SeqCst) {
print_help_message();
return;
}
- Some(other_path) => other_path,
- None => "/tmp/constraints.node%.dot".to_string(),
+ Ok(other_path) => other_path,
+ Err(_) => "/tmp/constraints.node%.dot".to_string(),
};
if output_template.len() == 0 {
impl<'a, 'tcx> dot::Labeller<'a, Node, Edge> for ConstraintGraph<'a, 'tcx> {
fn graph_id(&self) -> dot::Id {
- dot::Id::new(&*self.graph_name).ok().unwrap()
+ dot::Id::new(&*self.graph_name).unwrap()
}
fn node_id(&self, n: &Node) -> dot::Id {
let node_id = match self.node_ids.get(n) {
ConstrainVarSubReg(_, region) => {
state.result.push(RegionAndOrigin {
region: region,
- origin: this.constraints.borrow()[edge.data].clone()
+ origin: this.constraints.borrow().get(&edge.data).unwrap().clone()
});
}
}
match expr.node {
// live nodes required for uses or definitions of variables:
ast::ExprPath(..) => {
- let def = ir.tcx.def_map.borrow()[expr.id].full_def();
+ let def = ir.tcx.def_map.borrow().get(&expr.id).unwrap().full_def();
debug!("expr {}: path that leads to {:?}", expr.id, def);
if let DefLocal(..) = def {
ir.add_live_node_for_node(expr.id, ExprNode(expr.span));
fn access_path(&mut self, expr: &Expr, succ: LiveNode, acc: u32)
-> LiveNode {
- match self.ir.tcx.def_map.borrow()[expr.id].full_def() {
+ match self.ir.tcx.def_map.borrow().get(&expr.id).unwrap().full_def() {
DefLocal(nid) => {
let ln = self.live_node(expr.id, expr.span);
if acc != 0 {
fn check_lvalue(&mut self, expr: &Expr) {
match expr.node {
ast::ExprPath(..) => {
- if let DefLocal(nid) = self.ir.tcx.def_map.borrow()[expr.id].full_def() {
+ if let DefLocal(nid) = self.ir.tcx.def_map.borrow().get(&expr.id)
+ .unwrap()
+ .full_def() {
// Assignment to an immutable variable or argument: only legal
// if there is no later assignment. If this local is actually
// mutable, then check for a reassignment to flag the mutability
}
ast::ExprPath(..) => {
- let def = self.tcx().def_map.borrow()[expr.id].full_def();
+ let def = self.tcx().def_map.borrow().get(&expr.id).unwrap().full_def();
self.cat_def(expr.id, expr.span, expr_ty, def)
}
contains_bindings
}
+/// Checks if the pattern contains any `ref` or `ref mut` bindings.
+pub fn pat_contains_ref_binding(dm: &DefMap, pat: &ast::Pat) -> bool {
+ let mut result = false;
+ pat_bindings(dm, pat, |mode, _, _, _| {
+ match mode {
+ ast::BindingMode::BindByRef(_) => { result = true; }
+ ast::BindingMode::BindByValue(_) => { }
+ }
+ });
+ result
+}
+
+/// Checks if the patterns for this arm contain any `ref` or `ref mut`
+/// bindings.
+pub fn arm_contains_ref_binding(dm: &DefMap, arm: &ast::Arm) -> bool {
+ arm.pats.iter().any(|pat| pat_contains_ref_binding(dm, pat))
+}
+
/// Checks if the pattern contains any patterns that bind something to
/// an ident or wildcard, e.g. `foo`, or `Foo(_)`, `foo @ Bar(..)`,
pub fn pat_contains_bindings_or_wild(dm: &DefMap, pat: &ast::Pat) -> bool {
}
ast::ExprMethodCall(..) => {
let method_call = ty::MethodCall::expr(expr.id);
- match (*self.tcx.method_map.borrow())[method_call].origin {
+ match (*self.tcx.method_map.borrow()).get(&method_call).unwrap().origin {
ty::MethodStatic(def_id) => {
if is_local(def_id) {
if self.def_id_represents_local_inlined_item(def_id) {
// individually as it's possible to have a stable trait with unstable
// items.
ast::ItemImpl(_, _, _, Some(ref t), _, ref impl_items) => {
- let trait_did = tcx.def_map.borrow()[t.ref_id].def_id();
+ let trait_did = tcx.def_map.borrow().get(&t.ref_id).unwrap().def_id();
let trait_items = ty::trait_items(tcx, trait_did);
for impl_item in impl_items {
FulfillmentError,
FulfillmentErrorCode,
MismatchedProjectionTypes,
+ Obligation,
ObligationCauseCode,
OutputTypeParameterMismatch,
PredicateObligation,
use fmt_macros::{Parser, Piece, Position};
use middle::infer::InferCtxt;
use middle::ty::{self, AsPredicate, ReferencesError, ToPolyTraitRef, TraitRef};
+use middle::ty_fold::TypeFoldable;
use std::collections::HashMap;
use syntax::codemap::{DUMMY_SP, Span};
use syntax::attr::{AttributeMethods, AttrMetaMethods};
report
}
+/// Reports that an overflow has occurred and halts compilation. We
+/// halt compilation unconditionally because it is important that
+/// overflows never be masked -- they basically represent computations
+/// whose result could not be truly determined and thus we can't say
+/// if the program type checks or not -- and they are unusual
+/// occurrences in any case.
+pub fn report_overflow_error<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>,
+ obligation: &Obligation<'tcx, T>)
+ -> !
+ where T: UserString<'tcx> + TypeFoldable<'tcx>
+{
+ let predicate =
+ infcx.resolve_type_vars_if_possible(&obligation.predicate);
+ span_err!(infcx.tcx.sess, obligation.cause.span, E0275,
+ "overflow evaluating the requirement `{}`",
+ predicate.user_string(infcx.tcx));
+
+ suggest_new_overflow_limit(infcx.tcx, obligation.cause.span);
+
+ note_obligation_cause(infcx, obligation);
+
+ infcx.tcx.sess.abort_if_errors();
+ unreachable!();
+}
+
pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
obligation: &PredicateObligation<'tcx>,
error: &SelectionError<'tcx>)
{
match *error {
- SelectionError::Overflow => {
- // We could track the stack here more precisely if we wanted, I imagine.
- let predicate =
- infcx.resolve_type_vars_if_possible(&obligation.predicate);
- span_err!(infcx.tcx.sess, obligation.cause.span, E0275,
- "overflow evaluating the requirement `{}`",
- predicate.user_string(infcx.tcx));
-
- suggest_new_overflow_limit(infcx.tcx, obligation.cause.span);
-
- note_obligation_cause(infcx, obligation);
- }
-
SelectionError::Unimplemented => {
match &obligation.cause.code {
&ObligationCauseCode::CompareImplMethodObligation => {
}
}
-fn note_obligation_cause<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
- obligation: &PredicateObligation<'tcx>)
+fn note_obligation_cause<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>,
+ obligation: &Obligation<'tcx, T>)
+ where T: UserString<'tcx>
{
note_obligation_cause_code(infcx,
&obligation.predicate,
&obligation.cause.code);
}
-fn note_obligation_cause_code<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
- predicate: &ty::Predicate<'tcx>,
- cause_span: Span,
- cause_code: &ObligationCauseCode<'tcx>)
+fn note_obligation_cause_code<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>,
+ predicate: &T,
+ cause_span: Span,
+ cause_code: &ObligationCauseCode<'tcx>)
+ where T: UserString<'tcx>
{
let tcx = infcx.tcx;
match *cause_code {
use std::rc::Rc;
use syntax::ast;
use syntax::codemap::{Span, DUMMY_SP};
-use util::ppaux::{Repr, UserString};
+use util::ppaux::Repr;
pub use self::error_reporting::report_fulfillment_errors;
+pub use self::error_reporting::report_overflow_error;
pub use self::error_reporting::suggest_new_overflow_limit;
pub use self::coherence::orphan_check;
pub use self::coherence::overlapping_impls;
#[derive(Clone,Debug)]
pub enum SelectionError<'tcx> {
Unimplemented,
- Overflow,
OutputTypeParameterMismatch(ty::PolyTraitRef<'tcx>,
ty::PolyTraitRef<'tcx>,
ty::type_err<'tcx>),
let result = match fulfill_cx.select_all_or_error(infcx, typer) {
Ok(()) => Ok(Some(())), // Success, we know it implements Copy.
Err(errors) => {
- // Check if overflow occurred anywhere and propagate that.
- if errors.iter().any(
- |err| match err.code { CodeSelectionError(Overflow) => true, _ => false })
- {
- return Err(Overflow);
- }
-
- // Otherwise, if there were any hard errors, propagate an
- // arbitrary one of those. If no hard errors at all,
- // report ambiguity.
+ // If there were any hard errors, propagate an arbitrary
+ // one of those. If no hard errors at all, report
+ // ambiguity.
let sel_error =
errors.iter()
.filter_map(|err| {
// soldering on, so just treat this like not implemented
false
}
- Err(Overflow) => {
- span_err!(infcx.tcx.sess, span, E0285,
- "overflow evaluating whether `{}` is `{}`",
- ty.user_string(infcx.tcx),
- bound.user_string(infcx.tcx));
- suggest_new_overflow_limit(infcx.tcx, span);
- false
- }
Err(_) => {
- // other errors: not implemented.
+ // errors: not implemented.
false
}
}
{
FulfillmentError { obligation: obligation, code: code }
}
-
- pub fn is_overflow(&self) -> bool {
- match self.code {
- CodeAmbiguity => false,
- CodeSelectionError(Overflow) => true,
- CodeSelectionError(_) => false,
- CodeProjectionError(_) => false,
- }
- }
}
impl<'tcx> TraitObligation<'tcx> {
//! Code for projecting associated types out of trait references.
use super::elaborate_predicates;
+use super::report_overflow_error;
use super::Obligation;
use super::ObligationCause;
-use super::Overflow;
use super::PredicateObligation;
use super::SelectionContext;
use super::SelectionError;
let recursion_limit = selcx.tcx().sess.recursion_limit.get();
if obligation.recursion_depth >= recursion_limit {
debug!("project: overflow!");
- return Err(ProjectionTyError::TraitSelectionError(Overflow));
+ report_overflow_error(selcx.infcx(), &obligation);
}
let obligation_trait_ref =
let impl_items_map = selcx.tcx().impl_items.borrow();
let impl_or_trait_items_map = selcx.tcx().impl_or_trait_items.borrow();
- let impl_items = &impl_items_map[impl_vtable.impl_def_id];
+ let impl_items = impl_items_map.get(&impl_vtable.impl_def_id).unwrap();
let mut impl_ty = None;
for impl_item in impl_items {
- let assoc_type = match impl_or_trait_items_map[impl_item.def_id()] {
+ let assoc_type = match *impl_or_trait_items_map.get(&impl_item.def_id()).unwrap() {
ty::TypeTraitItem(ref assoc_type) => assoc_type.clone(),
ty::MethodTraitItem(..) => { continue; }
};
use super::project;
use super::project::{normalize_with_depth, Normalized};
use super::{PredicateObligation, TraitObligation, ObligationCause};
+use super::{report_overflow_error};
use super::{ObligationCauseCode, BuiltinDerivedObligation, ImplDerivedObligation};
-use super::{SelectionError, Unimplemented, Overflow, OutputTypeParameterMismatch};
+use super::{SelectionError, Unimplemented, OutputTypeParameterMismatch};
use super::{Selection};
use super::{SelectionResult};
use super::{VtableBuiltin, VtableImpl, VtableParam, VtableClosure,
// not update) the cache.
let recursion_limit = self.infcx.tcx.sess.recursion_limit.get();
if stack.obligation.recursion_depth >= recursion_limit {
- debug!("{} --> overflow (limit={})",
- stack.obligation.repr(self.tcx()),
- recursion_limit);
- return Err(Overflow)
+ report_overflow_error(self.infcx(), &stack.obligation);
}
// Check the cache. Note that we skolemize the trait-ref
match obligations {
Ok(mut obls) => {
- obls.push_all(normalized.obligations.as_slice());
+ obls.push_all(&normalized.obligations);
obls
},
Err(ErrorReported) => Vec::new()
impl<'tcx> EvaluationResult<'tcx> {
fn may_apply(&self) -> bool {
match *self {
- EvaluatedToOk
- | EvaluatedToAmbig
- | EvaluatedToErr(Overflow)
- | EvaluatedToErr(OutputTypeParameterMismatch(..)) => true,
- EvaluatedToErr(Unimplemented) => false,
+ EvaluatedToOk |
+ EvaluatedToAmbig |
+ EvaluatedToErr(OutputTypeParameterMismatch(..)) =>
+ true,
+
+ EvaluatedToErr(Unimplemented) =>
+ false,
}
}
}
impl<'tcx> Repr<'tcx> for super::SelectionError<'tcx> {
fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
match *self {
- super::Overflow =>
- format!("Overflow"),
-
super::Unimplemented =>
format!("Unimplemented"),
use middle::region;
use middle::resolve_lifetime;
use middle::infer;
+use middle::pat_util;
use middle::stability;
use middle::subst::{self, ParamSpace, Subst, Substs, VecPerParamSpace};
use middle::traits;
}
pub fn closure_kind(&self, def_id: ast::DefId) -> ty::ClosureKind {
- self.closure_kinds.borrow()[def_id]
+ *self.closure_kinds.borrow().get(&def_id).unwrap()
}
pub fn closure_type(&self,
substs: &subst::Substs<'tcx>)
-> ty::ClosureTy<'tcx>
{
- self.closure_tys.borrow()[def_id].subst(self, substs)
+ self.closure_tys.borrow().get(&def_id).unwrap().subst(self, substs)
}
pub fn type_parameter_def(&self,
node_id: ast::NodeId)
-> TypeParameterDef<'tcx>
{
- self.ty_param_defs.borrow()[node_id].clone()
+ self.ty_param_defs.borrow().get(&node_id).unwrap().clone()
+ }
+
+ pub fn pat_contains_ref_binding(&self, pat: &ast::Pat) -> bool {
+ pat_util::pat_contains_ref_binding(&self.def_map, pat)
+ }
+
+ pub fn arm_contains_ref_binding(&self, arm: &ast::Arm) -> bool {
+ pat_util::arm_contains_ref_binding(&self.def_map, arm)
}
}
pub fn trait_has_default_impl(tcx: &ctxt, trait_def_id: DefId) -> bool {
populate_implementations_for_trait_if_necessary(tcx, trait_def_id);
- match tcx.lang_items.to_builtin_kind(trait_def_id) {
- Some(BoundSend) | Some(BoundSync) => true,
- _ => tcx.traits_with_default_impls.borrow().contains_key(&trait_def_id),
- }
+ tcx.traits_with_default_impls.borrow().contains_key(&trait_def_id)
}
/// Records a trait-to-implementation mapping.
}
pub fn upvar_capture(&self, upvar_id: ty::UpvarId) -> Option<ty::UpvarCapture> {
- Some(self.upvar_capture_map.borrow()[upvar_id].clone())
+ Some(self.upvar_capture_map.borrow().get(&upvar_id).unwrap().clone())
}
}
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 = {
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 {
};
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(())
}
// except according to those terms.
use std::io;
-#[allow(deprecated)] use std::old_path;
+#[allow(deprecated)] use std::old_path::{self, GenericPath};
#[allow(deprecated)] use std::old_io;
use std::path::{Path, PathBuf};
pub fn realpath(original: &Path) -> io::Result<PathBuf> {
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())))
use std::old_io::fs::{File, symlink, mkdir, mkdir_recursive};
use super::old_realpath as realpath;
use std::old_io::TempDir;
+ use std::old_path::{Path, GenericPath};
#[test]
fn realpath_works() {
#![feature(std_misc)]
#![feature(path_relative_from)]
#![feature(step_by)]
+#![feature(convert)]
extern crate syntax;
extern crate serialize;
lib.pop();
let mut output = (config.realpath)(&cwd.join(&config.out_filename)).unwrap();
output.pop();
- let relative = relativize(&lib, &output);
+ let relative = path_relative_from(&lib, &output)
+ .expect(&format!("couldn't create relative path from {:?} to {:?}", output, lib));
// FIXME (#9639): This needs to handle non-utf8 paths
format!("{}/{}", prefix,
relative.to_str().expect("non-utf8 component in path"))
}
-fn relativize(path: &Path, rel: &Path) -> PathBuf {
- let mut res = PathBuf::new("");
- let mut cur = rel;
- while !path.starts_with(cur) {
- res.push("..");
- match cur.parent() {
- Some(p) => cur = p,
- None => panic!("can't create relative paths across filesystems"),
+// This routine is adapted from the *old* Path's `path_relative_from`
+// function, which works differently from the new `relative_from` function.
+// In particular, this handles the case on unix where both paths are
+// absolute but with only the root as the common directory.
+fn path_relative_from(path: &Path, base: &Path) -> Option<PathBuf> {
+ use std::path::Component;
+
+ if path.is_absolute() != base.is_absolute() {
+ if path.is_absolute() {
+ Some(PathBuf::new(path))
+ } else {
+ None
}
+ } else {
+ let mut ita = path.components();
+ let mut itb = base.components();
+ let mut comps: Vec<Component> = vec![];
+ loop {
+ match (ita.next(), itb.next()) {
+ (None, None) => break,
+ (Some(a), None) => {
+ comps.push(a);
+ comps.extend(ita.by_ref());
+ break;
+ }
+ (None, _) => comps.push(Component::ParentDir),
+ (Some(a), Some(b)) if comps.is_empty() && a == b => (),
+ (Some(a), Some(b)) if b == Component::CurDir => comps.push(a),
+ (Some(_), Some(b)) if b == Component::ParentDir => return None,
+ (Some(a), Some(_)) => {
+ comps.push(Component::ParentDir);
+ for _ in itb {
+ comps.push(Component::ParentDir);
+ }
+ comps.push(a);
+ comps.extend(ita.by_ref());
+ break;
+ }
+ }
+ }
+ Some(comps.iter().map(|c| c.as_os_str()).collect())
}
- match path.relative_from(cur) {
- Some(s) => { res.push(s); res }
- None => panic!("couldn't create relative path from {:?} to {:?}",
- rel, path),
- }
-
}
+
fn get_install_prefix_rpath(config: &mut RPathConfig) -> String {
let path = (config.get_install_prefix_lib_path)();
let path = env::current_dir().unwrap().join(&path);
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?
if let ast::ExprAddrOf(mutbl, ref base) = ex.node {
let param_env = ty::empty_parameter_environment(self.bccx.tcx);
let mc = mc::MemCategorizationContext::new(¶m_env);
- let base_cmt = mc.cat_expr(&**base).ok().unwrap();
+ let base_cmt = mc.cat_expr(&**base).unwrap();
let borrow_kind = ty::BorrowKind::from_mutbl(mutbl);
// Check that we don't allow borrows of unsafe static items.
if check_aliasability(self.bccx, ex.span, euv::AddrOf,
match path.loan_path.kind {
LpVar(..) | LpUpvar(..) | LpDowncast(..) => {
let kill_scope = path.loan_path.kill_scope(tcx);
- let path = self.path_map.borrow()[path.loan_path];
+ let path = *self.path_map.borrow().get(&path.loan_path).unwrap();
self.kill_moves(path, kill_scope.node_id(), dfcx_moves);
}
LpExtend(..) => {}
#![feature(rustc_private)]
#![feature(staged_api)]
#![feature(unsafe_destructor)]
+#![feature(into_cow)]
#[macro_use] extern crate log;
#[macro_use] extern crate syntax;
// 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();
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());
// 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
#![feature(io)]
#![feature(set_stdio)]
#![feature(unicode)]
+#![feature(convert)]
extern crate arena;
extern crate flate;
// Extract output directory and file from matches.
fn make_output(matches: &getopts::Matches) -> (Option<PathBuf>, Option<PathBuf>) {
- 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)
}
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
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)
}
impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
fn check_def(&mut self, sp: Span, id: ast::NodeId) {
- match self.cx.tcx.def_map.borrow()[id].full_def() {
+ match self.cx.tcx.def_map.borrow().get(&id).unwrap().full_def() {
def::DefPrimTy(ast::TyInt(ast::TyIs(_))) => {
self.cx.span_lint(IMPROPER_CTYPES, sp,
"found rust type `isize` in foreign module, while \
}
},
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);
}
},
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 \
ast::ItemImpl(_, _, _, _, ref ty, ref impl_items) => {
let public_ty = match ty.node {
ast::TyPath(..) => {
- match self.tcx.def_map.borrow()[ty.id].full_def() {
+ match self.tcx.def_map.borrow().get(&ty.id).unwrap().full_def() {
def::DefPrimTy(..) => true,
def => {
let did = def.def_id();
ast::ItemTy(ref ty, _) if public_first => {
if let ast::TyPath(..) = ty.node {
- match self.tcx.def_map.borrow()[ty.id].full_def() {
+ match self.tcx.def_map.borrow().get(&ty.id).unwrap().full_def() {
def::DefPrimTy(..) | def::DefTyParam(..) => {},
def => {
let did = def.def_id();
// crate module gets processed as well.
if self.prev_exported {
assert!(self.export_map.contains_key(&id), "wut {}", id);
- for export in &self.export_map[id] {
+ for export in self.export_map.get(&id).unwrap() {
if is_local(export.def_id) {
self.reexports.insert(export.def_id.node);
}
// if we've reached the root, then everything was allowable and this
// access is public.
if closest_private_id == ast::CRATE_NODE_ID { return Allowable }
- closest_private_id = self.parents[closest_private_id];
+ closest_private_id = *self.parents.get(&closest_private_id).unwrap();
// If we reached the top, then we were public all the way down and
// we can allow this access.
/// whether the node is accessible by the current module that iteration is
/// inside.
fn private_accessible(&self, id: ast::NodeId) -> bool {
- let parent = self.parents[id];
+ let parent = *self.parents.get(&id).unwrap();
debug!("privacy - accessible parent {}", self.nodestr(parent));
// After finding `did`'s closest private member, we roll ourselves back
_ => {}
}
- cur = self.parents[cur];
+ cur = *self.parents.get(&cur).unwrap();
}
}
ast::TyPath(..) => {}
_ => return Some((err_span, err_msg, None)),
};
- let def = self.tcx.def_map.borrow()[ty.id].full_def();
+ let def = self.tcx.def_map.borrow().get(&ty.id).unwrap().full_def();
let did = def.def_id();
assert!(is_local(did));
match self.tcx.map.get(did.node) {
// Checks that a path is in scope.
fn check_path(&mut self, span: Span, path_id: ast::NodeId, last: ast::Ident) {
debug!("privacy - path {}", self.nodestr(path_id));
- let path_res = self.tcx.def_map.borrow()[path_id];
+ let path_res = *self.tcx.def_map.borrow().get(&path_id).unwrap();
let ck = |tyname: &str| {
let ck_public = |def: ast::DefId| {
debug!("privacy - ck_public {:?}", def);
}
}
ty::ty_enum(_, _) => {
- match self.tcx.def_map.borrow()[expr.id].full_def() {
+ match self.tcx.def_map.borrow().get(&expr.id).unwrap().full_def() {
def::DefVariant(_, variant_id, _) => {
for field in fields {
self.check_field(expr.span, variant_id,
return;
}
if self.glob_map.contains_key(&import_id) {
- self.glob_map[import_id].insert(name);
+ self.glob_map.get_mut(&import_id).unwrap().insert(name);
return;
}
// We've successfully resolved the import. Write the results in.
let mut import_resolutions = module_.import_resolutions.borrow_mut();
- let import_resolution = &mut (*import_resolutions)[target];
+ let import_resolution = import_resolutions.get_mut(&target).unwrap();
{
let mut check_and_write_import = |namespace, result: &_, used_public: &mut bool| {
-See the README.txt in ../librustc.
+See the README.md in ../librustc.
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 {
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);
}
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
&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);
}
// involves just passing the right -l flag.
let data = if dylib {
- &trans.crate_formats[config::CrateTypeDylib]
+ trans.crate_formats.get(&config::CrateTypeDylib).unwrap()
} else {
- &trans.crate_formats[config::CrateTypeExecutable]
+ trans.crate_formats.get(&config::CrateTypeExecutable).unwrap()
};
// Invoke get_used_crates to ensure that we get a topological sorting of
#![feature(path_ext)]
#![feature(fs)]
#![feature(hash)]
+#![feature(convert)]
#![feature(path_relative_from)]
extern crate arena;
self.sess.bug(&format!("def_map has no key for {} in lookup_type_ref",
ref_id));
}
- let def = self.analysis.ty_cx.def_map.borrow()[ref_id].full_def();
+ let def = self.analysis.ty_cx.def_map.borrow().get(&ref_id).unwrap().full_def();
match def {
def::DefPrimTy(_) => None,
_ => Some(def.def_id()),
self.sess.span_bug(span, &format!("def_map has no key for {} in lookup_def_kind",
ref_id));
}
- let def = def_map[ref_id].full_def();
+ let def = def_map.get(&ref_id).unwrap().full_def();
match def {
def::DefMod(_) |
def::DefForeignMod(_) => Some(recorder::ModRef),
self.collecting = false;
let span_utils = self.span.clone();
for &(id, ref p, _, _) in &self.collected_paths {
- let typ = ppaux::ty_to_string(&self.analysis.ty_cx,
- (*self.analysis.ty_cx.node_types.borrow())[id]);
+ let typ =
+ ppaux::ty_to_string(
+ &self.analysis.ty_cx,
+ *self.analysis.ty_cx.node_types.borrow().get(&id).unwrap());
// get the span only for the name of the variable (I hope the path is only ever a
// variable name, but who knows?)
self.fmt.formal_str(p.span,
ast::NamedField(ident, _) => {
let name = get_ident(ident);
let qualname = format!("{}::{}", qualname, name);
- let typ = ppaux::ty_to_string(&self.analysis.ty_cx,
- (*self.analysis.ty_cx.node_types.borrow())[field.node.id]);
+ let typ =
+ ppaux::ty_to_string(
+ &self.analysis.ty_cx,
+ *self.analysis.ty_cx.node_types.borrow().get(&field.node.id).unwrap());
match self.span.sub_span_before_token(field.span, token::Colon) {
Some(sub_span) => self.fmt.field_str(field.span,
Some(sub_span),
self.sess.span_bug(span,
&format!("def_map has no key for {} in visit_expr", id));
}
- let def = def_map[id].full_def();
+ let def = def_map.get(&id).unwrap().full_def();
let sub_span = self.span.span_for_last_ident(span);
match def {
def::DefUpvar(..) |
.ty_cx
.impl_items
.borrow();
- Some((*impl_items)[def_id]
+ Some(impl_items.get(&def_id)
+ .unwrap()
.iter()
.find(|mr| {
ty::impl_or_trait_item(
ex: &ast::Expr,
args: &Vec<P<ast::Expr>>) {
let method_map = self.analysis.ty_cx.method_map.borrow();
- let method_callee = &(*method_map)[ty::MethodCall::expr(ex.id)];
+ let method_callee = method_map.get(&ty::MethodCall::expr(ex.id)).unwrap();
let (def_id, decl_id) = match method_callee.origin {
ty::MethodStatic(def_id) |
ty::MethodStaticClosure(def_id) => {
self.collected_paths.push((p.id, path.clone(), false, recorder::StructRef));
visit::walk_path(self, path);
- let def = self.analysis.ty_cx.def_map.borrow()[p.id].full_def();
+ let def = self.analysis.ty_cx.def_map.borrow().get(&p.id).unwrap().full_def();
let struct_def = match def {
def::DefConst(..) => None,
def::DefVariant(_, variant_id, _) => Some(variant_id),
let glob_map = &self.analysis.glob_map;
let glob_map = glob_map.as_ref().unwrap();
if glob_map.contains_key(&item.id) {
- for n in &glob_map[item.id] {
+ for n in glob_map.get(&item.id).unwrap() {
if name_string.len() > 0 {
name_string.push_str(", ");
}
&format!("def_map has no key for {} in visit_arm",
id));
}
- let def = def_map[id].full_def();
+ let def = def_map.get(&id).unwrap().full_def();
match def {
def::DefLocal(id) => {
let value = if *immut {
for &(id, ref p, ref immut, _) in &self.collected_paths {
let value = if *immut { value.to_string() } else { "<mutable>".to_string() };
let types = self.analysis.ty_cx.node_types.borrow();
- let typ = ppaux::ty_to_string(&self.analysis.ty_cx, (*types)[id]);
+ let typ = ppaux::ty_to_string(&self.analysis.ty_cx, *types.get(&id).unwrap());
// Get the span only for the name of the variable (I hope the path
// is only ever a variable name, but who knows?).
let sub_span = self.span.span_for_last_ident(p.span);
// 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"),
},
};
LowerBound(Result<'blk, 'tcx>)
}
-#[derive(Clone, Copy)]
+#[derive(Clone, Copy, PartialEq)]
pub enum TransBindingMode {
TrByCopy(/* llbinding */ ValueRef),
TrByMove,
None => {
let data = &m[0].data;
for &(ref ident, ref value_ptr) in &m[0].bound_ptrs {
- let llmatch = data.bindings_map[*ident].llmatch;
- call_lifetime_start(bcx, llmatch);
- Store(bcx, *value_ptr, llmatch);
+ let binfo = *data.bindings_map.get(ident).unwrap();
+ call_lifetime_start(bcx, binfo.llmatch);
+ if binfo.trmode == TrByRef && type_is_fat_ptr(bcx.tcx(), binfo.ty) {
+ expr::copy_fat_ptr(bcx, *value_ptr, binfo.llmatch);
+ }
+ else {
+ Store(bcx, *value_ptr, binfo.llmatch);
+ }
}
match data.arm.guard {
Some(ref guard_expr) => {
_ => None
}
};
-
match adt_vals {
Some(field_vals) => {
let pats = enter_match(bcx, dm, m, col, val, |pats|
ast::BindByRef(_) => {
// By ref binding: the value of the variable
- // is the pointer `val` itself.
- Store(bcx, val, llval);
+ // is the pointer `val` itself or fat pointer referenced by `val`
+ if type_is_fat_ptr(bcx.tcx(), ty) {
+ expr::copy_fat_ptr(bcx, val, llval);
+ }
+ else {
+ Store(bcx, val, llval);
+ }
+
bcx
}
}
// no failure occurred preparing operands, no need to cleanup
fcx.pop_custom_cleanup_scope(temp_scope);
- let mut constraints = constraints.iter()
- .map(|s| s.to_string())
- .chain(ext_constraints.into_iter())
- .collect::<Vec<String>>()
- .connect(",");
-
- let mut clobbers = ia.clobbers.iter()
- .map(|s| format!("~{{{}}}", &s))
- .collect::<Vec<String>>()
- .connect(",");
- let more_clobbers = get_clobbers();
- if !more_clobbers.is_empty() {
- if !clobbers.is_empty() {
- clobbers.push(',');
- }
- clobbers.push_str(&more_clobbers[..]);
- }
-
- // Add the clobbers to our constraints list
- if clobbers.len() != 0 && constraints.len() != 0 {
- constraints.push(',');
- constraints.push_str(&clobbers[..]);
- } else {
- constraints.push_str(&clobbers[..]);
- }
+ let clobbers = ia.clobbers.iter()
+ .map(|s| format!("~{{{}}}", &s));
+
+ // Default per-arch clobbers
+ // Basically what clang does
+ let arch_clobbers = match bcx.sess().target.target.arch.as_slice() {
+ "x86" | "x86_64" => vec!("~{dirflag}", "~{fpsr}", "~{flags}"),
+ _ => Vec::new()
+ };
- debug!("Asm Constraints: {}", &constraints[..]);
+ let all_constraints= constraints.iter()
+ .map(|s| s.to_string())
+ .chain(ext_constraints.into_iter())
+ .chain(clobbers)
+ .chain(arch_clobbers.iter()
+ .map(|s| s.to_string()))
+ .collect::<Vec<String>>()
+ .connect(",");
- let num_outputs = outputs.len();
+ debug!("Asm Constraints: {}", &all_constraints[..]);
// Depending on how many outputs we have, the return type is different
- let output_type = if num_outputs == 0 {
- Type::void(bcx.ccx())
- } else if num_outputs == 1 {
- output_types[0]
- } else {
- Type::struct_(bcx.ccx(), &output_types[..], false)
+ let num_outputs = outputs.len();
+ let output_type = match num_outputs {
+ 0 => Type::void(bcx.ccx()),
+ 1 => output_types[0],
+ _ => Type::struct_(bcx.ccx(), &output_types[..], false)
};
let dialect = match ia.dialect {
};
let asm = CString::new(ia.asm.as_bytes()).unwrap();
- let constraints = CString::new(constraints).unwrap();
+ let constraint_cstr = CString::new(all_constraints).unwrap();
let r = InlineAsmCall(bcx,
asm.as_ptr(),
- constraints.as_ptr(),
+ constraint_cstr.as_ptr(),
&inputs,
output_type,
ia.volatile,
}
-// Default per-arch clobbers
-// Basically what clang does
-
-#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
-fn get_clobbers() -> String {
- "".to_string()
-}
-
-#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
-fn get_clobbers() -> String {
- "~{dirflag},~{fpsr},~{flags}".to_string()
-}
}
pub fn kind_for_closure(ccx: &CrateContext, closure_id: ast::DefId) -> ty::ClosureKind {
- ccx.tcx().closure_kinds.borrow()[closure_id]
+ *ccx.tcx().closure_kinds.borrow().get(&closure_id).unwrap()
}
pub fn decl_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
}
pub fn cast_shift_expr_rhs(cx: Block,
- op: ast::BinOp,
+ op: ast::BinOp_,
lhs: ValueRef,
rhs: ValueRef)
-> ValueRef {
|a,b| ZExt(cx, a, b))
}
-pub fn cast_shift_const_rhs(op: ast::BinOp,
+pub fn cast_shift_const_rhs(op: ast::BinOp_,
lhs: ValueRef, rhs: ValueRef) -> ValueRef {
cast_shift_rhs(op, lhs, rhs,
|a, b| unsafe { llvm::LLVMConstTrunc(a, b.to_ref()) },
|a, b| unsafe { llvm::LLVMConstZExt(a, b.to_ref()) })
}
-pub fn cast_shift_rhs<F, G>(op: ast::BinOp,
- lhs: ValueRef,
- rhs: ValueRef,
- trunc: F,
- zext: G)
- -> ValueRef where
+fn cast_shift_rhs<F, G>(op: ast::BinOp_,
+ lhs: ValueRef,
+ rhs: ValueRef,
+ trunc: F,
+ zext: G)
+ -> ValueRef where
F: FnOnce(ValueRef, Type) -> ValueRef,
G: FnOnce(ValueRef, Type) -> ValueRef,
{
// Shifts may have any size int on the rhs
- if ast_util::is_shift_binop(op.node) {
+ if ast_util::is_shift_binop(op) {
let mut rhs_llty = val_ty(rhs);
let mut lhs_llty = val_ty(lhs);
if rhs_llty.kind() == Vector { rhs_llty = rhs_llty.element_type() }
/// gives us better information about what we are loading.
pub fn load_ty<'blk, 'tcx>(cx: Block<'blk, 'tcx>,
ptr: ValueRef, t: Ty<'tcx>) -> ValueRef {
- if type_is_zero_size(cx.ccx(), t) {
- C_undef(type_of::type_of(cx.ccx(), t))
- } else if type_is_immediate(cx.ccx(), t) && type_of::type_of(cx.ccx(), t).is_aggregate() {
- // We want to pass small aggregates as immediate values, but using an aggregate LLVM type
- // for this leads to bad optimizations, so its arg type is an appropriately sized integer
- // and we have to convert it
- Load(cx, BitCast(cx, ptr, type_of::arg_type_of(cx.ccx(), t).ptr_to()))
- } else {
- unsafe {
- let global = llvm::LLVMIsAGlobalVariable(ptr);
- if !global.is_null() && llvm::LLVMIsGlobalConstant(global) == llvm::True {
- let val = llvm::LLVMGetInitializer(global);
- if !val.is_null() {
- // This could go into its own function, for DRY.
- // (something like "pre-store packing/post-load unpacking")
- if ty::type_is_bool(t) {
- return Trunc(cx, val, Type::i1(cx.ccx()));
- } else {
- return val;
- }
- }
+ if cx.unreachable.get() || type_is_zero_size(cx.ccx(), t) {
+ return C_undef(type_of::type_of(cx.ccx(), t));
+ }
+
+ let ptr = to_arg_ty_ptr(cx, ptr, t);
+
+ if type_is_immediate(cx.ccx(), t) && type_of::type_of(cx.ccx(), t).is_aggregate() {
+ return Load(cx, ptr);
+ }
+
+ unsafe {
+ let global = llvm::LLVMIsAGlobalVariable(ptr);
+ if !global.is_null() && llvm::LLVMIsGlobalConstant(global) == llvm::True {
+ let val = llvm::LLVMGetInitializer(global);
+ if !val.is_null() {
+ return from_arg_ty(cx, val, t);
}
}
- if ty::type_is_bool(t) {
- Trunc(cx, LoadRangeAssert(cx, ptr, 0, 2, llvm::False), Type::i1(cx.ccx()))
- } else if ty::type_is_char(t) {
- // a char is a Unicode codepoint, and so takes values from 0
- // to 0x10FFFF inclusive only.
- LoadRangeAssert(cx, ptr, 0, 0x10FFFF + 1, llvm::False)
- } else if (ty::type_is_region_ptr(t) || ty::type_is_unique(t))
- && !common::type_is_fat_ptr(cx.tcx(), t) {
- LoadNonNull(cx, ptr)
- } else {
- Load(cx, ptr)
- }
}
+
+ let val = if ty::type_is_bool(t) {
+ LoadRangeAssert(cx, ptr, 0, 2, llvm::False)
+ } else if ty::type_is_char(t) {
+ // a char is a Unicode codepoint, and so takes values from 0
+ // to 0x10FFFF inclusive only.
+ LoadRangeAssert(cx, ptr, 0, 0x10FFFF + 1, llvm::False)
+ } else if (ty::type_is_region_ptr(t) || ty::type_is_unique(t))
+ && !common::type_is_fat_ptr(cx.tcx(), t) {
+ LoadNonNull(cx, ptr)
+ } else {
+ Load(cx, ptr)
+ };
+
+ from_arg_ty(cx, val, t)
}
/// Helper for storing values in memory. Does the necessary conversion if the in-memory type
/// differs from the type used for SSA values.
pub fn store_ty<'blk, 'tcx>(cx: Block<'blk, 'tcx>, v: ValueRef, dst: ValueRef, t: Ty<'tcx>) {
- if ty::type_is_bool(t) {
- Store(cx, ZExt(cx, v, Type::i8(cx.ccx())), dst);
- } else if type_is_immediate(cx.ccx(), t) && type_of::type_of(cx.ccx(), t).is_aggregate() {
+ Store(cx, to_arg_ty(cx, v, t), to_arg_ty_ptr(cx, dst, t));
+}
+
+pub fn to_arg_ty(bcx: Block, val: ValueRef, ty: Ty) -> ValueRef {
+ if ty::type_is_bool(ty) {
+ ZExt(bcx, val, Type::i8(bcx.ccx()))
+ } else {
+ val
+ }
+}
+
+pub fn from_arg_ty(bcx: Block, val: ValueRef, ty: Ty) -> ValueRef {
+ if ty::type_is_bool(ty) {
+ Trunc(bcx, val, Type::i1(bcx.ccx()))
+ } else {
+ val
+ }
+}
+
+pub fn to_arg_ty_ptr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ptr: ValueRef, ty: Ty<'tcx>) -> ValueRef {
+ if type_is_immediate(bcx.ccx(), ty) && type_of::type_of(bcx.ccx(), ty).is_aggregate() {
// We want to pass small aggregates as immediate values, but using an aggregate LLVM type
// for this leads to bad optimizations, so its arg type is an appropriately sized integer
// and we have to convert it
- Store(cx, v, BitCast(cx, dst, type_of::arg_type_of(cx.ccx(), t).ptr_to()));
+ BitCast(bcx, ptr, type_of::arg_type_of(bcx.ccx(), ty).ptr_to())
} else {
- Store(cx, v, dst);
+ ptr
}
}
static");
}
- let v = ccx.static_values().borrow()[item.id].clone();
+ let v = ccx.static_values().borrow().get(&item.id).unwrap().clone();
unsafe {
if !(llvm::LLVMConstIntGetZExtValue(v) != 0) {
ccx.sess().span_fatal(expr.span, "static assertion failed");
let ref_ty = match node {
ExprId(id) => ty::node_id_to_type(tcx, id),
MethodCallKey(method_call) => {
- (*tcx.method_map.borrow())[method_call].ty
+ tcx.method_map.borrow().get(&method_call).unwrap().ty
}
};
let ref_ty = monomorphize::apply_param_substs(tcx,
}
fn upvar_capture(&self, upvar_id: ty::UpvarId) -> Option<ty::UpvarCapture> {
- Some(self.tcx().upvar_capture_map.borrow()[upvar_id].clone())
+ Some(self.tcx().upvar_capture_map.borrow().get(&upvar_id).unwrap().clone())
}
fn type_moves_by_default(&self, span: Span, ty: Ty<'tcx>) -> bool {
// shallow result we are looking for -- that is, what specific impl.
let typer = NormalizingClosureTyper::new(tcx);
let mut selcx = traits::SelectionContext::new(&infcx, &typer);
- let obligation = traits::Obligation::new(traits::ObligationCause::dummy(),
- trait_ref.to_poly_trait_predicate());
+ let obligation =
+ traits::Obligation::new(traits::ObligationCause::misc(span, ast::DUMMY_NODE_ID),
+ trait_ref.to_poly_trait_predicate());
let selection = match selcx.select(&obligation) {
Ok(Some(selection)) => selection,
Ok(None) => {
let obligation = traits::Obligation::new(traits::ObligationCause::dummy(), predicate);
fulfill_cx.register_predicate_obligation(&infcx, obligation);
}
- drain_fulfillment_cx(DUMMY_SP, &infcx, &mut fulfill_cx, &()).is_ok()
+ drain_fulfillment_cx(&infcx, &mut fulfill_cx, &()).is_ok()
}
pub struct NormalizingClosureTyper<'a,'tcx:'a> {
-> T
where T : TypeFoldable<'tcx> + Repr<'tcx>
{
- match drain_fulfillment_cx(span, infcx, fulfill_cx, result) {
+ match drain_fulfillment_cx(infcx, fulfill_cx, result) {
Ok(v) => v,
Err(errors) => {
infcx.tcx.sess.span_bug(
/// inference variables that appear in `result` to be unified, and
/// hence we need to process those obligations to get the complete
/// picture of the type.
-pub fn drain_fulfillment_cx<'a,'tcx,T>(span: Span,
- infcx: &infer::InferCtxt<'a,'tcx>,
+pub fn drain_fulfillment_cx<'a,'tcx,T>(infcx: &infer::InferCtxt<'a,'tcx>,
fulfill_cx: &mut traits::FulfillmentContext<'tcx>,
result: &T)
-> StdResult<T,Vec<traits::FulfillmentError<'tcx>>>
match fulfill_cx.select_all_or_error(infcx, &typer) {
Ok(()) => { }
Err(errors) => {
- // We always want to surface any overflow errors, no matter what.
- if errors.iter().all(|e| e.is_overflow()) {
- infcx.tcx.sess.span_fatal(
- span,
- "reached the recursion limit during monomorphization");
- } else {
- return Err(errors);
- }
+ return Err(errors);
}
}
ty::node_id_item_substs(tcx, id).substs
}
MethodCallKey(method_call) => {
- (*tcx.method_map.borrow())[method_call].substs.clone()
+ tcx.method_map.borrow().get(&method_call).unwrap().substs.clone()
}
};
// Special-case constants to cache a common global for all uses.
match expr.node {
ast::ExprPath(..) => {
- let def = ccx.tcx().def_map.borrow()[expr.id].full_def();
+ let def = ccx.tcx().def_map.borrow().get(&expr.id).unwrap().full_def();
match def {
def::DefConst(def_id) => {
if !ccx.tcx().adjustments.borrow().contains_key(&expr.id) {
let signed = ty::type_is_signed(intype);
let (te2, _) = const_expr(cx, &**e2, param_substs);
- let te2 = base::cast_shift_const_rhs(b, te1, te2);
+ let te2 = base::cast_shift_const_rhs(b.node, te1, te2);
match b.node {
ast::BiAdd => {
}
}
ast::ExprPath(..) => {
- let def = cx.tcx().def_map.borrow()[e.id].full_def();
+ let def = cx.tcx().def_map.borrow().get(&e.id).unwrap().full_def();
match def {
def::DefFn(..) | def::DefMethod(..) => {
expr::trans_def_fn_unadjusted(cx, e, def, param_substs).val
let g = base::get_item_val(ccx, id);
// At this point, get_item_val has already translated the
// constant's initializer to determine its LLVM type.
- let v = ccx.static_values().borrow()[id].clone();
+ let v = ccx.static_values().borrow().get(&id).unwrap().clone();
// boolean SSA values are i1, but they have to be stored in i8 slots,
// otherwise some LLVM optimization passes don't work as expected
let v = if llvm::LLVMTypeOf(v) == Type::i1(ccx).to_ref() {
};
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 {
return datum.store_to_dest(bcx, dest, expr.id);
}
- let qualif = bcx.tcx().const_qualif_map.borrow()[expr.id];
+ let qualif = *bcx.tcx().const_qualif_map.borrow().get(&expr.id).unwrap();
if !qualif.intersects(check_const::NOT_CONST | check_const::NEEDS_DROP) {
if !qualif.intersects(check_const::PREFER_IN_PLACE) {
if let SaveIn(lldest) = dest {
let mut bcx = bcx;
let fcx = bcx.fcx;
- let qualif = bcx.tcx().const_qualif_map.borrow()[expr.id];
+ let qualif = *bcx.tcx().const_qualif_map.borrow().get(&expr.id).unwrap();
let adjusted_global = !qualif.intersects(check_const::NON_STATIC_BORROWS);
let global = if !qualif.intersects(check_const::NOT_CONST | check_const::NEEDS_DROP) {
let global = consts::get_const_expr_as_global(bcx.ccx(), expr, qualif,
GEPi(bcx, fat_ptr, &[0, abi::FAT_PTR_ADDR])
}
+pub fn copy_fat_ptr(bcx: Block, src_ptr: ValueRef, dst_ptr: ValueRef) {
+ Store(bcx, Load(bcx, get_dataptr(bcx, src_ptr)), get_dataptr(bcx, dst_ptr));
+ Store(bcx, Load(bcx, get_len(bcx, src_ptr)), get_len(bcx, dst_ptr));
+}
+
// Retrieve the information we are losing (making dynamic) in an unsizing
// adjustment.
//
base_datum,
vec![(ix_datum, idx.id)],
Some(SaveIn(scratch.val)),
- true));
+ false));
let datum = scratch.to_expr_datum();
if type_is_sized(bcx.tcx(), elt_ty) {
Datum::new(datum.to_llscalarish(bcx), elt_ty, LvalueExpr)
ty.repr(tcx)));
}
Some(node_id) => {
- let def = tcx.def_map.borrow()[node_id].full_def();
+ let def = tcx.def_map.borrow().get(&node_id).unwrap().full_def();
match def {
def::DefVariant(enum_id, variant_id, _) => {
let variant_info = ty::enum_variant_with_id(tcx, enum_id, variant_id);
};
let is_float = ty::type_is_fp(intype);
let is_signed = ty::type_is_signed(intype);
- let rhs = base::cast_shift_expr_rhs(bcx, op, lhs, rhs);
let info = expr_info(binop_expr);
let binop_debug_loc = binop_expr.debug_loc();
ast::BiBitOr => Or(bcx, lhs, rhs, binop_debug_loc),
ast::BiBitAnd => And(bcx, lhs, rhs, binop_debug_loc),
ast::BiBitXor => Xor(bcx, lhs, rhs, binop_debug_loc),
- ast::BiShl => Shl(bcx, lhs, rhs, binop_debug_loc),
+ ast::BiShl => {
+ let (newbcx, res) = with_overflow_check(
+ bcx, OverflowOp::Shl, info, lhs_t, lhs, rhs, binop_debug_loc);
+ bcx = newbcx;
+ res
+ }
ast::BiShr => {
- if is_signed {
- AShr(bcx, lhs, rhs, binop_debug_loc)
- } else {
- LShr(bcx, lhs, rhs, binop_debug_loc)
- }
+ let (newbcx, res) = with_overflow_check(
+ bcx, OverflowOp::Shr, info, lhs_t, lhs, rhs, binop_debug_loc);
+ bcx = newbcx;
+ res
}
ast::BiEq | ast::BiNe | ast::BiLt | ast::BiGe | ast::BiLe | ast::BiGt => {
if is_simd {
dest: Option<Dest>,
autoref: bool)
-> Result<'blk, 'tcx> {
- let method_ty = (*bcx.tcx().method_map.borrow())[method_call].ty;
+ let method_ty = bcx.tcx().method_map.borrow().get(&method_call).unwrap().ty;
callee::trans_call_inner(bcx,
expr.debug_loc(),
monomorphize_type(bcx, method_ty),
dest: Option<Dest>)
-> Block<'blk, 'tcx> {
let method_call = MethodCall::expr(expr.id);
- let method_type = (*bcx.tcx()
- .method_map
- .borrow())[method_call]
- .ty;
+ let method_type = bcx.tcx()
+ .method_map
+ .borrow()
+ .get(&method_call)
+ .unwrap()
+ .ty;
let mut all_args = vec!(callee);
all_args.extend(args.iter().map(|e| &**e));
unpack_result!(bcx,
Add,
Sub,
Mul,
+ Shl,
+ Shr,
}
impl OverflowOp {
+ fn codegen_strategy(&self) -> OverflowCodegen {
+ use self::OverflowCodegen::{ViaIntrinsic, ViaInputCheck};
+ match *self {
+ OverflowOp::Add => ViaIntrinsic(OverflowOpViaIntrinsic::Add),
+ OverflowOp::Sub => ViaIntrinsic(OverflowOpViaIntrinsic::Sub),
+ OverflowOp::Mul => ViaIntrinsic(OverflowOpViaIntrinsic::Mul),
+
+ OverflowOp::Shl => ViaInputCheck(OverflowOpViaInputCheck::Shl),
+ OverflowOp::Shr => ViaInputCheck(OverflowOpViaInputCheck::Shr),
+ }
+ }
+}
+
+enum OverflowCodegen {
+ ViaIntrinsic(OverflowOpViaIntrinsic),
+ ViaInputCheck(OverflowOpViaInputCheck),
+}
+
+enum OverflowOpViaInputCheck { Shl, Shr, }
+
+enum OverflowOpViaIntrinsic { Add, Sub, Mul, }
+
+impl OverflowOpViaIntrinsic {
+ fn to_intrinsic<'blk, 'tcx>(&self, bcx: Block<'blk, 'tcx>, lhs_ty: Ty) -> ValueRef {
+ let name = self.to_intrinsic_name(bcx.tcx(), lhs_ty);
+ bcx.ccx().get_intrinsic(&name)
+ }
fn to_intrinsic_name(&self, tcx: &ty::ctxt, ty: Ty) -> &'static str {
use syntax::ast::IntTy::*;
use syntax::ast::UintTy::*;
};
match *self {
- OverflowOp::Add => match new_sty {
+ OverflowOpViaIntrinsic::Add => match new_sty {
ty_int(TyI8) => "llvm.sadd.with.overflow.i8",
ty_int(TyI16) => "llvm.sadd.with.overflow.i16",
ty_int(TyI32) => "llvm.sadd.with.overflow.i32",
_ => unreachable!(),
},
- OverflowOp::Sub => match new_sty {
+ OverflowOpViaIntrinsic::Sub => match new_sty {
ty_int(TyI8) => "llvm.ssub.with.overflow.i8",
ty_int(TyI16) => "llvm.ssub.with.overflow.i16",
ty_int(TyI32) => "llvm.ssub.with.overflow.i32",
_ => unreachable!(),
},
- OverflowOp::Mul => match new_sty {
+ OverflowOpViaIntrinsic::Mul => match new_sty {
ty_int(TyI8) => "llvm.smul.with.overflow.i8",
ty_int(TyI16) => "llvm.smul.with.overflow.i16",
ty_int(TyI32) => "llvm.smul.with.overflow.i32",
},
}
}
-}
-
-fn with_overflow_check<'a, 'b>(bcx: Block<'a, 'b>, oop: OverflowOp, info: NodeIdAndSpan,
- lhs_t: Ty, lhs: ValueRef, rhs: ValueRef, binop_debug_loc: DebugLoc)
- -> (Block<'a, 'b>, ValueRef) {
- if bcx.unreachable.get() { return (bcx, _Undef(lhs)); }
- if bcx.ccx().check_overflow() {
- let name = oop.to_intrinsic_name(bcx.tcx(), lhs_t);
- let llfn = bcx.ccx().get_intrinsic(&name);
+ fn build_intrinsic_call<'blk, 'tcx>(&self, bcx: Block<'blk, 'tcx>,
+ info: NodeIdAndSpan,
+ lhs_t: Ty<'tcx>, lhs: ValueRef,
+ rhs: ValueRef,
+ binop_debug_loc: DebugLoc)
+ -> (Block<'blk, 'tcx>, ValueRef) {
+ let llfn = self.to_intrinsic(bcx, lhs_t);
let val = Call(bcx, llfn, &[lhs, rhs], None, binop_debug_loc);
let result = ExtractValue(bcx, val, 0); // iN operation result
InternedString::new("arithmetic operation overflowed")));
(bcx, result)
+ }
+}
+
+impl OverflowOpViaInputCheck {
+ fn build_with_input_check<'blk, 'tcx>(&self,
+ bcx: Block<'blk, 'tcx>,
+ info: NodeIdAndSpan,
+ lhs_t: Ty<'tcx>,
+ lhs: ValueRef,
+ rhs: ValueRef,
+ binop_debug_loc: DebugLoc)
+ -> (Block<'blk, 'tcx>, ValueRef)
+ {
+ let lhs_llty = val_ty(lhs);
+ let rhs_llty = val_ty(rhs);
+
+ // Panic if any bits are set outside of bits that we always
+ // mask in.
+ //
+ // Note that the mask's value is derived from the LHS type
+ // (since that is where the 32/64 distinction is relevant) but
+ // the mask's type must match the RHS type (since they will
+ // both be fed into a and-binop)
+ let invert_mask = !shift_mask_val(lhs_llty);
+ let invert_mask = C_integral(rhs_llty, invert_mask, true);
+
+ let outer_bits = And(bcx, rhs, invert_mask, binop_debug_loc);
+ let cond = ICmp(bcx, llvm::IntNE, outer_bits,
+ C_integral(rhs_llty, 0, false), binop_debug_loc);
+ let result = match *self {
+ OverflowOpViaInputCheck::Shl =>
+ build_unchecked_lshift(bcx, lhs, rhs, binop_debug_loc),
+ OverflowOpViaInputCheck::Shr =>
+ build_unchecked_rshift(bcx, lhs_t, lhs, rhs, binop_debug_loc),
+ };
+ let bcx =
+ base::with_cond(bcx, cond, |bcx|
+ controlflow::trans_fail(bcx, info,
+ InternedString::new("shift operation overflowed")));
+
+ (bcx, result)
+ }
+}
+
+fn shift_mask_val(llty: Type) -> u64 {
+ // i8/u8 can shift by at most 7, i16/u16 by at most 15, etc.
+ llty.int_width() - 1
+}
+
+// To avoid UB from LLVM, these two functions mask RHS with an
+// appropriate mask unconditionally (i.e. the fallback behavior for
+// all shifts). For 32- and 64-bit types, this matches the semantics
+// of Java. (See related discussion on #1877 and #10183.)
+
+fn build_unchecked_lshift<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
+ lhs: ValueRef,
+ rhs: ValueRef,
+ binop_debug_loc: DebugLoc) -> ValueRef {
+ let rhs = base::cast_shift_expr_rhs(bcx, ast::BinOp_::BiShl, lhs, rhs);
+ // #1877, #10183: Ensure that input is always valid
+ let rhs = shift_mask_rhs(bcx, rhs, binop_debug_loc);
+ Shl(bcx, lhs, rhs, binop_debug_loc)
+}
+
+fn build_unchecked_rshift<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
+ lhs_t: Ty<'tcx>,
+ lhs: ValueRef,
+ rhs: ValueRef,
+ binop_debug_loc: DebugLoc) -> ValueRef {
+ let rhs = base::cast_shift_expr_rhs(bcx, ast::BinOp_::BiShr, lhs, rhs);
+ // #1877, #10183: Ensure that input is always valid
+ let rhs = shift_mask_rhs(bcx, rhs, binop_debug_loc);
+ let is_signed = ty::type_is_signed(lhs_t);
+ if is_signed {
+ AShr(bcx, lhs, rhs, binop_debug_loc)
+ } else {
+ LShr(bcx, lhs, rhs, binop_debug_loc)
+ }
+}
+
+fn shift_mask_rhs<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
+ rhs: ValueRef,
+ debug_loc: DebugLoc) -> ValueRef {
+ let rhs_llty = val_ty(rhs);
+ let mask = shift_mask_val(rhs_llty);
+ And(bcx, rhs, C_integral(rhs_llty, mask, false), debug_loc)
+}
+
+fn with_overflow_check<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, oop: OverflowOp, info: NodeIdAndSpan,
+ lhs_t: Ty<'tcx>, lhs: ValueRef,
+ rhs: ValueRef,
+ binop_debug_loc: DebugLoc)
+ -> (Block<'blk, 'tcx>, ValueRef) {
+ if bcx.unreachable.get() { return (bcx, _Undef(lhs)); }
+ if bcx.ccx().check_overflow() {
+
+ match oop.codegen_strategy() {
+ OverflowCodegen::ViaIntrinsic(oop) =>
+ oop.build_intrinsic_call(bcx, info, lhs_t, lhs, rhs, binop_debug_loc),
+ OverflowCodegen::ViaInputCheck(oop) =>
+ oop.build_with_input_check(bcx, info, lhs_t, lhs, rhs, binop_debug_loc),
+ }
} else {
let res = match oop {
OverflowOp::Add => Add(bcx, lhs, rhs, binop_debug_loc),
OverflowOp::Sub => Sub(bcx, lhs, rhs, binop_debug_loc),
OverflowOp::Mul => Mul(bcx, lhs, rhs, binop_debug_loc),
+
+ OverflowOp::Shl =>
+ build_unchecked_lshift(bcx, lhs, rhs, binop_debug_loc),
+ OverflowOp::Shr =>
+ build_unchecked_rshift(bcx, lhs_t, lhs, rhs, binop_debug_loc),
};
(bcx, res)
}
call_debug_location)
}
(_, "volatile_load") => {
- VolatileLoad(bcx, llargs[0])
+ let tp_ty = *substs.types.get(FnSpace, 0);
+ let ptr = to_arg_ty_ptr(bcx, llargs[0], tp_ty);
+ from_arg_ty(bcx, VolatileLoad(bcx, ptr), tp_ty)
},
(_, "volatile_store") => {
- VolatileStore(bcx, llargs[1], llargs[0]);
+ let tp_ty = *substs.types.get(FnSpace, 0);
+ let ptr = to_arg_ty_ptr(bcx, llargs[0], tp_ty);
+ let val = to_arg_ty(bcx, llargs[1], tp_ty);
+ VolatileStore(bcx, val, ptr);
C_nil(ccx)
},
llvm::SequentiallyConsistent
};
- let res = AtomicCmpXchg(bcx, llargs[0], llargs[1],
- llargs[2], order,
+ let tp_ty = *substs.types.get(FnSpace, 0);
+ let ptr = to_arg_ty_ptr(bcx, llargs[0], tp_ty);
+ let cmp = to_arg_ty(bcx, llargs[1], tp_ty);
+ let src = to_arg_ty(bcx, llargs[2], tp_ty);
+ let res = AtomicCmpXchg(bcx, ptr, cmp, src, order,
strongest_failure_ordering);
if unsafe { llvm::LLVMVersionMinor() >= 5 } {
ExtractValue(bcx, res, 0)
}
"load" => {
- AtomicLoad(bcx, llargs[0], order)
+ let tp_ty = *substs.types.get(FnSpace, 0);
+ let ptr = to_arg_ty_ptr(bcx, llargs[0], tp_ty);
+ from_arg_ty(bcx, AtomicLoad(bcx, ptr, order), tp_ty)
}
"store" => {
- AtomicStore(bcx, llargs[1], llargs[0], order);
+ let tp_ty = *substs.types.get(FnSpace, 0);
+ let ptr = to_arg_ty_ptr(bcx, llargs[0], tp_ty);
+ let val = to_arg_ty(bcx, llargs[1], tp_ty);
+ AtomicStore(bcx, val, ptr, order);
C_nil(ccx)
}
_ => ccx.sess().fatal("unknown atomic operation")
};
- AtomicRMW(bcx, atom_op, llargs[0], llargs[1], order)
+ let tp_ty = *substs.types.get(FnSpace, 0);
+ let ptr = to_arg_ty_ptr(bcx, llargs[0], tp_ty);
+ let val = to_arg_ty(bcx, llargs[1], tp_ty);
+ AtomicRMW(bcx, atom_op, ptr, val, order)
}
}
return (tcx.types.err, ty_path_def);
};
- let ty_param_name = tcx.ty_param_defs.borrow()[ty_param_node_id].name;
+ let ty_param_name = tcx.ty_param_defs.borrow().get(&ty_param_node_id).unwrap().name;
let bounds = match this.get_type_parameter_bounds(span, ty_param_node_id) {
Ok(v) => v,
demand::eqtype(fcx, pat.span, expected, lhs_ty);
}
ast::PatEnum(..) | ast::PatIdent(..) if pat_is_const(&tcx.def_map, pat) => {
- let const_did = tcx.def_map.borrow()[pat.id].def_id();
+ let const_did = tcx.def_map.borrow().get(&pat.id).unwrap().def_id();
let const_scheme = ty::lookup_item_type(tcx, const_did);
assert!(const_scheme.generics.is_empty());
let const_ty = pcx.fcx.instantiate_type_scheme(pat.span,
// if there are multiple arms, make sure they all agree on
// what the type of the binding `x` ought to be
- let canon_id = pcx.map[path.node];
+ let canon_id = *pcx.map.get(&path.node).unwrap();
if canon_id != pat.id {
let ct = fcx.local_ty(pat.span, canon_id);
demand::eqtype(fcx, pat.span, ct, typ);
// (nmatsakis) an hour or two debugging to remember, so I thought
// I'd write them down this time.
//
- // 1. Most importantly, there is no loss of expressiveness
- // here. What we are saying is that the type of `x`
- // becomes *exactly* what is expected. This might seem
- // like it will cause errors in a case like this:
+ // 1. There is no loss of expressiveness here, though it does
+ // cause some inconvenience. What we are saying is that the type
+ // of `x` becomes *exactly* what is expected. This can cause unnecessary
+ // errors in some cases, such as this one:
+ // it will cause errors in a case like this:
//
// ```
// fn foo<'x>(x: &'x int) {
match_src: ast::MatchSource) {
let tcx = fcx.ccx.tcx;
- let discrim_ty = fcx.infcx().next_ty_var();
- check_expr_has_type(fcx, discrim, discrim_ty);
+ // Not entirely obvious: if matches may create ref bindings, we
+ // want to use the *precise* type of the discriminant, *not* some
+ // supertype, as the "discriminant type" (issue #23116).
+ let contains_ref_bindings = arms.iter().any(|a| tcx.arm_contains_ref_binding(a));
+ let discrim_ty;
+ if contains_ref_bindings {
+ check_expr(fcx, discrim);
+ discrim_ty = fcx.expr_ty(discrim);
+ } else {
+ // ...but otherwise we want to use any supertype of the
+ // discriminant. This is sort of a workaround, see note (*) in
+ // `check_pat` for some details.
+ discrim_ty = fcx.infcx().next_ty_var();
+ check_expr_has_type(fcx, discrim, discrim_ty);
+ };
// Typecheck the patterns first, so that we get types for all the
// bindings.
let fcx = pcx.fcx;
let tcx = pcx.fcx.ccx.tcx;
- let def = tcx.def_map.borrow()[pat.id].full_def();
+ let def = tcx.def_map.borrow().get(&pat.id).unwrap().full_def();
let (enum_def_id, variant_def_id) = match def {
def::DefTrait(_) => {
let name = pprust::path_to_string(path);
let fcx = pcx.fcx;
let tcx = pcx.fcx.ccx.tcx;
- let def = tcx.def_map.borrow()[pat.id].full_def();
+ let def = tcx.def_map.borrow().get(&pat.id).unwrap().full_def();
let enum_def = def.variant_def_ids()
.map_or_else(|| def.def_id(), |(enum_def, _)| enum_def);
Ok(None) // No coercion required.
}
+ fn outlives(&self, a: ty::Region, b: ty::Region) -> cres<'tcx, ()> {
+ let sub = Sub(self.fcx.infcx().combine_fields(false, self.trace.clone()));
+ try!(sub.regions(b, a));
+ Ok(())
+ }
+
fn unpack_actual_value<T, F>(&self, a: Ty<'tcx>, f: F) -> T where
F: FnOnce(Ty<'tcx>) -> T,
{
Some((ty, ty::UnsizeLength(len)))
}
(&ty::ty_trait(ref data_a), &ty::ty_trait(ref data_b)) => {
- // For now, we only support upcasts from
- // `Foo+Send` to `Foo` (really, any time there are
- // fewer builtin bounds then before). These are
- // convenient because they don't require any sort
- // of change to the vtable at runtime.
- if data_a.bounds.builtin_bounds != data_b.bounds.builtin_bounds &&
- data_a.bounds.builtin_bounds.is_superset(&data_b.bounds.builtin_bounds)
- {
+ // Upcasts permit two things:
+ //
+ // 1. Dropping builtin bounds, e.g. `Foo+Send` to `Foo`
+ // 2. Tightening the region bound, e.g. `Foo+'a` to `Foo+'b` if `'a : 'b`
+ //
+ // Note that neither of these changes requires any
+ // change at runtime. Eventually this will be
+ // generalized.
+ //
+ // We always upcast when we can because of reason
+ // #2 (region bounds).
+ if data_a.bounds.builtin_bounds.is_superset(&data_b.bounds.builtin_bounds) {
+ // construct a type `a1` which is a version of
+ // `a` using the upcast bounds from `b`
let bounds_a1 = ty::ExistentialBounds {
- region_bound: data_a.bounds.region_bound,
+ // From type b
+ region_bound: data_b.bounds.region_bound,
builtin_bounds: data_b.bounds.builtin_bounds,
+
+ // From type a
projection_bounds: data_a.bounds.projection_bounds.clone(),
};
let ty_a1 = ty::mk_trait(tcx, data_a.principal.clone(), bounds_a1);
- match self.fcx.infcx().try(|_| self.subtype(ty_a1, ty_b)) {
+
+ // relate `a1` to `b`
+ let result = self.fcx.infcx().try(|_| {
+ // it's ok to upcast from Foo+'a to Foo+'b so long as 'a : 'b
+ try!(self.outlives(data_a.bounds.region_bound,
+ data_b.bounds.region_bound));
+ self.subtype(ty_a1, ty_b)
+ });
+
+ // if that was successful, we have a coercion
+ match result {
Ok(_) => Some((ty_b, ty::UnsizeUpcast(ty_b))),
Err(_) => None,
}
substs: &subst::Substs<'tcx>)
-> ty::ClosureTy<'tcx>
{
- self.inh.closure_tys.borrow()[def_id].subst(self.tcx(), substs)
+ self.inh.closure_tys.borrow().get(&def_id).unwrap().subst(self.tcx(), substs)
}
fn closure_upvars(&self,
debug!("Local variable {} is assigned type {}",
self.fcx.pat_to_string(&*local.pat),
self.fcx.infcx().ty_to_string(
- self.fcx.inh.locals.borrow()[local.id].clone()));
+ self.fcx.inh.locals.borrow().get(&local.id).unwrap().clone()));
visit::walk_local(self, local);
}
debug!("Pattern binding {} is assigned to {} with type {}",
token::get_ident(path1.node),
self.fcx.infcx().ty_to_string(
- self.fcx.inh.locals.borrow()[p.id].clone()),
+ self.fcx.inh.locals.borrow().get(&p.id).unwrap().clone()),
var_ty.repr(self.fcx.tcx()));
}
}
let mut missing_fields = Vec::new();
for class_field in field_types {
let name = class_field.name;
- let (_, seen) = class_field_map[name];
+ let (_, seen) = *class_field_map.get(&name).unwrap();
if !seen {
missing_fields.push(
format!("`{}`", &token::get_name(name)))
}
pub fn check_decl_initializer<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
- nid: ast::NodeId,
+ local: &'tcx ast::Local,
init: &'tcx ast::Expr)
{
- let local_ty = fcx.local_ty(init.span, nid);
- check_expr_coercable_to_type(fcx, init, local_ty)
+ let ref_bindings = fcx.tcx().pat_contains_ref_binding(&local.pat);
+
+ let local_ty = fcx.local_ty(init.span, local.id);
+ if !ref_bindings {
+ check_expr_coercable_to_type(fcx, init, local_ty)
+ } else {
+ // Somewhat subtle: if we have a `ref` binding in the pattern,
+ // we want to avoid introducing coercions for the RHS. This is
+ // both because it helps preserve sanity and, in the case of
+ // ref mut, for soundness (issue #23116). In particular, in
+ // the latter case, we need to be clear that the type of the
+ // referent for the reference that results is *equal to* the
+ // type of the lvalue it is referencing, and not some
+ // supertype thereof.
+ check_expr(fcx, init);
+ let init_ty = fcx.expr_ty(init);
+ demand::eqtype(fcx, init.span, init_ty, local_ty);
+ };
}
pub fn check_decl_local<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, local: &'tcx ast::Local) {
fcx.write_ty(local.id, t);
if let Some(ref init) = local.init {
- check_decl_initializer(fcx, local.id, &**init);
+ check_decl_initializer(fcx, local, &**init);
let init_ty = fcx.expr_ty(&**init);
if ty::type_is_error(init_ty) {
fcx.write_ty(local.id, init_ty);
let inh = static_inherited_fields(ccx);
let rty = ty::node_id_to_type(ccx.tcx, id);
let fcx = blank_fn_ctxt(ccx, &inh, ty::FnConverging(rty), e.id);
- let declty = (*fcx.ccx.tcx.tcache.borrow())[local_def(id)].ty;
+ let declty = fcx.ccx.tcx.tcache.borrow().get(&local_def(id)).unwrap().ty;
check_const_with_ty(&fcx, sp, e, declty);
}
// borrow_kind of the upvar to make sure it
// is inferred to mutable if necessary
let mut upvar_capture_map = self.fcx.inh.upvar_capture_map.borrow_mut();
- let ub = &mut upvar_capture_map[upvar_id];
+ let ub = upvar_capture_map.get_mut(&upvar_id).unwrap();
self.adjust_upvar_borrow_kind(upvar_id, ub, borrow_kind);
// also need to be in an FnMut closure since this is not an ImmBorrow
let closure_def_id = ast_util::local_def(closure_id);
let mut closure_kinds = self.fcx.inh.closure_kinds.borrow_mut();
- let existing_kind = closure_kinds[closure_def_id];
+ let existing_kind = *closure_kinds.get(&closure_def_id).unwrap();
debug!("adjust_closure_kind: closure_id={}, existing_kind={:?}, new_kind={:?}",
closure_id, existing_kind, new_kind);
fn get_self_type_for_implementation(&self, impl_did: DefId)
-> TypeScheme<'tcx> {
- self.crate_context.tcx.tcache.borrow()[impl_did].clone()
+ self.crate_context.tcx.tcache.borrow().get(&impl_did).unwrap().clone()
}
// Converts an implementation in the AST to a vector of items.
};
for &impl_did in &*trait_impls.borrow() {
- let items = &(*impl_items)[impl_did];
+ let items = impl_items.get(&impl_did).unwrap();
if items.len() < 1 {
// We'll error out later. For now, just don't ICE.
continue;
tcx: &'cx ty::ctxt<'tcx>
}
-impl<'cx, 'tcx,'v> visit::Visitor<'v> for UnsafetyChecker<'cx, 'tcx> {
- fn visit_item(&mut self, item: &'v ast::Item) {
- match item.node {
- ast::ItemImpl(unsafety, polarity, _, _, _, _) => {
- match ty::impl_trait_ref(self.tcx, ast_util::local_def(item.id)) {
- None => {
- // Inherent impl.
- match unsafety {
- ast::Unsafety::Normal => { /* OK */ }
- ast::Unsafety::Unsafe => {
- span_err!(self.tcx.sess, item.span, E0197,
- "inherent impls cannot be declared as unsafe");
- }
- }
+impl<'cx, 'tcx, 'v> UnsafetyChecker<'cx, 'tcx> {
+ fn check_unsafety_coherence(&mut self, item: &'v ast::Item,
+ unsafety: ast::Unsafety,
+ polarity: ast::ImplPolarity) {
+ match ty::impl_trait_ref(self.tcx, ast_util::local_def(item.id)) {
+ None => {
+ // Inherent impl.
+ match unsafety {
+ ast::Unsafety::Normal => { /* OK */ }
+ ast::Unsafety::Unsafe => {
+ span_err!(self.tcx.sess, item.span, E0197,
+ "inherent impls cannot be declared as unsafe");
}
+ }
+ }
- Some(trait_ref) => {
- let trait_def = ty::lookup_trait_def(self.tcx, trait_ref.def_id);
- match (trait_def.unsafety, unsafety, polarity) {
- (ast::Unsafety::Unsafe,
- ast::Unsafety::Unsafe, ast::ImplPolarity::Negative) => {
- span_err!(self.tcx.sess, item.span, E0198,
- "negative implementations are not unsafe");
- }
+ Some(trait_ref) => {
+ let trait_def = ty::lookup_trait_def(self.tcx, trait_ref.def_id);
+ match (trait_def.unsafety, unsafety, polarity) {
+ (ast::Unsafety::Unsafe,
+ ast::Unsafety::Unsafe, ast::ImplPolarity::Negative) => {
+ span_err!(self.tcx.sess, item.span, E0198,
+ "negative implementations are not unsafe");
+ }
- (ast::Unsafety::Normal, ast::Unsafety::Unsafe, _) => {
- span_err!(self.tcx.sess, item.span, E0199,
- "implementing the trait `{}` is not unsafe",
- trait_ref.user_string(self.tcx));
- }
+ (ast::Unsafety::Normal, ast::Unsafety::Unsafe, _) => {
+ span_err!(self.tcx.sess, item.span, E0199,
+ "implementing the trait `{}` is not unsafe",
+ trait_ref.user_string(self.tcx));
+ }
- (ast::Unsafety::Unsafe,
- ast::Unsafety::Normal, ast::ImplPolarity::Positive) => {
- span_err!(self.tcx.sess, item.span, E0200,
- "the trait `{}` requires an `unsafe impl` declaration",
- trait_ref.user_string(self.tcx));
- }
+ (ast::Unsafety::Unsafe,
+ ast::Unsafety::Normal, ast::ImplPolarity::Positive) => {
+ span_err!(self.tcx.sess, item.span, E0200,
+ "the trait `{}` requires an `unsafe impl` declaration",
+ trait_ref.user_string(self.tcx));
+ }
- (ast::Unsafety::Unsafe,
- ast::Unsafety::Normal, ast::ImplPolarity::Negative) |
- (ast::Unsafety::Unsafe,
- ast::Unsafety::Unsafe, ast::ImplPolarity::Positive) |
- (ast::Unsafety::Normal, ast::Unsafety::Normal, _) => {
- /* OK */
- }
- }
+ (ast::Unsafety::Unsafe,
+ ast::Unsafety::Normal, ast::ImplPolarity::Negative) |
+ (ast::Unsafety::Unsafe,
+ ast::Unsafety::Unsafe, ast::ImplPolarity::Positive) |
+ (ast::Unsafety::Normal, ast::Unsafety::Normal, _) => {
+ /* OK */
}
}
}
+ }
+ }
+}
+
+impl<'cx, 'tcx,'v> visit::Visitor<'v> for UnsafetyChecker<'cx, 'tcx> {
+ fn visit_item(&mut self, item: &'v ast::Item) {
+ match item.node {
+ ast::ItemDefaultImpl(unsafety, _) => {
+ self.check_unsafety_coherence(item, unsafety, ast::ImplPolarity::Positive);
+ }
+ ast::ItemImpl(unsafety, polarity, _, _, _, _) => {
+ self.check_unsafety_coherence(item, unsafety, polarity);
+ }
_ => { }
}
fn method_ty(&self, method_id: ast::NodeId) -> Rc<ty::Method<'tcx>> {
let def_id = local_def(method_id);
- match self.tcx.impl_or_trait_items.borrow()[def_id] {
+ match *self.tcx.impl_or_trait_items.borrow().get(&def_id).unwrap() {
ty::MethodTraitItem(ref mty) => mty.clone(),
ty::TypeTraitItem(..) => {
self.tcx.sess.bug(&format!("method with id {} has the wrong type", method_id));
-> bool
{
if let ast::TyPath(None, _) = ast_ty.node {
- let path_res = tcx.def_map.borrow()[ast_ty.id];
+ let path_res = *tcx.def_map.borrow().get(&ast_ty.id).unwrap();
match path_res.base_def {
def::DefSelfTy(node_id) =>
path_res.depth == 0 && node_id == param_id,
}
}
-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,
"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);
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);
}
}
tcx.predicates.borrow_mut().insert(local_def(ctor_id), predicates);
} else if struct_def.fields[0].node.kind.is_unnamed() {
// Tuple-like.
- let inputs: Vec<_> = struct_def.fields.iter().map(
- |field| (*tcx.tcache.borrow())[
- local_def(field.node.id)].ty).collect();
+ let inputs: Vec<_> =
+ struct_def.fields
+ .iter()
+ .map(|field| tcx.tcache.borrow().get(&local_def(field.node.id))
+ .unwrap()
+ .ty)
+ .collect();
let ctor_fn_ty = ty::mk_ctor_fn(tcx,
local_def(ctor_id),
&inputs[..],
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();
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 {
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(),
if ast_util::is_local(did) || cache.inlined.contains(&did) {
Some(repeat("../").take(loc.len()).collect::<String>())
} else {
- match cache.extern_locations[did.krate] {
+ match cache.extern_locations[&did.krate] {
render::Remote(ref s) => Some(s.to_string()),
render::Local => {
Some(repeat("../").take(loc.len()).collect::<String>())
needs_termination = true;
}
Some(&cnum) => {
- let path = &m.paths[ast::DefId {
+ let path = &m.paths[&ast::DefId {
krate: cnum,
node: ast::CRATE_NODE_ID,
}];
- let loc = match m.extern_locations[cnum] {
+ let loc = match m.extern_locations[&cnum] {
render::Remote(ref s) => Some(s.to_string()),
render::Local => {
let len = CURRENT_LOCATION_KEY.with(|s| s.borrow().len());
passes: HashSet<String>) -> 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,
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
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()
// located, then we return `None`.
} else {
let cache = cache();
- let path = &cache.external_paths[self.item.def_id];
- let root = match cache.extern_locations[self.item.def_id.krate] {
+ let path = &cache.external_paths[&self.item.def_id];
+ let root = match cache.extern_locations[&self.item.def_id.krate] {
Remote(ref s) => s.to_string(),
Local => self.cx.root_path.clone(),
Unknown => return None,
path = if ast_util::is_local(it.def_id) {
cx.current.connect("/")
} else {
- let path = &cache.external_paths[it.def_id];
+ let path = &cache.external_paths[&it.def_id];
path[..path.len() - 1].connect("/")
},
ty = shortty(it).to_static_str(),
#![feature(file_path)]
#![feature(path_ext)]
#![feature(path_relative_from)]
+#![feature(convert)]
extern crate arena;
extern crate getopts;
use std::rc::Rc;
use std::sync::mpsc::channel;
+#[allow(deprecated)] use std::old_path::Path;
+
use externalfiles::ExternalHtml;
use serialize::Decodable;
use serialize::json::{self, Json};
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(
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) => {}
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),
}
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),
}
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();
use serialize::json;
use std::mem;
use std::string::String;
+use std::old_path::{Path, GenericPath};
pub type PluginJson = Option<(String, json::Json)>;
pub type PluginResult = (clean::Crate, PluginJson);
mut test_args: Vec<String>,
crate_name: Option<String>)
-> 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 {
Some(tcx) => tcx,
None => return false
};
- let def = tcx.def_map.borrow()[id].def_id();
+ let def = tcx.def_map.borrow()[&id].def_id();
if !ast_util::is_local(def) { return false }
let analysis = match self.analysis {
Some(analysis) => analysis, None => return false
}
}
+#[cfg(stage0)]
impl<'a> Index<&'a str> for Json {
type Output = 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<uint> for Json {
type Output = Json;
}
}
+#[cfg(not(stage0))]
+impl Index<uint> 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 {
use std::{i64, u64, f32, f64};
use std::collections::BTreeMap;
use std::string;
+ use std::old_io::Writer;
#[derive(RustcDecodable, Eq, PartialEq, Debug)]
struct OptionData {
#![feature(std_misc)]
#![feature(unicode)]
#![feature(str_char)]
+#![feature(convert)]
#![cfg_attr(test, feature(test))]
// test harness access
*/
#[allow(deprecated)]
-use std::old_path;
+use std::old_path::{self, GenericPath};
use std::path;
use std::rc::Rc;
use std::cell::{Cell, RefCell};
impl Decodable for path::PathBuf {
fn decode<D: Decoder>(d: &mut D) -> Result<path::PathBuf, D::Error> {
let bytes: String = try!(Decodable::decode(d));
- Ok(path::PathBuf::new(&bytes))
+ Ok(path::PathBuf::from(bytes))
}
}
use iter::{self, Iterator, ExactSizeIterator, IntoIterator, IteratorExt, FromIterator, Extend, Map};
use marker::Sized;
use mem::{self, replace};
-use ops::{Deref, FnMut, Index, IndexMut};
+use ops::{Deref, FnMut, Index};
use option::Option::{self, Some, None};
use rand::{self, Rng};
use result::Result::{self, Ok, Err};
/// 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<Q: ?Sized>(&mut self, k: &Q) -> Option<&mut V>
///
/// 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<V> {
}
}
+#[cfg(stage0)]
#[stable(feature = "rust1", since = "1.0.0")]
impl<K, Q: ?Sized, V, S> Index<Q> for HashMap<K, V, S>
where K: Eq + Hash + Borrow<Q>,
}
}
+#[cfg(not(stage0))]
#[stable(feature = "rust1", since = "1.0.0")]
-impl<K, V, S, Q: ?Sized> IndexMut<Q> for HashMap<K, V, S>
+impl<'a, K, Q: ?Sized, V, S> Index<&'a Q> for HashMap<K, V, S>
where K: Eq + Hash + Borrow<Q>,
Q: Eq + Hash,
S: HashState,
{
+ type Output = V;
+
#[inline]
- fn index_mut<'a>(&'a mut self, index: &Q) -> &'a mut V {
- self.get_mut(index).expect("no entry found for key")
+ fn index(&self, index: &Q) -> &V {
+ self.get(index).expect("no entry found for key")
}
}
map.insert(2, 1);
map.insert(3, 4);
- assert_eq!(map[2], 1);
+ assert_eq!(map[&2], 1);
}
#[test]
map.insert(2, 1);
map.insert(3, 4);
- map[4];
+ map[&4];
}
#[test]
use prelude::v1::*;
+use env;
use ffi::CString;
use mem;
-use env;
-use str;
+use old_path::{Path, GenericPath};
use os;
+use str;
pub struct DynamicLibrary {
handle: *mut u8
use super::*;
use prelude::v1::*;
use libc;
+ use old_path::Path;
use mem;
#[test]
fn test_loading_cosine() {
// The math library does not need to be loaded since it is already
// statically linked in
- let none: Option<&Path> = None; // appease the typechecker
- let libm = match DynamicLibrary::open(none) {
+ let libm = match DynamicLibrary::open(None) {
Err(error) => panic!("Could not load self as module: {}", error),
Ok(libm) => libm
};
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;
/// println!("Successfully changed working directory to {}!", root.display());
/// ```
#[stable(feature = "env", since = "1.0.0")]
-pub fn set_current_dir<P: AsPath + ?Sized>(p: &P) -> io::Result<()> {
- os_imp::chdir(p.as_path())
+pub fn set_current_dir<P: AsRef<Path> + ?Sized>(p: &P) -> io::Result<()> {
+ os_imp::chdir(p.as_ref())
}
static ENV_LOCK: StaticMutex = MUTEX_INIT;
mod tests {
use prelude::v1::*;
use super::*;
+
use iter::repeat;
use rand::{self, Rng};
use ffi::{OsString, OsStr};
- use path::PathBuf;
+ use path::{Path, PathBuf};
fn make_rand_name() -> OsString {
let mut rng = rand::thread_rng();
#![unstable(feature = "std_misc")]
+use convert::Into;
use cmp::{PartialEq, Eq, PartialOrd, Ord, Ordering};
use error::{Error, FromError};
use fmt;
/// 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<Vec<u8>> instead")]
+#[unstable(feature = "std_misc")]
pub trait IntoBytes {
/// Consumes this container, returning a vector of bytes.
fn into_bytes(self) -> Vec<u8>;
/// 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: IntoBytes>(t: T) -> Result<CString, NulError> {
- let bytes = t.into_bytes();
+ pub fn new<T: Into<Vec<u8>>>(t: T) -> Result<CString, NulError> {
+ 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) }),
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<u8> { self.as_bytes().to_vec() }
}
+#[allow(deprecated)]
impl<'a> IntoBytes for &'a [u8] {
fn into_bytes(self) -> Vec<u8> { self.to_vec() }
}
+#[allow(deprecated)]
impl IntoBytes for String {
fn into_bytes(self) -> Vec<u8> { self.into_bytes() }
}
+#[allow(deprecated)]
impl IntoBytes for Vec<u8> {
fn into_bytes(self) -> Vec<u8> { self }
}
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`.
/// Extend the string with the given `&OsStr` slice.
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn push<T: AsOsStr + ?Sized>(&mut self, s: &T) {
- self.inner.push_slice(&s.as_os_str().inner)
+ pub fn push<T: AsRef<OsStr>>(&mut self, s: T) {
+ self.inner.push_slice(&s.as_ref().inner)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl From<String> 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() }
}
}
+#[cfg(stage0)]
#[stable(feature = "rust1", since = "1.0.0")]
impl ops::Index<ops::RangeFull> for OsString {
type Output = OsStr;
}
}
+#[cfg(not(stage0))]
+#[stable(feature = "rust1", since = "1.0.0")]
+impl ops::Index<ops::RangeFull> for OsString {
+ type Output = OsStr;
+
+ #[inline]
+ fn index(&self, _index: ops::RangeFull) -> &OsStr {
+ unsafe { mem::transmute(self.inner.as_slice()) }
+ }
+}
+
#[stable(feature = "rust1", since = "1.0.0")]
impl ops::Deref for OsString {
type Target = 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<OsStr> for OsStr {
+ fn as_ref(&self) -> &OsStr {
+ self
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRef<OsStr> for OsString {
+ fn as_ref(&self) -> &OsStr {
+ self
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRef<OsStr> for str {
+ fn as_ref(&self) -> &OsStr {
+ OsStr::from_str(self)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRef<OsStr> 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 {
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;
/// 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<P: AsPath>(path: P) -> io::Result<File> {
+ pub fn open<P: AsRef<Path>>(path: P) -> io::Result<File> {
OpenOptions::new().read(true).open(path)
}
///
/// See the `OpenOptions::open` function for more details.
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn create<P: AsPath>(path: P) -> io::Result<File> {
+ pub fn create<P: AsRef<Path>>(path: P) -> io::Result<File> {
OpenOptions::new().write(true).create(true).truncate(true).open(path)
}
/// permissions for
/// * Filesystem-level errors (full disk, etc)
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn open<P: AsPath>(&self, path: P) -> io::Result<File> {
- let path = path.as_path();
+ pub fn open<P: AsRef<Path>>(&self, path: P) -> io::Result<File> {
+ let path = path.as_ref();
let inner = try!(fs_imp::File::open(path, &self.0));
Ok(File { path: path.to_path_buf(), inner: inner })
}
/// 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<P: AsPath>(path: P) -> io::Result<()> {
- fs_imp::unlink(path.as_path())
+pub fn remove_file<P: AsRef<Path>>(path: P) -> io::Result<()> {
+ fs_imp::unlink(path.as_ref())
}
/// Given a path, query the file system to get information about a file,
/// 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<P: AsPath>(path: P) -> io::Result<Metadata> {
- fs_imp::stat(path.as_path()).map(Metadata)
+pub fn metadata<P: AsRef<Path>>(path: P) -> io::Result<Metadata> {
+ fs_imp::stat(path.as_ref()).map(Metadata)
}
/// Rename a file or directory to a new name.
/// reside on separate filesystems, or if some other intermittent I/O error
/// occurs.
#[stable(feature = "rust1", since = "1.0.0")]
-pub fn rename<P: AsPath, Q: AsPath>(from: P, to: Q) -> io::Result<()> {
- fs_imp::rename(from.as_path(), to.as_path())
+pub fn rename<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<()> {
+ fs_imp::rename(from.as_ref(), to.as_ref())
}
/// Copies the contents of one file to another. This function will also
/// * 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<P: AsPath, Q: AsPath>(from: P, to: Q) -> io::Result<u64> {
- let from = from.as_path();
- let to = to.as_path();
+pub fn copy<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<u64> {
+ 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",
/// 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<P: AsPath, Q: AsPath>(src: P, dst: Q) -> io::Result<()> {
- fs_imp::link(src.as_path(), dst.as_path())
+pub fn hard_link<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()> {
+ fs_imp::link(src.as_ref(), dst.as_ref())
}
/// Creates a new 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<P: AsPath, Q: AsPath>(src: P, dst: Q) -> io::Result<()> {
- fs_imp::symlink(src.as_path(), dst.as_path())
+pub fn soft_link<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()> {
+ fs_imp::symlink(src.as_ref(), dst.as_ref())
}
/// Reads a soft link, returning the file that the link points to.
/// 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<P: AsPath>(path: P) -> io::Result<PathBuf> {
- fs_imp::readlink(path.as_path())
+pub fn read_link<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> {
+ fs_imp::readlink(path.as_ref())
}
/// Create a new, empty directory at the provided path
/// 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<P: AsPath>(path: P) -> io::Result<()> {
- fs_imp::mkdir(path.as_path())
+pub fn create_dir<P: AsRef<Path>>(path: P) -> io::Result<()> {
+ fs_imp::mkdir(path.as_ref())
}
/// Recursively create a directory and all of its parent components if they
/// 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<P: AsPath>(path: P) -> io::Result<()> {
- let path = path.as_path();
+pub fn create_dir_all<P: AsRef<Path>>(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)
/// 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<P: AsPath>(path: P) -> io::Result<()> {
- fs_imp::rmdir(path.as_path())
+pub fn remove_dir<P: AsRef<Path>>(path: P) -> io::Result<()> {
+ fs_imp::rmdir(path.as_ref())
}
/// Removes a directory at this path, after removing all its contents. Use
///
/// See `file::remove_file` and `fs::remove_dir`
#[stable(feature = "rust1", since = "1.0.0")]
-pub fn remove_dir_all<P: AsPath>(path: P) -> io::Result<()> {
- let path = path.as_path();
+pub fn remove_dir_all<P: AsRef<Path>>(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));
/// 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<P: AsPath>(path: P) -> io::Result<ReadDir> {
- fs_imp::readdir(path.as_path()).map(ReadDir)
+pub fn read_dir<P: AsRef<Path>>(path: P) -> io::Result<ReadDir> {
+ fs_imp::readdir(path.as_ref()).map(ReadDir)
}
/// Returns an iterator that will recursively walk the directory structure
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<P: AsPath>(path: P) -> io::Result<WalkDir> {
+pub fn walk_dir<P: AsRef<Path>>(path: P) -> io::Result<WalkDir> {
let start = try!(read_dir(path));
Ok(WalkDir { cur: Some(start), stack: Vec::new() })
}
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<P: AsPath>(path: P, accessed: u64,
+pub fn set_file_times<P: AsRef<Path>>(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.
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<P: AsPath>(path: P, perm: Permissions) -> io::Result<()> {
- fs_imp::set_perm(path.as_path(), perm.0)
+pub fn set_permissions<P: AsRef<Path>>(path: P, perm: Permissions) -> io::Result<()> {
+ fs_imp::set_perm(path.as_ref(), perm.0)
}
#[cfg(test)]
use prelude::v1::*;
use io::prelude::*;
+ use env;
use fs::{self, File, OpenOptions};
use io::{ErrorKind, SeekFrom};
use path::PathBuf;
}
pub fn tmpdir() -> TempDir {
- let s = os::tmpdir();
- let p = Path2::new(s.as_str().unwrap());
+ let p = env::temp_dir();
let ret = p.join(&format!("rust-{}", rand::random::<u32>()));
check!(fs::create_dir(&ret));
TempDir(ret)
let dir = &tmpdir.join("di_readdir");
check!(fs::create_dir(dir));
let prefix = "foo";
- for n in range(0, 3) {
+ for n in 0..3 {
let f = dir.join(&format!("{}.txt", n));
let mut w = check!(File::create(&f));
let msg_str = format!("{}{}", prefix, n.to_string());
#[test]
fn binary_file() {
let mut bytes = [0; 1024];
- StdRng::new().ok().unwrap().fill_bytes(&mut bytes);
+ StdRng::new().unwrap().fill_bytes(&mut bytes);
let tmpdir = tmpdir();
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
///
/// If no directory can be created, `Err` is returned.
#[allow(deprecated)] // rand usage
- pub fn new_in<P: AsPath + ?Sized>(tmpdir: &P, prefix: &str)
- -> io::Result<TempDir> {
+ pub fn new_in<P: AsRef<path::Path>>(tmpdir: P, prefix: &str) -> io::Result<TempDir> {
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);
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<W> error::Error for IntoInnerError<W> {
+impl<W: Send + fmt::Debug> error::Error for IntoInnerError<W> {
fn description(&self) -> &str {
error::Error::description(self.error())
}
fn read_to_end() {
let mut reader = Cursor::new(vec!(0, 1, 2, 3, 4, 5, 6, 7));
let mut v = Vec::new();
- reader.read_to_end(&mut v).ok().unwrap();
+ reader.read_to_end(&mut v).unwrap();
assert_eq!(v, [0, 1, 2, 3, 4, 5, 6, 7]);
}
#![stable(feature = "rust1", since = "1.0.0")]
-pub use super::{Read, Write, BufRead};
+pub use super::{Read, Write, BufRead, Seek};
pub use fs::PathExt;
-
-// FIXME: pub use as `Seek` when the name isn't in the actual prelude any more
-pub use super::Seek as NewSeek;
#![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.
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;
/* 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;
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!
unique_local: bool, global: bool,
u_link_local: bool, u_site_local: bool, u_global: bool,
m_scope: Option<Ipv6MulticastScope>) {
- let ip: Ipv6Addr = str_addr.parse().ok().unwrap();
+ let ip: Ipv6Addr = str_addr.parse().unwrap();
assert_eq!(str_addr, ip.to_string());
assert_eq!(ip.is_unspecified(), unspec);
.iter()
.map(|&seg| format!("{:x}", seg))
.collect::<Vec<String>>()
- .as_slice()
.connect(":")
}
#![test]
assert_eq!((0 as $T).next_power_of_two(), 1);
let mut next_power = 1;
- for i in range::<$T>(1, 40) {
+ for i in 1 as $T..40 {
assert_eq!(i.next_power_of_two(), next_power);
if i == next_power { next_power *= 2 }
}
assert_eq!(($T::MAX - 1).checked_next_power_of_two(), None);
assert_eq!($T::MAX.checked_next_power_of_two(), None);
let mut next_power = 1;
- for i in range::<$T>(1, 40) {
+ for i in 1 as $T..40 {
assert_eq!(i.checked_next_power_of_two(), Some(next_power));
if i == next_power { next_power *= 2 }
}
/// # Examples
///
/// ```
-/// use std::old_io::{BufferedReader, File};
+/// use std::old_io::*;
+/// use std::old_path::Path;
///
/// let file = File::open(&Path::new("message.txt"));
/// let mut reader = BufferedReader::new(file);
/// # Examples
///
/// ```
-/// use std::old_io::{BufferedWriter, File};
+/// use std::old_io::*;
+/// use std::old_path::Path;
///
/// let file = File::create(&Path::new("message.txt")).unwrap();
/// let mut writer = BufferedWriter::new(file);
///
/// ```
/// # #![allow(unused_must_use)]
-/// use std::old_io::{BufferedStream, File};
+/// use std::old_io::*;
+/// use std::old_path::Path;
///
/// let file = File::open(&Path::new("message.txt"));
/// let mut stream = BufferedStream::new(file);
#[cfg(test)]
mod test {
extern crate test;
- use old_io;
+ use old_io::{self, Reader, Writer, Buffer, BufferPrelude};
use prelude::v1::*;
use super::*;
use super::super::{IoResult, EndOfFile};
///
/// ```
/// use std::sync::mpsc::channel;
-/// use std::old_io::ChanReader;
+/// use std::old_io::*;
///
/// let (tx, rx) = channel();
/// # drop(tx);
/// ```
/// # #![allow(unused_must_use)]
/// use std::sync::mpsc::channel;
-/// use std::old_io::ChanWriter;
+/// use std::old_io::*;
///
/// let (tx, rx) = channel();
/// # drop(rx);
use sync::mpsc::channel;
use super::*;
- use old_io;
+ use old_io::{self, Reader, Writer, Buffer};
use thread;
#[test]
#[cfg(test)]
mod test {
use prelude::v1::*;
- use old_io;
+ use old_io::{self, Reader, Writer};
use old_io::{MemReader, BytesReader};
struct InitialZeroByteReader {
//! ```rust
//! # #![allow(unused_must_use)]
//! use std::old_io::fs::PathExtensions;
-//! use std::old_io::{File, fs};
+//! use std::old_io::*;
+//! use std::old_path::Path;
//!
//! let path = Path::new("foo.txt");
//!
/// # Examples
///
/// ```rust,should_fail
- /// use std::old_io::{File, Open, ReadWrite};
+ /// use std::old_io::*;
+ /// use std::old_path::Path;
///
/// let p = Path::new("/some/file/path.txt");
///
/// # Examples
///
/// ```
- /// use std::old_io::File;
+ /// use std::old_io::*;
+ /// use std::old_path::Path;
///
/// let contents = File::open(&Path::new("foo.txt")).read_to_end();
/// ```
///
/// ```
/// # #![allow(unused_must_use)]
- /// use std::old_io::File;
+ /// use std::old_io::*;
+ /// use std::old_path::Path;
///
/// let mut f = File::create(&Path::new("foo.txt"));
/// f.write(b"This is a sample file");
///
/// ```
/// # #![allow(unused_must_use)]
-/// use std::old_io::fs;
+/// use std::old_io::*;
+/// use std::old_path::Path;
///
/// let p = Path::new("/some/file/path.txt");
/// fs::unlink(&p);
/// # Examples
///
/// ```
-/// use std::old_io::fs;
+/// use std::old_io::*;
+/// use std::old_path::Path;
///
/// let p = Path::new("/some/file/path.txt");
/// match fs::stat(&p) {
///
/// ```
/// # #![allow(unused_must_use)]
-/// use std::old_io::fs;
+/// use std::old_io::*;
+/// use std::old_path::Path;
///
/// fs::rename(&Path::new("foo"), &Path::new("bar"));
/// ```
///
/// ```
/// # #![allow(unused_must_use)]
-/// use std::old_io::fs;
+/// use std::old_io::*;
+/// use std::old_path::Path;
///
/// fs::copy(&Path::new("foo.txt"), &Path::new("bar.txt"));
/// ```
/// ```
/// # #![allow(unused_must_use)]
/// use std::old_io;
-/// use std::old_io::fs;
+/// use std::old_io::*;
+/// use std::old_path::Path;
///
/// fs::chmod(&Path::new("file.txt"), old_io::USER_FILE);
/// fs::chmod(&Path::new("file.txt"), old_io::USER_READ | old_io::USER_WRITE);
/// ```
/// # #![allow(unused_must_use)]
/// use std::old_io;
-/// use std::old_io::fs;
+/// use std::old_io::*;
+/// use std::old_path::Path;
///
/// let p = Path::new("/some/dir");
/// fs::mkdir(&p, old_io::USER_RWX);
///
/// ```
/// # #![allow(unused_must_use)]
-/// use std::old_io::fs;
+/// use std::old_io::*;
+/// use std::old_path::Path;
///
/// let p = Path::new("/some/dir");
/// fs::rmdir(&p);
///
/// ```
/// use std::old_io::fs::PathExtensions;
-/// use std::old_io::fs;
/// use std::old_io;
+/// use std::old_io::*;
+/// use std::old_path::Path;
///
/// // one possible implementation of fs::walk_dir only visiting files
/// fn visit_dirs<F>(dir: &Path, cb: &mut F) -> old_io::IoResult<()> where
mod test {
use prelude::v1::*;
use old_io::{SeekSet, SeekCur, SeekEnd, Read, Open, ReadWrite, FileType};
- use old_io;
+ use old_io::{self, Reader, Writer, Seek};
+ use old_path::{Path, GenericPath};
use str;
use old_io::fs::*;
use rand::{StdRng, Rng};
let mut bytes = [0; 1024];
- StdRng::new().ok().unwrap().fill_bytes(&mut bytes);
+ StdRng::new().unwrap().fill_bytes(&mut bytes);
let tmpdir = tmpdir();
///
/// ```
/// # #![allow(unused_must_use)]
-/// use std::old_io::MemWriter;
+/// use std::old_io::*;
///
/// let mut w = MemWriter::new();
/// w.write(&[0, 1, 2]);
///
/// ```
/// # #![allow(unused_must_use)]
-/// use std::old_io::MemReader;
+/// use std::old_io::*;
///
/// let mut r = MemReader::new(vec!(0, 1, 2));
///
///
/// ```
/// # #![allow(unused_must_use)]
-/// use std::old_io::BufWriter;
+/// use std::old_io::*;
///
/// let mut buf = [0; 4];
/// {
///
/// ```
/// # #![allow(unused_must_use)]
-/// use std::old_io::BufReader;
+/// use std::old_io::*;
///
/// let buf = [0, 1, 2, 3];
/// let mut r = BufReader::new(&buf);
#[cfg(test)]
mod test {
extern crate "test" as test_crate;
- use old_io::{SeekSet, SeekCur, SeekEnd, Reader, Writer, Seek};
- use prelude::v1::{Ok, Err, range, Vec, Buffer, AsSlice};
+ use old_io::{SeekSet, SeekCur, SeekEnd, Reader, Writer, Seek, Buffer};
+ use prelude::v1::{Ok, Err, Vec, AsSlice};
use prelude::v1::IteratorExt;
use old_io;
use iter::repeat;
//!
//! ```rust
//! use std::old_io as io;
+//! use std::old_io::*;
//!
//! let mut stdin = io::stdin();
//! for line in stdin.lock().lines() {
//! * Read a complete file
//!
//! ```rust
-//! use std::old_io::File;
+//! use std::old_io::*;
+//! use std::old_path::Path;
//!
//! let contents = File::open(&Path::new("message.txt")).read_to_end();
//! ```
//!
//! ```rust
//! # #![allow(unused_must_use)]
-//! use std::old_io::File;
+//! use std::old_io::*;
+//! use std::old_path::Path;
//!
//! let mut file = File::create(&Path::new("message.txt"));
//! file.write_all(b"hello, file!\n");
//! * Iterate over the lines of a file
//!
//! ```rust,no_run
-//! use std::old_io::BufferedReader;
-//! use std::old_io::File;
+//! use std::old_io::*;
+//! use std::old_path::Path;
//!
//! let path = Path::new("message.txt");
//! let mut file = BufferedReader::new(File::open(&path));
//! * Pull the lines of a file into a vector of strings
//!
//! ```rust,no_run
-//! use std::old_io::BufferedReader;
-//! use std::old_io::File;
+//! use std::old_io::*;
+//! use std::old_path::Path;
//!
//! let path = Path::new("message.txt");
//! let mut file = BufferedReader::new(File::open(&path));
//!
//! ```rust
//! # #![allow(unused_must_use)]
-//! use std::old_io::TcpStream;
+//! use std::old_io::*;
//!
//! # // connection doesn't fail if a server is running on 8080
//! # // locally, we still want to be type checking this code, so lets
//! # fn main() { }
//! # fn foo() {
//! # #![allow(dead_code)]
-//! use std::old_io::{TcpListener, TcpStream};
-//! use std::old_io::{Acceptor, Listener};
+//! use std::old_io::*;
//! use std::thread;
//!
//! let listener = TcpListener::bind("127.0.0.1:80");
//!
//! ```rust
//! # #![allow(unused_must_use)]
-//! use std::old_io::File;
+//! use std::old_io::*;
+//! use std::old_path::Path;
//!
//! match File::create(&Path::new("diary.txt")).write_all(b"Met a girl.\n") {
//! Ok(()) => (), // succeeded
//! If you wanted to read several `u32`s from a file and return their product:
//!
//! ```rust
-//! use std::old_io::{File, IoResult};
+//! use std::old_io::*;
+//! use std::old_path::Path;
//!
//! fn file_product(p: &Path) -> IoResult<u32> {
//! let mut f = File::open(p);
///
/// ```
/// use std::old_io as io;
-/// use std::old_io::ByRefReader;
+/// use std::old_io::*;
/// use std::old_io::util::LimitReader;
///
/// fn process_input<R: Reader>(r: R) {}
///
/// ```
/// use std::old_io::util::TeeReader;
-/// use std::old_io::{stdin, ByRefWriter};
+/// use std::old_io::*;
///
/// fn process_input<R: Reader>(r: R) {}
///
/// # Examples
///
/// ```
- /// use std::old_io::BufReader;
+ /// use std::old_io::*;
///
/// let mut reader = BufReader::new(b"hello\nworld");
/// assert_eq!("hello\n", &*reader.read_line().unwrap());
/// ```no_run
///
/// use std::old_io::fs::PathExtensions;
+/// use std::old_path::Path;
///
/// let info = match Path::new("foo.txt").stat() {
/// Ok(stat) => stat,
mod tests {
use self::BadReaderBehavior::*;
use super::{IoResult, Reader, MemReader, NoProgress, InvalidInput, Writer};
- use prelude::v1::{Ok, Vec, Buffer};
+ use super::Buffer;
+ use prelude::v1::{Ok, Vec};
use usize;
#[derive(Clone, PartialEq, Debug)]
use ffi::CString;
use old_path::BytesContainer;
use old_io::{Listener, Acceptor, IoResult, TimedOut, standard_error};
+use old_io::{Reader, Writer};
use sys::pipe::UnixAcceptor as UnixAcceptorImp;
use sys::pipe::UnixListener as UnixListenerImp;
use sys::pipe::UnixStream as UnixStreamImp;
/// ```
/// # #![allow(unused_must_use)]
/// use std::old_io::net::pipe::UnixStream;
+ /// use std::old_io::*;
+ /// use std::old_path::Path;
///
/// let server = Path::new("path/to/my/socket");
/// let mut stream = UnixStream::connect(&server);
/// ```
/// # fn foo() {
/// use std::old_io::net::pipe::UnixListener;
- /// use std::old_io::{Listener, Acceptor};
+ /// use std::old_io::*;
+ /// use std::old_path::Path;
///
/// let server = Path::new("/path/to/my/socket");
/// let stream = UnixListener::bind(&server);
use old_io::{EndOfFile, TimedOut, ShortWrite, IoError, ConnectionReset};
use old_io::{NotConnected, BrokenPipe, FileNotFound, InvalidInput, OtherIoError};
use old_io::{PermissionDenied, Acceptor, Listener};
+ use old_io::{Reader, Writer};
use old_io::test::*;
use super::*;
use sync::mpsc::channel;
/// # Examples
///
/// ```no_run
-/// use std::old_io::TcpStream;
+/// use std::old_io::*;
///
/// {
/// let mut stream = TcpStream::connect("127.0.0.1:34254");
///
/// ```no_run
/// # #![allow(unused_must_use)]
- /// use std::old_io::timer;
- /// use std::old_io::TcpStream;
+ /// use std::old_io::*;
/// use std::time::Duration;
/// use std::thread;
///
///
/// ```
/// # fn foo() {
-/// use std::old_io::{TcpListener, TcpStream};
-/// use std::old_io::{Acceptor, Listener};
+/// use std::old_io::*;
/// use std::thread;
///
/// let listener = TcpListener::bind("127.0.0.1:80").unwrap();
/// # Examples
///
/// ```no_run
- /// use std::old_io::TcpListener;
- /// use std::old_io::{Listener, Acceptor, TimedOut};
+ /// use std::old_io::*;
///
/// let mut a = TcpListener::bind("127.0.0.1:8482").listen().unwrap();
///
/// # Examples
///
/// ```
- /// use std::old_io::{TcpListener, Listener, Acceptor, EndOfFile};
+ /// use std::old_io::*;
/// use std::thread;
///
/// let mut a = TcpListener::bind("127.0.0.1:8482").listen().unwrap();
use old_io::{ConnectionReset, NotConnected, PermissionDenied, OtherIoError};
use old_io::{InvalidInput};
use old_io::{Acceptor, Listener};
+ use old_io::{Reader, Writer};
// FIXME #11530 this fails on android because tests are run as root
#[cfg_attr(any(windows, target_os = "android"), ignore)]
use prelude::v1::*;
-use old_io::IoResult;
+use old_io::{IoResult, Reader, Writer};
use libc;
use sync::Arc;
/// # #![allow(unused_must_use)]
/// extern crate libc;
///
- /// use std::old_io::pipe::PipeStream;
+ /// use std::old_io::*;
///
/// fn main() {
/// let mut pipe = PipeStream::open(libc::STDERR_FILENO);
mod test {
use prelude::v1::*;
+ use old_io::{Writer, Reader};
use sync::mpsc::channel;
use thread;
use ffi::CString;
use fmt;
use old_io::pipe::{PipeStream, PipePair};
-use old_io::{IoResult, IoError};
+use old_io::{IoResult, IoError, Reader, Writer};
use old_io;
+use old_path::{Path, GenericPath};
use libc;
use os;
use old_path::BytesContainer;
/// # Examples
///
/// ```should_fail
-/// use std::old_io::Command;
+/// use std::old_io::*;
///
/// let mut child = match Command::new("/bin/cat").arg("file.txt").spawn() {
/// Ok(child) => child,
/// to be changed (for example, by adding arguments) prior to spawning:
///
/// ```
-/// use std::old_io::Command;
+/// use std::old_io::*;
///
/// let mut process = match Command::new("sh").arg("-c").arg("echo hello").spawn() {
/// Ok(p) => p,
#[cfg(test)]
mod tests {
use old_io::{Truncate, Write, TimedOut, timer, process, FileNotFound};
- use prelude::v1::{Ok, Err, range, drop, Some, None, Vec};
- use prelude::v1::{Path, String, Reader, Writer, Clone};
- use prelude::v1::{Str, AsSlice, ToString, GenericPath};
+ use old_io::{Reader, Writer};
+ use prelude::v1::{Ok, Err, drop, Some, None, Vec};
+ use prelude::v1::{String, Clone};
+ use prelude::v1::{Str, AsSlice, ToString};
+ use old_path::{GenericPath, Path};
use old_io::fs::PathExtensions;
use old_io::timer::*;
use rt::running_on_valgrind;
mod test {
use prelude::v1::*;
use super::super::mem::*;
- use old_io;
+ use old_io::{self, Reader, Writer};
#[test]
fn test_option_writer() {
//! ```rust
//! # #![allow(unused_must_use)]
//! use std::old_io;
+//! use std::old_io::*;
//!
//! let mut out = old_io::stdout();
//! out.write_all(b"Hello, world!");
///
/// ```
/// use std::old_io;
+ /// use std::old_io::*;
///
/// let mut stdin = old_io::stdin();
/// for line in stdin.lock().lines() {
/// # Examples
///
/// ```no_run
-/// use std::old_io::TempDir;
+/// use std::old_io::*;
+/// use std::old_path::{Path, GenericPath};
///
/// {
/// // create a temporary directory
use env;
use libc;
-use std::old_io::net::ip::*;
+use old_io::net::ip::*;
+use old_path::{Path, GenericPath};
use sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
/// Get a port number, starting at 9600, for use in tests
use prelude::v1::*;
use cmp;
-use old_io;
+use old_io::{self, Reader, Writer, Buffer};
use slice::bytes::MutableByteVector;
/// Wraps a `Reader`, limiting the number of bytes that can be read from it.
mod test {
use prelude::v1::*;
- use old_io::{MemReader, ByRefReader};
+ use old_io::{MemReader, ByRefReader, Reader, Writer, Buffer};
use old_io;
use super::*;
//!
//! ```rust
//! use std::old_io::fs::PathExtensions;
+//! use std::old_path::{Path, GenericPath};
//!
//! let mut path = Path::new("/tmp/path");
//! println!("path: {}", path.display());
/// # Examples
///
/// ```
+ /// use std::old_path::{Path, GenericPath};
/// # foo();
/// # #[cfg(windows)] fn foo() {}
/// # #[cfg(unix)] fn foo() {
/// # Examples
///
/// ```
+ /// use std::old_path::{Path, GenericPath};
/// # foo();
/// # #[cfg(windows)] fn foo() {}
/// # #[cfg(unix)] fn foo() {
/// # Examples
///
/// ```
+ /// use std::old_path::{Path, GenericPath};
/// # foo();
/// # #[cfg(windows)] fn foo() {}
/// # #[cfg(unix)] fn foo() {
/// # Examples
///
/// ```
+ /// use std::old_path::{Path, GenericPath};
/// # foo();
/// # #[cfg(windows)] fn foo() {}
/// # #[cfg(unix)] fn foo() {
/// # Examples
///
/// ```
+ /// use std::old_path::{Path, GenericPath};
/// # foo();
/// # #[cfg(windows)] fn foo() {}
/// # #[cfg(unix)] fn foo() {
/// # Examples
///
/// ```
+ /// use std::old_path::{Path, GenericPath};
/// # foo();
/// # #[cfg(windows)] fn foo() {}
/// # #[cfg(unix)] fn foo() {
/// # Examples
///
/// ```
+ /// use std::old_path::{Path, GenericPath};
/// # foo();
/// # #[cfg(windows)] fn foo() {}
/// # #[cfg(unix)] fn foo() {
/// # Examples
///
/// ```
+ /// use std::old_path::{Path, GenericPath};
/// # foo();
/// # #[cfg(windows)] fn foo() {}
/// # #[cfg(unix)] fn foo() {
/// # Examples
///
/// ```
+ /// use std::old_path::{Path, GenericPath};
/// # foo();
/// # #[cfg(windows)] fn foo() {}
/// # #[cfg(unix)] fn foo() {
/// # Examples
///
/// ```
+ /// use std::old_path::{Path, GenericPath};
/// # foo();
/// # #[cfg(windows)] fn foo() {}
/// # #[cfg(unix)] fn foo() {
/// # Examples
///
/// ```
+ /// use std::old_path::{Path, GenericPath};
/// # foo();
/// # #[cfg(windows)] fn foo() {}
/// # #[cfg(unix)] fn foo() {
/// # Examples
///
/// ```
+ /// use std::old_path::{Path, GenericPath};
/// # foo();
/// # #[cfg(windows)] fn foo() {}
/// # #[cfg(unix)] fn foo() {
/// # Examples
///
/// ```
+ /// use std::old_path::{Path, GenericPath};
/// # foo();
/// # #[cfg(windows)] fn foo() {}
/// # #[cfg(unix)] fn foo() {
/// # Examples
///
/// ```
+ /// use std::old_path::{Path, GenericPath};
/// # foo();
/// # #[cfg(windows)] fn foo() {}
/// # #[cfg(unix)] fn foo() {
/// # Examples
///
/// ```
+ /// use std::old_path::{Path, GenericPath};
/// # foo();
/// # #[cfg(windows)] fn foo() {}
/// # #[cfg(unix)] fn foo() {
/// # Examples
///
/// ```
+ /// use std::old_path::{Path, GenericPath};
/// # foo();
/// # #[cfg(windows)] fn foo() {}
/// # #[cfg(unix)] fn foo() {
/// # Examples
///
/// ```
+ /// use std::old_path::{Path, GenericPath};
/// # foo();
/// # #[cfg(windows)] fn foo() {}
/// # #[cfg(unix)] fn foo() {
/// # Examples
///
/// ```
+ /// use std::old_path::{Path, GenericPath};
/// # foo();
/// # #[cfg(windows)] fn foo() {}
/// # #[cfg(unix)] fn foo() {
/// # Examples
///
/// ```
+ /// use std::old_path::{Path, GenericPath};
/// # foo();
/// # #[cfg(windows)] fn foo() {}
/// # #[cfg(unix)] fn foo() {
/// # Examples
///
/// ```
+ /// use std::old_path::{Path, GenericPath};
/// # foo();
/// # #[cfg(windows)] fn foo() {}
/// # #[cfg(unix)] fn foo() {
/// # Examples
///
/// ```
+ /// use std::old_path::{Path, GenericPath};
/// # foo();
/// # #[cfg(windows)] fn foo() {}
/// # #[cfg(unix)] fn foo() {
/// # Examples
///
/// ```
+ /// use std::old_path::{Path, GenericPath};
/// # foo();
/// # #[cfg(windows)] fn foo() {}
/// # #[cfg(unix)] fn foo() {
/// # Examples
///
/// ```
+ /// use std::old_path::{Path, GenericPath};
/// # foo();
/// # #[cfg(windows)] fn foo() {}
/// # #[cfg(unix)] fn foo() {
/// # Examples
///
/// ```
+ /// use std::old_path::{Path, GenericPath};
/// # foo();
/// # #[cfg(windows)] fn foo() {}
/// # #[cfg(unix)] fn foo() {
/// # Examples
///
/// ```
+ /// use std::old_path::{Path, GenericPath};
/// # foo();
/// # #[cfg(windows)] fn foo() {}
/// # #[cfg(unix)] fn foo() {
/// # Examples
///
/// ```
+ /// use std::old_path::{Path, GenericPath};
/// # foo();
/// # #[cfg(windows)] fn foo() {}
/// # #[cfg(unix)] fn foo() {
/// # Examples
///
/// ```
+ /// use std::old_path::{Path, GenericPath};
/// # foo();
/// # #[cfg(windows)] fn foo() {}
/// # #[cfg(unix)] fn foo() {
/// # Examples
///
/// ```
+ /// use std::old_path::{Path, GenericPath};
/// # foo();
/// # #[cfg(windows)] fn foo() {}
/// # #[cfg(unix)] fn foo() {
/// # Examples
///
/// ```
+ /// use std::old_path::{Path, GenericPath};
/// # foo();
/// # #[cfg(windows)] fn foo() {}
/// # #[cfg(unix)] fn foo() {
/// # Examples
///
/// ```
+ /// use std::old_path::{Path, GenericPath};
/// # foo();
/// # #[cfg(windows)] fn foo() {}
/// # #[cfg(unix)] fn foo() {
/// # Examples
///
/// ```
+ /// use std::old_path::{Path, GenericPath};
/// # foo();
/// # #[cfg(windows)] fn foo() {}
/// # #[cfg(unix)] fn foo() {
extern crate test;
use self::test::Bencher;
use super::*;
- use prelude::v1::{Clone, GenericPath};
+ use old_path::GenericPath;
+ use prelude::v1::Clone;
#[bench]
fn join_home_dir(b: &mut Bencher) {
/// # Examples
///
/// ```
+ /// use std::old_path::{Path, GenericPath};
/// println!("{}", Path::new(r"C:\some\path").display());
/// ```
#[inline]
/// # Examples
///
/// ```
+ /// use std::old_path::{Path, GenericPath};
/// let path = Path::new_opt(r"C:\some\path");
///
/// match path {
use boxed::Box;
use clone::Clone;
+use convert::From;
use env;
use error::{FromError, Error};
use ffi::{OsString, OsStr};
#[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(<OsStr as OsStrExt>::from_bytes(path.as_vec()))
+ PathBuf::from(<OsStr as OsStrExt>::from_bytes(path.as_vec()))
}
#[cfg(unix)]
///
/// ```
/// use std::os;
+/// use std::old_path::{Path, GenericPath};
///
/// // We assume that we are in a valid directory.
/// let current_working_directory = os::getcwd().unwrap();
///
/// ```
/// use std::os;
+/// use std::old_path::{Path, GenericPath};
///
/// let key = "PATH";
/// match os::getenv_as_bytes(key) {
///
/// ```
/// use std::os;
+/// use std::old_path::{Path, GenericPath};
///
/// match os::self_exe_name() {
/// Some(exe_path) => println!("Path of this executable is: {}", exe_path.display()),
///
/// ```
/// use std::os;
+/// use std::old_path::{Path, GenericPath};
///
/// match os::self_exe_path() {
/// Some(exe_path) => println!("Executable's Path is: {}", exe_path.display()),
///
/// ```
/// use std::os;
+/// use std::old_path::{Path, GenericPath};
///
/// match os::homedir() {
/// Some(ref p) => println!("{}", p.display()),
///
/// ```
/// use std::os;
-/// use std::old_path::Path;
+/// use std::old_path::{Path, GenericPath};
///
/// // Assume we're in a path like /home/someuser
/// let rel_path = Path::new("..");
///
/// ```
/// use std::os;
-/// use std::old_path::Path;
+/// use std::old_path::{Path, GenericPath};
///
/// let root = Path::new("/");
/// assert!(os::change_dir(&root).is_ok());
use os;
use rand::Rng;
use rand;
+ use old_path::{Path, GenericPath};
+ use old_io::{Reader, Writer, Seek};
#[test]
pub fn last_os_error() {
use iter::{self, IntoIterator};
use mem;
use ops::{self, Deref};
+use string::String;
use vec::Vec;
use fmt;
}
}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a> AsRef<OsStr> 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
}
/// 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(); }
}
}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a> AsRef<Path> for Components<'a> {
+ fn as_ref(&self) -> &Path {
+ self.as_path()
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a> AsRef<OsStr> 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")]
}
}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a> AsRef<Path> for Iter<'a> {
+ fn as_ref(&self) -> &Path {
+ self.as_path()
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a> AsRef<OsStr> 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;
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: AsOsStr>(s: S) -> PathBuf {
- PathBuf { inner: s.as_os_str().to_os_string() }
+ pub fn new() -> PathBuf {
+ PathBuf { inner: OsString::new() }
}
/// Extend `self` with `path`.
/// 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<P: AsPath>(&mut self, path: P) {
- let path = path.as_path();
+ pub fn push<P: AsRef<Path>>(&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);
/// assert!(buf == PathBuf::new("/baz.txt"));
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn set_file_name<S: AsOsStr>(&mut self, file_name: S) {
+ pub fn set_file_name<S: AsRef<OsStr>>(&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`.
/// 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<S: AsOsStr>(&mut self, extension: S) -> bool {
+ pub fn set_extension<S: AsRef<OsStr>>(&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);
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<P: AsPath> iter::FromIterator<P> 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<String> 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<OsString> for PathBuf {
+ fn from(s: OsString) -> PathBuf {
+ PathBuf { inner: s }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<P: AsRef<Path>> iter::FromIterator<P> for PathBuf {
fn from_iter<I: IntoIterator<Item = P>>(iter: I) -> PathBuf {
- let mut buf = PathBuf::new("");
+ let mut buf = PathBuf::new();
buf.extend(iter);
buf
}
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<P: AsPath> iter::Extend<P> for PathBuf {
+impl<P: AsRef<Path>> iter::Extend<P> for PathBuf {
fn extend<I: IntoIterator<Item = P>>(&mut self, iter: I) {
for p in iter {
self.push(p)
}
#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRef<OsStr> 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<OsString> 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
///
/// This is a cost-free conversion.
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn new<S: ?Sized + AsOsStr>(s: &S) -> &Path {
- unsafe { mem::transmute(s.as_os_str()) }
+ pub fn new<S: AsRef<OsStr> + ?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.
/// 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.
}
/// Returns a path that, when joined onto `base`, yields `self`.
+ ///
+ /// If `base` is not a prefix of `self` (i.e. `starts_with`
+ /// returns false), then `relative_from` returns `None`.
#[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<Path>>(&'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<P: AsPath>(&self, base: P) -> bool {
- iter_after(self.components(), base.as_path().components()).is_some()
+ pub fn starts_with<P: AsRef<Path>>(&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<P: AsPath>(&self, child: P) -> bool {
- iter_after(self.components().rev(), child.as_path().components().rev()).is_some()
+ pub fn ends_with<P: AsRef<Path>>(&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()`.
///
/// See `PathBuf::push` for more details on what it means to adjoin a path.
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn join<P: AsPath>(&self, path: P) -> PathBuf {
+ pub fn join<P: AsRef<Path>>(&self, path: P) -> PathBuf {
let mut buf = self.to_path_buf();
buf.push(path);
buf
///
/// See `PathBuf::set_file_name` for more details.
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn with_file_name<S: AsOsStr>(&self, file_name: S) -> PathBuf {
+ pub fn with_file_name<S: AsRef<OsStr>>(&self, file_name: S) -> PathBuf {
let mut buf = self.to_path_buf();
buf.set_file_name(file_name);
buf
///
/// See `PathBuf::set_extension` for more details.
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn with_extension<S: AsOsStr>(&self, extension: S) -> PathBuf {
+ pub fn with_extension<S: AsRef<OsStr>>(&self, extension: S) -> PathBuf {
let mut buf = self.to_path_buf();
buf.set_extension(extension);
buf
}
#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRef<OsStr> for Path {
+ fn as_ref(&self) -> &OsStr {
+ &self.inner
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+#[deprecated(since = "1.0.0", reason = "trait is deprecated")]
impl AsOsStr for Path {
fn as_os_str(&self) -> &OsStr {
&self.inner
/// Freely convertible to a `Path`.
#[unstable(feature = "std_misc")]
+#[deprecated(since = "1.0.0", reason = "use std::convert::AsRef<Path> instead")]
pub trait AsPath {
/// Convert to a `Path`.
#[unstable(feature = "std_misc")]
}
#[unstable(feature = "std_misc")]
+#[deprecated(since = "1.0.0", reason = "use std::convert::AsRef<Path> instead")]
+#[allow(deprecated)]
impl<T: AsOsStr + ?Sized> AsPath for T {
fn as_path(&self) -> &Path { Path::new(self.as_os_str()) }
}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRef<Path> for Path {
+ fn as_ref(&self) -> &Path { self }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRef<Path> for OsStr {
+ fn as_ref(&self) -> &Path { Path::new(self) }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRef<Path> for OsString {
+ fn as_ref(&self) -> &Path { Path::new(self) }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRef<Path> for str {
+ fn as_ref(&self) -> &Path { Path::new(self) }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRef<Path> for String {
+ fn as_ref(&self) -> &Path { Path::new(self) }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRef<Path> for PathBuf {
+ fn as_ref(&self) -> &Path { self }
+}
+
#[cfg(test)]
mod tests {
use super::*;
#[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")]
#[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};
#[stable(feature = "rust1", since = "1.0.0")]
#[doc(no_inline)] pub use vec::Vec;
-// NB: remove when path reform lands
-#[doc(no_inline)] pub use old_path::{Path, GenericPath};
-// NB: remove when I/O reform lands
-#[doc(no_inline)] pub use old_io::{Buffer, Writer, Reader, Seek, BufferPrelude};
-// NB: remove when range syntax lands
-#[allow(deprecated)]
-#[doc(no_inline)] pub use iter::range;
-
+// FIXME(#23454) should these be here?
#[doc(no_inline)] pub use num::wrapping::{Wrapping, WrappingOps};
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;
/// Set the working directory for the child process.
#[stable(feature = "process", since = "1.0.0")]
- pub fn current_dir<P: AsPath>(&mut self, dir: P) -> &mut Command {
- self.inner.cwd(dir.as_path().as_os_str());
+ pub fn current_dir<P: AsRef<path::Path>>(&mut self, dir: P) -> &mut Command {
+ self.inner.cwd(dir.as_ref().as_os_str());
self
}
use io::prelude::*;
use prelude::v1::{Ok, Err, drop, Some, Vec};
use prelude::v1::{String, Clone};
- use prelude::v1::{Str, AsSlice, ToString, GenericPath};
- use old_path;
+ use prelude::v1::{Str, AsSlice, ToString};
+ use old_path::{self, GenericPath};
use old_io::fs::PathExtensions;
use rt::running_on_valgrind;
use str;
//
// ignore-lexer-test FIXME #15677
-use prelude::v1::*;
use io::prelude::*;
use env;
// asleep (we're looking at it), so the receiver
// can't go away.
(*a.get()).send(t).ok().unwrap();
- token.signal();
+ token.signal();
(a, Ok(()))
}
}
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T> error::Error for SendError<T> {
+impl<T: Send> error::Error for SendError<T> {
fn description(&self) -> &str {
"sending on a closed channel"
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T> error::Error for TrySendError<T> {
+impl<T: Send> error::Error for TrySendError<T> {
fn description(&self) -> &str {
match *self {
/// among threads to ensure that a possibly invalid invariant is not witnessed.
///
/// A poisoned mutex, however, does not prevent all access to the underlying
-/// data. The `PoisonError` type has an `into_guard` method which will return
+/// data. The `PoisonError` type has an `into_inner` method which will return
/// the guard that would have otherwise been returned on a successful lock. This
/// allows access to the data, despite the lock being poisoned.
///
/// // pattern matched on to return the underlying guard on both branches.
/// let mut guard = match lock.lock() {
/// Ok(guard) => guard,
-/// Err(poisoned) => poisoned.into_guard(),
+/// Err(poisoned) => poisoned.into_inner(),
/// };
///
/// *guard += 1;
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> fmt::Display for PoisonError<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- self.description().fmt(f)
+ "poisoned lock: another task failed inside".fmt(f)
}
}
-impl<T> Error for PoisonError<T> {
+impl<T: Send> Error for PoisonError<T> {
fn description(&self) -> &str {
"poisoned lock: another task failed inside"
}
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T> fmt::Display for TryLockError<T> {
+impl<T: Send> fmt::Display for TryLockError<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.description().fmt(f)
}
}
-impl<T> Error for TryLockError<T> {
+impl<T: Send> Error for TryLockError<T> {
fn description(&self) -> &str {
match *self {
TryLockError::Poisoned(ref p) => p.description(),
use cell::RefCell;
use string::String;
use thread::Thread;
-use thread_local::State;
+use thread::LocalKeyState;
struct ThreadInfo {
stack_guard: uint,
impl ThreadInfo {
fn with<R, F>(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");
}
///
/// 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<ops::Range<usize>> for Wtf8 {
type Output = 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<ops::Range<usize>> for Wtf8 {
+ type Output = Wtf8;
+
+ #[inline]
+ fn index(&self, range: ops::Range<usize>) -> &Wtf8 {
+ // is_code_point_boundary checks that the index is in [0, .len()]
+ if range.start <= range.end &&
+ is_code_point_boundary(self, range.start) &&
+ is_code_point_boundary(self, range.end) {
+ unsafe { slice_unchecked(self, range.start, range.end) }
+ } else {
+ slice_error_fail(self, range.start, range.end)
+ }
+ }
+}
+
/// 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<ops::RangeFrom<usize>> for Wtf8 {
type Output = 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<ops::RangeFrom<usize>> for Wtf8 {
+ type Output = Wtf8;
+
+ #[inline]
+ fn index(&self, range: ops::RangeFrom<usize>) -> &Wtf8 {
+ // is_code_point_boundary checks that the index is in [0, .len()]
+ if is_code_point_boundary(self, range.start) {
+ unsafe { slice_unchecked(self, range.start, self.len()) }
+ } else {
+ slice_error_fail(self, range.start, self.len())
+ }
+ }
+}
+
/// 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<ops::RangeTo<usize>> for Wtf8 {
type Output = 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<ops::RangeTo<usize>> for Wtf8 {
+ type Output = Wtf8;
+
+ #[inline]
+ fn index(&self, range: ops::RangeTo<usize>) -> &Wtf8 {
+ // is_code_point_boundary checks that the index is in [0, .len()]
+ if is_code_point_boundary(self, range.end) {
+ unsafe { slice_unchecked(self, 0, range.end) }
+ } else {
+ slice_error_fail(self, 0, range.end)
+ }
+ }
+}
+
+#[cfg(stage0)]
impl ops::Index<ops::RangeFull> for Wtf8 {
type Output = Wtf8;
}
}
+#[cfg(not(stage0))]
+impl ops::Index<ops::RangeFull> for Wtf8 {
+ type Output = Wtf8;
+
+ #[inline]
+ fn index(&self, _range: ops::RangeFull) -> &Wtf8 {
+ self
+ }
+}
+
#[inline]
fn decode_surrogate(second_byte: u8, third_byte: u8) -> u16 {
// The first byte is assumed to be 0xED
#[allow(dead_code)]
fn output_fileline(w: &mut Write, file: &[u8], line: libc::c_int,
more: bool) -> io::Result<()> {
- let file = str::from_utf8(file).ok().unwrap_or("<unknown>");
+ let file = str::from_utf8(file).unwrap_or("<unknown>");
// prior line: " ##: {:2$} - func"
try!(write!(w, " {:3$}at {}:{}", "", file, line, HEX_WIDTH));
if more {
use old_io::{IoResult, FileStat, SeekStyle};
use old_io::{Read, Truncate, SeekCur, SeekSet, ReadWrite, SeekEnd, Append};
use old_io;
+use old_path::{Path, GenericPath};
use libc::{self, c_int, c_void};
use mem;
use ptr;
let mut reader = FileDesc::new(reader, true);
let mut writer = FileDesc::new(writer, true);
- writer.write(b"test").ok().unwrap();
+ writer.write(b"test").unwrap();
let mut buf = [0; 4];
match reader.read(&mut buf) {
Ok(4) => {
}));
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<()> {
}
pub fn signal(fd: libc::c_int) {
- FileDesc::new(fd, false).write(&[0]).ok().unwrap();
+ FileDesc::new(fd, false).write(&[0]).unwrap();
}
pub fn close(fd: libc::c_int) {
const TMPBUF_SZ: usize = 128;
fn bytes2path(b: &[u8]) -> PathBuf {
- PathBuf::new(<OsStr as OsStrExt>::from_bytes(b))
+ PathBuf::from(<OsStr as OsStrExt>::from_bytes(b))
}
fn os2path(os: OsString) -> PathBuf {
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)))
}
}
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")
}
})
}
// drain the file descriptor
let mut buf = [0];
- assert_eq!(fd.read(&mut buf).ok().unwrap(), 1);
+ assert_eq!(fd.read(&mut buf).unwrap(), 1);
}
-1 if os::errno() == libc::EINTR as i32 => {}
#![allow(deprecated)] // for old path for dynamic lib
use prelude::v1::*;
+use io::prelude::*;
use dynamic_lib::DynamicLibrary;
-use io;
-use io::prelude::*;
use ffi::CStr;
use intrinsics;
+use io;
use libc;
use mem;
+use old_path::Path;
use ptr;
use str;
use sync::{StaticMutex, MUTEX_INIT};
use sys;
use sys_common::{self, mkerr_libc};
+use old_path::{Path, GenericPath};
use old_io::{FilePermission, Write, UnstableFileStat, Open, FileAccess, FileMode};
use old_io::{IoResult, IoError, FileStat, SeekStyle};
use old_io::{Read, Truncate, SeekCur, SeekSet, ReadWrite, SeekEnd, Append};
impl Clone for UnixAcceptor {
fn clone(&self) -> UnixAcceptor {
- let name = to_utf16(&self.listener.name).ok().unwrap();
+ let name = to_utf16(&self.listener.name).unwrap();
UnixAcceptor {
inner: self.inner.clone(),
- event: Event::new(true, false).ok().unwrap(),
+ event: Event::new(true, false).unwrap(),
deadline: 0,
listener: UnixListener {
name: self.listener.name.clone(),
use old_io::{IoResult, IoError};
use old_io;
use os;
-use old_path::BytesContainer;
+use old_path::{BytesContainer, GenericPath};
use ptr;
use str;
use sync::{StaticMutex, MUTEX_INIT};
use prelude::v1::*;
-use old_io::{self, IoError, IoResult, MemReader};
+use old_io::{self, IoError, IoResult, MemReader, Reader};
use iter::repeat;
use libc::types::os::arch::extra::LPCVOID;
use libc::{c_int, HANDLE, LPDWORD, DWORD, LPVOID};
+++ /dev/null
-// 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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! 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 thunk::Thunk;
-use time::Duration;
-
-use sys::thread as imp;
-use sys_common::{stack, thread_info};
-
-/// 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<String>,
- // The size of the stack for the spawned thread
- stack_size: Option<usize>,
-}
-
-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<Writer + Send + 'static>) -> 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<Writer + Send + 'static>) -> 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<F>(self, f: F) -> io::Result<JoinHandle> 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<T>`, 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<JoinGuard<'a, T>> 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<T: Send>(self, f: Thunk<(), T>) -> io::Result<JoinInner<T>> {
- 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: 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<T>`, 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<String>,
- lock: Mutex<bool>, // 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<Inner>,
-}
-
-impl Thread {
- // Used only internally to construct a thread object without spawning
- fn new(name: Option<String>) -> 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: 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<String>) -> 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<T> = ::result::Result<T, Box<Any + Send + 'static>>;
-
-struct Packet<T>(Arc<UnsafeCell<Option<Result<T>>>>);
-
-unsafe impl<T:Send> Send for Packet<T> {}
-unsafe impl<T> Sync for Packet<T> {}
-
-/// Inner representation for JoinHandle and JoinGuard
-struct JoinInner<T> {
- native: imp::rust_thread,
- thread: Thread,
- packet: Packet<T>,
- joined: bool,
-}
-
-impl<T> JoinInner<T> {
- fn join(&mut self) -> Result<T> {
- 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<T>,
- _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<T: Send> 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<F>(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::<T>());
- assert_eq!(*e.downcast::<T>().ok().unwrap(), "static string");
- }
- Ok(()) => panic!()
- }
- }
-
- #[test]
- fn test_try_panic_message_owned_str() {
- match thread::spawn(move|| {
- panic!("owned string".to_string());
- }).join() {
- Err(e) => {
- type T = String;
- assert!(e.is::<T>());
- assert_eq!(*e.downcast::<T>().ok().unwrap(), "owned string".to_string());
- }
- Ok(()) => panic!()
- }
- }
-
- #[test]
- fn test_try_panic_message_any() {
- match thread::spawn(move|| {
- panic!(box 413u16 as Box<Any + Send>);
- }).join() {
- Err(e) => {
- type T = Box<Any + Send>;
- assert!(e.is::<T>());
- let any = e.downcast::<T>().ok().unwrap();
- assert!(any.is::<u16>());
- assert_eq!(*any.downcast::<u16>().ok().unwrap(), 413);
- }
- Ok(()) => panic!()
- }
- }
-
- #[test]
- fn test_try_panic_message_unit_struct() {
- struct Juju;
-
- match thread::spawn(move|| {
- panic!(Juju)
- }).join() {
- Err(ref e) if e.is::<Juju>() => {}
- Err(_) | Ok(()) => panic!()
- }
- }
-
- #[test]
- fn test_park_timeout_unpark_before() {
- for _ in 0..10 {
- thread::current().unpark();
- thread::park_timeout(Duration::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.
-}
--- /dev/null
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! 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<u32> = RefCell::new(1));
+///
+/// FOO.with(|f| {
+/// assert_eq!(*f.borrow(), 1);
+/// *f.borrow_mut() = 2;
+/// });
+///
+/// // each thread starts out with the initial value of 1
+/// 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<T> {
+ // 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<UnsafeCell<Option<T>>>,
+
+ // 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> = {
+ ::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(
+ ::std::thread::__local::__impl::destroy_value::<$t>
+ ),
+ },
+ }
+ };
+
+ _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<T: 'static> LocalKey<T> {
+ /// 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<F, R>(&'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<Option<T>>) -> &T {
+ // Execute the initialization up front, *then* move it into our slot,
+ // just in case initialization fails.
+ let value = (self.init)();
+ let ptr = slot.get();
+ *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<T> {
+ // 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<T>,
+
+ // 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<bool>, // should be Cell
+ #[unstable(feature = "thread_local_internals")]
+ pub dtor_running: UnsafeCell<bool>, // should be Cell
+ }
+
+ unsafe impl<T> ::marker::Sync for Key<T> { }
+
+ #[doc(hidden)]
+ impl<T> Key<T> {
+ pub unsafe fn get(&'static self) -> Option<&'static T> {
+ if intrinsics::needs_drop::<T>() && *self.dtor_running.get() {
+ return None
+ }
+ self.register_dtor();
+ Some(&*self.inner.get())
+ }
+
+ unsafe fn register_dtor(&self) {
+ if !intrinsics::needs_drop::<T>() || *self.dtor_registered.get() {
+ return
+ }
+
+ register_dtor(self as *const _ as *mut u8,
+ destroy_value::<T>);
+ *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<List> = 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<List> = 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<T>(ptr: *mut u8) {
+ let ptr = ptr as *mut Key<T>;
+ // Right before we run the user destructor be sure to flag the
+ // destructor as running for this thread so calls to `get` will return
+ // `None`.
+ *(*ptr).dtor_running.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<T> {
+ // Statically allocated initialization expression, using an `UnsafeCell`
+ // for the same reasons as above.
+ #[unstable(feature = "thread_local_internals")]
+ pub inner: UnsafeCell<T>,
+
+ // OS-TLS key that we'll use to key off.
+ #[unstable(feature = "thread_local_internals")]
+ pub os: OsStaticKey,
+ }
+
+ unsafe impl<T> ::marker::Sync for Key<T> { }
+
+ struct Value<T: 'static> {
+ key: &'static Key<T>,
+ value: T,
+ }
+
+ #[doc(hidden)]
+ impl<T> Key<T> {
+ 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<T>;
+ 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<Value<T>> = box Value {
+ key: self,
+ value: mem::transmute_copy(&self.inner),
+ };
+ let ptr: *mut Value<T> = 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<T: 'static>(ptr: *mut u8) {
+ // The OS TLS ensures that this key contains a NULL value when this
+ // destructor starts to run. We set it back to a sentinel value of 1 to
+ // ensure that any future calls to `get` for this thread will return
+ // `None`.
+ //
+ // Note that to prevent an infinite loop we reset it back to null right
+ // before we return from the destructor ourselves.
+ let ptr: Box<Value<T>> = Box::from_raw(ptr as *mut Value<T>);
+ let key = ptr.key;
+ key.os.set(1 as *mut u8);
+ drop(ptr);
+ key.os.set(ptr::null_mut());
+ }
+}
+
+#[cfg(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<i32> = 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<Option<Foo>> = 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<Option<S1>> = UnsafeCell {
+ value: None
+ });
+ thread_local!(static K2: UnsafeCell<Option<S2>> = 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<Option<S1>> = 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<Option<S1>> = UnsafeCell {
+ value: None
+ });
+ thread_local!(static K2: UnsafeCell<Option<Foo>> = 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<HashMap<i32, i32>> {
+ let mut m = HashMap::new();
+ m.insert(1, 2);
+ RefCell::new(m)
+ }
+ thread_local!(static FOO: RefCell<HashMap<i32, i32>> = map());
+
+ FOO.with(|map| {
+ assert_eq!(map.borrow()[&1], 2);
+ });
+ }
+
+ #[test]
+ fn refcell_vec() {
+ thread_local!(static FOO: RefCell<Vec<u32>> = RefCell::new(vec![1, 2, 3]));
+
+ FOO.with(|vec| {
+ assert_eq!(vec.borrow().len(), 3);
+ vec.borrow_mut().push(4);
+ assert_eq!(vec.borrow()[3], 4);
+ });
+ }
+}
--- /dev/null
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! 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<String>,
+ // The size of the stack for the spawned thread
+ stack_size: Option<usize>,
+}
+
+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<Writer + Send + 'static>) -> 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<Writer + Send + 'static>) -> 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<F>(self, f: F) -> io::Result<JoinHandle> 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<T>`, 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<JoinGuard<'a, T>> 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<T: Send>(self, f: Thunk<(), T>) -> io::Result<JoinInner<T>> {
+ 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: 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<T>`, 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<String>,
+ lock: Mutex<bool>, // 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<Inner>,
+}
+
+impl Thread {
+ // Used only internally to construct a thread object without spawning
+ fn new(name: Option<String>) -> 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: 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<String>) -> 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<T> = ::result::Result<T, Box<Any + Send + 'static>>;
+
+struct Packet<T>(Arc<UnsafeCell<Option<Result<T>>>>);
+
+unsafe impl<T:Send> Send for Packet<T> {}
+unsafe impl<T> Sync for Packet<T> {}
+
+/// Inner representation for JoinHandle and JoinGuard
+struct JoinInner<T> {
+ native: imp::rust_thread,
+ thread: Thread,
+ packet: Packet<T>,
+ joined: bool,
+}
+
+impl<T> JoinInner<T> {
+ fn join(&mut self) -> Result<T> {
+ 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<T>,
+ _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<T: Send> 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<F>(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::<T>());
+ assert_eq!(*e.downcast::<T>().unwrap(), "static string");
+ }
+ Ok(()) => panic!()
+ }
+ }
+
+ #[test]
+ fn test_try_panic_message_owned_str() {
+ match thread::spawn(move|| {
+ panic!("owned string".to_string());
+ }).join() {
+ Err(e) => {
+ type T = String;
+ assert!(e.is::<T>());
+ assert_eq!(*e.downcast::<T>().unwrap(), "owned string".to_string());
+ }
+ Ok(()) => panic!()
+ }
+ }
+
+ #[test]
+ fn test_try_panic_message_any() {
+ match thread::spawn(move|| {
+ panic!(box 413u16 as Box<Any + Send>);
+ }).join() {
+ Err(e) => {
+ type T = Box<Any + Send>;
+ assert!(e.is::<T>());
+ let any = e.downcast::<T>().unwrap();
+ assert!(any.is::<u16>());
+ assert_eq!(*any.downcast::<u16>().unwrap(), 413);
+ }
+ Ok(()) => panic!()
+ }
+ }
+
+ #[test]
+ fn test_try_panic_message_unit_struct() {
+ struct Juju;
+
+ match thread::spawn(move|| {
+ panic!(Juju)
+ }).join() {
+ Err(ref e) if e.is::<Juju>() => {}
+ Err(_) | Ok(()) => panic!()
+ }
+ }
+
+ #[test]
+ fn test_park_timeout_unpark_before() {
+ for _ in 0..10 {
+ thread::current().unpark();
+ thread::park_timeout(Duration::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.
+}
--- /dev/null
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! 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<T> { #[doc(hidden)] pub inner: __impl::KeyInner<T> }
+
+/// 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<T> ScopedKey<T> {
+ /// 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<R, F>(&'static self, t: &T, cb: F) -> R where
+ F: FnOnce() -> R,
+ {
+ struct Reset<'a, T: 'a> {
+ key: &'a __impl::KeyInner<T>,
+ 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<R, F>(&'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<T> { pub inner: UnsafeCell<*mut T> }
+
+ unsafe impl<T> ::marker::Sync for KeyInner<T> { }
+
+ #[doc(hidden)]
+ impl<T> KeyInner<T> {
+ #[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<T> {
+ pub inner: OsStaticKey,
+ pub marker: marker::PhantomData<Cell<T>>,
+ }
+
+ unsafe impl<T> ::marker::Sync for KeyInner<T> { }
+
+ #[doc(hidden)]
+ impl<T> KeyInner<T> {
+ #[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<u32>);
+
+ 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());
+ }
+}
+++ /dev/null
-// 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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! 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<u32> = RefCell::new(1));
-///
-/// FOO.with(|f| {
-/// assert_eq!(*f.borrow(), 1);
-/// *f.borrow_mut() = 2;
-/// });
-///
-/// // each thread starts out with the initial value of 1
-/// 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<T> {
- // 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<UnsafeCell<Option<T>>>,
-
- // 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<T: 'static> Key<T> {
- /// 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<F, R>(&'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<Option<T>>) -> &T {
- // Execute the initialization up front, *then* move it into our slot,
- // just in case initialization fails.
- let value = (self.init)();
- let ptr = slot.get();
- *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<T> {
- // 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<T>,
-
- // 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<bool>, // should be Cell
- #[unstable(feature = "thread_local_internals")]
- pub dtor_running: UnsafeCell<bool>, // should be Cell
- }
-
- unsafe impl<T> ::marker::Sync for Key<T> { }
-
- #[doc(hidden)]
- impl<T> Key<T> {
- pub unsafe fn get(&'static self) -> Option<&'static T> {
- if intrinsics::needs_drop::<T>() && *self.dtor_running.get() {
- return None
- }
- self.register_dtor();
- Some(&*self.inner.get())
- }
-
- unsafe fn register_dtor(&self) {
- if !intrinsics::needs_drop::<T>() || *self.dtor_registered.get() {
- return
- }
-
- register_dtor(self as *const _ as *mut u8,
- destroy_value::<T>);
- *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<List> = 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<List> = 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<T>(ptr: *mut u8) {
- let ptr = ptr as *mut Key<T>;
- // Right before we run the user destructor be sure to flag the
- // destructor as running for this thread so calls to `get` will return
- // `None`.
- *(*ptr).dtor_running.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<T> {
- // Statically allocated initialization expression, using an `UnsafeCell`
- // for the same reasons as above.
- #[unstable(feature = "thread_local_internals")]
- pub inner: UnsafeCell<T>,
-
- // OS-TLS key that we'll use to key off.
- #[unstable(feature = "thread_local_internals")]
- pub os: OsStaticKey,
- }
-
- unsafe impl<T> ::marker::Sync for Key<T> { }
-
- struct Value<T: 'static> {
- key: &'static Key<T>,
- value: T,
- }
-
- #[doc(hidden)]
- impl<T> Key<T> {
- 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<T>;
- 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<Value<T>> = box Value {
- key: self,
- value: mem::transmute_copy(&self.inner),
- };
- let ptr: *mut Value<T> = 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<T: 'static>(ptr: *mut u8) {
- // The OS TLS ensures that this key contains a NULL value when this
- // destructor starts to run. We set it back to a sentinel value of 1 to
- // ensure that any future calls to `get` for this thread will return
- // `None`.
- //
- // Note that to prevent an infinite loop we reset it back to null right
- // before we return from the destructor ourselves.
- let ptr: Box<Value<T>> = Box::from_raw(ptr as *mut Value<T>);
- let key = ptr.key;
- key.os.set(1 as *mut u8);
- drop(ptr);
- key.os.set(ptr::null_mut());
- }
-}
-
-#[cfg(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<i32> = 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<Option<Foo>> = 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<Option<S1>> = UnsafeCell {
- value: None
- });
- thread_local!(static K2: UnsafeCell<Option<S2>> = 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<Option<S1>> = 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<Option<S1>> = UnsafeCell {
- value: None
- });
- thread_local!(static K2: UnsafeCell<Option<Foo>> = 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<HashMap<i32, i32>> {
- let mut m = HashMap::new();
- m.insert(1, 2);
- RefCell::new(m)
- }
- thread_local!(static FOO: RefCell<HashMap<i32, i32>> = map());
-
- FOO.with(|map| {
- assert_eq!(map.borrow()[1], 2);
- });
- }
-
- #[test]
- fn refcell_vec() {
- thread_local!(static FOO: RefCell<Vec<u32>> = RefCell::new(vec![1, 2, 3]));
-
- FOO.with(|vec| {
- assert_eq!(vec.borrow().len(), 3);
- vec.borrow_mut().push(4);
- assert_eq!(vec.borrow()[3], 4);
- });
- }
-}
+++ /dev/null
-// 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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! 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<T> { #[doc(hidden)] pub inner: __impl::KeyInner<T> }
-
-/// 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<T> Key<T> {
- /// 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<R, F>(&'static self, t: &T, cb: F) -> R where
- F: FnOnce() -> R,
- {
- struct Reset<'a, T: 'a> {
- key: &'a __impl::KeyInner<T>,
- 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<R, F>(&'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<T> { pub inner: UnsafeCell<*mut T> }
-
- unsafe impl<T> ::marker::Sync for KeyInner<T> { }
-
- #[doc(hidden)]
- impl<T> KeyInner<T> {
- #[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<T> {
- pub inner: OsStaticKey,
- pub marker: marker::PhantomData<Cell<T>>,
- }
-
- unsafe impl<T> ::marker::Sync for KeyInner<T> { }
-
- #[doc(hidden)]
- impl<T> KeyInner<T> {
- #[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<u32>);
-
- 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());
- }
-}
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()
//! fn encode(&self, s: &mut S) -> Result<(), E> {
//! s.emit_struct("Spanned", 2, |this| {
//! this.emit_struct_field("node", 0, |this| self.node.encode(this))
-//! .ok().unwrap();
+//! .unwrap();
//! this.emit_struct_field("span", 1, |this| self.span.encode(this))
//! })
//! }
//! d.read_struct("Spanned", 2, |this| {
//! Ok(Spanned {
//! node: this.read_struct_field("node", 0, |this| Decodable::decode(this))
-//! .ok().unwrap(),
+//! .unwrap(),
//! span: this.read_struct_field("span", 1, |this| Decodable::decode(this))
-//! .ok().unwrap(),
+//! .unwrap(),
//! })
//! })
//! }
let lname = self.ecx.ident_of(&format!("__arg{}",
*name));
pats.push(self.ecx.pat_ident(e.span, lname));
- names[self.name_positions[*name]] =
+ names[*self.name_positions.get(name).unwrap()] =
Some(Context::format_arg(self.ecx, e.span, arg_ty,
self.ecx.expr_ident(e.span, lname)));
heads.push(self.ecx.expr_addr_of(e.span, e));
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
argument_gram);
// Extract the arguments:
- let lhses = match *argument_map[lhs_nm] {
+ let lhses = match **argument_map.get(&lhs_nm).unwrap() {
MatchedSeq(ref s, _) => /* FIXME (#2543) */ (*s).clone(),
_ => cx.span_bug(def.span, "wrong-structured lhs")
};
check_lhs_nt_follows(cx, &**lhs, def.span);
}
- let rhses = match *argument_map[rhs_nm] {
+ let rhses = match **argument_map.get(&rhs_nm).unwrap() {
MatchedSeq(ref s, _) => /* FIXME (#2543) */ (*s).clone(),
_ => cx.span_bug(def.span, "wrong-structured rhs")
};
}
}
+ ast::ItemDefaultImpl(..) => {
+ self.gate_feature("optin_builtin_traits",
+ i.span,
+ "default trait implementations are experimental \
+ and possibly buggy");
+ }
+
ast::ItemImpl(_, polarity, _, _, _, _) => {
match polarity {
ast::ImplPolarity::Negative => {
#![feature(unicode)]
#![feature(path_ext)]
#![feature(str_char)]
+#![feature(convert)]
+#![feature(into_cow)]
extern crate arena;
extern crate fmt_macros;
// find the integer representing the name
self.scan_digits(base);
let encoded_name : u32 = self.with_str_from(start_bpos, |s| {
- num::from_str_radix(s, 10).ok().unwrap_or_else(|| {
+ num::from_str_radix(s, 10).unwrap_or_else(|_| {
panic!("expected digits representing a name, got {:?}, {}, range [{:?},{:?}]",
s, whence, start_bpos, self.last_pos);
})
let start_bpos = self.last_pos;
self.scan_digits(base);
let encoded_ctxt : ast::SyntaxContext = self.with_str_from(start_bpos, |s| {
- num::from_str_radix(s, 10).ok().unwrap_or_else(|| {
+ num::from_str_radix(s, 10).unwrap_or_else(|_| {
panic!("expected digits representing a ctxt, got {:?}, {}", s, whence);
})
});
outer_attrs: &[ast::Attribute],
id_sp: Span)
-> (ast::Item_, Vec<ast::Attribute> ) {
- 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 {
#![feature(std_misc)]
#![feature(str_char)]
#![feature(path_ext)]
+#![feature(convert)]
#![cfg_attr(windows, feature(libc))]
#[macro_use] extern crate log;
}
};
- let entry = open(&term[..]);
- if entry.is_err() {
- if env::var("MSYSCON").ok().map_or(false, |s| {
- "mintty.exe" == s
- }) {
- // msys terminal
- return Some(box TerminfoTerminal {out: out,
- ti: msys_terminfo(),
- num_colors: 8} as Box<Terminal<T>+Send>);
- }
- debug!("error finding terminfo entry: {:?}", entry.err().unwrap());
- return None;
- }
+ let mut file = match open(&term[..]) {
+ Ok(f) => f,
+ Err(err) => return match env::var("MSYSCON") {
+ Ok(ref val) if &val[..] == "mintty.exe" => {
+ // msys terminal
+ Some(box TerminfoTerminal{
+ out: out,
+ ti: msys_terminfo(),
+ num_colors: 8,
+ } as Box<Terminal<T>+Send>)
+ },
+ _ => {
+ debug!("error finding terminfo entry: {:?}", err);
+ None
+ },
+ },
+ };
- let mut file = entry.unwrap();
let ti = parse(&mut file, false);
if ti.is_err() {
debug!("error parsing terminfo entry: {:?}", ti.err().unwrap());
// 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;
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:
// ~/.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"));
}
}
}
#![feature(libc)]
#![feature(set_stdio)]
#![feature(os)]
+#![feature(convert)]
extern crate getopts;
extern crate serialize;
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 ||
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 => {}
}
mod tests {
use stats::Stats;
use stats::Summary;
- use std::old_io;
+ use std::old_io::{self, Writer};
use std::f64;
macro_rules! assert_approx_eq {
// 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!(),
});
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::<String>());
let item = BookItem {
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();
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));
pub type CommandResult<T> = Result<T, CommandError>;
pub fn err(s: &str) -> CliError {
+ #[derive(Debug)]
struct E(String);
impl Error for E {
#![feature(rustdoc)]
#![feature(rustc_private)]
#![feature(path_relative_from)]
+#![feature(convert)]
extern crate rustdoc;
extern crate rustc_back;
// the unused ty param is necessary so this gets monomorphized
pub fn request<T>(req: &header_map) {
- let data = req["METHOD".to_string()].clone();
+ let data = req[&"METHOD".to_string()].clone();
let _x = data.borrow().clone()[0].clone();
}
fn baz() { }
pub fn test() {
- let none: Option<&Path> = None; // appease the typechecker
- let lib = DynamicLibrary::open(none).unwrap();
+ let lib = DynamicLibrary::open(None).unwrap();
unsafe {
assert!(lib.symbol::<int>("foo").is_ok());
assert!(lib.symbol::<int>("baz").is_err());
let mac_expr = match TokenTree::parse(cx, &mbe_matcher[..], args) {
Success(map) => {
- match (&*map[str_to_ident("matched")], &*map[str_to_ident("pat")]) {
+ match (&*map[&str_to_ident("matched")], &*map[&str_to_ident("pat")]) {
(&MatchedNonterminal(NtExpr(ref matched_expr)),
&MatchedSeq(ref pats, seq_sp)) => {
let pats: Vec<P<Pat>> = pats.iter().map(|pat_nt|
#![feature(unboxed_closures)]
-use std::old_io::File;
+use std::old_io::*;
+use std::old_path::{Path, GenericPath};
use std::iter::repeat;
use std::mem::swap;
use std::env;
// OF THE POSSIBILITY OF SUCH DAMAGE.
use std::cmp::min;
-use std::old_io::{stdout, IoResult};
+use std::old_io::*;
use std::iter::repeat;
use std::env;
use std::slice::bytes::copy_memory;
// OF THE POSSIBILITY OF SUCH DAMAGE.
use std::cmp::min;
-use std::old_io::{BufferedWriter, File};
+use std::old_io::*;
use std::old_io;
+use std::old_path::Path;
use std::num::Float;
use std::env;
// given a FASTA file on stdin, process sequence THREE
fn main() {
- use std::old_io::{stdio, MemReader, BufferedReader};
+ use std::old_io::*;
let rdr = if env::var_os("RUST_BENCH").is_some() {
let foo = include_bytes!("shootout-k-nucleotide.data");
// ignore-pretty very bad with line comments
use std::old_io;
+use std::old_io::*;
use std::env;
use std::simd::f64x2;
use std::sync::Arc;
extern crate libc;
use std::old_io::stdio::{stdin_raw, stdout_raw};
-use std::old_io::{IoResult, EndOfFile};
+use std::old_io::*;
use std::ptr::{copy_memory, Unique};
use std::thread;
--- /dev/null
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that macro reexports item are gated by `macro_reexport` feature gate.
+
+// aux-build:macro_reexport_1.rs
+// ignore-stage1
+
+#![crate_type = "dylib"]
+
+#[macro_reexport(reexported)]
+#[macro_use] #[no_link]
+extern crate macro_reexport_1;
+//~^ ERROR macros reexports are experimental and possibly buggy
+//~| HELP add #![feature(macro_reexport)] to the crate attributes to enable
+++ /dev/null
-// 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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#![feature(box_syntax)]
-
-use std::ops::Index;
-
-struct MyVec<T> {
- data: Vec<T>,
-}
-
-impl<T> Index<usize> for MyVec<T> {
- type Output = T;
-
- fn index(&self, &i: &usize) -> &T {
- &self.data[i]
- }
-}
-
-fn main() {
- let v = MyVec::<Box<_>> { data: vec!(box 1, box 2, box 3) };
- let good = &v[0]; // Shouldn't fail here
- let bad = v[0];
- //~^ ERROR cannot move out of indexed content
-}
impl<T> Index<usize> for MyVec<T> {
type Output = T;
- fn index(&self, _: &usize) -> &T {
+ fn index(&self, _: usize) -> &T {
&self.x
}
}
y: isize,
}
+#[cfg(stage0)]
impl Index<String> for Foo {
type Output = isize;
}
}
-impl IndexMut<String> for Foo {
- fn index_mut<'a>(&'a mut self, z: &String) -> &'a mut isize {
+impl<'a> Index<&'a String> for Foo {
+ type Output = isize;
+
+ fn index(&self, z: &String) -> &isize {
+ if *z == "x" {
+ &self.x
+ } else {
+ &self.y
+ }
+ }
+}
+
+impl<'a> IndexMut<&'a String> for Foo {
+ fn index_mut(&mut self, z: &String) -> &mut isize {
if *z == "x" {
&mut self.x
} else {
}
fn test1(mut f: Box<Foo>, s: String) {
- let _p = &mut f[s];
- let _q = &f[s]; //~ ERROR cannot borrow
+ let _p = &mut f[&s];
+ let _q = &f[&s]; //~ ERROR cannot borrow
}
fn test2(mut f: Box<Foo>, s: String) {
- let _p = &mut f[s];
- let _q = &mut f[s]; //~ ERROR cannot borrow
+ let _p = &mut f[&s];
+ let _q = &mut f[&s]; //~ ERROR cannot borrow
}
struct Bar {
}
fn test3(mut f: Box<Bar>, s: String) {
- let _p = &mut f.foo[s];
- let _q = &mut f.foo[s]; //~ ERROR cannot borrow
+ let _p = &mut f.foo[&s];
+ let _q = &mut f.foo[&s]; //~ ERROR cannot borrow
}
fn test4(mut f: Box<Bar>, s: String) {
- let _p = &f.foo[s];
- let _q = &f.foo[s];
+ let _p = &f.foo[&s];
+ let _q = &f.foo[&s];
}
fn test5(mut f: Box<Bar>, s: String) {
- let _p = &f.foo[s];
- let _q = &mut f.foo[s]; //~ ERROR cannot borrow
+ let _p = &f.foo[&s];
+ let _q = &mut f.foo[&s]; //~ ERROR cannot borrow
}
fn test6(mut f: Box<Bar>, g: Foo, s: String) {
- let _p = &f.foo[s];
+ let _p = &f.foo[&s];
f.foo = g; //~ ERROR cannot assign
}
fn test7(mut f: Box<Bar>, g: Bar, s: String) {
- let _p = &f.foo[s];
+ let _p = &f.foo[&s];
*f = g; //~ ERROR cannot assign
}
fn test8(mut f: Box<Bar>, g: Foo, s: String) {
- let _p = &mut f.foo[s];
+ let _p = &mut f.foo[&s];
f.foo = g; //~ ERROR cannot assign
}
fn test9(mut f: Box<Bar>, g: Bar, s: String) {
- let _p = &mut f.foo[s];
+ let _p = &mut f.foo[&s];
*f = g; //~ ERROR cannot assign
}
--- /dev/null
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(box_syntax)]
+
+use std::ops::Index;
+
+struct MyVec<T> {
+ data: Vec<T>,
+}
+
+impl<T> Index<usize> for MyVec<T> {
+ type Output = T;
+
+ fn index(&self, i: usize) -> &T {
+ &self.data[i]
+ }
+}
+
+fn main() {
+ let v = MyVec::<Box<_>> { data: vec!(box 1, box 2, box 3) };
+ let good = &v[0]; // Shouldn't fail here
+ let bad = v[0];
+ //~^ ERROR cannot move out of indexed content
+}
--- /dev/null
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::ops::{Index, IndexMut};
+
+struct Foo {
+ x: isize,
+ y: isize,
+}
+
+impl Index<String> for Foo {
+ type Output = isize;
+
+ fn index(&self, z: String) -> &isize {
+ if z == "x" {
+ &self.x
+ } else {
+ &self.y
+ }
+ }
+}
+
+impl IndexMut<String> for Foo {
+ fn index_mut(&mut self, z: String) -> &mut isize {
+ if z == "x" {
+ &mut self.x
+ } else {
+ &mut self.y
+ }
+ }
+}
+
+struct Bar {
+ x: isize,
+}
+
+impl Index<isize> for Bar {
+ type Output = isize;
+
+ fn index<'a>(&'a self, z: isize) -> &'a isize {
+ &self.x
+ }
+}
+
+fn main() {
+ let mut f = Foo {
+ x: 1,
+ y: 2,
+ };
+ let mut s = "hello".to_string();
+ let rs = &mut s;
+
+ println!("{}", f[s]);
+ //~^ ERROR cannot move out of `s` because it is borrowed
+
+ f[s] = 10;
+ //~^ ERROR cannot move out of `s` because it is borrowed
+ //~| ERROR use of moved value: `s`
+
+ let s = Bar {
+ x: 1,
+ };
+ let i = 2;
+ let _j = &i;
+ println!("{}", s[i]); // no error, i is copy
+ println!("{}", s[i]);
+}
--- /dev/null
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::ops::{Index, IndexMut};
+
+struct Foo {
+ x: isize,
+ y: isize,
+}
+
+impl<'a> Index<&'a String> for Foo {
+ type Output = isize;
+
+ fn index(&self, z: &String) -> &isize {
+ if *z == "x" {
+ &self.x
+ } else {
+ &self.y
+ }
+ }
+}
+
+impl<'a> IndexMut<&'a String> for Foo {
+ fn index_mut(&mut self, z: &String) -> &mut isize {
+ if *z == "x" {
+ &mut self.x
+ } else {
+ &mut self.y
+ }
+ }
+}
+
+struct Bar {
+ x: isize,
+}
+
+impl Index<isize> for Bar {
+ type Output = isize;
+
+ fn index<'a>(&'a self, z: isize) -> &'a isize {
+ &self.x
+ }
+}
+
+fn main() {
+ let mut f = Foo {
+ x: 1,
+ y: 2,
+ };
+ let mut s = "hello".to_string();
+ let rs = &mut s;
+ println!("{}", f[&s]);
+ //~^ ERROR cannot borrow `s` as immutable because it is also borrowed as mutable
+ f[&s] = 10;
+ //~^ ERROR cannot borrow `s` as immutable because it is also borrowed as mutable
+ let s = Bar {
+ x: 1,
+ };
+ s[2] = 20;
+ //~^ ERROR cannot assign to immutable indexed content
+}
+++ /dev/null
-// 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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use std::ops::{Index, IndexMut};
-
-struct Foo {
- x: isize,
- y: isize,
-}
-
-impl Index<String> for Foo {
- type Output = isize;
-
- fn index<'a>(&'a self, z: &String) -> &'a isize {
- if *z == "x" {
- &self.x
- } else {
- &self.y
- }
- }
-}
-
-impl IndexMut<String> for Foo {
- fn index_mut<'a>(&'a mut self, z: &String) -> &'a mut isize {
- if *z == "x" {
- &mut self.x
- } else {
- &mut self.y
- }
- }
-}
-
-struct Bar {
- x: isize,
-}
-
-impl Index<isize> for Bar {
- type Output = isize;
-
- fn index<'a>(&'a self, z: &isize) -> &'a isize {
- &self.x
- }
-}
-
-fn main() {
- let mut f = Foo {
- x: 1,
- y: 2,
- };
- let mut s = "hello".to_string();
- let rs = &mut s;
- println!("{}", f[s]);
- //~^ ERROR cannot borrow `s` as immutable because it is also borrowed as mutable
- f[s] = 10;
- //~^ ERROR cannot borrow `s` as immutable because it is also borrowed as mutable
- let s = Bar {
- x: 1,
- };
- s[2] = 20;
- //~^ ERROR cannot assign to immutable indexed content
-}
#![feature(unboxed_closures)]
+use std::io::Read;
+
fn to_fn_once<A,F:FnOnce<A>>(f: F) -> F { f }
fn main() {
to_fn_once(move|| { x = 2; });
//~^ ERROR: cannot assign to immutable captured outer variable
- let s = std::old_io::stdin();
- to_fn_once(move|| { s.read_to_end(); });
+ let s = std::io::stdin();
+ to_fn_once(move|| { s.read_to_end(&mut Vec::new()); });
//~^ ERROR: cannot borrow immutable captured outer variable
}
impl MyTrait for .. {}
//~^ ERROR conflicting implementations for trait `MyTrait`
+trait MySafeTrait: MarkerTrait {}
+
+unsafe impl MySafeTrait for .. {}
+//~^ ERROR implementing the trait `MySafeTrait` is not unsafe
+
+unsafe trait MyUnsafeTrait: MarkerTrait {}
+
+impl MyUnsafeTrait for .. {}
+//~^ ERROR the trait `MyUnsafeTrait` requires an `unsafe impl` declaration
+
fn main() {}
impl Index<usize> for S {
type Output = str;
- fn index<'a>(&'a self, _: &usize) -> &'a str {
+ fn index(&self, _: usize) -> &str {
"hello"
}
}
impl Index<usize> for T {
type Output = Debug + 'static;
- fn index<'a>(&'a self, idx: &usize) -> &'a (Debug + 'static) {
+ fn index<'a>(&'a self, idx: usize) -> &'a (Debug + 'static) {
static x: usize = 42;
&x
}
--- /dev/null
+// Copyright 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that patterns including the box syntax are gated by `box_patterns` feature gate.
+
+fn main() {
+ let x = Box::new(1);
+
+ match x {
+ box 1 => (),
+ //~^ box pattern syntax is experimental
+ //~| add #![feature(box_patterns)] to the crate attributes to enable
+ _ => ()
+ };
+}
--- /dev/null
+// Copyright 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that the use of the box syntax is gated by `box_syntax` feature gate.
+
+fn main() {
+ let x = box 3;
+ //~^ ERROR box expression syntax is experimental; you can call `Box::new` instead.
+ //~| HELP add #![feature(box_syntax)] to the crate attributes to enable
+}
--- /dev/null
+// Copyright 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that the use of smid types in the ffi is gated by `smid_ffi` feature gate.
+
+#![feature(simd)]
+
+#[repr(C)]
+#[derive(Copy)]
+#[simd]
+pub struct f32x4(f32, f32, f32, f32);
+
+#[allow(dead_code)]
+extern {
+ fn foo(x: f32x4);
+ //~^ ERROR use of SIMD type `f32x4` in FFI is highly experimental and may result in invalid code
+ //~| HELP add #![feature(simd_ffi)] to the crate attributes to enable
+}
+
+fn main() {}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::old_io;
+use std::io::{self, Read};
use std::vec;
pub struct Container<'a> {
- reader: &'a mut Reader
+ reader: &'a mut Read
}
impl<'a> Container<'a> {
- pub fn wrap<'s>(reader: &'s mut Reader) -> Container<'s> {
+ pub fn wrap<'s>(reader: &'s mut io::Read) -> Container<'s> {
Container { reader: reader }
}
}
pub fn for_stdin<'a>() -> Container<'a> {
- let mut r = old_io::stdin();
- Container::wrap(&mut r as &mut Reader)
+ let mut r = io::stdin();
+ Container::wrap(&mut r as &mut io::Read)
}
fn main() {
0.contains(bits);
//~^ ERROR overflow
- //~| ERROR overflow
- //~| ERROR overflow
- //~| ERROR mismatched types
}
--- /dev/null
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Check that when making a ref mut binding with type `&mut T`, the
+// type `T` must match precisely the type `U` of the value being
+// matched, and in particular cannot be some supertype of `U`. Issue
+// #23116. This test focuses on a `match`.
+
+#![allow(dead_code)]
+struct S<'b>(&'b i32);
+impl<'b> S<'b> {
+ fn bar<'a>(&'a mut self) -> &'a mut &'a i32 {
+ match self.0 { ref mut x => x } //~ ERROR mismatched types
+ }
+}
+
+fn main() {}
--- /dev/null
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Check that when making a ref mut binding with type `&mut T`, the
+// type `T` must match precisely the type `U` of the value being
+// matched, and in particular cannot be some supertype of `U`. Issue
+// #23116. This test focuses on a `let`.
+
+#![allow(dead_code)]
+struct S<'b>(&'b i32);
+impl<'b> S<'b> {
+ fn bar<'a>(&'a mut self) -> &'a mut &'a i32 {
+ let ref mut x = self.0;
+ x //~ ERROR mismatched types
+ }
+}
+
+fn main() {}
fn main() {
is_send::<A>();
//~^ ERROR overflow evaluating
- //~^^ NOTE consider adding a `#![recursion_limit="20"]` attribute to your crate
- //~^^^ NOTE required by `is_send`
- //~^^^^ ERROR overflow evaluating
- //~^^^^^ NOTE consider adding a `#![recursion_limit="20"]` attribute to your crate
- //~^^^^^^ NOTE required by `is_send`
- //~^^^^^^^ ERROR overflow evaluating
- //~^^^^^^^^ NOTE consider adding a `#![recursion_limit="20"]` attribute to your crate
- //~^^^^^^^^^ NOTE required by `is_send`
+ //~| NOTE consider adding a `#![recursion_limit="20"]` attribute to your crate
}
--- /dev/null
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+trait Dummy { fn dummy(&self); }
+
+fn foo1<'a:'b,'b>(x: &'a mut (Dummy+'a)) -> &'b mut (Dummy+'b) {
+ // Here, we are able to coerce
+ x
+}
+
+fn foo2<'a:'b,'b>(x: &'b mut (Dummy+'a)) -> &'b mut (Dummy+'b) {
+ // Here, we are able to coerce
+ x
+}
+
+fn foo3<'a,'b>(x: &'a mut Dummy) -> &'b mut Dummy {
+ // Without knowing 'a:'b, we can't coerce
+ x //~ ERROR mismatched types
+ //~^ ERROR cannot infer
+}
+
+struct Wrapper<T>(T);
+fn foo4<'a:'b,'b>(x: Wrapper<&'a mut Dummy>) -> Wrapper<&'b mut Dummy> {
+ // We can't coerce because it is packed in `Wrapper`
+ x //~ ERROR mismatched types
+}
+
+fn main() {}
--- /dev/null
+// Copyright 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// error-pattern:thread '<main>' panicked at 'shift operation overflowed'
+// compile-flags: -C debug-assertions
+
+// (Work around constant-evaluation)
+fn id<T>(x: T) -> T { x }
+
+fn main() {
+ let _x = 1_i32 << id(32);
+}
--- /dev/null
+// Copyright 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// error-pattern:thread '<main>' panicked at 'shift operation overflowed'
+// compile-flags: -C debug-assertions
+
+// (Work around constant-evaluation)
+fn id<T>(x: T) -> T { x }
+
+fn main() {
+ let _x = 1 << id(-1);
+}
--- /dev/null
+// Copyright 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// error-pattern:thread '<main>' panicked at 'shift operation overflowed'
+// compile-flags: -C debug-assertions
+
+// (Work around constant-evaluation)
+fn id<T>(x: T) -> T { x }
+
+fn main() {
+ let _x = 1_u64 << id(64);
+}
--- /dev/null
+// Copyright 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// error-pattern:thread '<main>' panicked at 'shift operation overflowed'
+// compile-flags: -C debug-assertions
+
+// This function is checking that our automatic truncation does not
+// sidestep the overflow checking.
+
+// (Work around constant-evaluation)
+fn id<T>(x: T) -> T { x }
+
+fn main() {
+ // this signals overflow when checking is on
+ let x = 1_i8 << id(17);
+
+ // ... but when checking is off, the fallback will truncate the
+ // input to its lower three bits (= 1). Note that this is *not*
+ // the behavior of the x86 processor for 8- and 16-bit types,
+ // but it is necessary to avoid undefined behavior from LLVM.
+ //
+ // We check that here, by ensuring the result has only been
+ // shifted by one place; if overflow checking is turned off, then
+ // this assertion will pass (and the compiletest driver will
+ // report that the test did not produce the error expected above).
+ assert_eq!(x, 2_i8);
+}
--- /dev/null
+// Copyright 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// error-pattern:thread '<main>' panicked at 'shift operation overflowed'
+// compile-flags: -C debug-assertions
+
+// (Work around constant-evaluation)
+fn id<T>(x: T) -> T { x }
+
+fn main() {
+ let _x = -1_i32 >> id(32);
+}
--- /dev/null
+// Copyright 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// error-pattern:thread '<main>' panicked at 'shift operation overflowed'
+// compile-flags: -C debug-assertions
+
+// (Work around constant-evaluation)
+fn id<T>(x: T) -> T { x }
+
+fn main() {
+ let _x = -1_i32 >> id(-1);
+}
--- /dev/null
+// Copyright 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// error-pattern:thread '<main>' panicked at 'shift operation overflowed'
+// compile-flags: -C debug-assertions
+
+// (Work around constant-evaluation)
+fn id<T>(x: T) -> T { x }
+
+fn main() {
+ let _x = -1_i64 >> id(64);
+}
--- /dev/null
+// Copyright 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// error-pattern:thread '<main>' panicked at 'shift operation overflowed'
+// compile-flags: -C debug-assertions
+
+// This function is checking that our (type-based) automatic
+// truncation does not sidestep the overflow checking.
+
+// (Work around constant-evaluation)
+fn id<T>(x: T) -> T { x }
+
+fn main() {
+ // this signals overflow when checking is on
+ let x = 2_i8 >> id(17);
+
+ // ... but when checking is off, the fallback will truncate the
+ // input to its lower three bits (= 1). Note that this is *not*
+ // the behavior of the x86 processor for 8- and 16-bit types,
+ // but it is necessary to avoid undefined behavior from LLVM.
+ //
+ // We check that here, by ensuring the result is not zero; if
+ // overflow checking is turned off, then this assertion will pass
+ // (and the compiletest driver will report that the test did not
+ // produce the error expected above).
+ assert_eq!(x, 1_i8);
+}
// except according to those terms.
use std::env;
-use std::old_io::{File, Command};
+use std::fs::File;
+use std::process::Command;
+use std::io::Write;
+use std::path::Path;
// creates broken.rs, which has the Ident \x00name_0,ctxt_0\x00
// embedded within it, and then attempts to compile broken.rs with the
let main_file = tmpdir.join("broken.rs");
let _ = File::create(&main_file).unwrap()
- .write_str("pub fn main() {
+ .write_all(b"pub fn main() {
let \x00name_0,ctxt_0\x00 = 3;
println!(\"{}\", \x00name_0,ctxt_0\x00);
- }");
+ }").unwrap();
// rustc is passed to us with --out-dir and -L etc., so we
// can't exec it directly
let result = Command::new("sh")
.arg("-c")
- .arg(&format!("{} {}",
- rustc,
- main_file.as_str()
- .unwrap()))
+ .arg(&format!("{} {}", rustc, main_file.display()))
.output().unwrap();
- let err = String::from_utf8_lossy(&result.error);
+ let err = String::from_utf8_lossy(&result.stderr);
// positive test so that this test will be updated when the
// compiler changes.
use std::dynamic_lib::DynamicLibrary;
use std::os;
+use std::old_path::Path;
pub fn main() {
unsafe {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![feature(optin_builtin_traits)]
+
pub mod bar {
use std::marker;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::{char, env};
-use std::old_io::{File, Command};
+use std::fs::File;
+use std::io::prelude::*;
+use std::path::Path;
+use std::process::Command;
use std::rand::{thread_rng, Rng};
+use std::{char, env};
// creates unicode_input_multiple_files_{main,chars}.rs, where the
// former imports the latter. `_chars` just contains an identifier
let main_file = tmpdir.join("unicode_input_multiple_files_main.rs");
{
let _ = File::create(&main_file).unwrap()
- .write_str("mod unicode_input_multiple_files_chars;");
+ .write_all(b"mod unicode_input_multiple_files_chars;").unwrap();
}
for _ in 0..100 {
let randoms = tmpdir.join("unicode_input_multiple_files_chars.rs");
let mut w = File::create(&randoms).unwrap();
for _ in 0..30 {
- let _ = w.write_char(random_char());
+ write!(&mut w, "{}", random_char()).unwrap();
}
}
.arg("-c")
.arg(&format!("{} {}",
rustc,
- main_file.as_str()
- .unwrap()))
+ main_file.display()))
.output().unwrap();
- let err = String::from_utf8_lossy(&result.error);
+ let err = String::from_utf8_lossy(&result.stderr);
// positive test so that this test will be updated when the
// compiler changes.
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::old_io::{File, Command};
+use std::fs::File;
+use std::io::prelude::*;
use std::iter::repeat;
+use std::path::Path;
+use std::process::Command;
use std::rand::{thread_rng, Rng};
use std::{char, env};
.arg("-c")
.arg(&format!("{} {}",
rustc,
- main_file.as_str()
+ main_file.to_str()
.unwrap()))
.output().unwrap();
- let err = String::from_utf8_lossy(&result.error);
+ let err = String::from_utf8_lossy(&result.stderr);
// the span should end the line (e.g no extra ~'s)
let expected_span = format!("^{}\n", repeat("~").take(n - 1)
}
// Extra characters. Every line is preceded by `filename:lineno <actual code>`
- let offset = main_file.as_str().unwrap().len() + 3;
+ let offset = main_file.to_str().unwrap().len() + 3;
let result = Command::new("sh")
.arg("-c")
.arg(format!("{} {}",
rustc,
- main_file.as_str()
- .unwrap()))
+ main_file.display()))
.output().unwrap();
- let err = String::from_utf8_lossy(result.error.as_slice());
+ let err = String::from_utf8_lossy(&result.stderr);
// Test both the length of the snake and the leading spaces up to it
// compile-flags:-g
// ignore-pretty as this critically relies on line numbers
-use std::old_io::stderr;
+use std::io;
+use std::io::prelude::*;
use std::env;
#[path = "backtrace-debuginfo-aux.rs"] mod aux;
fn run_test(me: &str) {
use std::str;
- use std::old_io::process::Command;
+ use std::process::Command;
let mut template = Command::new(me);
template.env("RUST_BACKTRACE", "1");
let mut i = 0;
loop {
- let p = template.clone().arg(i.to_string()).spawn().unwrap();
- let out = p.wait_with_output().unwrap();
- let output = str::from_utf8(&out.output).unwrap();
- let error = str::from_utf8(&out.error).unwrap();
+ let out = Command::new(me)
+ .env("RUST_BACKTRACE", "1")
+ .arg(i.to_string()).output().unwrap();
+ let output = str::from_utf8(&out.stdout).unwrap();
+ let error = str::from_utf8(&out.stderr).unwrap();
if out.status.success() {
assert!(output.contains("done."), "bad output for successful run: {}", output);
break;
let args: Vec<String> = env::args().collect();
if args.len() >= 2 {
let case = args[1].parse().unwrap();
- writeln!(&mut stderr(), "test case {}", case).unwrap();
+ writeln!(&mut io::stderr(), "test case {}", case).unwrap();
outer(case, pos!());
println!("done.");
} else {
use log::{set_logger, Logger, LogRecord};
use std::sync::mpsc::channel;
use std::fmt;
-use std::old_io::{ChanReader, ChanWriter};
+use std::old_io::{ChanReader, ChanWriter, Reader, Writer};
use std::thread::Thread;
struct MyWriter(ChanWriter);
// no-pretty-expanded
-#![allow(unused_must_use, dead_code, deprecated)]
-use std::old_io::MemWriter;
+use std::io::Write;
use std::fmt;
struct Foo<'a> {
- writer: &'a mut (Writer+'a),
+ writer: &'a mut (Write+'a),
other: &'a str,
}
}
fn main() {
- let mut w = MemWriter::new();
- write!(&mut w as &mut Writer, "");
+ let mut w = Vec::new();
+ write!(&mut w as &mut Write, "");
write!(&mut w, ""); // should coerce
println!("ok");
impl Index<uint> for S {
type Output = str;
- fn index<'a>(&'a self, _: &uint) -> &'a str {
+ fn index<'a>(&'a self, _: uint) -> &'a str {
"hello"
}
}
impl Index<uint> for T {
type Output = Debug + 'static;
- fn index<'a>(&'a self, idx: &uint) -> &'a (Debug + 'static) {
+ fn index<'a>(&'a self, idx: uint) -> &'a (Debug + 'static) {
static X: uint = 42;
&X as &(Debug + 'static)
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![feature(convert)]
+
use std::env::*;
use std::path::PathBuf;
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") {
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")));
}
fn desugared_for_loop_bad(byte: u8) -> u8 {
let mut result = 0;
- let mut x = IntoIterator::into_iter(range(0, u8::BITS));
+ let mut x = IntoIterator::into_iter(0..u8::BITS);
let mut y = Iterator::next(&mut x);
let mut z = y.unwrap();
byte >> z;
// except according to those terms.
use std::env;
-use std::old_io::{stdio, Command};
+use std::process::Command;
+use std::io::{self, Write};
fn main() {
let mut args = env::args();
if args.len() > 1 {
- let mut out = stdio::stdout();
+ let mut out = io::stdout();
out.write(&['a' as u8; 128 * 1024]).unwrap();
} else {
let out = Command::new(&args.next().unwrap()).arg("child").output();
impl<T> Index<(uint, uint)> for Mat<T> {
type Output = T;
- fn index<'a>(&'a self, &(row, col): &(uint, uint)) -> &'a T {
+ fn index<'a>(&'a self, (row, col): (uint, uint)) -> &'a T {
&self.data[row * self.cols + col]
}
}
impl<'a, T> Index<(uint, uint)> for &'a Mat<T> {
type Output = T;
- fn index<'b>(&'b self, index: &(uint, uint)) -> &'b T {
+ fn index<'b>(&'b self, index: (uint, uint)) -> &'b T {
(*self).index(index)
}
}
impl<T, M: Index<(uint, uint), Output=T>> Index<uint> for Row<M> {
type Output = T;
- fn index<'a>(&'a self, col: &uint) -> &'a T {
- &self.mat[(self.row, *col)]
+ fn index<'a>(&'a self, col: uint) -> &'a T {
+ &self.mat[(self.row, col)]
}
}
let m = Mat::new(vec!(1, 2, 3, 4, 5, 6), 3);
let r = m.row(1);
- assert!(r.index(&2) == &6);
+ assert!(r.index(2) == &6);
assert!(r[2] == 6);
assert!(r[2] == 6);
assert!(6 == r[2]);
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::old_io::BufReader;
-use std::old_io::BufferedReader;
-use std::old_io::File;
-use std::old_io::IoResult;
+use std::fs::File;
+use std::io::{self, BufReader, Read};
-struct Lexer<R: Reader>
+struct Lexer<R: Read>
{
- reader: BufferedReader<R>,
+ reader: BufReader<R>,
}
-impl<R: Reader> Lexer<R>
+impl<R: Read> Lexer<R>
{
pub fn new_from_reader(r: R) -> Lexer<R>
{
- Lexer{reader: BufferedReader::new(r)}
+ Lexer{reader: BufReader::new(r)}
}
- pub fn new_from_file(p: Path) -> IoResult<Lexer<File>>
+ pub fn new_from_file(p: &str) -> io::Result<Lexer<File>>
{
- Ok(Lexer::new_from_reader(try!(File::open(&p))))
+ Ok(Lexer::new_from_reader(try!(File::open(p))))
}
- pub fn new_from_str<'a>(s: &'a str) -> Lexer<BufReader<'a>>
+ pub fn new_from_str<'a>(s: &'a str) -> Lexer<&'a [u8]>
{
- Lexer::new_from_reader(BufReader::new(s.as_bytes()))
+ Lexer::new_from_reader(s.as_bytes())
}
}
// A reduced version of the rustbook ice. The problem this encountered
// had to do with trans ignoring binders.
-#![feature(associated_types)]
-#![feature(macro_rules)]
-
use std::iter;
use std::os;
-use std::old_io::File;
+use std::fs::File;
+use std::io::prelude::*;
+use std::env;
+use std::path::Path;
-#[allow(unused)]
-pub fn parse_summary<R: Reader>(_: R, _: &Path) {
+pub fn parse_summary<R: Read>(_: R, _: &Path) {
let path_from_root = Path::new("");
- Path::new(iter::repeat("../")
+ Path::new(&iter::repeat("../")
.take(path_from_root.components().count() - 1)
.collect::<String>());
}
-fn main() {
- let cwd = os::getcwd().unwrap();
+fn foo() {
+ let cwd = env::current_dir().unwrap();
let src = cwd.clone();
- let summary = File::open(&src.join("SUMMARY.md"));
+ let summary = File::open(&src.join("SUMMARY.md")).unwrap();
let _ = parse_summary(summary, &src);
}
+
+fn main() {}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// ignore-android
-// ignore-windows
-
// Regression test for #20797.
use std::default::Default;
-use std::old_io::IoResult;
-use std::old_io::fs;
-use std::old_io::fs::PathExtensions;
+use std::io;
+use std::fs;
+use std::path::{PathBuf, Path};
+
+pub trait PathExtensions {
+ fn is_dir(&self) -> bool { false }
+}
+
+impl PathExtensions for PathBuf {}
/// A strategy for acquiring more subpaths to walk.
pub trait Strategy {
- type P: PathExtensions;
- /// Get additional subpaths from a given path.
- fn get_more(&self, item: &Self::P) -> IoResult<Vec<Self::P>>;
- /// Determine whether a path should be walked further.
- /// This is run against each item from `get_more()`.
- fn prune(&self, p: &Self::P) -> bool;
+ type P: PathExtensions;
+ /// Get additional subpaths from a given path.
+ fn get_more(&self, item: &Self::P) -> io::Result<Vec<Self::P>>;
+ /// Determine whether a path should be walked further.
+ /// This is run against each item from `get_more()`.
+ fn prune(&self, p: &Self::P) -> bool;
}
/// The basic fully-recursive strategy. Nothing is pruned.
pub struct Recursive;
impl Strategy for Recursive {
- type P = Path;
- fn get_more(&self, p: &Path) -> IoResult<Vec<Path>> { fs::readdir(p) }
+ type P = PathBuf;
+ fn get_more(&self, p: &PathBuf) -> io::Result<Vec<PathBuf>> {
+ Ok(fs::read_dir(p).unwrap().map(|s| s.unwrap().path()).collect())
+ }
- fn prune(&self, _: &Path) -> bool { false }
+ fn prune(&self, _: &PathBuf) -> bool { false }
}
/// A directory walker of `P` using strategy `S`.
}
impl<S: Strategy> Subpaths<S> {
- /// Create a directory walker with a root path and strategy.
- pub fn new(p: &S::P, strategy: S) -> IoResult<Subpaths<S>> {
- let stack = try!(strategy.get_more(p));
- Ok(Subpaths { stack: stack, strategy: strategy })
- }
+ /// Create a directory walker with a root path and strategy.
+ pub fn new(p: &S::P, strategy: S) -> io::Result<Subpaths<S>> {
+ let stack = try!(strategy.get_more(p));
+ Ok(Subpaths { stack: stack, strategy: strategy })
+ }
}
impl<S: Default + Strategy> Subpaths<S> {
- /// Create a directory walker with a root path and a default strategy.
- pub fn walk(p: &S::P) -> IoResult<Subpaths<S>> {
- Subpaths::new(p, Default::default())
- }
+ /// Create a directory walker with a root path and a default strategy.
+ pub fn walk(p: &S::P) -> io::Result<Subpaths<S>> {
+ Subpaths::new(p, Default::default())
+ }
}
impl<S: Default + Strategy> Default for Subpaths<S> {
- fn default() -> Subpaths<S> {
- Subpaths { stack: Vec::new(), strategy: Default::default() }
- }
+ fn default() -> Subpaths<S> {
+ Subpaths { stack: Vec::new(), strategy: Default::default() }
+ }
}
impl<S: Strategy> Iterator for Subpaths<S> {
- type Item = S::P;
- fn next (&mut self) -> Option<S::P> {
- let mut opt_path = self.stack.pop();
- while opt_path.is_some() && self.strategy.prune(opt_path.as_ref().unwrap()) {
- opt_path = self.stack.pop();
- }
- match opt_path {
- Some(path) => {
- if PathExtensions::is_dir(&path) {
- let result = self.strategy.get_more(&path);
- match result {
- Ok(dirs) => { self.stack.extend(dirs.into_iter()); },
- Err(..) => { }
- }
+ type Item = S::P;
+ fn next (&mut self) -> Option<S::P> {
+ let mut opt_path = self.stack.pop();
+ while opt_path.is_some() && self.strategy.prune(opt_path.as_ref().unwrap()) {
+ opt_path = self.stack.pop();
+ }
+ match opt_path {
+ Some(path) => {
+ if path.is_dir() {
+ let result = self.strategy.get_more(&path);
+ match result {
+ Ok(dirs) => { self.stack.extend(dirs.into_iter()); },
+ Err(..) => { }
+ }
+ }
+ Some(path)
+ }
+ None => None,
}
- Some(path)
- }
- None => None,
}
- }
}
-fn main() {
- let mut walker: Subpaths<Recursive> = Subpaths::walk(&Path::new("/home")).unwrap();
+fn foo() {
+ let mut walker: Subpaths<Recursive> = Subpaths::walk(&PathBuf::new("/home")).unwrap();
}
+
+fn main() {}
--- /dev/null
+// Copyright 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(core)]
+#![allow(warnings)]
+
+use std::intrinsics;
+
+#[derive(Copy)]
+struct Wrap(i64);
+
+// These volatile and atomic intrinsics used to cause an ICE
+
+unsafe fn test_bool(p: &mut bool, v: bool) {
+ intrinsics::volatile_load(p);
+ intrinsics::volatile_store(p, v);
+ intrinsics::atomic_load(p);
+ intrinsics::atomic_cxchg(p, v, v);
+ intrinsics::atomic_store(p, v);
+ intrinsics::atomic_xchg(p, v);
+}
+
+unsafe fn test_immediate_fca(p: &mut Wrap, v: Wrap) {
+ intrinsics::volatile_load(p);
+ intrinsics::volatile_store(p, v);
+ intrinsics::atomic_load(p);
+ intrinsics::atomic_cxchg(p, v, v);
+ intrinsics::atomic_store(p, v);
+ intrinsics::atomic_xchg(p, v);
+}
+
+fn main() {}
use std::collections::HashMap;
fn add_interfaces(managed_ip: String, device: HashMap<String, int>) {
- println!("{}, {}", managed_ip, device["interfaces".to_string()]);
+ println!("{}, {}", managed_ip, device["interfaces"]);
}
pub fn main() {}
fn add_interfaces(store: int, managed_ip: String, device: HashMap<String, json::Json>)
-> Vec<(String, object)> {
- match device["interfaces".to_string()]
- {
+ match device["interfaces"] {
Json::Array(ref interfaces) =>
{
interfaces.iter().map(|interface| {
_ =>
{
println!("Expected list for {} interfaces, found {}", managed_ip,
- device["interfaces".to_string()]);
+ device["interfaces"]);
Vec::new()
}
}
if false {
panic!();
} else {
- let _b = &(*a)[2];
+ let _b = &(*a)[&2];
}
}
let mut m: HashMap<int, A> = HashMap::new();
m.insert(1, A(0, 0));
- let A(ref _a, ref _b) = m[1];
- let (a, b) = match m[1] { A(ref _a, ref _b) => (_a, _b) };
+ let A(ref _a, ref _b) = m[&1];
+ let (a, b) = match m[&1] { A(ref _a, ref _b) => (_a, _b) };
}
// This used to cause an ICE because the retslot for the "return" had the wrong type
fn testcase<'a>() -> Box<Iterator<Item=usize> + 'a> {
- return Box::new(range(0, 3).map(|i| { return i; }));
+ return Box::new((0..3).map(|i| { return i; }));
}
fn main() {
--- /dev/null
+// Copyright 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Binding unsized expressions to ref patterns
+
+pub fn main() {
+ let ref a = *"abcdef";
+ assert_eq!(a, "abcdef");
+
+ match *"12345" {
+ ref b => { assert_eq!(b, "12345") }
+ }
+}
impl ops::Index<bool> for Point {
type Output = int;
- fn index(&self, x: &bool) -> &int {
- if *x {
+ fn index(&self, x: bool) -> &int {
+ if x {
&self.x
} else {
&self.y
// Regression test for issue #152.
pub fn main() {
let mut b: uint = 1_usize;
- while b <= 32_usize {
+ while b < std::mem::size_of::<usize>() {
0_usize << b;
b <<= 1_usize;
println!("{}", b);
}
}
-impl<K: PartialEq + std::fmt::Debug, V:Clone> Index<K> for AssociationList<K,V> {
+impl<'a, K: PartialEq + std::fmt::Debug, V:Clone> Index<&'a K> for AssociationList<K,V> {
type Output = V;
fn index<'a>(&'a self, index: &K) -> &'a V {
list.push(foo.clone(), 22);
list.push(bar.clone(), 44);
- assert!(list[foo] == 22);
- assert!(list[bar] == 44);
+ assert!(list[&foo] == 22);
+ assert!(list[&bar] == 44);
- assert!(list[foo] == 22);
- assert!(list[bar] == 44);
+ assert!(list[&foo] == 22);
+ assert!(list[&bar] == 44);
}
impl Index<int> for Foo {
type Output = int;
- fn index(&self, z: &int) -> &int {
- if *z == 0 {
+ fn index(&self, z: int) -> &int {
+ if z == 0 {
&self.x
} else {
&self.y
}
impl IndexMut<int> for Foo {
- fn index_mut(&mut self, z: &int) -> &mut int {
- if *z == 0 {
+ fn index_mut(&mut self, z: int) -> &mut int {
+ if z == 0 {
&mut self.x
} else {
&mut self.y
impl Index<int> for Foo {
type Output = int;
- fn index(&self, z: &int) -> &int {
- if *z == 0 {
+ fn index(&self, z: int) -> &int {
+ if z == 0 {
&self.x
} else {
&self.y
impl Index<int> for Foo {
type Output = int;
- fn index(&self, z: &int) -> &int {
- if *z == 0 {
+ fn index(&self, z: int) -> &int {
+ if z == 0 {
&self.x
} else {
&self.y
}
impl IndexMut<int> for Foo {
- fn index_mut(&mut self, z: &int) -> &mut int {
- if *z == 0 {
+ fn index_mut(&mut self, z: int) -> &mut int {
+ if z == 0 {
&mut self.x
} else {
&mut self.y
fn main() {
let my_args = env::args().collect::<Vec<_>>();
- let my_cwd = PathBuf::new(os::getcwd().unwrap().as_str().unwrap());
+ let my_cwd = env::current_dir().unwrap();
let my_env = env::vars().collect::<Vec<_>>();
- let my_path = PathBuf::new(os::self_exe_name().unwrap().as_str().unwrap());
+ let my_path = env::current_exe().unwrap();
let my_dir = my_path.parent().unwrap();
let my_ext = my_path.extension().and_then(|s| s.to_str()).unwrap_or("");
// This test can't be a unit test in std,
// because it needs TempDir, which is in extra
-extern crate libc;
-
use std::ffi::CString;
-use std::old_io::TempDir;
-use std::old_io::fs::PathExtensions;
-use std::old_io::fs;
-use std::old_io;
-use std::os;
+use std::fs::{self, TempDir, File, PathExt};
fn rename_directory() {
- unsafe {
- static U_RWX: i32 = (libc::S_IRUSR | libc::S_IWUSR | libc::S_IXUSR) as i32;
-
- let tmpdir = TempDir::new("rename_directory").ok().expect("rename_directory failed");
- let tmpdir = tmpdir.path();
- let old_path = tmpdir.join_many(&["foo", "bar", "baz"]);
- fs::mkdir_recursive(&old_path, old_io::USER_RWX);
- let test_file = &old_path.join("temp.txt");
-
- /* Write the temp input file */
- let fromp = CString::new(test_file.as_vec()).unwrap();
- let modebuf = CString::new(&b"w+b"[..]).unwrap();
- let ostream = libc::fopen(fromp.as_ptr(), modebuf.as_ptr());
- assert!((ostream as uint != 0));
- let s = "hello".to_string();
- let buf = CString::new(&b"hello"[..]).unwrap();
- let write_len = libc::fwrite(buf.as_ptr() as *mut _,
- 1_usize as libc::size_t,
- (s.len() + 1_usize) as libc::size_t,
- ostream);
- assert_eq!(write_len, (s.len() + 1) as libc::size_t);
- assert_eq!(libc::fclose(ostream), (0_usize as libc::c_int));
-
- let new_path = tmpdir.join_many(&["quux", "blat"]);
- fs::mkdir_recursive(&new_path, old_io::USER_RWX);
- fs::rename(&old_path, &new_path.join("newdir"));
- assert!(new_path.join("newdir").is_dir());
- assert!(new_path.join_many(&["newdir", "temp.txt"]).exists());
- }
+ let tmpdir = TempDir::new("rename_directory").ok().expect("rename_directory failed");
+ let tmpdir = tmpdir.path();
+ let old_path = tmpdir.join("foo/bar/baz");
+ fs::create_dir_all(&old_path).unwrap();
+ let test_file = &old_path.join("temp.txt");
+
+ File::create(test_file).unwrap();
+
+ let new_path = tmpdir.join("quux/blat");
+ fs::create_dir_all(&new_path).unwrap();
+ fs::rename(&old_path, &new_path.join("newdir"));
+ assert!(new_path.join("newdir").is_dir());
+ assert!(new_path.join("newdir/temp.txt").exists());
}
pub fn main() { rename_directory() }
--- /dev/null
+// Copyright 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: -C debug-assertions
+
+// Check that we do *not* overflow on a number of edge cases.
+// (compare with test/run-fail/overflowing-{lsh,rsh}*.rs)
+
+// (Work around constant-evaluation)
+fn id<T>(x: T) -> T { x }
+
+fn main() {
+ test_left_shift();
+ test_right_shift();
+}
+
+fn test_left_shift() {
+ // negative rhs can panic, but values in [0,N-1] are okay for iN
+
+ macro_rules! tests {
+ ($iN:ty, $uN:ty, $max_rhs:expr, $expect_i:expr, $expect_u:expr) => { {
+ let x = (1 as $iN) << id(0);
+ assert_eq!(x, 1);
+ let x = (1 as $uN) << id(0);
+ assert_eq!(x, 1);
+ let x = (1 as $iN) << id($max_rhs);
+ assert_eq!(x, $expect_i);
+ let x = (1 as $uN) << id($max_rhs);
+ assert_eq!(x, $expect_u);
+ // high-order bits on LHS are silently discarded without panic.
+ let x = (3 as $iN) << id($max_rhs);
+ assert_eq!(x, $expect_i);
+ let x = (3 as $uN) << id($max_rhs);
+ assert_eq!(x, $expect_u);
+ } }
+ }
+
+ let x = 1_i8 << id(0);
+ assert_eq!(x, 1);
+ let x = 1_u8 << id(0);
+ assert_eq!(x, 1);
+ let x = 1_i8 << id(7);
+ assert_eq!(x, std::i8::MIN);
+ let x = 1_u8 << id(7);
+ assert_eq!(x, 0x80);
+ // high-order bits on LHS are silently discarded without panic.
+ let x = 3_i8 << id(7);
+ assert_eq!(x, std::i8::MIN);
+ let x = 3_u8 << id(7);
+ assert_eq!(x, 0x80);
+
+ // above is (approximately) expanded from:
+ tests!(i8, u8, 7, std::i8::MIN, 0x80_u8);
+
+ tests!(i16, u16, 15, std::i16::MIN, 0x8000_u16);
+ tests!(i32, u32, 31, std::i32::MIN, 0x8000_0000_u32);
+ tests!(i64, u64, 63, std::i64::MIN, 0x8000_0000_0000_0000_u64);
+}
+
+fn test_right_shift() {
+ // negative rhs can panic, but values in [0,N-1] are okay for iN
+
+ macro_rules! tests {
+ ($iN:ty, $uN:ty, $max_rhs:expr,
+ $signbit_i:expr, $highbit_i:expr, $highbit_u:expr) =>
+ { {
+ let x = (1 as $iN) >> id(0);
+ assert_eq!(x, 1);
+ let x = (1 as $uN) >> id(0);
+ assert_eq!(x, 1);
+ let x = ($highbit_i) >> id($max_rhs-1);
+ assert_eq!(x, 1);
+ let x = ($highbit_u) >> id($max_rhs);
+ assert_eq!(x, 1);
+ // sign-bit is carried by arithmetic right shift
+ let x = ($signbit_i) >> id($max_rhs);
+ assert_eq!(x, -1);
+ // low-order bits on LHS are silently discarded without panic.
+ let x = ($highbit_i + 1) >> id($max_rhs-1);
+ assert_eq!(x, 1);
+ let x = ($highbit_u + 1) >> id($max_rhs);
+ assert_eq!(x, 1);
+ let x = ($signbit_i + 1) >> id($max_rhs);
+ assert_eq!(x, -1);
+ } }
+ }
+
+ tests!(i8, u8, 7, std::i8::MIN, 0x40_i8, 0x80_u8);
+ tests!(i16, u16, 15, std::i16::MIN, 0x4000_u16, 0x8000_u16);
+ tests!(i32, u32, 31, std::i32::MIN, 0x4000_0000_u32, 0x8000_0000_u32);
+ tests!(i64, u64, 63, std::i64::MIN,
+ 0x4000_0000_0000_0000_u64, 0x8000_0000_0000_0000_u64);
+}
// Be sure that when a SIGPIPE would have been received that the entire process
// doesn't die in a ball of fire, but rather it's gracefully handled.
-use std::os;
use std::env;
-use std::old_io::PipeStream;
-use std::old_io::Command;
+use std::io::prelude::*;
+use std::io;
+use std::process::{Command, Stdio};
fn test() {
- let os::Pipe { reader, writer } = unsafe { os::pipe().unwrap() };
- let reader = PipeStream::open(reader);
- let mut writer = PipeStream::open(writer);
- drop(reader);
-
- let _ = writer.write(&[1]);
+ let _ = io::stdin().read_line(&mut String::new());
+ io::stdout().write(&[1]);
+ assert!(io::stdout().flush().is_err());
}
fn main() {
}
let mut p = Command::new(&args[0])
+ .stdout(Stdio::piped())
+ .stdin(Stdio::piped())
.arg("test").spawn().unwrap();
+ drop(p.stdout.take());
assert!(p.wait().unwrap().success());
}
impl Index<Range<Foo>> for Foo {
type Output = Foo;
- fn index(&self, index: &Range<Foo>) -> &Foo {
+ fn index(&self, index: Range<Foo>) -> &Foo {
unsafe { COUNT += 1; }
self
}
}
impl Index<RangeTo<Foo>> for Foo {
type Output = Foo;
- fn index(&self, index: &RangeTo<Foo>) -> &Foo {
+ fn index(&self, index: RangeTo<Foo>) -> &Foo {
unsafe { COUNT += 1; }
self
}
}
impl Index<RangeFrom<Foo>> for Foo {
type Output = Foo;
- fn index(&self, index: &RangeFrom<Foo>) -> &Foo {
+ fn index(&self, index: RangeFrom<Foo>) -> &Foo {
unsafe { COUNT += 1; }
self
}
}
impl Index<RangeFull> for Foo {
type Output = Foo;
- fn index(&self, _index: &RangeFull) -> &Foo {
+ fn index(&self, _index: RangeFull) -> &Foo {
unsafe { COUNT += 1; }
self
}
}
impl IndexMut<Range<Foo>> for Foo {
- fn index_mut(&mut self, index: &Range<Foo>) -> &mut Foo {
+ fn index_mut(&mut self, index: Range<Foo>) -> &mut Foo {
unsafe { COUNT += 1; }
self
}
}
impl IndexMut<RangeTo<Foo>> for Foo {
- fn index_mut(&mut self, index: &RangeTo<Foo>) -> &mut Foo {
+ fn index_mut(&mut self, index: RangeTo<Foo>) -> &mut Foo {
unsafe { COUNT += 1; }
self
}
}
impl IndexMut<RangeFrom<Foo>> for Foo {
- fn index_mut(&mut self, index: &RangeFrom<Foo>) -> &mut Foo {
+ fn index_mut(&mut self, index: RangeFrom<Foo>) -> &mut Foo {
unsafe { COUNT += 1; }
self
}
}
impl IndexMut<RangeFull> for Foo {
- fn index_mut(&mut self, _index: &RangeFull) -> &mut Foo {
+ fn index_mut(&mut self, _index: RangeFull) -> &mut Foo {
unsafe { COUNT += 1; }
self
}
pub fn main() {
let t = thread::spawn(move|| child((10, 20, 30, 40, 50, 60, 70, 80, 90)) );
- t.join().ok().unwrap();
+ t.join().ok().unwrap(); // forget Err value, since it doesn't implement Debug
}
fn child(args: (int, int, int, int, int, int, int, int, int)) {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::old_io::fs::PathExtensions;
-use std::old_io::{File, TempDir};
+use std::fs::{File, TempDir};
+use std::io::prelude::*;
pub fn main() {
- let dir = TempDir::new_in(&Path::new("."), "").unwrap();
+ let dir = TempDir::new_in(".", "").unwrap();
let path = dir.path().join("file");
{
Err(..) => unreachable!(),
Ok(f) => {
let mut f = f;
- for _ in 0_usize..1000 {
+ for _ in 0..1000 {
f.write(&[0]);
}
}
}
assert!(path.exists());
- assert_eq!(path.stat().unwrap().size, 1000);
+ assert_eq!(path.metadata().unwrap().len(), 1000);
}
use std::sync::mpsc::channel;
use std::old_io::net::tcp::{TcpListener, TcpStream};
-use std::old_io::{Acceptor, Listener};
+use std::old_io::{Acceptor, Listener, Reader, Writer};
use std::thread::{Builder, Thread};
use std::time::Duration;
// they're in a different location than before. Hence, these tests are all run
// serially here.
+use std::old_path::{Path, GenericPath};
use std::old_io::fs::PathExtensions;
use std::old_io::{fs, TempDir};
use std::old_io;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![allow(unknown_features)]
#![feature(box_syntax)]
-use std::old_io;
+use std::io::{self, Write};
trait Trait {
fn f(&self);
}
}
-fn foo(mut a: Box<Writer>) {
- a.write(b"Hello\n");
-}
+fn foo(mut a: Box<Write>) {}
// FIXME (#22405): Replace `Box::new` with `box` here when/if possible.
let c: &Trait = &a;
c.f();
- let out = old_io::stdout();
+ let out = io::stdout();
foo(Box::new(out));
}
let _b = Foo;
}).join();
- let s = x.err().unwrap().downcast::<&'static str>().ok().unwrap();
+ let s = x.err().unwrap().downcast::<&'static str>().unwrap();
assert_eq!(&**s, "This panic should happen.");
}