+Version 1.0.0-beta (April 2015)
+-------------------------------------
+
+* ~1100 changes, numerous bugfixes
+
+* Highlights
+
+ * The big news is that the vast majority of the standard library
+ is now `#[stable]` -- 75% of the non-deprecated API surface at
+ last count. Numerous crates are now running on stable
+ Rust. Starting with this release, it is not possible to use
+ unstable features on a stable build.
+ * Arithmetic on basic integer types now
+ [checks for overflow in debug builds][overflow].
+
+* Language
+
+ * [`Send` no longer implies `'static`][send-rfc], which made
+ possible the [`thread::scoped` API][scoped]. Scoped threads can
+ borrow data from their parent's stack frame -- safely!
+ * [UFCS now supports trait-less associated paths][moar-ufcs] like
+ `MyType::default()`.
+ * Primitive types [now have inherent methods][prim-inherent],
+ obviating the need for extension traits like `SliceExt`.
+ * Methods with `Self: Sized` in their `where` clause are
+ [considered object-safe][self-sized], allowing many extension
+ traits like `IteratorExt` to be merged into the traits they
+ extended.
+ * You can now [refer to associated types][assoc-where] whose
+ corresponding trait bounds appear only in a `where` clause.
+ * The final bits of [OIBIT landed][oibit-final], meaning that
+ traits like `Send` and `Sync` are now library-defined.
+ * A [Reflect trait][reflect] was introduced, which means that
+ downcasting via the `Any` trait is effectively limited to
+ concrete types. This helps retain the potentially-important
+ "parametricity" property: generic code cannot behave differently
+ for different type arguments except in minor ways.
+ * The `unsafe_destructor` feature is now deprecated in favor of
+ the [new `dropck`][dropck]. This change is a major reduction in
+ unsafe code.
+ * Trait coherence was [revised again][fundamental], this time with
+ an eye toward API evolution over time.
+
+* Libraries
+
+ * The new path and IO modules are complete and `#[stable]`. This
+ was the major library focus for this cycle.
+ * The path API was [revised][path-normalize] to normalize `.`,
+ adjusting the tradeoffs in favor of the most common usage.
+ * A large number of remaining APIs in `std` were also stabilized
+ during this cycle; about 75% of the non-deprecated API surface
+ is now stable.
+ * The new [string pattern API][string-pattern] landed, which makes
+ the string slice API much more internally consistent and flexible.
+ * A shiny [framework for Debug implementations][debug-builder] landed.
+ This makes it possible to opt in to "pretty-printed" debugging output.
+ * A new set of [generic conversion traits][conversion] replaced
+ many existing ad hoc traits.
+ * Generic numeric traits were
+ [completely removed][num-traits]. This was made possible thanks
+ to inherent methods for primitive types, and the removal gives
+ maximal flexibility for designing a numeric hierarchy in the future.
+ * The `Fn` traits are now related via [inheritance][fn-inherit]
+ and provide ergonomic [blanket implementations][fn-blanket].
+ * The `Index` and `IndexMut` traits were changed to
+ [take the index by value][index-value], enabling code like
+ `hash_map["string"]` to work.
+ * `Copy` now [inherits][copy-clone] from `Clone`, meaning that all
+ `Copy` data is known to be `Clone` as well.
+
+* Infrastructure
+
+ * Metadata was tuned, shrinking binaries [by 27%][metadata-shrink].
+ * Much headway was made on ecosystem-wide CI, making it possible
+ to [compare builds for breakage][ci-compare].
+
+[send-rfc]: https://github.com/rust-lang/rfcs/blob/master/text/0458-send-improvements.md
+[scoped]: http://static.rust-lang.org/doc/master/std/thread/fn.scoped.html
+[moar-ufcs]: https://github.com/rust-lang/rust/pull/22172
+[prim-inherent]: https://github.com/rust-lang/rust/pull/23104
+[overflow]: https://github.com/rust-lang/rfcs/blob/master/text/0560-integer-overflow.md
+[metadata-shrink]: https://github.com/rust-lang/rust/pull/22971
+[self-sized]: https://github.com/rust-lang/rust/pull/22301
+[assoc-where]: https://github.com/rust-lang/rust/pull/22512
+[string-pattern]: https://github.com/rust-lang/rust/pull/22466
+[oibit-final]: https://github.com/rust-lang/rust/pull/21689
+[reflect]: https://github.com/rust-lang/rust/pull/23712
+[debug-builder]: https://github.com/rust-lang/rfcs/blob/master/text/0640-debug-improvements.md
+[conversion]: https://github.com/rust-lang/rfcs/pull/529
+[num-traits]: https://github.com/rust-lang/rust/pull/23549
+[index-value]: https://github.com/rust-lang/rust/pull/23601
+[dropck]: https://github.com/rust-lang/rfcs/pull/769
+[fundamental]: https://github.com/rust-lang/rfcs/pull/1023
+[ci-compare]: https://gist.github.com/brson/a30a77836fbec057cbee
+[fn-inherit]: https://github.com/rust-lang/rust/pull/23282
+[fn-blanket]: https://github.com/rust-lang/rust/pull/23895
+[copy-clone]: https://github.com/rust-lang/rust/pull/23860
+[path-normalize]: https://github.com/rust-lang/rust/pull/23229
+
Version 1.0.0-alpha.2 (February 2015)
-------------------------------------
#![feature(std_misc)]
#![feature(test)]
#![feature(path_ext)]
-#![feature(convert)]
#![feature(str_char)]
#![deny(warnings)]
use std::env;
use std::fs;
use std::path::{Path, PathBuf};
-use std::thunk::Thunk;
use getopts::{optopt, optflag, reqopt};
use common::Config;
use common::{Pretty, DebugInfoGdb, DebugInfoLldb, Codegen};
pub fn make_test_closure(config: &Config, testfile: &Path) -> test::TestFn {
let config = (*config).clone();
let testfile = testfile.to_path_buf();
- test::DynTestFn(Thunk::new(move || {
+ test::DynTestFn(Box::new(move || {
runtest::run(config, &testfile)
}))
}
parse_name_value_directive(line, "exec-env").map(|nv| {
// nv is either FOO or FOO=BAR
let mut strs: Vec<String> = nv
- .splitn(1, '=')
+ .splitn(2, '=')
.map(|s| s.to_string())
.collect();
```
# #![feature(core)]
-use std::iter::range_step;
use std::option::Option::{Some, None};
use std::collections::hash_map::{self, HashMap};
fn bar(map1: HashMap<String, usize>, map2: hash_map::HashMap<String, usize>){}
fn main() {
- // Equivalent to 'std::iter::range_step(0, 10, 2);'
- range_step(0, 10, 2);
-
// Equivalent to 'foo(vec![std::option::Option::Some(1.0f64),
// std::option::Option::None]);'
foo(vec![Some(1.0f64), None]);
Implementations are defined with the keyword `impl`.
```
-# #[derive(Copy)]
+# #[derive(Copy, Clone)]
# struct Point {x: f64, y: f64};
# type Surface = i32;
# struct BoundingBox {x: f64, y: f64, width: f64, height: f64};
impl Copy for Circle {}
+impl Clone for Circle {
+ fn clone(&self) -> Circle { *self }
+}
+
impl Shape for Circle {
fn draw(&self, s: Surface) { do_draw_circle(s, *self); }
fn bounding_box(&self) -> BoundingBox {
* [Intrinsics](intrinsics.md)
* [Lang items](lang-items.md)
* [Link args](link-args.md)
+ * [Benchmark Tests](benchmark-tests.md)
+ * [Box Syntax and Patterns](box-syntax-and-patterns.md)
* [Conclusion](conclusion.md)
* [Glossary](glossary.md)
--- /dev/null
+% Benchmark tests
+
+Rust supports benchmark tests, which can test the performance of your
+code. Let's make our `src/lib.rs` look like this (comments elided):
+
+```{rust,ignore}
+#![feature(test)]
+
+extern crate test;
+
+pub fn add_two(a: i32) -> i32 {
+ a + 2
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use test::Bencher;
+
+ #[test]
+ fn it_works() {
+ assert_eq!(4, add_two(2));
+ }
+
+ #[bench]
+ fn bench_add_two(b: &mut Bencher) {
+ b.iter(|| add_two(2));
+ }
+}
+```
+
+Note the `test` feature gate, which enables this unstable feature.
+
+We've imported the `test` crate, which contains our benchmarking support.
+We have a new function as well, with the `bench` attribute. Unlike regular
+tests, which take no arguments, benchmark tests take a `&mut Bencher`. This
+`Bencher` provides an `iter` method, which takes a closure. This closure
+contains the code we'd like to benchmark.
+
+We can run benchmark tests with `cargo bench`:
+
+```bash
+$ cargo bench
+ Compiling adder v0.0.1 (file:///home/steve/tmp/adder)
+ Running target/release/adder-91b3e234d4ed382a
+
+running 2 tests
+test tests::it_works ... ignored
+test tests::bench_add_two ... bench: 1 ns/iter (+/- 0)
+
+test result: ok. 0 passed; 0 failed; 1 ignored; 1 measured
+```
+
+Our non-benchmark test was ignored. You may have noticed that `cargo bench`
+takes a bit longer than `cargo test`. This is because Rust runs our benchmark
+a number of times, and then takes the average. Because we're doing so little
+work in this example, we have a `1 ns/iter (+/- 0)`, but this would show
+the variance if there was one.
+
+Advice on writing benchmarks:
+
+
+* Move setup code outside the `iter` loop; only put the part you want to measure inside
+* Make the code do "the same thing" on each iteration; do not accumulate or change state
+* Make the outer function idempotent too; the benchmark runner is likely to run
+ it many times
+* Make the inner `iter` loop short and fast so benchmark runs are fast and the
+ calibrator can adjust the run-length at fine resolution
+* Make the code in the `iter` loop do something simple, to assist in pinpointing
+ performance improvements (or regressions)
+
+## Gotcha: optimizations
+
+There's another tricky part to writing benchmarks: benchmarks compiled with
+optimizations activated can be dramatically changed by the optimizer so that
+the benchmark is no longer benchmarking what one expects. For example, the
+compiler might recognize that some calculation has no external effects and
+remove it entirely.
+
+```{rust,ignore}
+#![feature(test)]
+
+extern crate test;
+use test::Bencher;
+
+#[bench]
+fn bench_xor_1000_ints(b: &mut Bencher) {
+ b.iter(|| {
+ (0..1000).fold(0, |old, new| old ^ new);
+ });
+}
+```
+
+gives the following results
+
+```text
+running 1 test
+test bench_xor_1000_ints ... bench: 0 ns/iter (+/- 0)
+
+test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured
+```
+
+The benchmarking runner offers two ways to avoid this. Either, the closure that
+the `iter` method receives can return an arbitrary value which forces the
+optimizer to consider the result used and ensures it cannot remove the
+computation entirely. This could be done for the example above by adjusting the
+`b.iter` call to
+
+```rust
+# struct X;
+# impl X { fn iter<T, F>(&self, _: F) where F: FnMut() -> T {} } let b = X;
+b.iter(|| {
+ // note lack of `;` (could also use an explicit `return`).
+ (0..1000).fold(0, |old, new| old ^ new)
+});
+```
+
+Or, the other option is to call the generic `test::black_box` function, which
+is an opaque "black box" to the optimizer and so forces it to consider any
+argument as used.
+
+```rust
+#![feature(test)]
+
+extern crate test;
+
+# fn main() {
+# struct X;
+# impl X { fn iter<T, F>(&self, _: F) where F: FnMut() -> T {} } let b = X;
+b.iter(|| {
+ let n = test::black_box(1000);
+
+ (0..n).fold(0, |a, b| a ^ b)
+})
+# }
+```
+
+Neither of these read or modify the value, and are very cheap for small values.
+Larger values can be passed indirectly to reduce overhead (e.g.
+`black_box(&huge_struct)`).
+
+Performing either of the above changes gives the following benchmarking results
+
+```text
+running 1 test
+test bench_xor_1000_ints ... bench: 131 ns/iter (+/- 3)
+
+test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured
+```
+
+However, the optimizer can still modify a testcase in an undesirable manner
+even when using either of the above.
--- /dev/null
+% Box Syntax and Patterns
+
+Currently the only stable way to create a `Box` is via the `Box::new` method.
+Also it is not possible in stable Rust to destructure a `Box` in a match
+pattern. The unstable `box` keyword can be used to both create and destructure
+a `Box`. An example usage would be:
+
+```
+#![feature(box_syntax, box_patterns)]
+
+fn main() {
+ let b = Some(box 5);
+ match b {
+ Some(box n) if n < 0 => {
+ println!("Box contains negative number {}", n);
+ },
+ Some(box n) if n >= 0 => {
+ println!("Box contains non-negative number {}", n);
+ },
+ None => {
+ println!("No box");
+ },
+ _ => unreachable!()
+ }
+}
+```
+
+Note that these features are currently hidden behind the `box_syntax` (box
+creation) and `box_patterns` (destructuring and pattern matching) gates
+because the syntax may still change in the future.
+
+# Returning Pointers
+
+In many languages with pointers, you'd return a pointer from a function
+so as to avoid copying a large data structure. For example:
+
+```{rust}
+struct BigStruct {
+ one: i32,
+ two: i32,
+ // etc
+ one_hundred: i32,
+}
+
+fn foo(x: Box<BigStruct>) -> Box<BigStruct> {
+ Box::new(*x)
+}
+
+fn main() {
+ let x = Box::new(BigStruct {
+ one: 1,
+ two: 2,
+ one_hundred: 100,
+ });
+
+ let y = foo(x);
+}
+```
+
+The idea is that by passing around a box, you're only copying a pointer, rather
+than the hundred `int`s that make up the `BigStruct`.
+
+This is an antipattern in Rust. Instead, write this:
+
+```rust
+#![feature(box_syntax)]
+
+struct BigStruct {
+ one: i32,
+ two: i32,
+ // etc
+ one_hundred: i32,
+}
+
+fn foo(x: Box<BigStruct>) -> BigStruct {
+ *x
+}
+
+fn main() {
+ let x = Box::new(BigStruct {
+ one: 1,
+ two: 2,
+ one_hundred: 100,
+ });
+
+ let y: Box<BigStruct> = box foo(x);
+}
+```
+
+This gives you flexibility without sacrificing performance.
+
+You may think that this gives us terrible performance: return a value and then
+immediately box it up ?! Isn't this pattern the worst of both worlds? Rust is
+smarter than that. There is no copy in this code. `main` allocates enough room
+for the `box`, passes a pointer to that memory into `foo` as `x`, and then
+`foo` writes the value straight into the `Box<T>`.
+
+This is important enough that it bears repeating: pointers are not for
+optimizing returning values from your code. Allow the caller to choose how they
+want to use your output.
% Closures
-So far, we've made lots of functions in Rust, but we've given them all names.
-Rust also allows us to create anonymous functions. Rust's anonymous
-functions are called *closures*. By themselves, closures aren't all that
-interesting, but when you combine them with functions that take closures as
-arguments, really powerful things are possible.
+Rust not only has named functions, but anonymous functions as well. Anonymous
+functions that have an associated environment are called 'closures', because they
+close over an environment. Rust has a really great implementation of them, as
+we'll see.
-Let's make a closure:
+# Syntax
-```{rust}
-let add_one = |x| { 1 + x };
+Closures look like this:
-println!("The sum of 5 plus 1 is {}.", add_one(5));
+```rust
+let plus_one = |x: i32| x + 1;
+
+assert_eq!(2, plus_one(1));
+```
+
+We create a binding, `plus_one`, and assign it to a closure. The closure's
+arguments go between the pipes (`|`), and the body is an expression, in this
+case, `x + 1`. Remember that `{ }` is an expression, so we can have multi-line
+closures too:
+
+```rust
+let plus_two = |x| {
+ let mut result: i32 = x;
+
+ result += 1;
+ result += 1;
+
+ result
+};
+
+assert_eq!(4, plus_two(2));
+```
+
+You'll notice a few things about closures that are a bit different than regular
+functions defined with `fn`. The first of which is that we did not need to
+annotate the types of arguments the closure takes or the values it returns. We
+can:
+
+```rust
+let plus_one = |x: i32| -> i32 { x + 1 };
+
+assert_eq!(2, plus_one(1));
+```
+
+But we don't have to. Why is this? Basically, it was chosen for ergonomic reasons.
+While specifying the full type for named functions is helpful with things like
+documentation and type inference, the types of closures are rarely documented
+since they’re anonymous, and they don’t cause the kinds of error-at-a-distance
+that inferring named function types can.
+
+The second is that the syntax is similar, but a bit different. I've added spaces
+here to make them look a little closer:
+
+```rust
+fn plus_one_v1 ( x: i32 ) -> i32 { x + 1 }
+let plus_one_v2 = |x: i32 | -> i32 { x + 1 };
+let plus_one_v3 = |x: i32 | x + 1 ;
```
-We create a closure using the `|...| { ... }` syntax, and then we create a
-binding so we can use it later. Note that we call the function using the
-binding name and two parentheses, just like we would for a named function.
+Small differences, but they're similar in ways.
-Let's compare syntax. The two are pretty close:
+# Closures and their environment
-```{rust}
-let add_one = |x: i32| -> i32 { 1 + x };
-fn add_one (x: i32) -> i32 { 1 + x }
+Closures are called such because they 'close over their environment.' It
+looks like this:
+
+```rust
+let num = 5;
+let plus_num = |x: i32| x + num;
+
+assert_eq!(10, plus_num(5));
```
-As you may have noticed, closures infer their argument and return types, so you
-don't need to declare one. This is different from named functions, which
-default to returning unit (`()`).
+This closure, `plus_num`, refers to a `let` binding in its scope: `num`. More
+specifically, it borrows the binding. If we do something that would conflict
+with that binding, we get an error. Like this one:
+
+```rust,ignore
+let mut num = 5;
+let plus_num = |x: i32| x + num;
-There's one big difference between a closure and named functions, and it's in
-the name: a closure "closes over its environment." What does that mean? It means
-this:
+let y = &mut num;
+```
-```{rust}
+Which errors with:
+
+```text
+error: cannot borrow `num` as mutable because it is also borrowed as immutable
+ let y = &mut num;
+ ^~~
+note: previous borrow of `num` occurs here due to use in closure; the immutable
+ borrow prevents subsequent moves or mutable borrows of `num` until the borrow
+ ends
+ let plus_num = |x| x + num;
+ ^~~~~~~~~~~
+note: previous borrow ends here
fn main() {
- let x: i32 = 5;
+ let mut num = 5;
+ let plus_num = |x| x + num;
+
+ let y = &mut num;
+}
+^
+```
+
+A verbose yet helpful error message! As it says, we can't take a mutable borrow
+on `num` because the closure is already borrowing it. If we let the closure go
+out of scope, we can:
+
+```rust
+let mut num = 5;
+{
+ let plus_num = |x: i32| x + num;
+
+} // plus_num goes out of scope, borrow of num ends
- let printer = || { println!("x is: {}", x); };
+let y = &mut num;
+```
+
+If your closure requires it, however, Rust will take ownership and move
+the environment instead:
+
+```rust,ignore
+let nums = vec![1, 2, 3];
+
+let takes_nums = || nums;
+
+println!("{:?}", nums);
+```
+
+This gives us:
+
+```text
+note: `nums` moved into closure environment here because it has type
+ `[closure(()) -> collections::vec::Vec<i32>]`, which is non-copyable
+let takes_nums = || nums;
+ ^~~~~~~
+```
+
+`Vec<T>` has ownership over its contents, and therefore, when we refer to it
+in our closure, we have to take ownership of `nums`. It's the same as if we'd
+passed `nums` to a function that took ownership of it.
+
+## `move` closures
+
+We can force our closure to take ownership of its environment with the `move`
+keyword:
- printer(); // prints "x is: 5"
+```rust
+let num = 5;
+
+let owns_num = move |x: i32| x + num;
+```
+
+Now, even though the keyword is `move`, the variables follow normal move semantics.
+In this case, `5` implements `Copy`, and so `owns_num` takes ownership of a copy
+of `num`. So what's the difference?
+
+```rust
+let mut num = 5;
+
+{
+ let mut add_num = |x: i32| num += x;
+
+ add_num(5);
}
+
+assert_eq!(10, num);
```
-The `||` syntax means this is an anonymous closure that takes no arguments.
-Without it, we'd just have a block of code in `{}`s.
+So in this case, our closure took a mutable reference to `num`, and then when
+we called `add_num`, it mutated the underlying value, as we'd expect. We also
+needed to declare `add_num` as `mut` too, because we’re mutating its
+environment.
-In other words, a closure has access to variables in the scope where it's
-defined. The closure borrows any variables it uses, so this will error:
+We also had to declare `add_num` as mut, since we will be modifying its
+environment.
-```{rust,ignore}
-fn main() {
- let mut x: i32 = 5;
+If we change to a `move` closure, it's different:
+
+```rust
+let mut num = 5;
- let printer = || { println!("x is: {}", x); };
+{
+ let mut add_num = move |x: i32| num += x;
- x = 6; // error: cannot assign to `x` because it is borrowed
+ add_num(5);
}
+
+assert_eq!(5, num);
```
-## Moving closures
+We only get `5`. Rather than taking a mutable borrow out on our `num`, we took
+ownership of a copy.
+
+Another way to think about `move` closures: they give a closure its own stack
+frame. Without `move`, a closure may be tied to the stack frame that created
+it, while a `move` closure is self-contained. This means that you cannot
+generally return a non-`move` closure from a function, for example.
+
+But before we talk about taking and returning closures, we should talk some more
+about the way that closures are implemented. As a systems language, Rust gives
+you tons of control over what your code does, and closures are no different.
-Rust has a second type of closure, called a *moving closure*. Moving
-closures are indicated using the `move` keyword (e.g., `move || x *
-x`). The difference between a moving closure and an ordinary closure
-is that a moving closure always takes ownership of all variables that
-it uses. Ordinary closures, in contrast, just create a reference into
-the enclosing stack frame. Moving closures are most useful with Rust's
-concurrency features, and so we'll just leave it at this for
-now. We'll talk about them more in the "Concurrency" chapter of the book.
+# Closure implementation
-## Accepting closures as arguments
+Rust's implementation of closures is a bit different than other languages. They
+are effectively syntax sugar for traits. You'll want to make sure to have read
+the [traits chapter][traits] before this one, as well as the chapter on [static
+and dynamic dispatch][dispatch], which talks about trait objects.
-Closures are most useful as an argument to another function. Here's an example:
+[traits]: traits.html
+[dispatch]: static-and-dynamic-dispatch.html
-```{rust}
-fn twice<F: Fn(i32) -> i32>(x: i32, f: F) -> i32 {
- f(x) + f(x)
+Got all that? Good.
+
+The key to understanding how closures work under the hood is something a bit
+strange: Using `()` to call a function, like `foo()`, is an overloadable
+operator. From this, everything else clicks into place. In Rust, we use the
+trait system to overload operators. Calling functions is no different. We have
+three separate traits to overload with:
+
+```rust
+# mod foo {
+pub trait Fn<Args> : FnMut<Args> {
+ extern "rust-call" fn call(&self, args: Args) -> Self::Output;
}
-fn main() {
- let square = |x: i32| { x * x };
+pub trait FnMut<Args> : FnOnce<Args> {
+ extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output;
+}
+
+pub trait FnOnce<Args> {
+ type Output;
- twice(5, square); // evaluates to 50
+ extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
}
+# }
```
-Let's break the example down, starting with `main`:
+You'll notice a few differences between these traits, but a big one is `self`:
+`Fn` takes `&self`, `FnMut` takes `&mut self`, and `FnOnce` takes `self`. This
+covers all three kinds of `self` via the usual method call syntax. But we've
+split them up into three traits, rather than having a single one. This gives us
+a large amount of control over what kind of closures we can take.
-```{rust}
-let square = |x: i32| { x * x };
-```
+The `|| {}` syntax for closures is sugar for these three traits. Rust will
+generate a struct for the environment, `impl` the appropriate trait, and then
+use it.
+
+# Taking closures as arguments
+
+Now that we know that closures are traits, we already know how to accept and
+return closures: just like any other trait!
+
+This also means that we can choose static vs dynamic dispatch as well. First,
+let's write a function which takes something callable, calls it, and returns
+the result:
+
+```rust
+fn call_with_one<F>(some_closure: F) -> i32
+ where F : Fn(i32) -> i32 {
+
+ some_closure(1)
+}
-We've seen this before. We make a closure that takes an integer, and returns
-its square.
+let answer = call_with_one(|x| x + 2);
-```{rust}
-# fn twice<F: Fn(i32) -> i32>(x: i32, f: F) -> i32 { f(x) + f(x) }
-# let square = |x: i32| { x * x };
-twice(5, square); // evaluates to 50
+assert_eq!(3, answer);
```
-This line is more interesting. Here, we call our function, `twice`, and we pass
-it two arguments: an integer, `5`, and our closure, `square`. This is just like
-passing any other two variable bindings to a function, but if you've never
-worked with closures before, it can seem a little complex. Just think: "I'm
-passing two variables: one is an i32, and one is a function."
+We pass our closure, `|x| x + 2`, to `call_with_one`. It just does what it
+suggests: it calls the closure, giving it `1` as an argument.
-Next, let's look at how `twice` is defined:
+Let's examine the signature of `call_with_one` in more depth:
-```{rust,ignore}
-fn twice<F: Fn(i32) -> i32>(x: i32, f: F) -> i32 {
+```rust
+fn call_with_one<F>(some_closure: F) -> i32
+# where F : Fn(i32) -> i32 {
+# some_closure(1) }
```
-`twice` takes two arguments, `x` and `f`. That's why we called it with two
-arguments. `x` is an `i32`, we've done that a ton of times. `f` is a function,
-though, and that function takes an `i32` and returns an `i32`. This is
-what the requirement `Fn(i32) -> i32` for the type parameter `F` says.
-Now `F` represents *any* function that takes an `i32` and returns an `i32`.
+We take one parameter, and it has the type `F`. We also return a `i32`. This part
+isn't interesting. The next part is:
-This is the most complicated function signature we've seen yet! Give it a read
-a few times until you can see how it works. It takes a teeny bit of practice, and
-then it's easy. The good news is that this kind of passing a closure around
-can be very efficient. With all the type information available at compile-time
-the compiler can do wonders.
+```rust
+# fn call_with_one<F>(some_closure: F) -> i32
+ where F : Fn(i32) -> i32 {
+# some_closure(1) }
+```
+
+Because `Fn` is a trait, we can bound our generic with it. In this case, our closure
+takes a `i32` as an argument and returns an `i32`, and so the generic bound we use
+is `Fn(i32) -> i32`.
-Finally, `twice` returns an `i32` as well.
+There's one other key point here: because we're bounding a generic with a
+trait, this will get monomorphized, and therefore, we'll be doing static
+dispatch into the closure. That's pretty neat. In many langauges, closures are
+inherently heap allocated, and will always involve dynamic dispatch. In Rust,
+we can stack allocate our closure environment, and statically dispatch the
+call. This happens quite often with iterators and their adapters, which often
+take closures as arguments.
-Okay, let's look at the body of `twice`:
+Of course, if we want dynamic dispatch, we can get that too. A trait object
+handles this case, as usual:
-```{rust}
-fn twice<F: Fn(i32) -> i32>(x: i32, f: F) -> i32 {
- f(x) + f(x)
+```rust
+fn call_with_one(some_closure: &Fn(i32) -> i32) -> i32 {
+ some_closure(1)
}
+
+let answer = call_with_one(&|x| x + 2);
+
+assert_eq!(3, answer);
```
-Since our closure is named `f`, we can call it just like we called our closures
-before, and we pass in our `x` argument to each one, hence the name `twice`.
+Now we take a trait object, a `&Fn`. And we have to make a reference
+to our closure when we pass it to `call_with_one`, so we use `&||`.
-If you do the math, `(5 * 5) + (5 * 5) == 50`, so that's the output we get.
+# Returning closures
-Play around with this concept until you're comfortable with it. Rust's standard
-library uses lots of closures where appropriate, so you'll be using
-this technique a lot.
+It’s very common for functional-style code to return closures in various
+situations. If you try to return a closure, you may run into an error. At
+first, it may seem strange, but we'll figure it out. Here's how you'd probably
+try to return a closure from a function:
-If we didn't want to give `square` a name, we could just define it inline.
-This example is the same as the previous one:
+```rust,ignore
+fn factory() -> (Fn(i32) -> Vec<i32>) {
+ let vec = vec![1, 2, 3];
-```{rust}
-fn twice<F: Fn(i32) -> i32>(x: i32, f: F) -> i32 {
- f(x) + f(x)
+ |n| vec.push(n)
}
-fn main() {
- twice(5, |x: i32| { x * x }); // evaluates to 50
-}
+let f = factory();
+
+let answer = f(4);
+assert_eq!(vec![1, 2, 3, 4], answer);
```
-A named function's name can be used wherever you'd use a closure. Another
-way of writing the previous example:
+This gives us these long, related errors:
+
+```text
+error: the trait `core::marker::Sized` is not implemented for the type
+`core::ops::Fn(i32) -> collections::vec::Vec<i32>` [E0277]
+f = factory();
+^
+note: `core::ops::Fn(i32) -> collections::vec::Vec<i32>` does not have a
+constant size known at compile-time
+f = factory();
+^
+error: the trait `core::marker::Sized` is not implemented for the type
+`core::ops::Fn(i32) -> collections::vec::Vec<i32>` [E0277]
+factory() -> (Fn(i32) -> Vec<i32>) {
+ ^~~~~~~~~~~~~~~~~~~~~
+note: `core::ops::Fn(i32) -> collections::vec::Vec<i32>` does not have a constant size known at compile-time
+fa ctory() -> (Fn(i32) -> Vec<i32>) {
+ ^~~~~~~~~~~~~~~~~~~~~
-```{rust}
-fn twice<F: Fn(i32) -> i32>(x: i32, f: F) -> i32 {
- f(x) + f(x)
-}
+```
-fn square(x: i32) -> i32 { x * x }
+In order to return something from a function, Rust needs to know what
+size the return type is. But since `Fn` is a trait, it could be various
+things of various sizes: many different types can implement `Fn`. An easy
+way to give something a size is to take a reference to it, as references
+have a known size. So we'd write this:
-fn main() {
- twice(5, square); // evaluates to 50
+```rust,ignore
+fn factory() -> &(Fn(i32) -> Vec<i32>) {
+ let vec = vec![1, 2, 3];
+
+ |n| vec.push(n)
}
+
+let f = factory();
+
+let answer = f(4);
+assert_eq!(vec![1, 2, 3, 4], answer);
+```
+
+But we get another error:
+
+```text
+error: missing lifetime specifier [E0106]
+fn factory() -> &(Fn(i32) -> i32) {
+ ^~~~~~~~~~~~~~~~~
```
-Doing this is not particularly common, but it's useful every once in a while.
+Right. Because we have a reference, we need to give it a lifetime. But
+our `factory()` function takes no arguments, so elision doesn't kick in
+here. What lifetime can we choose? `'static`:
-Before we move on, let us look at a function that accepts two closures.
+```rust,ignore
+fn factory() -> &'static (Fn(i32) -> i32) {
+ let num = 5;
-```{rust}
-fn compose<F, G>(x: i32, f: F, g: G) -> i32
- where F: Fn(i32) -> i32, G: Fn(i32) -> i32 {
- g(f(x))
+ |x| x + num
}
-fn main() {
- compose(5,
- |n: i32| { n + 42 },
- |n: i32| { n * 2 }); // evaluates to 94
+let f = factory();
+
+let answer = f(1);
+assert_eq!(6, answer);
+```
+
+But we get another error:
+
+```text
+error: mismatched types:
+ expected `&'static core::ops::Fn(i32) -> i32`,
+ found `[closure <anon>:7:9: 7:20]`
+(expected &-ptr,
+ found closure) [E0308]
+ |x| x + num
+ ^~~~~~~~~~~
+
+```
+
+This error is letting us know that we don't have a `&'static Fn(i32) -> i32`,
+we have a `[closure <anon>:7:9: 7:20]`. Wait, what?
+
+Because each closure generates its own environment `struct` and implementation
+of `Fn` and friends, these types are anonymous. They exist just solely for
+this closure. So Rust shows them as `closure <anon>`, rather than some
+autogenerated name.
+
+But why doesn't our closure implement `&'static Fn`? Well, as we discussed before,
+closures borrow their environment. And in this case, our environment is based
+on a stack-allocated `5`, the `num` variable binding. So the borrow has a lifetime
+of the stack frame. So if we returned this closure, the function call would be
+over, the stack frame would go away, and our closure is capturing an environment
+of garbage memory!
+
+So what to do? This _almost_ works:
+
+```rust,ignore
+fn factory() -> Box<Fn(i32) -> i32> {
+ let num = 5;
+
+ Box::new(|x| x + num)
}
+# fn main() {
+let f = factory();
+
+let answer = f(1);
+assert_eq!(6, answer);
+# }
```
-You might ask yourself: why do we need to introduce two type
-parameters `F` and `G` here? Evidently, both `f` and `g` have the
-same signature: `Fn(i32) -> i32`.
+We use a trait object, by `Box`ing up the `Fn`. There's just one last problem:
-That is because in Rust each closure has its own unique type.
-So, not only do closures with different signatures have different types,
-but different closures with the *same* signature have *different*
-types, as well!
+```text
+error: `num` does not live long enough
+Box::new(|x| x + num)
+ ^~~~~~~~~~~
+```
+
+We still have a reference to the parent stack frame. With one last fix, we can
+make this work:
-You can think of it this way: the behavior of a closure is part of its
-type. Therefore, using a single type parameter for both closures
-will accept the first of them, rejecting the second. The distinct
-type of the second closure does not allow it to be represented by the
-same type parameter as that of the first. We acknowledge this, and
-use two different type parameters `F` and `G`.
+```rust
+fn factory() -> Box<Fn(i32) -> i32> {
+ let num = 5;
-This also introduces the `where` clause, which lets us describe type
-parameters in a more flexible manner.
+ Box::new(move |x| x + num)
+}
+# fn main() {
+let f = factory();
+
+let answer = f(1);
+assert_eq!(6, answer);
+# }
+```
-That's all you need to get the hang of closures! Closures are a little bit
-strange at first, but once you're used to them, you'll miss them
-in other languages. Passing functions to other functions is
-incredibly powerful, as you will see in the following chapter about iterators.
+By making the inner closure a `move Fn`, we create a new stack frame for our
+closure. By `Box`ing it up, we've given it a known size, and allowing it to
+escape our stack frame.
it to get a reference to the data. Real code would have more robust error handling
here. We're then free to mutate it, since we have the lock.
-This timer bit is a bit awkward, however. We have picked a reasonable amount of
-time to wait, but it's entirely possible that we've picked too high, and that
-we could be taking less time. It's also possible that we've picked too low,
-and that we aren't actually finishing this computation.
-
-Rust's standard library provides a few more mechanisms for two threads to
-synchronize with each other. Let's talk about one: channels.
+Lastly, while the threads are running, we wait on a short timer. But
+this is not ideal: we may have picked a reasonable amount of time to
+wait but it's more likely we'll either be waiting longer than
+necessary or not long enough, depending on just how much time the
+threads actually take to finish computing when the program runs.
+
+A more precise alternative to the timer would be to use one of the
+mechanisms provided by the Rust standard library for synchronizing
+threads with each other. Let's talk about one of them: channels.
## Channels
# Upgrading failures to panics
In certain circumstances, even though a function may fail, we may want to treat
-it as a panic instead. For example, `io::stdin().read_line()` returns an
-`IoResult<String>`, a form of `Result`, when there is an error reading the
-line. This allows us to handle and possibly recover from this sort of error.
+it as a panic instead. For example, `io::stdin().read_line(&mut buffer)` returns
+an `Result<usize>`, when there is an error reading the line. This allows us to
+handle and possibly recover from error.
If we don't want to handle this error, and would rather just abort the program,
we can use the `unwrap()` method:
```{rust,ignore}
-io::stdin().read_line().unwrap();
+io::stdin().read_line(&mut buffer).unwrap();
```
`unwrap()` will `panic!` if the `Option` is `None`. This basically says "Give
There's another way of doing this that's a bit nicer than `unwrap()`:
```{rust,ignore}
-let input = io::stdin().read_line()
+let mut buffer = String::new();
+let input = io::stdin().read_line(&mut buffer)
.ok()
.expect("Failed to read line");
```
-`ok()` converts the `IoResult` into an `Option`, and `expect()` does the same
+`ok()` converts the `Result` into an `Option`, and `expect()` does the same
thing as `unwrap()`, but takes a message. This message is passed along to the
underlying `panic!`, providing a better error message if the code errors.
```
These two basic iterators should serve you well. There are some more
-advanced iterators, including ones that are infinite. Like `count`:
+advanced iterators, including ones that are infinite. Like using range syntax
+and `step_by`:
```rust
-# #![feature(core)]
-std::iter::count(1, 5);
+# #![feature(step_by)]
+(1..).step_by(5);
```
This iterator counts up from one, adding five each time. It will give
There are tons of interesting iterator adapters. `take(n)` will return an
iterator over the next `n` elements of the original iterator, note that this
has no side effect on the original iterator. Let's try it out with our infinite
-iterator from before, `count()`:
+iterator from before:
```rust
-# #![feature(core)]
-for i in std::iter::count(1, 5).take(5) {
+# #![feature(step_by)]
+for i in (1..).step_by(5).take(5) {
println!("{}", i);
}
```
```rust
let x: Vec<u32> = vec![1, 2, 3];
-# assert_eq!(&[1,2,3], &x);
+# assert_eq!(x, [1, 2, 3]);
```
This can't be an ordinary function, because it takes any number of arguments.
temp_vec.push(3);
temp_vec
};
-# assert_eq!(&[1,2,3], &x);
+# assert_eq!(x, [1, 2, 3]);
```
We can implement this shorthand, using a macro: [^actual]
};
}
# fn main() {
-# assert_eq!([1,2,3], vec![1,2,3]);
+# assert_eq!(vec![1,2,3], [1, 2, 3]);
# }
```
the item signature alone. However, for ergonomic reasons a very restricted
secondary inference algorithm called “lifetime elision” applies in function
signatures. It infers only based on the signature components themselves and not
-based on the body of the function, only infers lifetime paramters, and does
+based on the body of the function, only infers lifetime parameters, and does
this with only three easily memorizable and unambiguous rules. This makes
lifetime elision a shorthand for writing an item signature, while not hiding
away the actual types involved as full local inference would if applied to it.
```
We can mutably borrow `x` multiple times, but only if x itself is mutable, and
-it may not be *simultaneously* borrowed:
+it may not be *simultaneously* borrowed:
```{rust,ignore}
fn increment(x: &mut i32) {
## Best practices
-Boxes are appropriate to use in two situations: Recursive data structures,
-and occasionally, when returning data.
+Boxes are most appropriate to use when defining recursive data structures.
### Recursive data structures
Working with recursive or other unknown-sized data structures is the primary
use-case for boxes.
-### Returning data
-
-This is important enough to have its own section entirely. The TL;DR is this:
-you don't want to return pointers, even when you might in a language like C or
-C++.
-
-See [Returning Pointers](#returning-pointers) below for more.
-
# Rc and Arc
This part is coming soon.
This part is coming soon.
-# Returning Pointers
-
-In many languages with pointers, you'd return a pointer from a function
-so as to avoid copying a large data structure. For example:
-
-```{rust}
-struct BigStruct {
- one: i32,
- two: i32,
- // etc
- one_hundred: i32,
-}
-
-fn foo(x: Box<BigStruct>) -> Box<BigStruct> {
- Box::new(*x)
-}
-
-fn main() {
- let x = Box::new(BigStruct {
- one: 1,
- two: 2,
- one_hundred: 100,
- });
-
- let y = foo(x);
-}
-```
-
-The idea is that by passing around a box, you're only copying a pointer, rather
-than the hundred `int`s that make up the `BigStruct`.
-
-This is an antipattern in Rust. Instead, write this:
-
-```rust
-#![feature(box_syntax)]
-
-struct BigStruct {
- one: i32,
- two: i32,
- // etc
- one_hundred: i32,
-}
-
-fn foo(x: Box<BigStruct>) -> BigStruct {
- *x
-}
-
-fn main() {
- let x = Box::new(BigStruct {
- one: 1,
- two: 2,
- one_hundred: 100,
- });
-
- let y: Box<BigStruct> = box foo(x);
-}
-```
-
-Note that this uses the `box_syntax` feature gate, so this syntax may change in
-the future.
-
-This gives you flexibility without sacrificing performance.
-
-You may think that this gives us terrible performance: return a value and then
-immediately box it up ?! Isn't this pattern the worst of both worlds? Rust is
-smarter than that. There is no copy in this code. `main` allocates enough room
-for the `box`, passes a pointer to that memory into `foo` as `x`, and then
-`foo` writes the value straight into the `Box<T>`.
-
-This is important enough that it bears repeating: pointers are not for
-optimizing returning values from your code. Allow the caller to choose how they
-want to use your output.
-
# Creating your own Pointers
This part is coming soon.
for the function test. These will auto increment with names like `add_two_1` as
you add more examples.
-# Benchmark tests
-
-Rust also supports benchmark tests, which can test the performance of your
-code. Let's make our `src/lib.rs` look like this (comments elided):
-
-```{rust,ignore}
-extern crate test;
-
-pub fn add_two(a: i32) -> i32 {
- a + 2
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
- use test::Bencher;
-
- #[test]
- fn it_works() {
- assert_eq!(4, add_two(2));
- }
-
- #[bench]
- fn bench_add_two(b: &mut Bencher) {
- b.iter(|| add_two(2));
- }
-}
-```
-
-We've imported the `test` crate, which contains our benchmarking support.
-We have a new function as well, with the `bench` attribute. Unlike regular
-tests, which take no arguments, benchmark tests take a `&mut Bencher`. This
-`Bencher` provides an `iter` method, which takes a closure. This closure
-contains the code we'd like to benchmark.
-
-We can run benchmark tests with `cargo bench`:
-
-```bash
-$ cargo bench
- Compiling adder v0.0.1 (file:///home/steve/tmp/adder)
- Running target/release/adder-91b3e234d4ed382a
-
-running 2 tests
-test tests::it_works ... ignored
-test tests::bench_add_two ... bench: 1 ns/iter (+/- 0)
-
-test result: ok. 0 passed; 0 failed; 1 ignored; 1 measured
-```
-
-Our non-benchmark test was ignored. You may have noticed that `cargo bench`
-takes a bit longer than `cargo test`. This is because Rust runs our benchmark
-a number of times, and then takes the average. Because we're doing so little
-work in this example, we have a `1 ns/iter (+/- 0)`, but this would show
-the variance if there was one.
-
-Advice on writing benchmarks:
-
-
-* Move setup code outside the `iter` loop; only put the part you want to measure inside
-* Make the code do "the same thing" on each iteration; do not accumulate or change state
-* Make the outer function idempotent too; the benchmark runner is likely to run
- it many times
-* Make the inner `iter` loop short and fast so benchmark runs are fast and the
- calibrator can adjust the run-length at fine resolution
-* Make the code in the `iter` loop do something simple, to assist in pinpointing
- performance improvements (or regressions)
-
-## Gotcha: optimizations
-
-There's another tricky part to writing benchmarks: benchmarks compiled with
-optimizations activated can be dramatically changed by the optimizer so that
-the benchmark is no longer benchmarking what one expects. For example, the
-compiler might recognize that some calculation has no external effects and
-remove it entirely.
-
-```{rust,ignore}
-extern crate test;
-use test::Bencher;
-
-#[bench]
-fn bench_xor_1000_ints(b: &mut Bencher) {
- b.iter(|| {
- (0..1000).fold(0, |old, new| old ^ new);
- });
-}
-```
-
-gives the following results
-
-```text
-running 1 test
-test bench_xor_1000_ints ... bench: 0 ns/iter (+/- 0)
-
-test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured
-```
-
-The benchmarking runner offers two ways to avoid this. Either, the closure that
-the `iter` method receives can return an arbitrary value which forces the
-optimizer to consider the result used and ensures it cannot remove the
-computation entirely. This could be done for the example above by adjusting the
-`b.iter` call to
-
-```rust
-# struct X;
-# impl X { fn iter<T, F>(&self, _: F) where F: FnMut() -> T {} } let b = X;
-b.iter(|| {
- // note lack of `;` (could also use an explicit `return`).
- (0..1000).fold(0, |old, new| old ^ new)
-});
-```
-
-Or, the other option is to call the generic `test::black_box` function, which
-is an opaque "black box" to the optimizer and so forces it to consider any
-argument as used.
-
-```rust
-# #![feature(test)]
-
-extern crate test;
-
-# fn main() {
-# struct X;
-# impl X { fn iter<T, F>(&self, _: F) where F: FnMut() -> T {} } let b = X;
-b.iter(|| {
- let n = test::black_box(1000);
-
- (0..n).fold(0, |a, b| a ^ b)
-})
-# }
-```
-
-Neither of these read or modify the value, and are very cheap for small values.
-Larger values can be passed indirectly to reduce overhead (e.g.
-`black_box(&huge_struct)`).
-
-Performing either of the above changes gives the following benchmarking results
-
-```text
-running 1 test
-test bench_xor_1000_ints ... bench: 131 ns/iter (+/- 3)
-
-test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured
-```
-
-However, the optimizer can still modify a testcase in an undesirable manner
-even when using either of the above.
dispatched. What's that mean? Check out the chapter on [static and dynamic
dispatch](static-and-dynamic-dispatch.html) for more.
+## Multiple trait bounds
+
+You’ve seen that you can bound a generic type parameter with a trait:
+
+```rust
+fn foo<T: Clone>(x: T) {
+ x.clone();
+}
+```
+
+If you need more than one bound, you can use `+`:
+
+```rust
+use std::fmt::Debug;
+
+fn foo<T: Clone + Debug>(x: T) {
+ x.clone();
+ println!("{:?}", x);
+}
+```
+
+`T` now needs to be both `Clone` as well as `Debug`.
+
## Where clause
Writing functions with only a few generic types and a small number of trait
flag uninstall "only uninstall from the installation prefix"
valopt prefix "" "set installation prefix"
valopt date "" "use the YYYY-MM-DD nightly instead of the current nightly"
+valopt channel "beta" "use the selected release channel [beta]"
flag save "save the downloaded nightlies to ~/.rustup"
if [ $HELP -eq 1 ]
if [ $CFG_OSTYPE = Darwin -a $CFG_CPUTYPE = i386 ]
then
- # Darwin's `uname -s` lies and always returns i386. We have to use sysctl
+ # Darwin's `uname -m` lies and always returns i386. We have to use sysctl
# instead.
if sysctl hw.optional.x86_64 | grep -q ': 1'
then
fi
RUST_URL="https://static.rust-lang.org/dist"
-RUST_PACKAGE_NAME=rust-nightly
+case "$CFG_CHANNEL" in
+ nightly)
+ # add a date suffix if we want a particular nightly.
+ if [ -n "${CFG_DATE}" ];
+ then
+ RUST_URL="${RUST_URL}/${CFG_DATE}"
+ fi
+
+ RUST_PACKAGE_NAME=rust-nightly
+ ;;
+ beta)
+ RUST_PACKAGE_NAME=rust-1.0.0-beta
+ ;;
+ *)
+ err "Currently 'beta' and 'nightly' are the only supported channels"
+esac
+
RUST_PACKAGE_NAME_AND_TRIPLE="${RUST_PACKAGE_NAME}-${HOST_TRIPLE}"
RUST_TARBALL_NAME="${RUST_PACKAGE_NAME_AND_TRIPLE}.tar.gz"
RUST_LOCAL_INSTALL_DIR="${CFG_TMP_DIR}/${RUST_PACKAGE_NAME_AND_TRIPLE}"
RUST_LOCAL_INSTALL_SCRIPT="${RUST_LOCAL_INSTALL_DIR}/install.sh"
-# add a date suffix if we want a particular nighly.
-if [ -n "${CFG_DATE}" ];
-then
- RUST_URL="${RUST_URL}/${CFG_DATE}"
-fi
-
download_hash() {
msg "Downloading ${remote_sha256}"
remote_sha256=`"${CFG_CURL}" -f "${remote_sha256}"`
/// let child_numbers = shared_numbers.clone();
///
/// thread::spawn(move || {
-/// let local_numbers = child_numbers.as_slice();
+/// let local_numbers = &child_numbers[..];
///
/// // Work with the local numbers
/// });
#[unstable(feature = "alloc")]
pub fn strong_count<T>(this: &Arc<T>) -> usize { this.inner().strong.load(SeqCst) }
+
+/// Try accessing a mutable reference to the contents behind an unique `Arc<T>`.
+///
+/// The access is granted only if this is the only reference to the object.
+/// Otherwise, `None` is returned.
+///
+/// # Examples
+///
+/// ```
+/// # #![feature(alloc)]
+/// extern crate alloc;
+/// # fn main() {
+/// use alloc::arc;
+///
+/// let mut four = arc::Arc::new(4);
+///
+/// arc::unique(&mut four).map(|num| *num = 5);
+/// # }
+/// ```
+#[inline]
+#[unstable(feature = "alloc")]
+pub fn unique<T>(this: &mut Arc<T>) -> Option<&mut T> {
+ if strong_count(this) == 1 && weak_count(this) == 0 {
+ // This unsafety is ok because we're guaranteed that the pointer
+ // returned is the *only* pointer that will ever be returned to T. Our
+ // reference count is guaranteed to be 1 at this point, and we required
+ // the Arc itself to be `mut`, so we're returning the only possible
+ // reference to the inner data.
+ let inner = unsafe { &mut **this._ptr };
+ Some(&mut inner.data)
+ }else {
+ None
+ }
+}
+
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> Clone for Arc<T> {
/// Makes a clone of the `Arc<T>`.
}
}
-impl<T: Send + Sync + Clone> Arc<T> {
+impl<T: Clone> Arc<T> {
/// Make a mutable reference from the given `Arc<T>`.
///
/// This is also referred to as a copy-on-write operation because the inner
self.inner().weak.load(SeqCst) != 1 {
*self = Arc::new((**self).clone())
}
- // This unsafety is ok because we're guaranteed that the pointer
- // returned is the *only* pointer that will ever be returned to T. Our
- // reference count is guaranteed to be 1 at this point, and we required
- // the Arc itself to be `mut`, so we're returning the only possible
- // reference to the inner data.
+ // As with `unique()`, the unsafety is ok because our reference was
+ // either unique to begin with, or became one upon cloning the contents.
let inner = unsafe { &mut **self._ptr };
&mut inner.data
}
#[unstable(feature = "alloc",
reason = "Weak pointers may not belong in this module.")]
-impl<T: Sync + Send> Clone for Weak<T> {
+impl<T> Clone for Weak<T> {
/// Makes a clone of the `Weak<T>`.
///
/// This increases the weak reference count.
use std::sync::atomic::Ordering::{Acquire, SeqCst};
use std::thread;
use std::vec::Vec;
- use super::{Arc, Weak, weak_count, strong_count};
+ use super::{Arc, Weak, weak_count, strong_count, unique};
use std::sync::Mutex;
struct Canary(*mut atomic::AtomicUsize);
assert_eq!((*arc_v)[4], 5);
}
+ #[test]
+ fn test_arc_unique() {
+ let mut x = Arc::new(10);
+ assert!(unique(&mut x).is_some());
+ {
+ let y = x.clone();
+ assert!(unique(&mut x).is_none());
+ }
+ {
+ let z = x.downgrade();
+ assert!(unique(&mut x).is_none());
+ }
+ assert!(unique(&mut x).is_some());
+ }
+
#[test]
fn test_cowarc_clone_make_unique() {
let mut cow0 = Arc::new(75);
use core::any::Any;
use core::cmp::Ordering;
use core::default::Default;
-use core::error::{Error, FromError};
use core::fmt;
use core::hash::{self, Hash};
use core::mem;
use core::ops::{Deref, DerefMut};
-use core::ptr::Unique;
-use core::raw::TraitObject;
+use core::ptr::{Unique};
+use core::raw::{TraitObject};
/// A value that represents the heap. This is the default place that the `box`
/// keyword allocates into when no place is supplied.
/// See the [module-level documentation](../../std/boxed/index.html) for more.
#[lang = "owned_box"]
#[stable(feature = "rust1", since = "1.0.0")]
+#[fundamental]
pub struct Box<T>(Unique<T>);
impl<T> Box<T> {
}
}
-/// Extension methods for an owning `Any` trait object.
-#[unstable(feature = "alloc",
- reason = "this trait will likely disappear once compiler bugs blocking \
- a direct impl on `Box<Any>` have been fixed ")]
-// FIXME(#18737): this should be a direct impl on `Box<Any>`. If you're
-// removing this please make sure that you can downcase on
-// `Box<Any + Send>` as well as `Box<Any>`
-pub trait BoxAny {
- /// Returns the boxed value if it is of type `T`, or
- /// `Err(Self)` if it isn't.
- #[stable(feature = "rust1", since = "1.0.0")]
- fn downcast<T: Any>(self) -> Result<Box<T>, Box<Any>>;
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl BoxAny for Box<Any> {
+impl Box<Any> {
#[inline]
- fn downcast<T: Any>(self) -> Result<Box<T>, Box<Any>> {
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn downcast<T: Any>(self) -> Result<Box<T>, Box<Any>> {
if self.is::<T>() {
unsafe {
// Get the raw representation of the trait object
}
}
-#[stable(feature = "rust1", since = "1.0.0")]
-impl BoxAny for Box<Any+Send> {
+impl Box<Any+Send> {
#[inline]
- fn downcast<T: Any>(self) -> Result<Box<T>, Box<Any>> {
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn downcast<T: Any>(self) -> Result<Box<T>, Box<Any>> {
<Box<Any>>::downcast(self)
}
}
}
}
-#[stable(feature = "rust1", since = "1.0.0")]
-impl fmt::Debug for Box<Any> {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- f.pad("Box<Any>")
- }
-}
-
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> Deref for Box<T> {
type Target = T;
#[stable(feature = "rust1", since = "1.0.0")]
impl<I: ExactSizeIterator + ?Sized> ExactSizeIterator for Box<I> {}
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, E: Error + 'a> FromError<E> for Box<Error + 'a> {
- fn from_error(err: E) -> Box<Error + 'a> {
- Box::new(err)
+
+/// `FnBox` is a version of the `FnOnce` intended for use with boxed
+/// closure objects. The idea is that where one would normally store a
+/// `Box<FnOnce()>` in a data structure, you should use
+/// `Box<FnBox()>`. The two traits behave essentially the same, except
+/// that a `FnBox` closure can only be called if it is boxed. (Note
+/// that `FnBox` may be deprecated in the future if `Box<FnOnce()>`
+/// closures become directly usable.)
+///
+/// ### Example
+///
+/// Here is a snippet of code which creates a hashmap full of boxed
+/// once closures and then removes them one by one, calling each
+/// closure as it is removed. Note that the type of the closures
+/// stored in the map is `Box<FnBox() -> i32>` and not `Box<FnOnce()
+/// -> i32>`.
+///
+/// ```
+/// #![feature(core)]
+///
+/// use std::boxed::FnBox;
+/// use std::collections::HashMap;
+///
+/// fn make_map() -> HashMap<i32, Box<FnBox() -> i32>> {
+/// let mut map: HashMap<i32, Box<FnBox() -> i32>> = HashMap::new();
+/// map.insert(1, Box::new(|| 22));
+/// map.insert(2, Box::new(|| 44));
+/// map
+/// }
+///
+/// fn main() {
+/// let mut map = make_map();
+/// for i in &[1, 2] {
+/// let f = map.remove(&i).unwrap();
+/// assert_eq!(f(), i * 22);
+/// }
+/// }
+/// ```
+#[rustc_paren_sugar]
+#[unstable(feature = "core", reason = "Newly introduced")]
+pub trait FnBox<A> {
+ type Output;
+
+ fn call_box(self: Box<Self>, args: A) -> Self::Output;
+}
+
+impl<A,F> FnBox<A> for F
+ where F: FnOnce<A>
+{
+ type Output = F::Output;
+
+ fn call_box(self: Box<F>, args: A) -> F::Output {
+ self.call_once(args)
+ }
+}
+
+impl<'a,A,R> FnOnce<A> for Box<FnBox<A,Output=R>+'a> {
+ type Output = R;
+
+ extern "rust-call" fn call_once(self, args: A) -> R {
+ self.call_box(args)
+ }
+}
+
+impl<'a,A,R> FnOnce<A> for Box<FnBox<A,Output=R>+Send+'a> {
+ type Output = R;
+
+ extern "rust-call" fn call_once(self, args: A) -> R {
+ self.call_box(args)
}
}
use std::boxed;
use std::boxed::Box;
-use std::boxed::BoxAny;
#[test]
fn test_owned_clone() {
let b = Box::new(Test) as Box<Any>;
let a_str = format!("{:?}", a);
let b_str = format!("{:?}", b);
- assert_eq!(a_str, "Box<Any>");
- assert_eq!(b_str, "Box<Any>");
+ assert_eq!(a_str, "Any");
+ assert_eq!(b_str, "Any");
static EIGHT: usize = 8;
static TEST: Test = Test;
let a = &EIGHT as &Any;
let b = &TEST as &Any;
let s = format!("{:?}", a);
- assert_eq!(s, "&Any");
+ assert_eq!(s, "Any");
let s = format!("{:?}", b);
- assert_eq!(s, "&Any");
+ assert_eq!(s, "Any");
}
#[test]
#![feature(no_std)]
#![no_std]
#![feature(allocator)]
+#![feature(custom_attribute)]
+#![feature(fundamental)]
#![feature(lang_items, unsafe_destructor)]
#![feature(box_syntax)]
#![feature(optin_builtin_traits)]
//! use std::collections::BinaryHeap;
//! use std::usize;
//!
-//! #[derive(Copy, Eq, PartialEq)]
+//! #[derive(Copy, Clone, Eq, PartialEq)]
//! struct State {
//! cost: usize,
//! position: usize,
//! [sieve]: http://en.wikipedia.org/wiki/Sieve_of_Eratosthenes
//!
//! ```
-//! # #![feature(collections, core)]
+//! # #![feature(collections, core, step_by)]
//! use std::collections::{BitSet, BitVec};
//! use std::num::Float;
//! use std::iter;
//! if bv[i] {
//! // Mark all multiples of i as non-prime (any multiples below i * i
//! // will have been marked as non-prime previously)
-//! for j in iter::range_step(i * i, max_prime, i) { bv.set(j, false) }
+//! for j in (i * i..max_prime).step_by(i) { bv.set(j, false) }
//! }
//! }
//! BitSet::from_bit_vec(bv)
//
// Note that we can technically avoid this branch with the expression
// `(nbits + u32::BITS - 1) / 32::BITS`, but if nbits is almost usize::MAX this will overflow.
- if bits % u32::BITS as usize == 0 {
- bits / u32::BITS as usize
+ if bits % u32::BITS == 0 {
+ bits / u32::BITS
} else {
- bits / u32::BITS as usize + 1
+ bits / u32::BITS + 1
}
}
/// Computes the bitmask for the final word of the vector
fn mask_for_bits(bits: usize) -> u32 {
// Note especially that a perfect multiple of u32::BITS should mask all 1s.
- !0 >> (u32::BITS as usize - bits % u32::BITS as usize) % u32::BITS as usize
+ !0 >> (u32::BITS - bits % u32::BITS) % u32::BITS
}
impl BitVec {
/// An operation might screw up the unused bits in the last block of the
/// `BitVec`. As per (3), it's assumed to be all 0s. This method fixes it up.
fn fix_last_block(&mut self) {
- let extra_bits = self.len() % u32::BITS as usize;
+ let extra_bits = self.len() % u32::BITS;
if extra_bits > 0 {
let mask = (1 << extra_bits) - 1;
let storage_len = self.storage.len();
/// false, false, true, false]));
/// ```
pub fn from_bytes(bytes: &[u8]) -> BitVec {
- let len = bytes.len().checked_mul(u8::BITS as usize).expect("capacity overflow");
+ let len = bytes.len().checked_mul(u8::BITS).expect("capacity overflow");
let mut bit_vec = BitVec::with_capacity(len);
let complete_words = bytes.len() / 4;
let extra_bytes = bytes.len() % 4;
if i >= self.nbits {
return None;
}
- let w = i / u32::BITS as usize;
- let b = i % u32::BITS as usize;
+ let w = i / u32::BITS;
+ let b = i % u32::BITS;
self.storage.get(w).map(|&block|
(block & (1 << b)) != 0
)
reason = "panic semantics are likely to change in the future")]
pub fn set(&mut self, i: usize, x: bool) {
assert!(i < self.nbits);
- let w = i / u32::BITS as usize;
- let b = i % u32::BITS as usize;
+ let w = i / u32::BITS;
+ let b = i % u32::BITS;
let flag = 1 << b;
let val = if x { self.storage[w] | flag }
else { self.storage[w] & !flag };
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn capacity(&self) -> usize {
- self.storage.capacity().checked_mul(u32::BITS as usize).unwrap_or(usize::MAX)
+ self.storage.capacity().checked_mul(u32::BITS).unwrap_or(usize::MAX)
}
/// Grows the `BitVec` in-place, adding `n` copies of `value` to the `BitVec`.
// Correct the old tail word, setting or clearing formerly unused bits
let num_cur_blocks = blocks_for_bits(self.nbits);
- if self.nbits % u32::BITS as usize > 0 {
+ if self.nbits % u32::BITS > 0 {
let mask = mask_for_bits(self.nbits);
if value {
self.storage[num_cur_blocks - 1] |= !mask;
// (3)
self.set(i, false);
self.nbits = i;
- if self.nbits % u32::BITS as usize == 0 {
+ if self.nbits % u32::BITS == 0 {
// (2)
self.storage.pop();
}
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn push(&mut self, elem: bool) {
- if self.nbits % u32::BITS as usize == 0 {
+ if self.nbits % u32::BITS == 0 {
self.storage.push(0);
}
let insert_pos = self.nbits;
BitSet { bit_vec: bit_vec }
}
- /// Deprecated: use `from_bit_vec`.
- #[inline]
- #[deprecated(since = "1.0.0", reason = "renamed to from_bit_vec")]
- #[unstable(feature = "collections")]
- pub fn from_bitv(bit_vec: BitVec) -> BitSet {
- BitSet { bit_vec: bit_vec }
- }
-
/// Returns the capacity in bits for this bit vector. Inserting any
/// element less than this amount will not trigger a resizing.
///
// Truncate
let trunc_len = cmp::max(old_len - n, 1);
bit_vec.storage.truncate(trunc_len);
- bit_vec.nbits = trunc_len * u32::BITS as usize;
+ bit_vec.nbits = trunc_len * u32::BITS;
}
/// Iterator over each u32 stored in the `BitSet`.
fn next(&mut self) -> Option<usize> {
while self.next_idx < self.set.bit_vec.len() ||
self.next_idx < self.other.bit_vec.len() {
- let bit_idx = self.next_idx % u32::BITS as usize;
+ let bit_idx = self.next_idx % u32::BITS;
if bit_idx == 0 {
let s_bit_vec = &self.set.bit_vec;
let o_bit_vec = &self.other.bit_vec;
// Merging the two words is a bit of an awkward dance since
// one BitVec might be longer than the other
- let word_idx = self.next_idx / u32::BITS as usize;
+ let word_idx = self.next_idx / u32::BITS;
let w1 = if word_idx < s_bit_vec.storage.len() {
s_bit_vec.storage[word_idx]
} else { 0 };
#[stable(feature = "rust1", since = "1.0.0")]
pub trait Borrow<Borrowed: ?Sized> {
/// Immutably borrow from an owned value.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::borrow::Borrow;
+ ///
+ /// fn check<T: Borrow<str>>(s: T) {
+ /// assert_eq!("Hello", s.borrow());
+ /// }
+ ///
+ /// let s = "Hello".to_string();
+ ///
+ /// check(s);
+ ///
+ /// let s = "Hello";
+ ///
+ /// check(s);
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
fn borrow(&self) -> &Borrowed;
}
#[stable(feature = "rust1", since = "1.0.0")]
pub trait BorrowMut<Borrowed: ?Sized> : Borrow<Borrowed> {
/// Mutably borrow from an owned value.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::borrow::BorrowMut;
+ ///
+ /// fn check<T: BorrowMut<[i32]>>(mut v: T) {
+ /// assert_eq!(&mut [1, 2, 3], v.borrow_mut());
+ /// }
+ ///
+ /// let v = vec![1, 2, 3];
+ ///
+ /// check(v);
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
fn borrow_mut(&mut self) -> &mut Borrowed;
}
/// Acquire a mutable reference to the owned form of the data.
///
/// Copies the data if it is not already owned.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::borrow::Cow;
+ ///
+ /// let mut cow: Cow<[_]> = Cow::Owned(vec![1, 2, 3]);
+ ///
+ /// let hello = cow.to_mut();
+ ///
+ /// assert_eq!(hello, &[1, 2, 3]);
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn to_mut(&mut self) -> &mut <B as ToOwned>::Owned {
match *self {
/// Extract the owned data.
///
/// Copies the data if it is not already owned.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::borrow::Cow;
+ ///
+ /// let cow: Cow<[_]> = Cow::Owned(vec![1, 2, 3]);
+ ///
+ /// let hello = cow.into_owned();
+ ///
+ /// assert_eq!(vec![1, 2, 3], hello);
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn into_owned(self) -> <B as ToOwned>::Owned {
match self {
Owned(owned) => owned
}
}
-
- /// Returns true if this `Cow` wraps a borrowed value
- #[deprecated(since = "1.0.0", reason = "match on the enum instead")]
- #[unstable(feature = "std_misc")]
- pub fn is_borrowed(&self) -> bool {
- match *self {
- Borrowed(_) => true,
- _ => false,
- }
- }
-
- /// Returns true if this `Cow` wraps an owned value
- #[deprecated(since = "1.0.0", reason = "match on the enum instead")]
- #[unstable(feature = "std_misc")]
- pub fn is_owned(&self) -> bool {
- match *self {
- Owned(_) => true,
- _ => false,
- }
- }
}
#[stable(feature = "rust1", since = "1.0.0")]
}
}
- #[unstable(feature = "collections",
- reason = "matches entry v3 specification, waiting for dust to settle")]
+ #[stable(feature = "rust1", since = "1.0.0")]
/// Ensures a value is in the entry by inserting the default if empty, and returns
/// a mutable reference to the value in the entry.
pub fn or_insert(self, default: V) -> &'a mut V {
}
}
- #[unstable(feature = "collections",
- reason = "matches entry v3 specification, waiting for dust to settle")]
+ #[stable(feature = "rust1", since = "1.0.0")]
/// Ensures a value is in the entry by inserting the result of the default function if empty,
/// and returns a mutable reference to the value in the entry.
pub fn or_insert_with<F: FnOnce() -> V>(self, default: F) -> &'a mut V {
/// println!("Uninitialized memory: {:?}", handle.into_kv());
/// }
/// ```
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub struct Handle<NodeRef, Type, NodeType> {
node: NodeRef,
index: usize,
// FIXME(contentions): implement union family of methods? (general design may be wrong here)
-#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
+#[derive(PartialEq, Eq, PartialOrd, Ord, Hash)]
/// A specialized set implementation to use enum types.
///
/// It is a logic error for an item to be modified in such a way that the transformation of the
impl<E> Copy for EnumSet<E> {}
+impl<E> Clone for EnumSet<E> {
+ fn clone(&self) -> EnumSet<E> { *self }
+}
+
#[stable(feature = "rust1", since = "1.0.0")]
impl<E:CLike + fmt::Debug> fmt::Debug for EnumSet<E> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fn bit<E:CLike>(e: &E) -> usize {
use core::usize;
let value = e.to_usize();
- assert!(value < usize::BITS as usize,
+ assert!(value < usize::BITS,
"EnumSet only supports up to {} variants.", usize::BITS - 1);
1 << value
}
//! should always be printed.
//! * '-' - Currently not used
//! * '#' - This flag is indicates that the "alternate" form of printing should
-//! be used. By default, this only applies to the integer formatting
-//! traits and performs like:
-//! * `x` - precedes the argument with a "0x"
-//! * `X` - precedes the argument with a "0x"
-//! * `t` - precedes the argument with a "0b"
-//! * `o` - precedes the argument with a "0o"
+//! be used. For array slices, the alternate form omits the brackets.
+//! For the integer formatting traits, the alternate forms are:
+//! * `#x` - precedes the argument with a "0x"
+//! * `#X` - precedes the argument with a "0x"
+//! * `#t` - precedes the argument with a "0b"
+//! * `#o` - precedes the argument with a "0o"
//! * '0' - This is used to indicate for integer formats that the padding should
//! both be done with a `0` character as well as be sign-aware. A format
//! like `{:08}` would yield `00000001` for the integer `1`, while the
#![feature(unsafe_no_drop_flag, filling_drop)]
#![feature(step_by)]
#![feature(str_char)]
-#![feature(convert)]
#![feature(slice_patterns)]
#![feature(debug_builders)]
#![cfg_attr(test, feature(rand, rustc_private, test, hash, collections))]
pub use vec::Vec;
pub use vec_map::VecMap;
-#[deprecated(since = "1.0.0", reason = "renamed to vec_deque")]
-#[unstable(feature = "collections")]
-pub use vec_deque as ring_buf;
-
-#[deprecated(since = "1.0.0", reason = "renamed to linked_list")]
-#[unstable(feature = "collections")]
-pub use linked_list as dlist;
-
-#[deprecated(since = "1.0.0", reason = "renamed to bit_vec")]
-#[unstable(feature = "collections")]
-pub use bit_vec as bitv;
-
-#[deprecated(since = "1.0.0", reason = "renamed to bit_set")]
-#[unstable(feature = "collections")]
-pub use bit_set as bitv_set;
-
// Needed for the vec! macro
pub use alloc::boxed;
reason = "RFC 509")]
pub mod bit_vec {
pub use bit::{BitVec, Iter};
-
- #[deprecated(since = "1.0.0", reason = "renamed to BitVec")]
- #[unstable(feature = "collections")]
- pub use bit::BitVec as Bitv;
}
#[unstable(feature = "collections",
pub mod bit_set {
pub use bit::{BitSet, Union, Intersection, Difference, SymmetricDifference};
pub use bit::SetIter as Iter;
-
- #[deprecated(since = "1.0.0", reason = "renamed to BitSet")]
- #[unstable(feature = "collections")]
- pub use bit::BitSet as BitvSet;
}
#[stable(feature = "rust1", since = "1.0.0")]
use core::mem;
use core::ptr;
-#[deprecated(since = "1.0.0", reason = "renamed to LinkedList")]
-#[unstable(feature = "collections")]
-pub use LinkedList as DList;
-
/// A doubly-linked list.
#[stable(feature = "rust1", since = "1.0.0")]
pub struct LinkedList<T> {
/// }
/// println!("{}", b.len()); // prints 0
/// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
pub fn append(&mut self, other: &mut LinkedList<T>) {
match self.list_tail.resolve() {
None => {
#[stable(feature = "rust1", since = "1.0.0")]
impl<A> FromIterator<A> for LinkedList<A> {
fn from_iter<T: IntoIterator<Item=A>>(iter: T) -> LinkedList<A> {
- let mut ret = DList::new();
+ let mut ret = LinkedList::new();
ret.extend(iter);
ret
}
thread::spawn(move || {
check_links(&n);
let a: &[_] = &[&1,&2,&3];
- assert_eq!(a, n.iter().collect::<Vec<_>>());
+ assert_eq!(a, &n.iter().collect::<Vec<_>>()[..]);
}).join().ok().unwrap();
}
use core::marker::Sized;
use core::mem::size_of;
use core::mem;
-#[cfg(stage0)]
-use core::num::wrapping::WrappingOps;
use core::ops::FnMut;
use core::option::Option::{self, Some, None};
use core::ptr;
pub use core::slice::{SplitN, RSplitN, SplitNMut, RSplitNMut};
pub use core::slice::{bytes, mut_ref_slice, ref_slice};
pub use core::slice::{from_raw_parts, from_raw_parts_mut};
-pub use core::slice::{from_raw_buf, from_raw_mut_buf};
////////////////////////////////////////////////////////////////////////////////
// Basic slice extension methods
cmp::min(self.len(), end-start)
}
- /// Deprecated: use `&s[start .. end]` notation instead.
- #[unstable(feature = "collections",
- reason = "will be replaced by slice syntax")]
- #[deprecated(since = "1.0.0", reason = "use &s[start .. end] instead")]
- #[inline]
- pub fn slice(&self, start: usize, end: usize) -> &[T] {
- &self[start .. end]
- }
-
- /// Deprecated: use `&s[start..]` notation instead.
- #[unstable(feature = "collections",
- reason = "will be replaced by slice syntax")]
- #[deprecated(since = "1.0.0", reason = "use &s[start..] instead")]
- #[inline]
- pub fn slice_from(&self, start: usize) -> &[T] {
- &self[start ..]
- }
-
- /// Deprecated: use `&s[..end]` notation instead.
- #[unstable(feature = "collections",
- reason = "will be replaced by slice syntax")]
- #[deprecated(since = "1.0.0", reason = "use &s[..end] instead")]
- #[inline]
- pub fn slice_to(&self, end: usize) -> &[T] {
- &self[.. end]
- }
-
/// Divides one slice into two at an index.
///
/// The first will contain all indices from `[0, mid)` (excluding
}
/// Returns an iterator over subslices separated by elements that match
- /// `pred`, limited to splitting at most `n` times. The matched element is
+ /// `pred`, limited to returning at most `n` items. The matched element is
/// not contained in the subslices.
///
+ /// The last element returned, if any, will contain the remainder of the
+ /// slice.
+ ///
/// # Examples
///
/// Print the slice split once by numbers divisible by 3 (i.e. `[10, 40]`,
///
/// ```
/// let v = [10, 40, 30, 20, 60, 50];
- /// for group in v.splitn(1, |num| *num % 3 == 0) {
+ /// for group in v.splitn(2, |num| *num % 3 == 0) {
/// println!("{:?}", group);
/// }
/// ```
}
/// Returns an iterator over subslices separated by elements that match
- /// `pred` limited to splitting at most `n` times. This starts at the end of
+ /// `pred` limited to returning at most `n` items. This starts at the end of
/// the slice and works backwards. The matched element is not contained in
/// the subslices.
///
+ /// The last element returned, if any, will contain the remainder of the
+ /// slice.
+ ///
/// # Examples
///
/// Print the slice split once, starting from the end, by numbers divisible
///
/// ```
/// let v = [10, 40, 30, 20, 60, 50];
- /// for group in v.rsplitn(1, |num| *num % 3 == 0) {
+ /// for group in v.rsplitn(2, |num| *num % 3 == 0) {
/// println!("{:?}", group);
/// }
/// ```
/// ```rust
/// # #![feature(core)]
/// let s = [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55];
- /// let s = s.as_slice();
///
/// let seek = 13;
/// assert_eq!(s.binary_search_by(|probe| probe.cmp(&seek)), Ok(9));
core_slice::SliceExt::get_mut(self, index)
}
- /// Deprecated: use `&mut s[..]` instead.
- #[unstable(feature = "collections",
- reason = "will be replaced by slice syntax")]
- #[deprecated(since = "1.0.0", reason = "use &mut s[..] instead")]
- #[allow(deprecated)]
- pub fn as_mut_slice(&mut self) -> &mut [T] {
- core_slice::SliceExt::as_mut_slice(self)
- }
-
- /// Deprecated: use `&mut s[start .. end]` instead.
- #[unstable(feature = "collections",
- reason = "will be replaced by slice syntax")]
- #[deprecated(since = "1.0.0", reason = "use &mut s[start .. end] instead")]
- #[inline]
- pub fn slice_mut(&mut self, start: usize, end: usize) -> &mut [T] {
- &mut self[start .. end]
- }
-
- /// Deprecated: use `&mut s[start ..]` instead.
- #[unstable(feature = "collections",
- reason = "will be replaced by slice syntax")]
- #[deprecated(since = "1.0.0", reason = "use &mut s[start ..] instead")]
- #[inline]
- pub fn slice_from_mut(&mut self, start: usize) -> &mut [T] {
- &mut self[start ..]
- }
-
- /// Deprecated: use `&mut s[.. end]` instead.
- #[unstable(feature = "collections",
- reason = "will be replaced by slice syntax")]
- #[deprecated(since = "1.0.0", reason = "use &mut s[.. end] instead")]
- #[inline]
- pub fn slice_to_mut(&mut self, end: usize) -> &mut [T] {
- &mut self[.. end]
- }
-
/// Returns an iterator that allows modifying each value
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
}
/// Returns an iterator over subslices separated by elements that match
- /// `pred`, limited to splitting at most `n` times. The matched element is
+ /// `pred`, limited to returning at most `n` items. The matched element is
/// not contained in the subslices.
+ ///
+ /// The last element returned, if any, will contain the remainder of the
+ /// slice.
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn splitn_mut<F>(&mut self, n: usize, pred: F) -> SplitNMut<T, F>
}
/// Returns an iterator over subslices separated by elements that match
- /// `pred` limited to splitting at most `n` times. This starts at the end of
+ /// `pred` limited to returning at most `n` items. This starts at the end of
/// the slice and works backwards. The matched element is not contained in
/// the subslices.
+ ///
+ /// The last element returned, if any, will contain the remainder of the
+ /// slice.
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn rsplitn_mut<F>(&mut self, n: usize, pred: F) -> RSplitNMut<T, F>
/// ```rust
/// # #![feature(core)]
/// let s = [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55];
- /// let s = s.as_slice();
///
/// assert_eq!(s.binary_search(&13), Ok(9));
/// assert_eq!(s.binary_search(&4), Err(7));
core_slice::SliceExt::binary_search(self, x)
}
- /// Deprecated: use `binary_search` instead.
- #[unstable(feature = "collections")]
- #[deprecated(since = "1.0.0", reason = "use binary_search instead")]
- pub fn binary_search_elem(&self, x: &T) -> Result<usize, usize> where T: Ord {
- self.binary_search(x)
- }
-
/// Mutates the slice to the next lexicographic permutation.
///
/// Returns `true` if successful and `false` if the slice is at the
// #[inline]
fn next(&mut self) -> Option<(usize, usize)> {
fn new_pos_wrapping(i: usize, s: Direction) -> usize {
- i.wrapping_add(match s { Pos => 1, Neg => -1 })
+ i.wrapping_add(match s { Pos => 1, Neg => !0 /* aka -1 */ })
}
fn new_pos(i: usize, s: Direction) -> usize {
//
// ignore-lexer-test FIXME #15679
-//! Unicode string manipulation (the [`str`](../primitive.str.html) type).
+//! Unicode string manipulation (the `str` type).
//!
-//! Rust's [`str`](../primitive.str.html) type is one of the core primitive
-//! types of the language. `&str` is the borrowed string type. This type of
-//! string can only be created from other strings, unless it is a `&'static str`
-//! (see below). It is not possible to move out of borrowed strings because they
-//! are owned elsewhere.
+//! Rust's `str` type is one of the core primitive types of the language. `&str`
+//! is the borrowed string type. This type of string can only be created from
+//! other strings, unless it is a `&'static str` (see below). It is not possible
+//! to move out of borrowed strings because they are owned elsewhere.
//!
//! # Examples
//!
use slice::SliceConcatExt;
pub use core::str::{FromStr, Utf8Error, Str};
-pub use core::str::{Lines, LinesAny, MatchIndices, SplitStr, CharRange};
+pub use core::str::{Lines, LinesAny, MatchIndices, CharRange};
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 core::str::{from_utf8, Chars, CharIndices, Bytes};
+pub use core::str::{from_utf8_unchecked, ParseBoolError};
pub use unicode::str::{Words, Graphemes, GraphemeIndices};
pub use core::str::Pattern;
pub use core::str::{Searcher, ReverseSearcher, DoubleEndedSearcher, SearchStep};
core_str::StrExt::contains(&self[..], pat)
}
- /// Returns `true` if `self` contains a `char`.
- ///
- /// # Examples
- ///
- /// ```
- /// # #![feature(collections)]
- /// assert!("hello".contains_char('e'));
- ///
- /// assert!(!"hello".contains_char('z'));
- /// ```
- #[unstable(feature = "collections")]
- #[deprecated(since = "1.0.0", reason = "use `contains()` with a char")]
- pub fn contains_char<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool {
- core_str::StrExt::contains_char(&self[..], pat)
- }
-
/// An iterator over the codepoints of `self`.
///
/// # Examples
core_str::StrExt::split(&self[..], pat)
}
- /// An iterator over substrings of `self`, separated by characters matched by a pattern,
- /// restricted to splitting at most `count` times.
+ /// An iterator over substrings of `self`, separated by characters matched
+ /// by a pattern, returning most `count` items.
///
/// The pattern can be a simple `&str`, or a closure that determines
/// the split.
///
+ /// The last element returned, if any, will contain the remainder of the
+ /// string.
+ ///
/// # Examples
///
/// Simple `&str` patterns:
///
/// ```
/// let v: Vec<&str> = "Mary had a little lambda".splitn(2, ' ').collect();
- /// assert_eq!(v, ["Mary", "had", "a little lambda"]);
+ /// assert_eq!(v, ["Mary", "had a little lambda"]);
///
/// let v: Vec<&str> = "lionXXtigerXleopard".splitn(2, 'X').collect();
- /// assert_eq!(v, ["lion", "", "tigerXleopard"]);
+ /// assert_eq!(v, ["lion", "XtigerXleopard"]);
///
- /// let v: Vec<&str> = "abcXdef".splitn(0, 'X').collect();
+ /// let v: Vec<&str> = "abcXdef".splitn(1, 'X').collect();
/// assert_eq!(v, ["abcXdef"]);
///
/// let v: Vec<&str> = "".splitn(1, 'X').collect();
/// More complex patterns with a lambda:
///
/// ```
- /// let v: Vec<&str> = "abc1def2ghi".splitn(1, |c: char| c.is_numeric()).collect();
+ /// let v: Vec<&str> = "abc1def2ghi".splitn(2, |c: char| c.is_numeric()).collect();
/// assert_eq!(v, ["abc", "def2ghi"]);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
}
/// An iterator over substrings of `self`, separated by a pattern,
- /// starting from the end of the string, restricted to splitting
- /// at most `count` times.
+ /// starting from the end of the string, restricted to returning
+ /// at most `count` items.
+ ///
+ /// The last element returned, if any, will contain the remainder of the
+ /// string.
///
/// # Examples
///
/// Simple patterns:
///
/// ```
- /// let v: Vec<&str> = "Mary had a little lamb".rsplitn(2, ' ').collect();
+ /// let v: Vec<&str> = "Mary had a little lamb".rsplitn(3, ' ').collect();
/// assert_eq!(v, ["lamb", "little", "Mary had a"]);
///
- /// let v: Vec<&str> = "lion::tiger::leopard".rsplitn(1, "::").collect();
+ /// let v: Vec<&str> = "lion::tiger::leopard".rsplitn(2, "::").collect();
/// assert_eq!(v, ["leopard", "lion::tiger"]);
/// ```
///
/// More complex patterns with a lambda:
///
/// ```
- /// let v: Vec<&str> = "abc1def2ghi".rsplitn(1, |c: char| c.is_numeric()).collect();
+ /// let v: Vec<&str> = "abc1def2ghi".rsplitn(2, |c: char| c.is_numeric()).collect();
/// assert_eq!(v, ["ghi", "abc1def"]);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
core_str::StrExt::match_indices(&self[..], pat)
}
- /// An iterator over the substrings of `self` separated by a `&str`.
- ///
- /// # Examples
- ///
- /// ```
- /// # #![feature(collections)]
- /// let v: Vec<&str> = "abcXXXabcYYYabc".split_str("abc").collect();
- /// assert_eq!(v, ["", "XXX", "YYY", ""]);
- ///
- /// let v: Vec<&str> = "1abcabc2".split_str("abc").collect();
- /// assert_eq!(v, ["1", "", "2"]);
- /// ```
- #[unstable(feature = "collections")]
- #[deprecated(since = "1.0.0", reason = "use `split()` with a `&str`")]
- #[allow(deprecated) /* for SplitStr */]
- pub fn split_str<'a, P: Pattern<'a>>(&'a self, pat: P) -> SplitStr<'a, P> {
- core_str::StrExt::split_str(&self[..], pat)
- }
-
/// An iterator over the lines of a string, separated by `\n`.
///
/// This does not include the empty string after a trailing `\n`.
pub fn lines_any(&self) -> LinesAny {
core_str::StrExt::lines_any(&self[..])
}
-
- /// Deprecated: use `s[a .. b]` instead.
- #[unstable(feature = "collections",
- reason = "use slice notation [a..b] instead")]
- #[deprecated(since = "1.0.0", reason = "use slice notation [a..b] instead")]
- pub fn slice(&self, begin: usize, end: usize) -> &str {
- &self[begin..end]
- }
-
- /// Deprecated: use `s[a..]` instead.
- #[unstable(feature = "collections",
- reason = "use slice notation [a..b] instead")]
- #[deprecated(since = "1.0.0", reason = "use slice notation [a..] instead")]
- pub fn slice_from(&self, begin: usize) -> &str {
- &self[begin..]
- }
-
- /// Deprecated: use `s[..a]` instead.
- #[unstable(feature = "collections",
- reason = "use slice notation [a..b] instead")]
- #[deprecated(since = "1.0.0", reason = "use slice notation [..a] instead")]
- pub fn slice_to(&self, end: usize) -> &str {
- &self[..end]
- }
-
/// Returns a slice of the string from the character range [`begin`..`end`).
///
/// That is, start at the `begin`-th code point of the string and continue
core_str::StrExt::rfind(&self[..], pat)
}
- /// Returns the byte index of the first matching substring if it exists.
- ///
- /// Returns `None` if it doesn't exist.
- ///
- /// The pattern can be a simple `&str`, or a closure that determines the split.
- ///
- /// # Examples
- ///
- /// ```
- /// # #![feature(collections)]
- /// let s = "Löwe 老虎 Léopard";
- ///
- /// assert_eq!(s.find_str("老虎 L"), Some(6));
- /// assert_eq!(s.find_str("muffin man"), None);
- /// ```
- #[unstable(feature = "collections")]
- #[deprecated(since = "1.0.0", reason = "use `find()` with a `&str`")]
- pub fn find_str<'a, P: Pattern<'a>>(&'a self, needle: P) -> Option<usize> {
- core_str::StrExt::find_str(&self[..], needle)
- }
-
/// Retrieves the first character from a `&str` and returns it.
///
/// This does not allocate a new string; instead, it returns a slice that points one character
/// let gr1 = "a\u{310}e\u{301}o\u{308}\u{332}".graphemes(true).collect::<Vec<&str>>();
/// let b: &[_] = &["a\u{310}", "e\u{301}", "o\u{308}\u{332}"];
///
- /// assert_eq!(gr1.as_slice(), b);
+ /// assert_eq!(&gr1[..], b);
///
/// let gr2 = "a\r\nb🇷🇺🇸🇹".graphemes(true).collect::<Vec<&str>>();
/// let b: &[_] = &["a", "\r\n", "b", "🇷🇺🇸🇹"];
///
- /// assert_eq!(gr2.as_slice(), b);
+ /// assert_eq!(&gr2[..], b);
/// ```
#[unstable(feature = "unicode",
reason = "this functionality may only be provided by libunicode")]
/// let gr_inds = "a̐éö̲\r\n".grapheme_indices(true).collect::<Vec<(usize, &str)>>();
/// let b: &[_] = &[(0, "a̐"), (3, "é"), (6, "ö̲"), (11, "\r\n")];
///
- /// assert_eq!(gr_inds.as_slice(), b);
+ /// assert_eq!(&gr_inds[..], b);
/// ```
#[unstable(feature = "unicode",
reason = "this functionality may only be provided by libunicode")]
use core::prelude::*;
use core::default::Default;
-use core::error::Error;
use core::fmt;
use core::hash;
use core::iter::{IntoIterator, FromIterator};
/// ```
/// # #![feature(collections, core)]
/// let s = String::from_str("hello");
- /// assert_eq!(s.as_slice(), "hello");
+ /// assert_eq!(&s[..], "hello");
/// ```
#[inline]
#[unstable(feature = "collections",
self.vec
}
+ /// Extract a string slice containing the entire string.
+ #[inline]
+ #[unstable(feature = "convert",
+ reason = "waiting on RFC revision")]
+ pub fn as_str(&self) -> &str {
+ self
+ }
+
/// Pushes the given string onto this string buffer.
///
/// # Examples
}
}
-#[stable(feature = "rust1", since = "1.0.0")]
-impl Error for FromUtf8Error {
- fn description(&self) -> &str { "invalid utf-8" }
-}
-
#[stable(feature = "rust1", since = "1.0.0")]
impl fmt::Display for FromUtf16Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
}
}
-#[stable(feature = "rust1", since = "1.0.0")]
-impl Error for FromUtf16Error {
- fn description(&self) -> &str { "invalid utf-16" }
-}
-
#[stable(feature = "rust1", since = "1.0.0")]
impl FromIterator<char> for String {
fn from_iter<I: IntoIterator<Item=char>>(iter: I) -> String {
#[allow(deprecated)]
impl Str for String {
#[inline]
- #[stable(feature = "rust1", since = "1.0.0")]
fn as_slice(&self) -> &str {
unsafe { mem::transmute(&*self.vec) }
}
}
}
-/// A clone-on-write string
-#[deprecated(since = "1.0.0", reason = "use Cow<'a, str> instead")]
-#[stable(feature = "rust1", since = "1.0.0")]
-pub type CowString<'a> = Cow<'a, str>;
-
#[stable(feature = "rust1", since = "1.0.0")]
impl fmt::Write for String {
#[inline]
/// Note that this will drop any excess capacity. Calling this and
/// converting back to a vector with `into_vec()` is equivalent to calling
/// `shrink_to_fit()`.
- #[unstable(feature = "collections")]
+ #[stable(feature = "rust1", since = "1.0.0")]
pub fn into_boxed_slice(mut self) -> Box<[T]> {
self.shrink_to_fit();
unsafe {
}
}
+ /// Extract a slice containing the entire vector.
+ #[inline]
+ #[unstable(feature = "convert",
+ reason = "waiting on RFC revision")]
+ pub fn as_slice(&self) -> &[T] {
+ self
+ }
+
/// Deprecated: use `&mut s[..]` instead.
#[inline]
- #[unstable(feature = "collections",
- reason = "will be replaced by slice syntax")]
- #[deprecated(since = "1.0.0", reason = "use &mut s[..] instead")]
+ #[unstable(feature = "convert",
+ reason = "waiting on RFC revision")]
pub fn as_mut_slice(&mut self) -> &mut [T] {
&mut self[..]
}
/// # #![feature(collections, core)]
/// let v = vec![0, 1, 2];
/// let w = v.map_in_place(|i| i + 3);
- /// assert_eq!(w.as_slice(), [3, 4, 5].as_slice());
+ /// assert_eq!(&w[..], &[3, 4, 5]);
///
/// #[derive(PartialEq, Debug)]
/// struct Newtype(u8);
/// let bytes = vec![0x11, 0x22];
/// let newtyped_bytes = bytes.map_in_place(|x| Newtype(x));
- /// assert_eq!(newtyped_bytes.as_slice(), [Newtype(0x11), Newtype(0x22)].as_slice());
+ /// assert_eq!(&newtyped_bytes[..], &[Newtype(0x11), Newtype(0x22)]);
/// ```
#[unstable(feature = "collections",
reason = "API may change to provide stronger guarantees")]
}
__impl_slice_eq1! { Vec<A>, Vec<B> }
-__impl_slice_eq2! { Vec<A>, &'b [B] }
-__impl_slice_eq2! { Vec<A>, &'b mut [B] }
-__impl_slice_eq2! { Cow<'a, [A]>, &'b [B], Clone }
-__impl_slice_eq2! { Cow<'a, [A]>, &'b mut [B], Clone }
-__impl_slice_eq2! { Cow<'a, [A]>, Vec<B>, Clone }
+__impl_slice_eq1! { Vec<A>, &'b [B] }
+__impl_slice_eq1! { Vec<A>, &'b mut [B] }
+__impl_slice_eq1! { Cow<'a, [A]>, &'b [B], Clone }
+__impl_slice_eq1! { Cow<'a, [A]>, &'b mut [B], Clone }
+__impl_slice_eq1! { Cow<'a, [A]>, Vec<B>, Clone }
macro_rules! array_impls {
($($N: expr)+) => {
$(
// NOTE: some less important impls are omitted to reduce code bloat
- __impl_slice_eq2! { Vec<A>, [B; $N] }
- __impl_slice_eq2! { Vec<A>, &'b [B; $N] }
- // __impl_slice_eq2! { Vec<A>, &'b mut [B; $N] }
- // __impl_slice_eq2! { Cow<'a, [A]>, [B; $N], Clone }
- // __impl_slice_eq2! { Cow<'a, [A]>, &'b [B; $N], Clone }
- // __impl_slice_eq2! { Cow<'a, [A]>, &'b mut [B; $N], Clone }
+ __impl_slice_eq1! { Vec<A>, [B; $N] }
+ __impl_slice_eq1! { Vec<A>, &'b [B; $N] }
+ // __impl_slice_eq1! { Vec<A>, &'b mut [B; $N] }
+ // __impl_slice_eq1! { Cow<'a, [A]>, [B; $N], Clone }
+ // __impl_slice_eq1! { Cow<'a, [A]>, &'b [B; $N], Clone }
+ // __impl_slice_eq1! { Cow<'a, [A]>, &'b mut [B; $N], Clone }
)+
}
}
}
}
-#[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] {
// Clone-on-write
////////////////////////////////////////////////////////////////////////////////
-/// A clone-on-write vector
-#[deprecated(since = "1.0.0", reason = "use Cow<'a, [T]> instead")]
-#[unstable(feature = "collections")]
-pub type CowVec<'a, T> = Cow<'a, [T]>;
-
#[unstable(feature = "collections")]
impl<'a, T> FromIterator<T> for Cow<'a, [T]> where T: Clone {
fn from_iter<I: IntoIterator<Item=T>>(it: I) -> Cow<'a, [T]> {
use core::fmt;
use core::iter::{self, repeat, FromIterator, IntoIterator, RandomAccessIterator};
use core::mem;
-#[cfg(stage0)]
-use core::num::wrapping::WrappingOps;
use core::ops::{Index, IndexMut};
use core::ptr::{self, Unique};
use core::slice;
use alloc::heap;
-#[deprecated(since = "1.0.0", reason = "renamed to VecDeque")]
-#[unstable(feature = "collections")]
-pub use VecDeque as RingBuf;
-
const INITIAL_CAPACITY: usize = 7; // 2^3 - 1
const MINIMUM_CAPACITY: usize = 1; // 2 - 1
/// buf.push_back(3);
/// buf.push_back(4);
/// let b: &[_] = &[&5, &3, &4];
- /// assert_eq!(buf.iter().collect::<Vec<&i32>>().as_slice(), b);
+ /// let c: Vec<&i32> = buf.iter().collect();
+ /// assert_eq!(&c[..], b);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn iter(&self) -> Iter<T> {
// len is the length *after* insertion
for len in 1..cap {
// 0, 1, 2, .., len - 1
- let expected = iter::count(0, 1).take(len).collect();
+ let expected = (0..).take(len).collect();
for tail_pos in 0..cap {
for to_insert in 0..len {
tester.tail = tail_pos;
// len is the length *after* removal
for len in 0..cap - 1 {
// 0, 1, 2, .., len - 1
- let expected = iter::count(0, 1).take(len).collect();
+ let expected = (0..).take(len).collect();
for tail_pos in 0..cap {
for to_remove in 0..len + 1 {
tester.tail = tail_pos;
for len in 0..cap + 1 {
// 0, 1, 2, .., len - 1
- let expected = iter::count(0, 1).take(len).collect();
+ let expected = (0..).take(len).collect();
for tail_pos in 0..max_cap + 1 {
tester.tail = tail_pos;
tester.head = tail_pos;
// index to split at
for at in 0..len + 1 {
// 0, 1, 2, .., at - 1 (may be empty)
- let expected_self = iter::count(0, 1).take(at).collect();
+ let expected_self = (0..).take(at).collect();
// at, at + 1, .., len - 1 (may be empty)
- let expected_other = iter::count(at, 1).take(len - at).collect();
+ let expected_other = (at..).take(len - at).collect();
for tail_pos in 0..cap {
tester.tail = tail_pos;
use std::cmp::Ordering::{Equal, Greater, Less};
use std::collections::{BitSet, BitVec};
-use std::iter::range_step;
#[test]
fn test_bit_set_show() {
assert_eq!(idxs, [0, 2, 3]);
let long: BitSet = (0..10000).filter(|&n| n % 2 == 0).collect();
- let real: Vec<_> = range_step(0, 10000, 2).collect();
+ let real: Vec<_> = (0..10000).step_by(2).collect();
let idxs: Vec<_> = long.iter().collect();
assert_eq!(idxs, real);
let mut bit_vec = BitSet::new();
b.iter(|| {
for _ in 0..100 {
- bit_vec.insert((r.next_u32() as usize) % u32::BITS as usize);
+ bit_vec.insert((r.next_u32() as usize) % u32::BITS);
}
black_box(&bit_vec);
});
#[test]
fn test_bit_vec_push_pop() {
- let mut s = BitVec::from_elem(5 * u32::BITS as usize - 2, false);
- assert_eq!(s.len(), 5 * u32::BITS as usize - 2);
- assert_eq!(s[5 * u32::BITS as usize - 3], false);
+ let mut s = BitVec::from_elem(5 * u32::BITS - 2, false);
+ assert_eq!(s.len(), 5 * u32::BITS - 2);
+ assert_eq!(s[5 * u32::BITS - 3], false);
s.push(true);
s.push(true);
- assert_eq!(s[5 * u32::BITS as usize - 2], true);
- assert_eq!(s[5 * u32::BITS as usize - 1], true);
+ assert_eq!(s[5 * u32::BITS - 2], true);
+ assert_eq!(s[5 * u32::BITS - 1], true);
// Here the internal vector will need to be extended
s.push(false);
- assert_eq!(s[5 * u32::BITS as usize], false);
+ assert_eq!(s[5 * u32::BITS], false);
s.push(false);
- assert_eq!(s[5 * u32::BITS as usize + 1], false);
- assert_eq!(s.len(), 5 * u32::BITS as usize + 2);
+ assert_eq!(s[5 * u32::BITS + 1], false);
+ assert_eq!(s.len(), 5 * u32::BITS + 2);
// Pop it all off
assert_eq!(s.pop(), Some(false));
assert_eq!(s.pop(), Some(false));
assert_eq!(s.pop(), Some(true));
assert_eq!(s.pop(), Some(true));
- assert_eq!(s.len(), 5 * u32::BITS as usize - 2);
+ assert_eq!(s.len(), 5 * u32::BITS - 2);
}
#[test]
fn test_bit_vec_truncate() {
- let mut s = BitVec::from_elem(5 * u32::BITS as usize, true);
+ let mut s = BitVec::from_elem(5 * u32::BITS, true);
- assert_eq!(s, BitVec::from_elem(5 * u32::BITS as usize, true));
- assert_eq!(s.len(), 5 * u32::BITS as usize);
- s.truncate(4 * u32::BITS as usize);
- assert_eq!(s, BitVec::from_elem(4 * u32::BITS as usize, true));
- assert_eq!(s.len(), 4 * u32::BITS as usize);
+ assert_eq!(s, BitVec::from_elem(5 * u32::BITS, true));
+ assert_eq!(s.len(), 5 * u32::BITS);
+ s.truncate(4 * u32::BITS);
+ assert_eq!(s, BitVec::from_elem(4 * u32::BITS, true));
+ assert_eq!(s.len(), 4 * u32::BITS);
// Truncating to a size > s.len() should be a noop
- s.truncate(5 * u32::BITS as usize);
- assert_eq!(s, BitVec::from_elem(4 * u32::BITS as usize, true));
- assert_eq!(s.len(), 4 * u32::BITS as usize);
- s.truncate(3 * u32::BITS as usize - 10);
- assert_eq!(s, BitVec::from_elem(3 * u32::BITS as usize - 10, true));
- assert_eq!(s.len(), 3 * u32::BITS as usize - 10);
+ s.truncate(5 * u32::BITS);
+ assert_eq!(s, BitVec::from_elem(4 * u32::BITS, true));
+ assert_eq!(s.len(), 4 * u32::BITS);
+ s.truncate(3 * u32::BITS - 10);
+ assert_eq!(s, BitVec::from_elem(3 * u32::BITS - 10, true));
+ assert_eq!(s.len(), 3 * u32::BITS - 10);
s.truncate(0);
assert_eq!(s, BitVec::from_elem(0, true));
assert_eq!(s.len(), 0);
#[test]
fn test_bit_vec_reserve() {
- let mut s = BitVec::from_elem(5 * u32::BITS as usize, true);
+ let mut s = BitVec::from_elem(5 * u32::BITS, true);
// Check capacity
- assert!(s.capacity() >= 5 * u32::BITS as usize);
- s.reserve(2 * u32::BITS as usize);
- assert!(s.capacity() >= 7 * u32::BITS as usize);
- s.reserve(7 * u32::BITS as usize);
- assert!(s.capacity() >= 12 * u32::BITS as usize);
- s.reserve_exact(7 * u32::BITS as usize);
- assert!(s.capacity() >= 12 * u32::BITS as usize);
- s.reserve(7 * u32::BITS as usize + 1);
- assert!(s.capacity() >= 12 * u32::BITS as usize + 1);
+ assert!(s.capacity() >= 5 * u32::BITS);
+ s.reserve(2 * u32::BITS);
+ assert!(s.capacity() >= 7 * u32::BITS);
+ s.reserve(7 * u32::BITS);
+ assert!(s.capacity() >= 12 * u32::BITS);
+ s.reserve_exact(7 * u32::BITS);
+ assert!(s.capacity() >= 12 * u32::BITS);
+ s.reserve(7 * u32::BITS + 1);
+ assert!(s.capacity() >= 12 * u32::BITS + 1);
// Check that length hasn't changed
- assert_eq!(s.len(), 5 * u32::BITS as usize);
+ assert_eq!(s.len(), 5 * u32::BITS);
s.push(true);
s.push(false);
s.push(true);
- assert_eq!(s[5 * u32::BITS as usize - 1], true);
- assert_eq!(s[5 * u32::BITS as usize - 0], true);
- assert_eq!(s[5 * u32::BITS as usize + 1], false);
- assert_eq!(s[5 * u32::BITS as usize + 2], true);
+ assert_eq!(s[5 * u32::BITS - 1], true);
+ assert_eq!(s[5 * u32::BITS - 0], true);
+ assert_eq!(s[5 * u32::BITS + 1], false);
+ assert_eq!(s[5 * u32::BITS + 2], true);
}
#[test]
let mut bit_vec = 0 as usize;
b.iter(|| {
for _ in 0..100 {
- bit_vec |= 1 << ((r.next_u32() as usize) % u32::BITS as usize);
+ bit_vec |= 1 << ((r.next_u32() as usize) % u32::BITS);
}
black_box(&bit_vec);
});
#[bench]
fn bench_bit_set_small(b: &mut Bencher) {
let mut r = rng();
- let mut bit_vec = BitVec::from_elem(u32::BITS as usize, false);
+ let mut bit_vec = BitVec::from_elem(u32::BITS, false);
b.iter(|| {
for _ in 0..100 {
- bit_vec.set((r.next_u32() as usize) % u32::BITS as usize, true);
+ bit_vec.set((r.next_u32() as usize) % u32::BITS, true);
}
black_box(&bit_vec);
});
#[bench]
fn bench_bit_vec_small_iter(b: &mut Bencher) {
- let bit_vec = BitVec::from_elem(u32::BITS as usize, false);
+ let bit_vec = BitVec::from_elem(u32::BITS, false);
b.iter(|| {
let mut sum = 0;
for _ in 0..10 {
use self::Foo::*;
-#[derive(Copy, PartialEq, Debug)]
+#[derive(Copy, Clone, PartialEq, Debug)]
#[repr(usize)]
enum Foo {
A, B, C
e1.insert(A);
let elems: Vec<_> = e1.iter().collect();
- assert_eq!([A], elems);
+ assert_eq!(elems, [A]);
e1.insert(C);
let elems: Vec<_> = e1.iter().collect();
- assert_eq!([A,C], elems);
+ assert_eq!(elems, [A,C]);
e1.insert(C);
let elems: Vec<_> = e1.iter().collect();
- assert_eq!([A,C], elems);
+ assert_eq!(elems, [A,C]);
e1.insert(B);
let elems: Vec<_> = e1.iter().collect();
- assert_eq!([A,B,C], elems);
+ assert_eq!(elems, [A,B,C]);
}
///////////////////////////////////////////////////////////////////////////
let e_union = e1 | e2;
let elems: Vec<_> = e_union.iter().collect();
- assert_eq!([A,B,C], elems);
+ assert_eq!(elems, [A,B,C]);
let e_intersection = e1 & e2;
let elems: Vec<_> = e_intersection.iter().collect();
- assert_eq!([C], elems);
+ assert_eq!(elems, [C]);
// Another way to express intersection
let e_intersection = e1 - (e1 - e2);
let elems: Vec<_> = e_intersection.iter().collect();
- assert_eq!([C], elems);
+ assert_eq!(elems, [C]);
let e_subtract = e1 - e2;
let elems: Vec<_> = e_subtract.iter().collect();
- assert_eq!([A], elems);
+ assert_eq!(elems, [A]);
// Bitwise XOR of two sets, aka symmetric difference
let e_symmetric_diff = e1 ^ e2;
let elems: Vec<_> = e_symmetric_diff.iter().collect();
- assert_eq!([A,B], elems);
+ assert_eq!(elems, [A,B]);
// Another way to express symmetric difference
let e_symmetric_diff = (e1 - e2) | (e2 - e1);
let elems: Vec<_> = e_symmetric_diff.iter().collect();
- assert_eq!([A,B], elems);
+ assert_eq!(elems, [A,B]);
// Yet another way to express symmetric difference
let e_symmetric_diff = (e1 | e2) - (e1 & e2);
let elems: Vec<_> = e_symmetric_diff.iter().collect();
- assert_eq!([A,B], elems);
+ assert_eq!(elems, [A,B]);
}
#[test]
#[should_panic]
fn test_overflow() {
#[allow(dead_code)]
- #[derive(Copy)]
+ #[derive(Copy, Clone)]
#[repr(usize)]
enum Bar {
V00, V01, V02, V03, V04, V05, V06, V07, V08, V09,
#[test]
fn test_format() {
let s = fmt::format(format_args!("Hello, {}!", "world"));
- assert_eq!(s.as_slice(), "Hello, world!");
+ assert_eq!(s, "Hello, world!");
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![allow(deprecated)]
#![feature(box_syntax)]
#![feature(collections)]
#![feature(core)]
#![feature(unicode)]
#![feature(unsafe_destructor)]
#![feature(into_cow)]
+#![feature(step_by)]
#![cfg_attr(test, feature(str_char))]
#[macro_use] extern crate log;
// Test on-heap from_elem.
v = vec![20; 6];
{
- let v = v.as_slice();
+ let v = &v[..];
assert_eq!(v[0], 20);
assert_eq!(v[1], 20);
assert_eq!(v[2], 20);
#[test]
fn test_slice_2() {
let v = vec![1, 2, 3, 4, 5];
- let v = v.slice(1, 3);
+ let v = &v[1..3];
assert_eq!(v.len(), 2);
assert_eq!(v[0], 2);
assert_eq!(v[1], 3);
let xs = &[1,2,3,4,5];
let splits: &[&[_]] = &[&[1,2,3,4,5]];
- assert_eq!(xs.splitn(0, |x| *x % 2 == 0).collect::<Vec<_>>(),
+ assert_eq!(xs.splitn(1, |x| *x % 2 == 0).collect::<Vec<_>>(),
splits);
let splits: &[&[_]] = &[&[1], &[3,4,5]];
- assert_eq!(xs.splitn(1, |x| *x % 2 == 0).collect::<Vec<_>>(),
+ assert_eq!(xs.splitn(2, |x| *x % 2 == 0).collect::<Vec<_>>(),
splits);
let splits: &[&[_]] = &[&[], &[], &[], &[4,5]];
- assert_eq!(xs.splitn(3, |_| true).collect::<Vec<_>>(),
+ assert_eq!(xs.splitn(4, |_| true).collect::<Vec<_>>(),
splits);
let xs: &[i32] = &[];
let splits: &[&[i32]] = &[&[]];
- assert_eq!(xs.splitn(1, |x| *x == 5).collect::<Vec<_>>(), splits);
+ assert_eq!(xs.splitn(2, |x| *x == 5).collect::<Vec<_>>(), splits);
}
#[test]
let xs = &mut [1,2,3,4,5];
let splits: &[&mut[_]] = &[&mut [1,2,3,4,5]];
- assert_eq!(xs.splitn_mut(0, |x| *x % 2 == 0).collect::<Vec<_>>(),
+ assert_eq!(xs.splitn_mut(1, |x| *x % 2 == 0).collect::<Vec<_>>(),
splits);
let splits: &[&mut[_]] = &[&mut [1], &mut [3,4,5]];
- assert_eq!(xs.splitn_mut(1, |x| *x % 2 == 0).collect::<Vec<_>>(),
+ assert_eq!(xs.splitn_mut(2, |x| *x % 2 == 0).collect::<Vec<_>>(),
splits);
let splits: &[&mut[_]] = &[&mut [], &mut [], &mut [], &mut [4,5]];
- assert_eq!(xs.splitn_mut(3, |_| true).collect::<Vec<_>>(),
+ assert_eq!(xs.splitn_mut(4, |_| true).collect::<Vec<_>>(),
splits);
let xs: &mut [i32] = &mut [];
let splits: &[&mut[i32]] = &[&mut []];
- assert_eq!(xs.splitn_mut(1, |x| *x == 5).collect::<Vec<_>>(),
+ assert_eq!(xs.splitn_mut(2, |x| *x == 5).collect::<Vec<_>>(),
splits);
}
let xs = &[1,2,3,4,5];
let splits: &[&[_]] = &[&[1,2,3,4,5]];
- assert_eq!(xs.rsplitn(0, |x| *x % 2 == 0).collect::<Vec<_>>(),
+ assert_eq!(xs.rsplitn(1, |x| *x % 2 == 0).collect::<Vec<_>>(),
splits);
let splits: &[&[_]] = &[&[5], &[1,2,3]];
- assert_eq!(xs.rsplitn(1, |x| *x % 2 == 0).collect::<Vec<_>>(),
+ assert_eq!(xs.rsplitn(2, |x| *x % 2 == 0).collect::<Vec<_>>(),
splits);
let splits: &[&[_]] = &[&[], &[], &[], &[1,2]];
- assert_eq!(xs.rsplitn(3, |_| true).collect::<Vec<_>>(),
+ assert_eq!(xs.rsplitn(4, |_| true).collect::<Vec<_>>(),
splits);
let xs: &[i32] = &[];
let splits: &[&[i32]] = &[&[]];
- assert_eq!(xs.rsplitn(1, |x| *x == 5).collect::<Vec<&[i32]>>(), splits);
+ assert_eq!(xs.rsplitn(2, |x| *x == 5).collect::<Vec<&[i32]>>(), splits);
+ assert!(xs.rsplitn(0, |x| *x % 2 == 0).next().is_none());
}
#[test]
#[should_panic]
fn test_overflow_does_not_cause_segfault() {
let mut v = vec![];
- v.reserve_exact(-1);
+ v.reserve_exact(!0);
v.push(1);
v.push(2);
}
#[should_panic]
fn test_overflow_does_not_cause_segfault_managed() {
let mut v = vec![Rc::new(1)];
- v.reserve_exact(-1);
+ v.reserve_exact(!0);
v.push(Rc::new(2));
}
fn test_into_bytes() {
let data = String::from_str("asdf");
let buf = data.into_bytes();
- assert_eq!(b"asdf", buf);
+ assert_eq!(buf, b"asdf");
}
#[test]
fn test_find_str() {
// byte positions
- assert_eq!("".find_str(""), Some(0));
- assert!("banana".find_str("apple pie").is_none());
+ assert_eq!("".find(""), Some(0));
+ assert!("banana".find("apple pie").is_none());
let data = "abcabc";
- assert_eq!(data[0..6].find_str("ab"), Some(0));
- assert_eq!(data[2..6].find_str("ab"), Some(3 - 2));
- assert!(data[2..4].find_str("ab").is_none());
+ assert_eq!(data[0..6].find("ab"), Some(0));
+ assert_eq!(data[2..6].find("ab"), Some(3 - 2));
+ assert!(data[2..4].find("ab").is_none());
let string = "ประเทศไทย中华Việt Nam";
let mut data = String::from_str(string);
data.push_str(string);
- assert!(data.find_str("ไท华").is_none());
- assert_eq!(data[0..43].find_str(""), Some(0));
- assert_eq!(data[6..43].find_str(""), Some(6 - 6));
+ assert!(data.find("ไท华").is_none());
+ assert_eq!(data[0..43].find(""), Some(0));
+ assert_eq!(data[6..43].find(""), Some(6 - 6));
- assert_eq!(data[0..43].find_str("ประ"), Some( 0));
- assert_eq!(data[0..43].find_str("ทศไ"), Some(12));
- assert_eq!(data[0..43].find_str("ย中"), Some(24));
- assert_eq!(data[0..43].find_str("iệt"), Some(34));
- assert_eq!(data[0..43].find_str("Nam"), Some(40));
+ assert_eq!(data[0..43].find("ประ"), Some( 0));
+ assert_eq!(data[0..43].find("ทศไ"), Some(12));
+ assert_eq!(data[0..43].find("ย中"), Some(24));
+ assert_eq!(data[0..43].find("iệt"), Some(34));
+ assert_eq!(data[0..43].find("Nam"), Some(40));
- assert_eq!(data[43..86].find_str("ประ"), Some(43 - 43));
- assert_eq!(data[43..86].find_str("ทศไ"), Some(55 - 43));
- assert_eq!(data[43..86].find_str("ย中"), Some(67 - 43));
- assert_eq!(data[43..86].find_str("iệt"), Some(77 - 43));
- assert_eq!(data[43..86].find_str("Nam"), Some(83 - 43));
+ assert_eq!(data[43..86].find("ประ"), Some(43 - 43));
+ assert_eq!(data[43..86].find("ทศไ"), Some(55 - 43));
+ assert_eq!(data[43..86].find("ย中"), Some(67 - 43));
+ assert_eq!(data[43..86].find("iệt"), Some(77 - 43));
+ assert_eq!(data[43..86].find("Nam"), Some(83 - 43));
}
#[test]
#[test]
fn test_slice() {
- assert_eq!("ab", "abc".slice(0, 2));
- assert_eq!("bc", "abc".slice(1, 3));
- assert_eq!("", "abc".slice(1, 1));
- assert_eq!("\u{65e5}", "\u{65e5}\u{672c}".slice(0, 3));
+ assert_eq!("ab", &"abc"[0..2]);
+ assert_eq!("bc", &"abc"[1..3]);
+ assert_eq!("", &"abc"[1..1]);
+ assert_eq!("\u{65e5}", &"\u{65e5}\u{672c}"[0..3]);
let data = "ประเทศไทย中华";
- assert_eq!("ป", data.slice(0, 3));
- assert_eq!("ร", data.slice(3, 6));
- assert_eq!("", data.slice(3, 3));
- assert_eq!("华", data.slice(30, 33));
+ assert_eq!("ป", &data[0..3]);
+ assert_eq!("ร", &data[3..6]);
+ assert_eq!("", &data[3..3]);
+ assert_eq!("华", &data[30..33]);
fn a_million_letter_x() -> String {
let mut i = 0;
}
let letters = a_million_letter_x();
assert!(half_a_million_letter_x() ==
- String::from_str(letters.slice(0, 3 * 500000)));
+ String::from_str(&letters[0..3 * 500000]));
}
#[test]
fn test_slice_2() {
let ss = "中华Việt Nam";
- assert_eq!("华", ss.slice(3, 6));
- assert_eq!("Việt Nam", ss.slice(6, 16));
+ assert_eq!("华", &ss[3..6]);
+ assert_eq!("Việt Nam", &ss[6..16]);
- assert_eq!("ab", "abc".slice(0, 2));
- assert_eq!("bc", "abc".slice(1, 3));
- assert_eq!("", "abc".slice(1, 1));
+ assert_eq!("ab", &"abc"[0..2]);
+ assert_eq!("bc", &"abc"[1..3]);
+ assert_eq!("", &"abc"[1..1]);
- assert_eq!("中", ss.slice(0, 3));
- assert_eq!("华V", ss.slice(3, 7));
- assert_eq!("", ss.slice(3, 3));
+ assert_eq!("中", &ss[0..3]);
+ assert_eq!("华V", &ss[3..7]);
+ assert_eq!("", &ss[3..3]);
/*0: 中
3: 华
6: V
#[test]
#[should_panic]
fn test_slice_fail() {
- "中华Việt Nam".slice(0, 2);
+ &"中华Việt Nam"[0..2];
}
#[test]
fn test_slice_from() {
- assert_eq!("abcd".slice_from(0), "abcd");
- assert_eq!("abcd".slice_from(2), "cd");
- assert_eq!("abcd".slice_from(4), "");
+ assert_eq!(&"abcd"[0..], "abcd");
+ assert_eq!(&"abcd"[2..], "cd");
+ assert_eq!(&"abcd"[4..], "");
}
#[test]
fn test_slice_to() {
- assert_eq!("abcd".slice_to(0), "");
- assert_eq!("abcd".slice_to(2), "ab");
- assert_eq!("abcd".slice_to(4), "abcd");
+ assert_eq!(&"abcd"[..0], "");
+ assert_eq!(&"abcd"[..2], "ab");
+ assert_eq!(&"abcd"[..4], "abcd");
}
#[test]
#[test]
fn test_contains_char() {
- assert!("abc".contains_char('b'));
- assert!("a".contains_char('a'));
- assert!(!"abc".contains_char('d'));
- assert!(!"".contains_char('a'));
+ assert!("abc".contains('b'));
+ assert!("a".contains('a'));
+ assert!(!"abc".contains('d'));
+ assert!(!"".contains('a'));
}
#[test]
fn test_splitn_char_iterator() {
let data = "\nMäry häd ä little lämb\nLittle lämb\n";
- let split: Vec<&str> = data.splitn(3, ' ').collect();
+ let split: Vec<&str> = data.splitn(4, ' ').collect();
assert_eq!(split, ["\nMäry", "häd", "ä", "little lämb\nLittle lämb\n"]);
- let split: Vec<&str> = data.splitn(3, |c: char| c == ' ').collect();
+ let split: Vec<&str> = data.splitn(4, |c: char| c == ' ').collect();
assert_eq!(split, ["\nMäry", "häd", "ä", "little lämb\nLittle lämb\n"]);
// Unicode
- let split: Vec<&str> = data.splitn(3, 'ä').collect();
+ let split: Vec<&str> = data.splitn(4, 'ä').collect();
assert_eq!(split, ["\nM", "ry h", "d ", " little lämb\nLittle lämb\n"]);
- let split: Vec<&str> = data.splitn(3, |c: char| c == 'ä').collect();
+ let split: Vec<&str> = data.splitn(4, |c: char| c == 'ä').collect();
assert_eq!(split, ["\nM", "ry h", "d ", " little lämb\nLittle lämb\n"]);
}
fn test_rsplitn() {
let data = "\nMäry häd ä little lämb\nLittle lämb\n";
- let split: Vec<&str> = data.rsplitn(1, ' ').collect();
+ let split: Vec<&str> = data.rsplitn(2, ' ').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();
+ let split: Vec<&str> = data.rsplitn(2, "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();
+ let split: Vec<&str> = data.rsplitn(2, |c: char| c == 'ä').collect();
assert_eq!(split, ["mb\n", "\nMäry häd ä little lämb\nLittle l"]);
}
}
#[test]
-fn test_split_strator() {
+fn test_splitator() {
fn t(s: &str, sep: &str, u: &[&str]) {
- let v: Vec<&str> = s.split_str(sep).collect();
+ let v: Vec<&str> = s.split(sep).collect();
assert_eq!(v, u);
}
t("--1233345--", "12345", &["--1233345--"]);
fn test_str_default() {
use std::default::Default;
- fn t<S: Default + Str>() {
+ fn t<S: Default + AsRef<str>>() {
let s: S = Default::default();
- assert_eq!(s.as_slice(), "");
+ assert_eq!(s.as_ref(), "");
}
t::<&str>();
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::borrow::IntoCow;
+use std::borrow::{IntoCow, Cow};
use std::iter::repeat;
use std::str::Utf8Error;
-use std::string::{CowString, as_string};
+use std::string::as_string;
use test::Bencher;
#[test]
fn test_from_utf8_lossy() {
let xs = b"hello";
- let ys: CowString = "hello".into_cow();
+ let ys: Cow<str> = "hello".into_cow();
assert_eq!(String::from_utf8_lossy(xs), ys);
let xs = "ศไทย中华Việt Nam".as_bytes();
- let ys: CowString = "ศไทย中华Việt Nam".into_cow();
+ let ys: Cow<str> = "ศไทย中华Việt Nam".into_cow();
assert_eq!(String::from_utf8_lossy(xs), ys);
let xs = b"Hello\xC2 There\xFF Goodbye";
use self::Taggypar::*;
#[test]
-#[allow(deprecated)]
fn test_simple() {
let mut d = VecDeque::new();
assert_eq!(d.len(), 0);
let u: Vec<_> = deq.iter().cloned().collect();
assert_eq!(u, v);
- let seq = iter::count(0, 2).take(256);
+ let seq = (0..).step_by(2).take(256);
let deq: VecDeque<_> = seq.collect();
for (i, &x) in deq.iter().enumerate() {
assert_eq!(2*i, x);
let (left, right) = ring.as_slices();
let expected: Vec<_> = (0..i+1).collect();
- assert_eq!(left, expected);
+ assert_eq!(left, &expected[..]);
assert_eq!(right, []);
}
let (left, right) = ring.as_slices();
let expected_left: Vec<_> = (-last..j+1).rev().collect();
let expected_right: Vec<_> = (0..first).collect();
- assert_eq!(left, expected_left);
- assert_eq!(right, expected_right);
+ assert_eq!(left, &expected_left[..]);
+ assert_eq!(right, &expected_right[..]);
}
assert_eq!(ring.len() as i32, cap);
let (left, right) = ring.as_mut_slices();
let expected: Vec<_> = (0..i+1).collect();
- assert_eq!(left, expected);
+ assert_eq!(left, &expected[..]);
assert_eq!(right, []);
}
let (left, right) = ring.as_mut_slices();
let expected_left: Vec<_> = (-last..j+1).rev().collect();
let expected_right: Vec<_> = (0..first).collect();
- assert_eq!(left, expected_left);
- assert_eq!(right, expected_right);
+ assert_eq!(left, &expected_left[..]);
+ assert_eq!(right, &expected_right[..]);
}
assert_eq!(ring.len() as i32, cap);
#![stable(feature = "rust1", since = "1.0.0")]
+use fmt;
use marker::Send;
use mem::transmute;
use option::Option::{self, Some, None};
// Extension methods for Any trait objects.
///////////////////////////////////////////////////////////////////////////////
+#[stable(feature = "rust1", since = "1.0.0")]
+impl fmt::Debug for Any {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.pad("Any")
+ }
+}
+
impl Any {
/// Returns true if the boxed type is the same as `T`
#[stable(feature = "rust1", since = "1.0.0")]
impl TypeId {
/// Returns the `TypeId` of the type this generic function has been
/// instantiated with
- #[unstable(feature = "core",
- reason = "may grow a `Reflect` bound soon via marker traits")]
+ #[stable(feature = "rust1", since = "1.0.0")]
pub fn of<T: ?Sized + Any>() -> TypeId {
TypeId {
t: unsafe { intrinsics::type_id::<T>() },
/// Rust's memory orderings are [the same as
/// C++'s](http://gcc.gnu.org/wiki/Atomic/GCCMM/AtomicSync).
#[stable(feature = "rust1", since = "1.0.0")]
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub enum Ordering {
/// No ordering constraints, only atomic operations.
#[stable(feature = "rust1", since = "1.0.0")]
AtomicUsize { v: UnsafeCell { value: 0, } };
// NB: Needs to be -1 (0b11111111...) to make fetch_nand work correctly
-const UINT_TRUE: usize = -1;
+const UINT_TRUE: usize = !0;
impl AtomicBool {
/// Creates a new `AtomicBool`.
}
}
}
-
-#[unstable(feature = "core")]
-#[deprecated(since = "1.0.0",
- reason = "renamed to AtomicIsize")]
-#[allow(missing_docs)]
-pub struct AtomicInt {
- v: UnsafeCell<isize>,
-}
-
-#[allow(deprecated)]
-unsafe impl Sync for AtomicInt {}
-
-#[unstable(feature = "core")]
-#[deprecated(since = "1.0.0",
- reason = "renamed to AtomicUsize")]
-#[allow(missing_docs)]
-pub struct AtomicUint {
- v: UnsafeCell<usize>,
-}
-
-#[allow(deprecated)]
-unsafe impl Sync for AtomicUint {}
-
-#[unstable(feature = "core")]
-#[deprecated(since = "1.0.0",
- reason = "use ATOMIC_ISIZE_INIT instead")]
-#[allow(missing_docs, deprecated)]
-pub const ATOMIC_INT_INIT: AtomicInt =
- AtomicInt { v: UnsafeCell { value: 0 } };
-#[unstable(feature = "core")]
-#[deprecated(since = "1.0.0",
- reason = "use ATOMIC_USIZE_INIT instead")]
-#[allow(missing_docs, deprecated)]
-pub const ATOMIC_UINT_INIT: AtomicUint =
- AtomicUint { v: UnsafeCell { value: 0, } };
-
-#[allow(missing_docs, deprecated)]
-impl AtomicInt {
- #[inline]
- pub fn new(v: isize) -> AtomicInt {
- AtomicInt {v: UnsafeCell::new(v)}
- }
-
- #[inline]
- pub fn load(&self, order: Ordering) -> isize {
- unsafe { atomic_load(self.v.get(), order) }
- }
-
- #[inline]
- pub fn store(&self, val: isize, order: Ordering) {
- unsafe { atomic_store(self.v.get(), val, order); }
- }
-
- #[inline]
- pub fn swap(&self, val: isize, order: Ordering) -> isize {
- unsafe { atomic_swap(self.v.get(), val, order) }
- }
-
- #[inline]
- pub fn compare_and_swap(&self, old: isize, new: isize, order: Ordering) -> isize {
- unsafe { atomic_compare_and_swap(self.v.get(), old, new, order) }
- }
-
- #[inline]
- pub fn fetch_add(&self, val: isize, order: Ordering) -> isize {
- unsafe { atomic_add(self.v.get(), val, order) }
- }
-
- #[inline]
- pub fn fetch_sub(&self, val: isize, order: Ordering) -> isize {
- unsafe { atomic_sub(self.v.get(), val, order) }
- }
-
- #[inline]
- pub fn fetch_and(&self, val: isize, order: Ordering) -> isize {
- unsafe { atomic_and(self.v.get(), val, order) }
- }
-
- #[inline]
- pub fn fetch_or(&self, val: isize, order: Ordering) -> isize {
- unsafe { atomic_or(self.v.get(), val, order) }
- }
-
- #[inline]
- pub fn fetch_xor(&self, val: isize, order: Ordering) -> isize {
- unsafe { atomic_xor(self.v.get(), val, order) }
- }
-}
-
-#[allow(missing_docs, deprecated)]
-impl AtomicUint {
- #[inline]
- pub fn new(v: usize) -> AtomicUint {
- AtomicUint { v: UnsafeCell::new(v) }
- }
-
- #[inline]
- pub fn load(&self, order: Ordering) -> usize {
- unsafe { atomic_load(self.v.get(), order) }
- }
-
- #[inline]
- pub fn store(&self, val: usize, order: Ordering) {
- unsafe { atomic_store(self.v.get(), val, order); }
- }
-
- #[inline]
- pub fn swap(&self, val: usize, order: Ordering) -> usize {
- unsafe { atomic_swap(self.v.get(), val, order) }
- }
-
- #[inline]
- pub fn compare_and_swap(&self, old: usize, new: usize, order: Ordering) -> usize {
- unsafe { atomic_compare_and_swap(self.v.get(), old, new, order) }
- }
-
- #[inline]
- pub fn fetch_add(&self, val: usize, order: Ordering) -> usize {
- unsafe { atomic_add(self.v.get(), val, order) }
- }
-
- #[inline]
- pub fn fetch_sub(&self, val: usize, order: Ordering) -> usize {
- unsafe { atomic_sub(self.v.get(), val, order) }
- }
-
- #[inline]
- pub fn fetch_and(&self, val: usize, order: Ordering) -> usize {
- unsafe { atomic_and(self.v.get(), val, order) }
- }
-
- #[inline]
- pub fn fetch_or(&self, val: usize, order: Ordering) -> usize {
- unsafe { atomic_or(self.v.get(), val, order) }
- }
-
- #[inline]
- pub fn fetch_xor(&self, val: usize, order: Ordering) -> usize {
- unsafe { atomic_xor(self.v.get(), val, order) }
- }
-}
// (will not outgrow its range since `usize` is the size of the address space)
type BorrowFlag = usize;
const UNUSED: BorrowFlag = 0;
-const WRITING: BorrowFlag = -1;
+const WRITING: BorrowFlag = !0;
impl<T> RefCell<T> {
/// Creates a new `RefCell` containing `value`.
}
}
- /// Attempts to immutably borrow the wrapped value.
- ///
- /// The borrow lasts until the returned `Ref` exits scope. Multiple
- /// immutable borrows can be taken out at the same time.
- ///
- /// Returns `None` if the value is currently mutably borrowed.
- #[unstable(feature = "core", reason = "may be renamed or removed")]
- #[deprecated(since = "1.0.0",
- reason = "dispatch on `cell.borrow_state()` instead")]
- #[inline]
- pub fn try_borrow<'a>(&'a self) -> Option<Ref<'a, T>> {
- match BorrowRef::new(&self.borrow) {
- Some(b) => Some(Ref { _value: unsafe { &*self.value.get() }, _borrow: b }),
- None => None,
- }
- }
-
/// Immutably borrows the wrapped value.
///
/// The borrow lasts until the returned `Ref` exits scope. Multiple
}
}
- /// Mutably borrows the wrapped value.
- ///
- /// The borrow lasts until the returned `RefMut` exits scope. The value
- /// cannot be borrowed while this borrow is active.
- ///
- /// Returns `None` if the value is currently borrowed.
- #[unstable(feature = "core", reason = "may be renamed or removed")]
- #[deprecated(since = "1.0.0",
- reason = "dispatch on `cell.borrow_state()` instead")]
- #[inline]
- pub fn try_borrow_mut<'a>(&'a self) -> Option<RefMut<'a, T>> {
- match BorrowRefMut::new(&self.borrow) {
- Some(b) => Some(RefMut { _value: unsafe { &mut *self.value.get() }, _borrow: b }),
- None => None,
- }
- }
-
/// Mutably borrows the wrapped value.
///
/// The borrow lasts until the returned `RefMut` exits scope. The value
/// inverse of `ne`; that is, `!(a == b)` if and only if `a != b`.
#[lang="eq"]
#[stable(feature = "rust1", since = "1.0.0")]
-#[old_orphan_check]
pub trait PartialEq<Rhs: ?Sized = Self> {
/// This method tests for `self` and `other` values to be equal, and is used by `==`.
#[stable(feature = "rust1", since = "1.0.0")]
/// Compare and return the minimum of two values.
///
+/// Returns the first argument if the comparison determines them to be equal.
+///
/// # Examples
///
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn min<T: Ord>(v1: T, v2: T) -> T {
- if v1 < v2 { v1 } else { v2 }
+ if v1 <= v2 { v1 } else { v2 }
}
/// Compare and return the maximum of two values.
///
+/// Returns the second argument if the comparison determines them to be equal.
+///
/// # Examples
///
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn max<T: Ord>(v1: T, v2: T) -> T {
- if v1 > v2 { v1 } else { v2 }
+ if v2 >= v1 { v2 } else { v1 }
}
/// Compare and return the minimum of two values if there is one.
/// Compare and return the maximum of two values if there is one.
///
-/// Returns the first argument if the comparison determines them to be equal.
+/// Returns the second argument if the comparison determines them to be equal.
///
/// # Examples
///
#[unstable(feature = "core")]
pub fn partial_max<T: PartialOrd>(v1: T, v2: T) -> Option<T> {
match v1.partial_cmp(&v2) {
- Some(Less) => Some(v2),
- Some(Equal) | Some(Greater) => Some(v1),
+ Some(Equal) | Some(Less) => Some(v2),
+ Some(Greater) => Some(v1),
None => None
}
}
#[macro_export]
macro_rules! __impl_slice_eq1 {
($Lhs: ty, $Rhs: ty) => {
+ __impl_slice_eq1! { $Lhs, $Rhs, Sized }
+ };
+ ($Lhs: ty, $Rhs: ty, $Bound: ident) => {
#[stable(feature = "rust1", since = "1.0.0")]
- impl<'a, 'b, A, B> PartialEq<$Rhs> for $Lhs where A: PartialEq<B> {
+ impl<'a, 'b, A: $Bound, B> PartialEq<$Rhs> for $Lhs where A: PartialEq<B> {
#[inline]
fn eq(&self, other: &$Rhs) -> bool { &self[..] == &other[..] }
#[inline]
__impl_slice_eq2! { $Lhs, $Rhs, Sized }
};
($Lhs: ty, $Rhs: ty, $Bound: ident) => {
- #[stable(feature = "rust1", since = "1.0.0")]
- impl<'a, 'b, A: $Bound, B> PartialEq<$Rhs> for $Lhs where A: PartialEq<B> {
- #[inline]
- fn eq(&self, other: &$Rhs) -> bool { &self[..] == &other[..] }
- #[inline]
- fn ne(&self, other: &$Rhs) -> bool { &self[..] != &other[..] }
- }
+ __impl_slice_eq1!($Lhs, $Rhs, $Bound);
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, 'b, A: $Bound, B> PartialEq<$Lhs> for $Rhs where B: PartialEq<A> {
//! 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")]
+#![stable(feature = "rust1", since = "1.0.0")]
use marker::Sized;
/// A cheap, reference-to-reference conversion.
+#[stable(feature = "rust1", since = "1.0.0")]
pub trait AsRef<T: ?Sized> {
/// Perform the conversion.
+ #[stable(feature = "rust1", since = "1.0.0")]
fn as_ref(&self) -> &T;
}
/// A cheap, mutable reference-to-mutable reference conversion.
+#[stable(feature = "rust1", since = "1.0.0")]
pub trait AsMut<T: ?Sized> {
/// Perform the conversion.
+ #[stable(feature = "rust1", since = "1.0.0")]
fn as_mut(&mut self) -> &mut T;
}
/// A conversion that consumes `self`, which may or may not be
/// expensive.
+#[stable(feature = "rust1", since = "1.0.0")]
pub trait Into<T>: Sized {
/// Perform the conversion.
+ #[stable(feature = "rust1", since = "1.0.0")]
fn into(self) -> T;
}
/// Construct `Self` via a conversion.
+#[stable(feature = "rust1", since = "1.0.0")]
pub trait From<T> {
/// Perform the conversion.
+ #[stable(feature = "rust1", since = "1.0.0")]
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 &
+#[stable(feature = "rust1", since = "1.0.0")]
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
+#[stable(feature = "rust1", since = "1.0.0")]
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
+#[stable(feature = "rust1", since = "1.0.0")]
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
+#[stable(feature = "rust1", since = "1.0.0")]
impl<T, U> Into<U> for T where U: From<T> {
fn into(self) -> U {
U::from(self)
}
}
+// From (and thus Into) is reflexive
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T> From<T> for T {
+ fn from(t: T) -> T { t }
+}
+
////////////////////////////////////////////////////////////////////////////////
// CONCRETE IMPLS
////////////////////////////////////////////////////////////////////////////////
+#[stable(feature = "rust1", since = "1.0.0")]
impl<T> AsRef<[T]> for [T] {
fn as_ref(&self) -> &[T] {
self
}
}
+#[stable(feature = "rust1", since = "1.0.0")]
impl<T> AsMut<[T]> for [T] {
fn as_mut(&mut self) -> &mut [T] {
self
}
}
+#[stable(feature = "rust1", since = "1.0.0")]
impl AsRef<str> for str {
fn as_ref(&self) -> &str {
self
+++ /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 working with Errors.
-//!
-//! # The `Error` trait
-//!
-//! `Error` is a trait representing the basic expectations for error values,
-//! i.e. values of type `E` in `Result<T, E>`. At a minimum, errors must provide
-//! a description, but they may optionally provide additional detail (via
-//! `Display`) and cause chain information:
-//!
-//! ```
-//! use std::fmt::Display;
-//!
-//! trait Error: Display {
-//! fn description(&self) -> &str;
-//!
-//! fn cause(&self) -> Option<&Error> { None }
-//! }
-//! ```
-//!
-//! The `cause` method is generally used when errors cross "abstraction
-//! boundaries", i.e. when a one module must report an error that is "caused"
-//! by an error from a lower-level module. This setup makes it possible for the
-//! high-level module to provide its own errors that do not commit to any
-//! particular implementation, but also reveal some of its implementation for
-//! debugging via `cause` chains.
-//!
-//! # The `FromError` trait
-//!
-//! `FromError` is a simple trait that expresses conversions between different
-//! error types. To provide maximum flexibility, it does not require either of
-//! the types to actually implement the `Error` trait, although this will be the
-//! common case.
-//!
-//! The main use of this trait is in the `try!` macro, which uses it to
-//! automatically convert a given error to the error specified in a function's
-//! return type.
-//!
-//! For example,
-//!
-//! ```
-//! #![feature(core)]
-//! use std::error::FromError;
-//! use std::{io, str};
-//! use std::fs::File;
-//!
-//! enum MyError {
-//! Io(io::Error),
-//! Utf8(str::Utf8Error),
-//! }
-//!
-//! impl FromError<io::Error> for MyError {
-//! fn from_error(err: io::Error) -> MyError { MyError::Io(err) }
-//! }
-//!
-//! impl FromError<str::Utf8Error> for MyError {
-//! fn from_error(err: str::Utf8Error) -> MyError { MyError::Utf8(err) }
-//! }
-//!
-//! #[allow(unused_variables)]
-//! fn open_and_map() -> Result<(), MyError> {
-//! let b = b"foo.txt";
-//! let s = try!(str::from_utf8(b));
-//! let f = try!(File::open(s));
-//!
-//! // do something interesting here...
-//! Ok(())
-//! }
-//! ```
-
-#![stable(feature = "rust1", since = "1.0.0")]
-
-use prelude::*;
-use fmt::{Debug, Display};
-
-/// Base functionality for all errors in Rust.
-#[stable(feature = "rust1", since = "1.0.0")]
-pub trait Error: Debug + Display {
- /// 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 }
-}
-
-/// A trait for types that can be converted from a given error type `E`.
-#[stable(feature = "rust1", since = "1.0.0")]
-pub trait FromError<E> {
- /// Perform the conversion.
- #[stable(feature = "rust1", since = "1.0.0")]
- fn from_error(err: E) -> Self;
-}
-
-// Any type is convertable from itself
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<E> FromError<E> for E {
- fn from_error(err: E) -> E {
- err
- }
-}
+++ /dev/null
-// Copyright 2013 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.
-
-//! The Finally trait provides a method, `finally` on
-//! stack closures that emulates Java-style try/finally blocks.
-//!
-//! Using the `finally` method is sometimes convenient, but the type rules
-//! prohibit any shared, mutable state between the "try" case and the
-//! "finally" case. For advanced cases, the `try_finally` function can
-//! also be used. See that function for more details.
-//!
-//! # Examples
-//!
-//! ```
-//! # #![feature(core)]
-//! # #![feature(unboxed_closures)]
-//!
-//! use std::finally::Finally;
-//!
-//! (|| {
-//! // ...
-//! }).finally(|| {
-//! // this code is always run
-//! })
-//! ```
-
-#![unstable(feature = "core")]
-#![deprecated(since = "1.0.0",
- reason = "It is unclear if this module is more robust than implementing \
- Drop on a custom type, and this module is being removed with no \
- replacement. Use a custom Drop implementation to regain existing \
- functionality.")]
-#![allow(deprecated)]
-
-use ops::{Drop, FnMut, FnOnce};
-
-/// A trait for executing a destructor unconditionally after a block of code,
-/// regardless of whether the blocked fails.
-pub trait Finally<T> {
- /// Executes this object, unconditionally running `dtor` after this block of
- /// code has run.
- fn finally<F>(&mut self, dtor: F) -> T where F: FnMut();
-}
-
-impl<T, F> Finally<T> for F where F: FnMut() -> T {
- fn finally<G>(&mut self, mut dtor: G) -> T where G: FnMut() {
- try_finally(&mut (), self, |_, f| (*f)(), |_| dtor())
- }
-}
-
-/// The most general form of the `finally` functions. The function
-/// `try_fn` will be invoked first; whether or not it panics, the
-/// function `finally_fn` will be invoked next. The two parameters
-/// `mutate` and `drop` are used to thread state through the two
-/// closures. `mutate` is used for any shared, mutable state that both
-/// closures require access to; `drop` is used for any state that the
-/// `try_fn` requires ownership of.
-///
-/// **WARNING:** While shared, mutable state between the try and finally
-/// function is often necessary, one must be very careful; the `try`
-/// function could have panicked at any point, so the values of the shared
-/// state may be inconsistent.
-///
-/// # Examples
-///
-/// ```
-/// # #![feature(core)]
-/// use std::finally::try_finally;
-///
-/// struct State<'a> { buffer: &'a mut [u8], len: usize }
-/// # let mut buf = [];
-/// let mut state = State { buffer: &mut buf, len: 0 };
-/// try_finally(
-/// &mut state, (),
-/// |state, ()| {
-/// // use state.buffer, state.len
-/// },
-/// |state| {
-/// // use state.buffer, state.len to cleanup
-/// })
-/// ```
-pub fn try_finally<T, U, R, F, G>(mutate: &mut T, drop: U, try_fn: F, finally_fn: G) -> R where
- F: FnOnce(&mut T, U) -> R,
- G: FnMut(&mut T),
-{
- let f = Finallyalizer {
- mutate: mutate,
- dtor: finally_fn,
- };
- try_fn(&mut *f.mutate, drop)
-}
-
-struct Finallyalizer<'a, A:'a, F> where F: FnMut(&mut A) {
- mutate: &'a mut A,
- dtor: F,
-}
-
-#[unsafe_destructor]
-impl<'a, A, F> Drop for Finallyalizer<'a, A, F> where F: FnMut(&mut A) {
- #[inline]
- fn drop(&mut self) {
- (self.dtor)(self.mutate);
- }
-}
#![stable(feature = "rust1", since = "1.0.0")]
-use any;
use cell::{Cell, RefCell, Ref, RefMut, BorrowState};
use char::CharExt;
+use clone::Clone;
use iter::Iterator;
use marker::{Copy, PhantomData, Sized};
use mem;
/// occurred. Any extra information must be arranged to be transmitted through
/// some other means.
#[stable(feature = "rust1", since = "1.0.0")]
-#[derive(Copy, Debug)]
+#[derive(Copy, Clone, Debug)]
pub struct Error;
/// A collection of methods that are required to format a message into a stream.
formatter: fn(&Void, &mut Formatter) -> Result,
}
+impl<'a> Clone for ArgumentV1<'a> {
+ fn clone(&self) -> ArgumentV1<'a> {
+ *self
+ }
+}
+
impl<'a> ArgumentV1<'a> {
#[inline(never)]
fn show_usize(x: &usize, f: &mut Formatter) -> Result {
}
// flags available in the v1 format of format_args
-#[derive(Copy)]
+#[derive(Copy, Clone)]
#[allow(dead_code)] // SignMinus isn't currently used
enum FlagV1 { SignPlus, SignMinus, Alternate, SignAwareZeroPad, }
/// macro validates the format string at compile-time so usage of the `write`
/// and `format` functions can be safely performed.
#[stable(feature = "rust1", since = "1.0.0")]
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub struct Arguments<'a> {
// Format string pieces to print.
pieces: &'a [&'a str],
tuple! { T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, }
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a> Debug for &'a (any::Any+'a) {
- fn fmt(&self, f: &mut Formatter) -> Result { f.pad("&Any") }
-}
-
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: Debug> Debug for [T] {
fn fmt(&self, f: &mut Formatter) -> Result {
/// A helper type for formatting radixes.
#[unstable(feature = "core",
reason = "may be renamed or move to a different module")]
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub struct RadixFmt<T, R>(T, R);
/// Constructs a radix formatter in the range of `2..36`.
#![stable(feature = "rust1", since = "1.0.0")]
-#[derive(Copy)]
+#[derive(Copy, Clone)]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Argument {
#[stable(feature = "rust1", since = "1.0.0")]
pub format: FormatSpec,
}
-#[derive(Copy)]
+#[derive(Copy, Clone)]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct FormatSpec {
#[stable(feature = "rust1", since = "1.0.0")]
}
/// Possible alignments that can be requested as part of a formatting directive.
-#[derive(Copy, PartialEq)]
+#[derive(Copy, Clone, PartialEq)]
#[stable(feature = "rust1", since = "1.0.0")]
pub enum Alignment {
/// Indication that contents should be left-aligned.
Unknown,
}
-#[derive(Copy)]
+#[derive(Copy, Clone)]
#[stable(feature = "rust1", since = "1.0.0")]
pub enum Count {
#[stable(feature = "rust1", since = "1.0.0")]
Implied,
}
-#[derive(Copy)]
+#[derive(Copy, Clone)]
#[stable(feature = "rust1", since = "1.0.0")]
pub enum Position {
#[stable(feature = "rust1", since = "1.0.0")]
fn hash_slice<H: Hasher>(data: &[$ty], state: &mut H) {
// FIXME(#23542) Replace with type ascription.
#![allow(trivial_casts)]
- let newlen = data.len() * ::$ty::BYTES as usize;
+ let newlen = data.len() * ::$ty::BYTES;
let ptr = data.as_ptr() as *const u8;
state.write(unsafe { slice::from_raw_parts(ptr, newlen) })
}
state
}
- /// Returns the computed hash.
- #[unstable(feature = "hash")]
- #[deprecated(since = "1.0.0", reason = "renamed to finish")]
- pub fn result(&self) -> u64 { self.finish() }
-
fn reset(&mut self) {
self.length = 0;
self.v0 = self.k0 ^ 0x736f6d6570736575;
/// Rust moves to non-zeroing dynamic drop (and thus removes the
/// embedded drop flags that are being established by this
/// intrinsic).
- #[cfg(not(stage0))]
pub fn init_dropped<T>() -> T;
/// Create a value initialized to zero.
//!
//! # The `Iterator` trait
//!
-//! This module defines Rust's core iteration trait. The `Iterator` trait has one
-//! unimplemented method, `next`. All other methods are derived through default
-//! methods to perform operations such as `zip`, `chain`, `enumerate`, and `fold`.
+//! This module defines Rust's core iteration trait. The `Iterator` trait has
+//! one unimplemented method, `next`. All other methods are derived through
+//! default methods to perform operations such as `zip`, `chain`, `enumerate`,
+//! and `fold`.
//!
//! The goal of this module is to unify iteration across all containers in Rust.
-//! An iterator can be considered as a state machine which is used to track which
-//! element will be yielded next.
+//! An iterator can be considered as a state machine which is used to track
+//! which element will be yielded next.
//!
-//! There are various extensions also defined in this module to assist with various
-//! types of iteration, such as the `DoubleEndedIterator` for iterating in reverse,
-//! the `FromIterator` trait for creating a container from an iterator, and much
-//! more.
+//! There are various extensions also defined in this module to assist with
+//! various types of iteration, such as the `DoubleEndedIterator` for iterating
+//! in reverse, the `FromIterator` trait for creating a container from an
+//! iterator, and much more.
//!
-//! ## Rust's `for` loop
+//! # Rust's `for` loop
//!
-//! The special syntax used by rust's `for` loop is based around the `Iterator`
-//! trait defined in this module. For loops can be viewed as a syntactical expansion
-//! into a `loop`, for example, the `for` loop in this example is essentially
-//! translated to the `loop` below.
+//! The special syntax used by rust's `for` loop is based around the
+//! `IntoIterator` trait defined in this module. `for` loops can be viewed as a
+//! syntactical expansion into a `loop`, for example, the `for` loop in this
+//! example is essentially translated to the `loop` below.
//!
//! ```
//! let values = vec![1, 2, 3];
//!
-//! // "Syntactical sugar" taking advantage of an iterator
-//! for &x in values.iter() {
+//! for x in values {
//! println!("{}", x);
//! }
//!
//! // Rough translation of the iteration without a `for` iterator.
-//! let mut it = values.iter();
+//! # let values = vec![1, 2, 3];
+//! let mut it = values.into_iter();
//! loop {
//! match it.next() {
-//! Some(&x) => {
-//! println!("{}", x);
-//! }
-//! None => { break }
+//! Some(x) => println!("{}", x),
+//! None => break,
//! }
//! }
//! ```
//!
-//! This `for` loop syntax can be applied to any iterator over any type.
+//! Because `Iterator`s implement `IntoIterator`, this `for` loop syntax can be applied to any
+//! iterator over any type.
#![stable(feature = "rust1", since = "1.0.0")]
use default::Default;
use marker;
use mem;
-use num::{Int, Zero, One, ToPrimitive};
-use ops::{Add, Sub, FnMut, RangeFrom};
-use option::Option;
-use option::Option::{Some, None};
+use num::{Int, Zero, One};
+use ops::{self, Add, Sub, FnMut, RangeFrom};
+use option::Option::{self, Some, None};
use marker::Sized;
use usize;
/// else.
#[lang="iterator"]
#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_on_unimplemented = "`{Self}` is not an iterator; maybe try calling `.iter()` or a similar \
- method"]
+#[rustc_on_unimplemented = "`{Self}` is not an iterator; maybe try calling \
+ `.iter()` or a similar method"]
pub trait Iterator {
/// The type of the elements being iterated
#[stable(feature = "rust1", since = "1.0.0")]
type Item;
- /// Advance the iterator and return the next value. Return `None` when the end is reached.
+ /// Advance the iterator and return the next value. Return `None` when the
+ /// end is reached.
#[stable(feature = "rust1", since = "1.0.0")]
fn next(&mut self) -> Option<Self::Item>;
/// Returns a lower and upper bound on the remaining length of the iterator.
///
- /// An upper bound of `None` means either there is no known upper bound, or the upper bound
- /// does not fit within a `usize`.
+ /// An upper bound of `None` means either there is no known upper bound, or
+ /// the upper bound does not fit within a `usize`.
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
fn size_hint(&self) -> (usize, Option<usize>) { (0, None) }
/// iterator plus the current index of iteration.
///
/// `enumerate` keeps its count as a `usize`. If you want to count by a
- /// different sized integer, the `zip` function provides similar functionality.
+ /// different sized integer, the `zip` function provides similar
+ /// functionality.
///
/// # Examples
///
/// # #![feature(core)]
/// let xs = [2, 3];
/// let ys = [0, 1, 0, 1, 2];
- /// let it = xs.iter().flat_map(|&x| std::iter::count(0, 1).take(x));
+ /// let it = xs.iter().flat_map(|&x| (0..).take(x));
/// // Check that `it` has the same elements as `ys`
/// for (i, x) in it.enumerate() {
/// assert_eq!(x, ys[i]);
/// # Examples
///
/// ```
- /// # #![feature(core)]
- /// let a = [1, 2, 3, 4, 5];
- /// let b: Vec<_> = a.iter().cloned().collect();
- /// assert_eq!(a, b);
+ /// let expected = [1, 2, 3, 4, 5];
+ /// let actual: Vec<_> = expected.iter().cloned().collect();
+ /// assert_eq!(actual, expected);
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
/// assert_eq!(even, [2, 4]);
/// assert_eq!(odd, [1, 3]);
/// ```
- #[unstable(feature = "core",
- reason = "recently added as part of collections reform")]
+ #[stable(feature = "rust1", since = "1.0.0")]
fn partition<B, F>(self, mut f: F) -> (B, B) where
Self: Sized,
B: Default + Extend<Self::Item>,
true
}
- /// Tests whether any element of an iterator satisfies the specified predicate.
+ /// Tests whether any element of an iterator satisfies the specified
+ /// predicate.
///
/// Does not consume the iterator past the first found element.
///
/// let a = [1, 2, 3, 4, 5];
/// let mut it = a.iter();
/// assert!(it.any(|x| *x == 3));
- /// assert_eq!(it.as_slice(), [4, 5]);
+ /// assert_eq!(&it[..], [4, 5]);
///
/// ```
#[inline]
/// let a = [1, 2, 3, 4, 5];
/// let mut it = a.iter();
/// assert_eq!(it.find(|&x| *x == 3).unwrap(), &3);
- /// assert_eq!(it.as_slice(), [4, 5]);
+ /// assert_eq!(&it[..], [4, 5]);
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
fn find<P>(&mut self, mut predicate: P) -> Option<Self::Item> where
/// let a = [1, 2, 3, 4, 5];
/// let mut it = a.iter();
/// assert_eq!(it.position(|x| *x == 3).unwrap(), 2);
- /// assert_eq!(it.as_slice(), [4, 5]);
+ /// assert_eq!(&it[..], [4, 5]);
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
fn position<P>(&mut self, mut predicate: P) -> Option<usize> where
/// let a = [1, 2, 2, 4, 5];
/// let mut it = a.iter();
/// assert_eq!(it.rposition(|x| *x == 2).unwrap(), 2);
- /// assert_eq!(it.as_slice(), [1, 2]);
+ /// assert_eq!(&it[..], [1, 2]);
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
fn rposition<P>(&mut self, mut predicate: P) -> Option<usize> where
/// Consumes the entire iterator to return the maximum element.
///
+ /// Returns the rightmost element if the comparison determines two elements
+ /// to be equally maximum.
+ ///
/// # Examples
///
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
fn max(self) -> Option<Self::Item> where Self: Sized, Self::Item: Ord
{
- self.fold(None, |max, x| {
+ self.fold(None, |max, y| {
match max {
- None => Some(x),
- Some(y) => Some(cmp::max(x, y))
+ None => Some(y),
+ Some(x) => Some(cmp::max(x, y))
}
})
}
/// Consumes the entire iterator to return the minimum element.
///
+ /// Returns the leftmost element if the comparison determines two elements
+ /// to be equally minimum.
+ ///
/// # Examples
///
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
fn min(self) -> Option<Self::Item> where Self: Sized, Self::Item: Ord
{
- self.fold(None, |min, x| {
+ self.fold(None, |min, y| {
match min {
- None => Some(x),
- Some(y) => Some(cmp::min(x, y))
+ None => Some(y),
+ Some(x) => Some(cmp::min(x, y))
}
})
}
/// element in the iterator and all elements are equal.
///
/// On an iterator of length `n`, `min_max` does `1.5 * n` comparisons,
- /// and so is faster than calling `min` and `max` separately which does `2 * n` comparisons.
+ /// and so is faster than calling `min` and `max` separately which does `2 *
+ /// n` comparisons.
///
/// # Examples
///
Some(x) => {
match self.next() {
None => return OneElement(x),
- Some(y) => if x < y {(x, y)} else {(y,x)}
+ Some(y) => if x <= y {(x, y)} else {(y, x)}
}
}
};
loop {
- // `first` and `second` are the two next elements we want to look at.
- // We first compare `first` and `second` (#1). The smaller one is then compared to
- // current minimum (#2). The larger one is compared to current maximum (#3). This
- // way we do 3 comparisons for 2 elements.
+ // `first` and `second` are the two next elements we want to look
+ // at. We first compare `first` and `second` (#1). The smaller one
+ // is then compared to current minimum (#2). The larger one is
+ // compared to current maximum (#3). This way we do 3 comparisons
+ // for 2 elements.
let first = match self.next() {
None => break,
Some(x) => x
None => {
if first < min {
min = first;
- } else if first > max {
+ } else if first >= max {
max = first;
}
break;
}
Some(x) => x
};
- if first < second {
- if first < min {min = first;}
- if max < second {max = second;}
+ if first <= second {
+ if first < min { min = first }
+ if second >= max { max = second }
} else {
- if second < min {min = second;}
- if max < first {max = first;}
+ if second < min { min = second }
+ if first >= max { max = first }
}
}
/// Return the element that gives the maximum value from the
/// specified function.
///
+ /// Returns the rightmost element if the comparison determines two elements
+ /// to be equally maximum.
+ ///
/// # Examples
///
/// ```
Self: Sized,
F: FnMut(&Self::Item) -> B,
{
- self.fold(None, |max: Option<(Self::Item, B)>, x| {
- let x_val = f(&x);
+ self.fold(None, |max: Option<(Self::Item, B)>, y| {
+ let y_val = f(&y);
match max {
- None => Some((x, x_val)),
- Some((y, y_val)) => if x_val > y_val {
- Some((x, x_val))
- } else {
+ None => Some((y, y_val)),
+ Some((x, x_val)) => if y_val >= x_val {
Some((y, y_val))
+ } else {
+ Some((x, x_val))
}
}
}).map(|(x, _)| x)
/// Return the element that gives the minimum value from the
/// specified function.
///
+ /// Returns the leftmost element if the comparison determines two elements
+ /// to be equally minimum.
+ ///
/// # Examples
///
/// ```
Self: Sized,
F: FnMut(&Self::Item) -> B,
{
- self.fold(None, |min: Option<(Self::Item, B)>, x| {
- let x_val = f(&x);
+ self.fold(None, |min: Option<(Self::Item, B)>, y| {
+ let y_val = f(&y);
match min {
- None => Some((x, x_val)),
- Some((y, y_val)) => if x_val < y_val {
+ None => Some((y, y_val)),
+ Some((x, x_val)) => if x_val <= y_val {
Some((x, x_val))
} else {
Some((y, y_val))
/// # #![feature(core)]
/// let a = [(1, 2), (3, 4)];
/// let (left, right): (Vec<_>, Vec<_>) = a.iter().cloned().unzip();
- /// assert_eq!([1, 3], left);
- /// assert_eq!([2, 4], right);
+ /// assert_eq!(left, [1, 3]);
+ /// assert_eq!(right, [2, 4]);
/// ```
- #[unstable(feature = "core", reason = "recent addition")]
+ #[stable(feature = "rust1", since = "1.0.0")]
fn unzip<A, B, FromA, FromB>(self) -> (FromA, FromB) where
FromA: Default + Extend<A>,
FromB: Default + Extend<B>,
/// assert_eq!(colors_set.len(), 3);
/// ```
///
- /// `FromIterator` is more commonly used implicitly via the `Iterator::collect` method:
+ /// `FromIterator` is more commonly used implicitly via the
+ /// `Iterator::collect` method:
///
/// ```
/// use std::collections::HashSet;
}
/// Conversion into an `Iterator`
+///
+/// Implementing this trait allows you to use your type with Rust's `for` loop. See
+/// the [module level documentation](../index.html) for more details.
#[stable(feature = "rust1", since = "1.0.0")]
pub trait IntoIterator {
/// The type of the elements being iterated
/// An object implementing random access indexing by `usize`
///
-/// A `RandomAccessIterator` should be either infinite or a `DoubleEndedIterator`.
-/// Calling `next()` or `next_back()` on a `RandomAccessIterator`
-/// reduces the indexable range accordingly. That is, `it.idx(1)` will become `it.idx(0)`
-/// after `it.next()` is called.
+/// A `RandomAccessIterator` should be either infinite or a
+/// `DoubleEndedIterator`. Calling `next()` or `next_back()` on a
+/// `RandomAccessIterator` reduces the indexable range accordingly. That is,
+/// `it.idx(1)` will become `it.idx(0)` after `it.next()` is called.
#[unstable(feature = "core",
- reason = "not widely used, may be better decomposed into Index and ExactSizeIterator")]
+ reason = "not widely used, may be better decomposed into Index \
+ and ExactSizeIterator")]
pub trait RandomAccessIterator: Iterator {
/// Return the number of indexable elements. At most `std::usize::MAX`
/// elements are indexable, even if the iterator represents a longer range.
F: FnMut(&I::Item),
{}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<I> ExactSizeIterator for Rev<I> where I: ExactSizeIterator + DoubleEndedIterator {}
+impl<I> ExactSizeIterator for Rev<I>
+ where I: ExactSizeIterator + DoubleEndedIterator {}
#[stable(feature = "rust1", since = "1.0.0")]
impl<B, I: ExactSizeIterator, F> ExactSizeIterator for Map<I, F> where
F: FnMut(I::Item) -> B,
{}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<A, B> ExactSizeIterator for Zip<A, B> where A: ExactSizeIterator, B: ExactSizeIterator {}
+impl<A, B> ExactSizeIterator for Zip<A, B>
+ where A: ExactSizeIterator, B: ExactSizeIterator {}
/// An double-ended iterator with the direction inverted
#[derive(Clone)]
}
#[unstable(feature = "core", reason = "trait is experimental")]
-impl<I> RandomAccessIterator for Rev<I> where I: DoubleEndedIterator + RandomAccessIterator {
+impl<I> RandomAccessIterator for Rev<I>
+ where I: DoubleEndedIterator + RandomAccessIterator
+{
#[inline]
fn indexable(&self) -> usize { self.iter.indexable() }
#[inline]
///
/// ```
/// # #![feature(core)]
- /// use std::iter::{count, MultiplicativeIterator};
+ /// use std::iter::MultiplicativeIterator;
///
/// fn factorial(n: usize) -> usize {
- /// count(1, 1).take_while(|&i| i <= n).product()
+ /// (1..).take_while(|&i| i <= n).product()
/// }
/// assert!(factorial(0) == 1);
/// assert!(factorial(1) == 1);
impl_multiplicative! { f32, 1.0 }
impl_multiplicative! { f64, 1.0 }
-/// `MinMaxResult` is an enum returned by `min_max`. See `Iterator::min_max` for more detail.
+/// `MinMaxResult` is an enum returned by `min_max`. See `Iterator::min_max` for
+/// more detail.
#[derive(Clone, PartialEq, Debug)]
#[unstable(feature = "core",
reason = "unclear whether such a fine-grained result is widely useful")]
/// Iterator with one element, so the minimum and maximum are the same
OneElement(T),
- /// More than one element in the iterator, the first element is not larger than the second
+ /// More than one element in the iterator, the first element is not larger
+ /// than the second
MinMax(T, T)
}
impl<T: Clone> MinMaxResult<T> {
- /// `into_option` creates an `Option` of type `(T,T)`. The returned `Option` has variant
- /// `None` if and only if the `MinMaxResult` has variant `NoElements`. Otherwise variant
- /// `Some(x,y)` is returned where `x <= y`. If `MinMaxResult` has variant `OneElement(x)`,
- /// performing this operation will make one clone of `x`.
+ /// `into_option` creates an `Option` of type `(T,T)`. The returned `Option`
+ /// has variant `None` if and only if the `MinMaxResult` has variant
+ /// `NoElements`. Otherwise variant `Some(x,y)` is returned where `x <= y`.
+ /// If `MinMaxResult` has variant `OneElement(x)`, performing this operation
+ /// will make one clone of `x`.
///
/// # Examples
///
}
#[allow(deprecated)]
-impl<A: Step> ::ops::Range<A> {
+impl<A: Step> ops::Range<A> {
/// Creates an iterator with the same range, but stepping by the
/// given amount at each iteration.
///
}
}
-/// An infinite iterator starting at `start` and advancing by `step` with each
-/// iteration
-#[unstable(feature = "core",
- reason = "may be renamed or replaced by range notation adapters")]
-#[deprecated(since = "1.0.0-beta", reason = "use range notation and step_by")]
-pub type Counter<A> = StepBy<A, RangeFrom<A>>;
-
-/// Deprecated: use `(start..).step_by(step)` instead.
-#[inline]
-#[unstable(feature = "core",
- reason = "may be renamed or replaced by range notation adapters")]
-#[deprecated(since = "1.0.0-beta", reason = "use (start..).step_by(step) instead")]
-#[allow(deprecated)]
-pub fn count<A>(start: A, step: A) -> Counter<A> {
- StepBy {
- range: RangeFrom { start: start },
- step_by: step,
- }
-}
-
#[stable(feature = "rust1", since = "1.0.0")]
impl<A> Iterator for StepBy<A, RangeFrom<A>> where
A: Clone,
}
}
-/// An iterator over the range [start, stop)
-#[allow(deprecated)]
-#[derive(Clone)]
-#[unstable(feature = "core",
- reason = "will be replaced by range notation")]
-#[deprecated(since = "1.0.0-beta", reason = "use range notation")]
-pub struct Range<A> {
- state: A,
- stop: A,
- one: A,
-}
-
-/// Deprecated: use `(start..stop)` instead.
-#[inline]
-#[unstable(feature = "core", reason = "will be replaced by range notation")]
-#[deprecated(since = "1.0.0-beta", reason = "use (start..stop) instead")]
-#[allow(deprecated)]
-pub fn range<A: Int>(start: A, stop: A) -> Range<A> {
- Range {
- state: start,
- stop: stop,
- one: Int::one(),
- }
-}
-
-// FIXME: #10414: Unfortunate type bound
-#[unstable(feature = "core",
- reason = "will be replaced by range notation")]
-#[deprecated(since = "1.0.0-beta", reason = "use range notation")]
-#[allow(deprecated)]
-impl<A: Int + ToPrimitive> Iterator for Range<A> {
- type Item = A;
-
- #[inline]
- fn next(&mut self) -> Option<A> {
- if self.state < self.stop {
- let result = self.state.clone();
- self.state = self.state + self.one;
- Some(result)
- } else {
- None
- }
- }
-
- #[inline]
- fn size_hint(&self) -> (usize, Option<usize>) {
- // This first checks if the elements are representable as i64. If they aren't, try u64 (to
- // handle cases like range(huge, huger)). We don't use usize/isize because the difference of
- // the i64/u64 might lie within their range.
- let bound = match self.state.to_i64() {
- Some(a) => {
- let sz = self.stop.to_i64().map(|b| b.checked_sub(a));
- match sz {
- Some(Some(bound)) => bound.to_usize(),
- _ => None,
- }
- },
- None => match self.state.to_u64() {
- Some(a) => {
- let sz = self.stop.to_u64().map(|b| b.checked_sub(a));
- match sz {
- Some(Some(bound)) => bound.to_usize(),
- _ => None
- }
- },
- None => None
- }
- };
-
- match bound {
- Some(b) => (b, Some(b)),
- // Standard fallback for unbounded/unrepresentable bounds
- None => (0, None)
- }
- }
-}
-
-/// `Int` is required to ensure the range will be the same regardless of
-/// the direction it is consumed.
-#[unstable(feature = "core",
- reason = "will be replaced by range notation")]
-#[deprecated(since = "1.0.0-beta", reason = "use range notation")]
-#[allow(deprecated)]
-impl<A: Int + ToPrimitive> DoubleEndedIterator for Range<A> {
- #[inline]
- fn next_back(&mut self) -> Option<A> {
- if self.stop > self.state {
- self.stop = self.stop - self.one;
- Some(self.stop.clone())
- } else {
- None
- }
- }
-}
-
/// An iterator over the range [start, stop]
#[derive(Clone)]
#[unstable(feature = "core",
reason = "likely to be replaced by range notation and adapters")]
-#[allow(deprecated)]
pub struct RangeInclusive<A> {
- range: Range<A>,
+ range: ops::Range<A>,
done: bool,
}
#[inline]
#[unstable(feature = "core",
reason = "likely to be replaced by range notation and adapters")]
-#[allow(deprecated)]
-pub fn range_inclusive<A: Int>(start: A, stop: A) -> RangeInclusive<A> {
+pub fn range_inclusive<A>(start: A, stop: A) -> RangeInclusive<A>
+ where A: Step + One + Clone
+{
RangeInclusive {
- range: range(start, stop),
+ range: start..stop,
done: false,
}
}
#[unstable(feature = "core",
reason = "likely to be replaced by range notation and adapters")]
-#[allow(deprecated)]
-impl<A: Int + ToPrimitive> Iterator for RangeInclusive<A> {
+impl<A: Step + One + Clone> Iterator for RangeInclusive<A> {
type Item = A;
#[inline]
match self.range.next() {
Some(x) => Some(x),
None => {
- if !self.done && self.range.state == self.range.stop {
+ if !self.done && self.range.start == self.range.end {
self.done = true;
- Some(self.range.stop.clone())
+ Some(self.range.end.clone())
} else {
None
}
#[unstable(feature = "core",
reason = "likely to be replaced by range notation and adapters")]
-#[allow(deprecated)]
-impl<A: Int + ToPrimitive> DoubleEndedIterator for RangeInclusive<A> {
+impl<A> DoubleEndedIterator for RangeInclusive<A>
+ where A: Step + One + Clone,
+ for<'a> &'a A: Sub<Output=A>
+{
#[inline]
fn next_back(&mut self) -> Option<A> {
- if self.range.stop > self.range.state {
- let result = self.range.stop.clone();
- self.range.stop = self.range.stop - self.range.one;
+ if self.range.end > self.range.start {
+ let result = self.range.end.clone();
+ self.range.end = &self.range.end - &A::one();
Some(result)
- } else if !self.done && self.range.state == self.range.stop {
+ } else if !self.done && self.range.start == self.range.end {
self.done = true;
- Some(self.range.stop.clone())
+ Some(self.range.end.clone())
} else {
None
}
}
}
-/// An iterator over the range [start, stop) by `step`. It handles overflow by stopping.
-#[unstable(feature = "core",
- reason = "likely to be replaced by range notation and adapters")]
-#[deprecated(since = "1.0.0-beta", reason = "use range notation and step_by")]
-pub type RangeStep<A> = StepBy<A, ::ops::Range<A>>;
-
-/// Deprecated: use `(start..stop).step_by(step)` instead.
-#[inline]
-#[unstable(feature = "core",
- reason = "likely to be replaced by range notation and adapters")]
-#[deprecated(since = "1.0.0-beta",
- reason = "use `(start..stop).step_by(step)` instead")]
-#[allow(deprecated)]
-pub fn range_step<A: Int>(start: A, stop: A, step: A) -> RangeStep<A> {
- StepBy {
- step_by: step,
- range: ::ops::Range { start: start, end: stop },
- }
-}
-
#[stable(feature = "rust1", since = "1.0.0")]
#[allow(deprecated)]
-impl<A: Step + Zero + Clone> Iterator for StepBy<A, ::ops::Range<A>> {
+impl<A: Step + Zero + Clone> Iterator for StepBy<A, ops::Range<A>> {
type Item = A;
#[inline]
macro_rules! range_exact_iter_impl {
($($t:ty)*) => ($(
#[stable(feature = "rust1", since = "1.0.0")]
- impl ExactSizeIterator for ::ops::Range<$t> { }
+ impl ExactSizeIterator for ops::Range<$t> { }
)*)
}
#[stable(feature = "rust1", since = "1.0.0")]
#[allow(deprecated)]
-impl<A: Step + One + Clone> Iterator for ::ops::Range<A> {
+impl<A: Step + One + Clone> Iterator for ops::Range<A> {
type Item = A;
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
#[allow(deprecated)]
-impl<A: Step + One + Clone> DoubleEndedIterator for ::ops::Range<A> where
+impl<A: Step + One + Clone> DoubleEndedIterator for ops::Range<A> where
for<'a> &'a A: Sub<&'a A, Output = A>
{
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
#[allow(deprecated)]
-impl<A: Step + One> Iterator for ::ops::RangeFrom<A> {
+impl<A: Step + One> Iterator for ops::RangeFrom<A> {
type Item = A;
#[inline]
#![feature(unboxed_closures)]
#![feature(rustc_attrs)]
#![feature(optin_builtin_traits)]
+#![feature(fundamental)]
#![feature(concat_idents)]
#![feature(reflect)]
+#![feature(custom_attribute)]
#[macro_use]
mod macros;
pub mod cell;
pub mod char;
pub mod panicking;
-pub mod finally;
pub mod iter;
pub mod option;
pub mod raw;
pub mod str;
pub mod hash;
pub mod fmt;
-pub mod error;
#[doc(primitive = "bool")]
mod bool {
);
}
-/// Asserts that two expressions are equal to each other, testing equality in
-/// both directions.
+/// Asserts that two expressions are equal to each other.
///
-/// On panic, this macro will print the values of the expressions.
+/// On panic, this macro will print the values of the expressions with their
+/// debug representations.
///
/// # Examples
///
($left:expr , $right:expr) => ({
match (&($left), &($right)) {
(left_val, right_val) => {
- // check both directions of equality....
- if !((*left_val == *right_val) &&
- (*right_val == *left_val)) {
- panic!("assertion failed: `(left == right) && (right == left)` \
+ if !(*left_val == *right_val) {
+ panic!("assertion failed: `(left == right)` \
(left: `{:?}`, right: `{:?}`)", *left_val, *right_val)
}
}
/// Short circuiting evaluation on Err
///
-/// `libstd` contains a more general `try!` macro that uses `FromError`.
+/// `libstd` contains a more general `try!` macro that uses `From<E>`.
#[macro_export]
macro_rules! try {
($e:expr) => ({
/// ```
/// # #![feature(core)]
/// fn divide_by_three(x: u32) -> u32 { // one of the poorest implementations of x/3
-/// for i in std::iter::count(0, 1) {
+/// for i in 0.. {
/// if 3*i < i { panic!("u32 overflow"); }
/// if x < 3*i { return i-1; }
/// }
#[stable(feature = "rust1", since = "1.0.0")]
#[lang="sized"]
#[rustc_on_unimplemented = "`{Self}` does not have a constant size known at compile-time"]
+#[fundamental] // for Default, for example, which requires that `[T]: !Default` be evaluatable
pub trait Sized : MarkerTrait {
// Empty.
}
///
/// ```
/// // we can just derive a `Copy` implementation
-/// #[derive(Debug, Copy)]
+/// #[derive(Debug, Copy, Clone)]
/// struct Foo;
///
/// let x = Foo;
/// There are two ways to implement `Copy` on your type:
///
/// ```
-/// #[derive(Copy)]
+/// #[derive(Copy, Clone)]
/// struct MyStruct;
/// ```
///
/// ```
/// struct MyStruct;
/// impl Copy for MyStruct {}
+/// impl Clone for MyStruct { fn clone(&self) -> MyStruct { *self } }
/// ```
///
/// There is a small difference between the two: the `derive` strategy will also place a `Copy`
/// change: that second example would fail to compile if we made `Foo` non-`Copy`.
#[stable(feature = "rust1", since = "1.0.0")]
#[lang="copy"]
-pub trait Copy : MarkerTrait {
+pub trait Copy : Clone {
// Empty.
}
#[stable(feature = "rust1", since = "1.0.0")]
pub trait PhantomFn<A:?Sized,R:?Sized=()> { }
-/// `PhantomData` is a way to tell the compiler about fake fields.
-/// Phantom data is required whenever type parameters are not used.
-/// The idea is that if the compiler encounters a `PhantomData<T>`
-/// instance, it will behave *as if* an instance of the type `T` were
-/// present for the purpose of various automatic analyses.
+/// `PhantomData<T>` allows you to describe that a type acts as if it stores a value of type `T`,
+/// even though it does not. This allows you to inform the compiler about certain safety properties
+/// of your code.
+///
+/// Though they both have scary names, `PhantomData<T>` and "phantom types" are unrelated. 👻👻👻
///
/// # Examples
///
/// When handling external resources over a foreign function interface, `PhantomData<T>` can
-/// prevent mismatches by enforcing types in the method implementations, although the struct
-/// doesn't actually contain values of the resource type.
+/// prevent mismatches by enforcing types in the method implementations:
///
/// ```
/// # trait ResType { fn foo(&self); };
/// commonly necessary if the structure is using an unsafe pointer
/// like `*mut T` whose referent may be dropped when the type is
/// dropped, as a `*mut T` is otherwise not treated as owned.
-///
-/// FIXME. Better documentation and examples of common patterns needed
-/// here! For now, please see [RFC 738][738] for more information.
-///
-/// [738]: https://github.com/rust-lang/rfcs/blob/master/text/0738-variance.md
#[lang="phantom_data"]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct PhantomData<T:?Sized>;
unsafe impl<'a, T: Send + ?Sized> Send for &'a mut T {}
}
-/// Old-style marker trait. Deprecated.
-#[unstable(feature = "core", reason = "deprecated")]
-#[deprecated(since = "1.0.0", reason = "Replace with `PhantomData<&'a ()>`")]
-#[lang="contravariant_lifetime"]
-pub struct ContravariantLifetime<'a>;
-
-/// Old-style marker trait. Deprecated.
-#[unstable(feature = "core", reason = "deprecated")]
-#[deprecated(since = "1.0.0", reason = "Replace with `PhantomData<fn(&'a ())>`")]
-#[lang="covariant_lifetime"]
-pub struct CovariantLifetime<'a>;
-
-/// Old-style marker trait. Deprecated.
-#[unstable(feature = "core", reason = "deprecated")]
-#[deprecated(since = "1.0.0", reason = "Replace with `PhantomData<Cell<&'a ()>>`")]
-#[lang="invariant_lifetime"]
-pub struct InvariantLifetime<'a>;
-
-/// Old-style marker trait. Deprecated.
-#[unstable(feature = "core", reason = "deprecated")]
-#[deprecated(since = "1.0.0", reason = "Replace with `PhantomData<fn(T)>`")]
-#[lang="contravariant_type"]
-pub struct ContravariantType<T>;
-
-/// Old-style marker trait. Deprecated.
-#[unstable(feature = "core", reason = "deprecated")]
-#[deprecated(since = "1.0.0", reason = "Replace with `PhantomData<T>`")]
-#[lang="covariant_type"]
-pub struct CovariantType<T>;
-
-/// Old-style marker trait. Deprecated.
-#[unstable(feature = "core", reason = "deprecated")]
-#[deprecated(since = "1.0.0", reason = "Replace with `PhantomData<Cell<T>>`")]
-#[lang="invariant_type"]
-pub struct InvariantType<T>;
-
/// A marker trait indicates a type that can be reflected over. This
/// trait is implemented for all types. Its purpose is to ensure that
/// when you write a generic function that will employ reflection,
pub trait Reflect : MarkerTrait {
}
-#[cfg(stage0)]
-impl<T> Reflect for T { }
-
-#[cfg(not(stage0))]
impl Reflect for .. { }
#[inline]
#[unstable(feature = "filling_drop")]
pub unsafe fn dropped<T>() -> T {
- #[cfg(stage0)]
- #[inline(always)]
- unsafe fn dropped_impl<T>() -> T { zeroed() }
-
- #[cfg(not(stage0))]
#[inline(always)]
unsafe fn dropped_impl<T>() -> T { intrinsics::init_dropped() }
// But having the sign bit set is a pain, so 0x1d is probably better.
//
// And of course, 0x00 brings back the old world of zero'ing on drop.
-#[cfg(not(stage0))] #[unstable(feature = "filling_drop")]
+#[unstable(feature = "filling_drop")]
pub const POST_DROP_U8: u8 = 0x1d;
-#[cfg(not(stage0))] #[unstable(feature = "filling_drop")]
+#[unstable(feature = "filling_drop")]
pub const POST_DROP_U32: u32 = repeat_u8_as_u32!(POST_DROP_U8);
-#[cfg(not(stage0))] #[unstable(feature = "filling_drop")]
+#[unstable(feature = "filling_drop")]
pub const POST_DROP_U64: u64 = repeat_u8_as_u64!(POST_DROP_U8);
#[cfg(target_pointer_width = "32")]
-#[cfg(not(stage0))] #[unstable(feature = "filling_drop")]
+#[unstable(feature = "filling_drop")]
pub const POST_DROP_USIZE: usize = POST_DROP_U32 as usize;
#[cfg(target_pointer_width = "64")]
-#[cfg(not(stage0))] #[unstable(feature = "filling_drop")]
+#[unstable(feature = "filling_drop")]
pub const POST_DROP_USIZE: usize = POST_DROP_U64 as usize;
-#[cfg(stage0)] #[unstable(feature = "filling_drop")]
-pub const POST_DROP_U8: u8 = 0;
-#[cfg(stage0)] #[unstable(feature = "filling_drop")]
-pub const POST_DROP_U32: u32 = 0;
-#[cfg(stage0)] #[unstable(feature = "filling_drop")]
-pub const POST_DROP_U64: u64 = 0;
-#[cfg(stage0)] #[unstable(feature = "filling_drop")]
-pub const POST_DROP_USIZE: usize = 0;
-
-/// Interprets `src` as `&U`, and then reads `src` without moving the contained value.
-///
-/// This function will unsafely assume the pointer `src` is valid for `sizeof(U)` bytes by
-/// transmuting `&T` to `&U` and then reading the `&U`. It will also unsafely create a copy of the
-/// contained value instead of moving out of `src`.
-///
-/// It is not a compile-time error if `T` and `U` have different sizes, but it is highly encouraged
-/// to only invoke this function where `T` and `U` have the same size. This function triggers
-/// undefined behavior if `U` is larger than `T`.
+/// Interprets `src` as `&U`, and then reads `src` without moving the contained
+/// value.
+///
+/// This function will unsafely assume the pointer `src` is valid for
+/// `sizeof(U)` bytes by transmuting `&T` to `&U` and then reading the `&U`. It
+/// will also unsafely create a copy of the contained value instead of moving
+/// out of `src`.
+///
+/// It is not a compile-time error if `T` and `U` have different sizes, but it
+/// is highly encouraged to only invoke this function where `T` and `U` have the
+/// same size. This function triggers undefined behavior if `U` is larger than
+/// `T`.
///
/// # Examples
///
// FIXME(#11621): Should be deprecated once CTFE is implemented in favour of
// calling the `mem::size_of` function.
#[unstable(feature = "core")]
-pub const BITS : u32 = $bits;
+pub const BITS : usize = $bits;
// FIXME(#11621): Should be deprecated once CTFE is implemented in favour of
// calling the `mem::size_of` function.
#[unstable(feature = "core")]
-pub const BYTES : u32 = ($bits / 8);
+pub const BYTES : usize = ($bits / 8);
// FIXME(#11621): Should be deprecated once CTFE is implemented in favour of
// calling the `Bounded::min_value` function.
use char::CharExt;
use clone::Clone;
use cmp::{PartialEq, Eq, PartialOrd, Ord};
-use error::Error;
use fmt;
use intrinsics;
use iter::Iterator;
/// intended to have wrapping semantics.
#[stable(feature = "rust1", since = "1.0.0")]
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Debug)]
-pub struct Wrapping<T>(pub T);
+pub struct Wrapping<T>(#[stable(feature = "rust1", since = "1.0.0")] pub T);
#[unstable(feature = "core", reason = "may be removed or relocated")]
pub mod wrapping;
fn min_value() -> $T { 0 }
#[inline]
- fn max_value() -> $T { -1 }
+ fn max_value() -> $T { !0 }
#[inline]
fn count_ones(self) -> u32 {
$add_with_overflow:path,
$sub_with_overflow:path,
$mul_with_overflow:path) => {
+ /// Returns the smallest value that can be represented by this integer type.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn min_value() -> $T {
+ (-1 as $T) << ($BITS - 1)
+ }
+
+ /// Returns the largest value that can be represented by this integer type.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn max_value() -> $T {
+ let min: $T = Int::min_value(); !min
+ }
+
/// Convert a string slice in a given base to an integer.
///
/// Leading and trailing whitespace represent an error.
$add_with_overflow:path,
$sub_with_overflow:path,
$mul_with_overflow:path) => {
+ /// Returns the smallest value that can be represented by this integer type.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn min_value() -> $T { 0 }
+
+ /// Returns the largest value that can be represented by this integer type.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn max_value() -> $T { !0 }
+
/// Convert a string slice in a given base to an integer.
///
/// Leading and trailing whitespace represent an error.
impl_num_cast! { f64, to_f64 }
/// Used for representing the classification of floating point numbers
-#[derive(Copy, PartialEq, Debug)]
+#[derive(Copy, Clone, PartialEq, Debug)]
#[stable(feature = "rust1", since = "1.0.0")]
pub enum FpCategory {
/// "Not a Number", often obtained by dividing by zero
Underflow,
}
-#[stable(feature = "rust1", since = "1.0.0")]
-impl fmt::Display for ParseIntError {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- self.description().fmt(f)
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl Error for ParseIntError {
- fn description(&self) -> &str {
+impl ParseIntError {
+ #[unstable(feature = "core", reason = "available through Error trait")]
+ pub fn description(&self) -> &str {
match self.kind {
IntErrorKind::Empty => "cannot parse integer from empty string",
IntErrorKind::InvalidDigit => "invalid digit found in string",
}
}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl fmt::Display for ParseIntError {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ self.description().fmt(f)
+ }
+}
+
/// An error which can be returned when parsing a float.
#[derive(Debug, Clone, PartialEq)]
#[stable(feature = "rust1", since = "1.0.0")]
Invalid,
}
-#[stable(feature = "rust1", since = "1.0.0")]
-impl fmt::Display for ParseFloatError {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- self.description().fmt(f)
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl Error for ParseFloatError {
- fn description(&self) -> &str {
+impl ParseFloatError {
+ #[unstable(feature = "core", reason = "available through Error trait")]
+ pub fn description(&self) -> &str {
match self.kind {
FloatErrorKind::Empty => "cannot parse float from empty string",
FloatErrorKind::Invalid => "invalid float literal",
}
}
}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl fmt::Display for ParseFloatError {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ self.description().fmt(f)
+ }
+}
macro_rules! uint_module { ($T:ty, $T_SIGNED:ty, $bits:expr) => (
#[unstable(feature = "core")]
-pub const BITS : u32 = $bits;
+pub const BITS : usize = $bits;
#[unstable(feature = "core")]
-pub const BYTES : u32 = ($bits / 8);
+pub const BYTES : usize = ($bits / 8);
#[stable(feature = "rust1", since = "1.0.0")]
pub const MIN: $T = 0 as $T;
use intrinsics::{i32_mul_with_overflow, u32_mul_with_overflow};
use intrinsics::{i64_mul_with_overflow, u64_mul_with_overflow};
+use ::{i8,i16,i32,i64};
+
#[unstable(feature = "core", reason = "may be removed, renamed, or relocated")]
#[deprecated(since = "1.0.0", reason = "moved to inherent methods")]
pub trait WrappingOps {
fn overflowing_add(self, rhs: Self) -> (Self, bool);
fn overflowing_sub(self, rhs: Self) -> (Self, bool);
fn overflowing_mul(self, rhs: Self) -> (Self, bool);
+
+ fn overflowing_div(self, rhs: Self) -> (Self, bool);
+ fn overflowing_rem(self, rhs: Self) -> (Self, bool);
+
+ fn overflowing_shl(self, rhs: u32) -> (Self, bool);
+ fn overflowing_shr(self, rhs: u32) -> (Self, bool);
}
macro_rules! sh_impl {
wrapping_impl! { usize u8 u16 u32 u64 isize i8 i16 i32 i64 }
-macro_rules! overflowing_impl {
+mod shift_max {
+ #![allow(non_upper_case_globals)]
+
+ pub const i8: u32 = (1 << 3) - 1;
+ pub const i16: u32 = (1 << 4) - 1;
+ pub const i32: u32 = (1 << 5) - 1;
+ pub const i64: u32 = (1 << 6) - 1;
+
+ pub const u8: u32 = i8;
+ pub const u16: u32 = i16;
+ pub const u32: u32 = i32;
+ pub const u64: u32 = i64;
+}
+
+macro_rules! signed_overflowing_impl {
($($t:ident)*) => ($(
impl OverflowingOps for $t {
#[inline(always)]
concat_idents!($t, _mul_with_overflow)(self, rhs)
}
}
+
+ #[inline(always)]
+ fn overflowing_div(self, rhs: $t) -> ($t, bool) {
+ if self == $t::MIN && rhs == -1 {
+ (1, true)
+ } else {
+ (self/rhs, false)
+ }
+ }
+ #[inline(always)]
+ fn overflowing_rem(self, rhs: $t) -> ($t, bool) {
+ if self == $t::MIN && rhs == -1 {
+ (0, true)
+ } else {
+ (self % rhs, false)
+ }
+ }
+
+ #[inline(always)]
+ fn overflowing_shl(self, rhs: u32) -> ($t, bool) {
+ (self << (rhs & self::shift_max::$t),
+ (rhs > self::shift_max::$t))
+ }
+ #[inline(always)]
+ fn overflowing_shr(self, rhs: u32) -> ($t, bool) {
+ (self >> (rhs & self::shift_max::$t),
+ (rhs > self::shift_max::$t))
+ }
}
)*)
}
-overflowing_impl! { u8 u16 u32 u64 i8 i16 i32 i64 }
+macro_rules! unsigned_overflowing_impl {
+ ($($t:ident)*) => ($(
+ impl OverflowingOps for $t {
+ #[inline(always)]
+ fn overflowing_add(self, rhs: $t) -> ($t, bool) {
+ unsafe {
+ concat_idents!($t, _add_with_overflow)(self, rhs)
+ }
+ }
+ #[inline(always)]
+ fn overflowing_sub(self, rhs: $t) -> ($t, bool) {
+ unsafe {
+ concat_idents!($t, _sub_with_overflow)(self, rhs)
+ }
+ }
+ #[inline(always)]
+ fn overflowing_mul(self, rhs: $t) -> ($t, bool) {
+ unsafe {
+ concat_idents!($t, _mul_with_overflow)(self, rhs)
+ }
+ }
+
+ #[inline(always)]
+ fn overflowing_div(self, rhs: $t) -> ($t, bool) {
+ (self/rhs, false)
+ }
+ #[inline(always)]
+ fn overflowing_rem(self, rhs: $t) -> ($t, bool) {
+ (self % rhs, false)
+ }
+
+ #[inline(always)]
+ fn overflowing_shl(self, rhs: u32) -> ($t, bool) {
+ (self << (rhs & self::shift_max::$t),
+ (rhs > self::shift_max::$t))
+ }
+ #[inline(always)]
+ fn overflowing_shr(self, rhs: u32) -> ($t, bool) {
+ (self >> (rhs & self::shift_max::$t),
+ (rhs > self::shift_max::$t))
+ }
+ }
+ )*)
+}
+
+signed_overflowing_impl! { i8 i16 i32 i64 }
+unsigned_overflowing_impl! { u8 u16 u32 u64 }
#[cfg(target_pointer_width = "64")]
impl OverflowingOps for usize {
(res.0 as usize, res.1)
}
}
+ #[inline(always)]
+ fn overflowing_div(self, rhs: usize) -> (usize, bool) {
+ let (r, f) = (self as u64).overflowing_div(rhs as u64);
+ (r as usize, f)
+ }
+ #[inline(always)]
+ fn overflowing_rem(self, rhs: usize) -> (usize, bool) {
+ let (r, f) = (self as u64).overflowing_rem(rhs as u64);
+ (r as usize, f)
+ }
+ #[inline(always)]
+ fn overflowing_shl(self, rhs: u32) -> (usize, bool) {
+ let (r, f) = (self as u64).overflowing_shl(rhs);
+ (r as usize, f)
+ }
+ #[inline(always)]
+ fn overflowing_shr(self, rhs: u32) -> (usize, bool) {
+ let (r, f) = (self as u64).overflowing_shr(rhs);
+ (r as usize, f)
+ }
}
#[cfg(target_pointer_width = "32")]
(res.0 as usize, res.1)
}
}
+ #[inline(always)]
+ fn overflowing_div(self, rhs: usize) -> (usize, bool) {
+ let (r, f) = (self as u32).overflowing_div(rhs as u32);
+ (r as usize, f)
+ }
+ #[inline(always)]
+ fn overflowing_rem(self, rhs: usize) -> (usize, bool) {
+ let (r, f) = (self as u32).overflowing_rem(rhs as u32);
+ (r as usize, f)
+ }
+ #[inline(always)]
+ fn overflowing_shl(self, rhs: u32) -> (usize, bool) {
+ let (r, f) = (self as u32).overflowing_shl(rhs);
+ (r as usize, f)
+ }
+ #[inline(always)]
+ fn overflowing_shr(self, rhs: u32) -> (usize, bool) {
+ let (r, f) = (self as u32).overflowing_shr(rhs);
+ (r as usize, f)
+ }
}
#[cfg(target_pointer_width = "64")]
(res.0 as isize, res.1)
}
}
+ #[inline(always)]
+ fn overflowing_div(self, rhs: isize) -> (isize, bool) {
+ let (r, f) = (self as i64).overflowing_div(rhs as i64);
+ (r as isize, f)
+ }
+ #[inline(always)]
+ fn overflowing_rem(self, rhs: isize) -> (isize, bool) {
+ let (r, f) = (self as i64).overflowing_rem(rhs as i64);
+ (r as isize, f)
+ }
+ #[inline(always)]
+ fn overflowing_shl(self, rhs: u32) -> (isize, bool) {
+ let (r, f) = (self as i64).overflowing_shl(rhs);
+ (r as isize, f)
+ }
+ #[inline(always)]
+ fn overflowing_shr(self, rhs: u32) -> (isize, bool) {
+ let (r, f) = (self as i64).overflowing_shr(rhs);
+ (r as isize, f)
+ }
}
#[cfg(target_pointer_width = "32")]
(res.0 as isize, res.1)
}
}
+ #[inline(always)]
+ fn overflowing_div(self, rhs: isize) -> (isize, bool) {
+ let (r, f) = (self as i32).overflowing_div(rhs as i32);
+ (r as isize, f)
+ }
+ #[inline(always)]
+ fn overflowing_rem(self, rhs: isize) -> (isize, bool) {
+ let (r, f) = (self as i32).overflowing_rem(rhs as i32);
+ (r as isize, f)
+ }
+ #[inline(always)]
+ fn overflowing_shl(self, rhs: u32) -> (isize, bool) {
+ let (r, f) = (self as i32).overflowing_shl(rhs);
+ (r as isize, f)
+ }
+ #[inline(always)]
+ fn overflowing_shr(self, rhs: u32) -> (isize, bool) {
+ let (r, f) = (self as i32).overflowing_shr(rhs);
+ (r as isize, f)
+ }
}
/// ```
/// use std::ops::Add;
///
-/// #[derive(Copy)]
+/// #[derive(Copy, Clone)]
/// struct Foo;
///
/// impl Add for Foo {
/// ```
/// use std::ops::Sub;
///
-/// #[derive(Copy)]
+/// #[derive(Copy, Clone)]
/// struct Foo;
///
/// impl Sub for Foo {
/// ```
/// use std::ops::Mul;
///
-/// #[derive(Copy)]
+/// #[derive(Copy, Clone)]
/// struct Foo;
///
/// impl Mul for Foo {
/// ```
/// use std::ops::Div;
///
-/// #[derive(Copy)]
+/// #[derive(Copy, Clone)]
/// struct Foo;
///
/// impl Div for Foo {
/// ```
/// use std::ops::Rem;
///
-/// #[derive(Copy)]
+/// #[derive(Copy, Clone)]
/// struct Foo;
///
/// impl Rem for Foo {
/// ```
/// use std::ops::Neg;
///
-/// #[derive(Copy)]
+/// #[derive(Copy, Clone)]
/// struct Foo;
///
/// impl Neg for Foo {
fn neg(self) -> Self::Output;
}
-macro_rules! neg_impl {
- ($($t:ty)*) => ($(
+
+
+macro_rules! neg_impl_core {
+ ($id:ident => $body:expr, $($t:ty)*) => ($(
#[stable(feature = "rust1", since = "1.0.0")]
#[allow(unsigned_negation)]
impl Neg for $t {
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
- fn neg(self) -> $t { -self }
+ fn neg(self) -> $t { let $id = self; $body }
}
forward_ref_unop! { impl Neg, neg for $t }
)*)
}
-neg_impl! { usize u8 u16 u32 u64 isize i8 i16 i32 i64 f32 f64 }
+macro_rules! neg_impl_numeric {
+ ($($t:ty)*) => { neg_impl_core!{ x => -x, $($t)*} }
+}
+
+macro_rules! neg_impl_unsigned {
+ ($($t:ty)*) => {
+ neg_impl_core!{ x => {
+ #[cfg(stage0)]
+ use ::num::wrapping::WrappingOps;
+ !x.wrapping_add(1)
+ }, $($t)*} }
+}
+
+// neg_impl_unsigned! { usize u8 u16 u32 u64 }
+neg_impl_numeric! { isize i8 i16 i32 i64 f32 f64 }
/// The `Not` trait is used to specify the functionality of unary `!`.
///
/// ```
/// use std::ops::Not;
///
-/// #[derive(Copy)]
+/// #[derive(Copy, Clone)]
/// struct Foo;
///
/// impl Not for Foo {
/// ```
/// use std::ops::BitAnd;
///
-/// #[derive(Copy)]
+/// #[derive(Copy, Clone)]
/// struct Foo;
///
/// impl BitAnd for Foo {
/// ```
/// use std::ops::BitOr;
///
-/// #[derive(Copy)]
+/// #[derive(Copy, Clone)]
/// struct Foo;
///
/// impl BitOr for Foo {
/// ```
/// use std::ops::BitXor;
///
-/// #[derive(Copy)]
+/// #[derive(Copy, Clone)]
/// struct Foo;
///
/// impl BitXor for Foo {
/// ```
/// use std::ops::Shl;
///
-/// #[derive(Copy)]
+/// #[derive(Copy, Clone)]
/// struct Foo;
///
/// impl Shl<Foo> for Foo {
/// ```
/// use std::ops::Shr;
///
-/// #[derive(Copy)]
+/// #[derive(Copy, Clone)]
/// struct Foo;
///
/// impl Shr<Foo> for Foo {
/// ```
/// use std::ops::Index;
///
-/// #[derive(Copy)]
+/// #[derive(Copy, Clone)]
/// struct Foo;
/// struct Bar;
///
/// ```
/// use std::ops::{Index, IndexMut};
///
-/// #[derive(Copy)]
+/// #[derive(Copy, Clone)]
/// struct Foo;
/// struct Bar;
///
#[lang="fn"]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_paren_sugar]
+#[fundamental] // so that regex can rely that `&str: !FnMut`
pub trait Fn<Args> : FnMut<Args> {
/// This is called when the call operator is used.
extern "rust-call" fn call(&self, args: Args) -> Self::Output;
#[lang="fn_mut"]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_paren_sugar]
+#[fundamental] // so that regex can rely that `&str: !FnMut`
pub trait FnMut<Args> : FnOnce<Args> {
/// This is called when the call operator is used.
extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output;
#[lang="fn_once"]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_paren_sugar]
+#[fundamental] // so that regex can rely that `&str: !FnMut`
pub trait FnOnce<Args> {
/// The returned type after the call operator is used.
type Output;
/// This is called when the call operator is used.
extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
}
+
+#[cfg(not(stage0))]
+mod impls {
+ use marker::Sized;
+ use super::{Fn, FnMut, FnOnce};
+
+ impl<'a,A,F:?Sized> Fn<A> for &'a F
+ where F : Fn<A>
+ {
+ extern "rust-call" fn call(&self, args: A) -> F::Output {
+ (**self).call(args)
+ }
+ }
+
+ impl<'a,A,F:?Sized> FnMut<A> for &'a F
+ where F : Fn<A>
+ {
+ extern "rust-call" fn call_mut(&mut self, args: A) -> F::Output {
+ (**self).call(args)
+ }
+ }
+
+ impl<'a,A,F:?Sized> FnOnce<A> for &'a F
+ where F : Fn<A>
+ {
+ type Output = F::Output;
+
+ extern "rust-call" fn call_once(self, args: A) -> F::Output {
+ (*self).call(args)
+ }
+ }
+
+ impl<'a,A,F:?Sized> FnMut<A> for &'a mut F
+ where F : FnMut<A>
+ {
+ extern "rust-call" fn call_mut(&mut self, args: A) -> F::Output {
+ (*self).call_mut(args)
+ }
+ }
+
+ impl<'a,A,F:?Sized> FnOnce<A> for &'a mut F
+ where F : FnMut<A>
+ {
+ type Output = F::Output;
+ extern "rust-call" fn call_once(mut self, args: A) -> F::Output {
+ (*self).call_mut(args)
+ }
+ }
+}
use ops::FnOnce;
use result::Result::{Ok, Err};
use result::Result;
-#[allow(deprecated)]
-use slice::AsSlice;
use slice;
// Note that this is not a lang item per se, but it has a hidden dependency on
// Trait implementations
/////////////////////////////////////////////////////////////////////////////
-#[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]
- fn as_slice<'a>(&'a self) -> &'a [T] {
- match *self {
- Some(ref x) => slice::ref_slice(x),
- None => {
- let result: &[_] = &[];
- result
- }
- }
- }
-}
-
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> Default for Option<T> {
#[inline]
pub use clone::Clone;
pub use cmp::{PartialEq, PartialOrd, Eq, Ord};
pub use convert::{AsRef, AsMut, Into, From};
-pub use iter::Extend;
-pub use iter::{Iterator, DoubleEndedIterator};
-pub use iter::{ExactSizeIterator};
+pub use iter::{Iterator, DoubleEndedIterator, Extend, ExactSizeIterator};
pub use option::Option::{self, Some, None};
pub use result::Result::{self, Ok, Err};
-pub use slice::{AsSlice, SliceExt};
-pub use str::{Str, StrExt};
+pub use slice::SliceExt;
+pub use str::StrExt;
+
+#[allow(deprecated)] pub use slice::AsSlice;
+#[allow(deprecated)] pub use str::Str;
#[stable(feature = "rust1", since = "1.0.0")]
pub fn null_mut<T>() -> *mut T { 0 as *mut T }
-/// Zeroes out `count * size_of::<T>` bytes of memory at `dst`. `count` may be
-/// `0`.
-///
-/// # Safety
-///
-/// Beyond accepting a raw pointer, this is unsafe because it will not drop the
-/// contents of `dst`, and may be used to create invalid instances of `T`.
-#[inline]
-#[unstable(feature = "core",
- reason = "may play a larger role in std::ptr future extensions")]
-#[deprecated(since = "1.0.0", reason = "use `write_bytes` instead")]
-pub unsafe fn zero_memory<T>(dst: *mut T, count: usize) {
- write_bytes(dst, 0, count);
-}
-
/// Swaps the values at two mutable locations of the same type, without
/// deinitialising either. They may overlap, unlike `mem::swap` which is
/// otherwise equivalent.
//!
//! Their definition should always match the ABI defined in `rustc::back::abi`.
+use clone::Clone;
use marker::Copy;
use mem;
}
impl<T> Copy for Slice<T> {}
-
-/// The representation of an old closure.
-#[repr(C)]
-#[derive(Copy)]
-#[unstable(feature = "core")]
-#[deprecated(reason = "unboxed new closures do not have a universal representation; \
- `&Fn` (etc) trait objects should use `TraitObject` instead",
- since= "1.0.0")]
-#[allow(deprecated) /* for deriving Copy impl */]
-pub struct Closure {
- pub code: *mut (),
- pub env: *mut (),
+impl<T> Clone for Slice<T> {
+ fn clone(&self) -> Slice<T> { *self }
}
/// The representation of a trait object like `&SomeTrait`.
/// assert_eq!(synthesized.bar(), 457);
/// ```
#[repr(C)]
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub struct TraitObject {
pub data: *mut (),
pub vtable: *mut (),
#[unstable(feature = "core")]
#[simd]
-#[derive(Copy, Debug)]
+#[derive(Copy, Clone, Debug)]
#[repr(C)]
pub struct i8x16(pub i8, pub i8, pub i8, pub i8,
pub i8, pub i8, pub i8, pub i8,
#[unstable(feature = "core")]
#[simd]
-#[derive(Copy, Debug)]
+#[derive(Copy, Clone, Debug)]
#[repr(C)]
pub struct i16x8(pub i16, pub i16, pub i16, pub i16,
pub i16, pub i16, pub i16, pub i16);
#[unstable(feature = "core")]
#[simd]
-#[derive(Copy, Debug)]
+#[derive(Copy, Clone, Debug)]
#[repr(C)]
pub struct i32x4(pub i32, pub i32, pub i32, pub i32);
#[unstable(feature = "core")]
#[simd]
-#[derive(Copy, Debug)]
+#[derive(Copy, Clone, Debug)]
#[repr(C)]
pub struct i64x2(pub i64, pub i64);
#[unstable(feature = "core")]
#[simd]
-#[derive(Copy, Debug)]
+#[derive(Copy, Clone, Debug)]
#[repr(C)]
pub struct u8x16(pub u8, pub u8, pub u8, pub u8,
pub u8, pub u8, pub u8, pub u8,
#[unstable(feature = "core")]
#[simd]
-#[derive(Copy, Debug)]
+#[derive(Copy, Clone, Debug)]
#[repr(C)]
pub struct u16x8(pub u16, pub u16, pub u16, pub u16,
pub u16, pub u16, pub u16, pub u16);
#[unstable(feature = "core")]
#[simd]
-#[derive(Copy, Debug)]
+#[derive(Copy, Clone, Debug)]
#[repr(C)]
pub struct u32x4(pub u32, pub u32, pub u32, pub u32);
#[unstable(feature = "core")]
#[simd]
-#[derive(Copy, Debug)]
+#[derive(Copy, Clone, Debug)]
#[repr(C)]
pub struct u64x2(pub u64, pub u64);
#[unstable(feature = "core")]
#[simd]
-#[derive(Copy, Debug)]
+#[derive(Copy, Clone, Debug)]
#[repr(C)]
pub struct f32x4(pub f32, pub f32, pub f32, pub f32);
#[unstable(feature = "core")]
#[simd]
-#[derive(Copy, Debug)]
+#[derive(Copy, Clone, Debug)]
#[repr(C)]
pub struct f64x2(pub f64, pub f64);
fn len(&self) -> usize;
fn is_empty(&self) -> bool { self.len() == 0 }
fn get_mut<'a>(&'a mut self, index: usize) -> Option<&'a mut Self::Item>;
- #[unstable(feature = "core",
- reason = "will be replaced by slice syntax")]
- #[deprecated(since = "1.0.0", reason = "use &mut s[..] instead")]
- fn as_mut_slice<'a>(&'a mut self) -> &'a mut [Self::Item];
fn iter_mut<'a>(&'a mut self) -> IterMut<'a, Self::Item>;
fn first_mut<'a>(&'a mut self) -> Option<&'a mut Self::Item>;
fn tail_mut<'a>(&'a mut self) -> &'a mut [Self::Item];
if index < self.len() { Some(&mut self[index]) } else { None }
}
- #[inline]
- #[unstable(feature = "core",
- reason = "will be replaced by slice syntax")]
- #[deprecated(since = "1.0.0", reason = "use &mut s[..] instead")]
- fn as_mut_slice(&mut self) -> &mut [T] { self }
-
#[inline]
fn split_at_mut(&mut self, mid: usize) -> (&mut [T], &mut [T]) {
unsafe {
#[inline]
fn next(&mut self) -> Option<T> {
- if self.count == 0 {
- self.iter.finish()
- } else {
- self.count -= 1;
- if self.invert { self.iter.next_back() } else { self.iter.next() }
+ match self.count {
+ 0 => None,
+ 1 => { self.count -= 1; self.iter.finish() }
+ _ => {
+ self.count -= 1;
+ if self.invert {self.iter.next_back()} else {self.iter.next()}
+ }
}
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let (lower, upper_opt) = self.iter.size_hint();
- (lower, upper_opt.map(|upper| cmp::min(self.count + 1, upper)))
+ (lower, upper_opt.map(|upper| cmp::min(self.count, upper)))
}
}
transmute(RawSlice { data: p, len: len })
}
-/// Forms a slice from a pointer and a length.
-///
-/// The pointer given is actually a reference to the base of the slice. This
-/// reference is used to give a concrete lifetime to tie the returned slice to.
-/// Typically this should indicate that the slice is valid for as long as the
-/// pointer itself is valid.
-///
-/// The `len` argument is the number of **elements**, not the number of bytes.
-///
-/// This function is unsafe as there is no guarantee that the given pointer is
-/// valid for `len` elements, nor whether the lifetime provided is a suitable
-/// lifetime for the returned slice.
-///
-/// # Examples
-///
-/// ```
-/// #![feature(core)]
-/// use std::slice;
-///
-/// // manifest a slice out of thin air!
-/// let ptr = 0x1234 as *const usize;
-/// let amt = 10;
-/// unsafe {
-/// let slice = slice::from_raw_buf(&ptr, amt);
-/// }
-/// ```
-#[inline]
-#[unstable(feature = "core")]
-#[deprecated(since = "1.0.0",
- reason = "use from_raw_parts")]
-pub unsafe fn from_raw_buf<'a, T>(p: &'a *const T, len: usize) -> &'a [T] {
- transmute(RawSlice { data: *p, len: len })
-}
-
-/// Performs the same functionality as `from_raw_buf`, except that a mutable
-/// slice is returned.
-///
-/// This function is unsafe for the same reasons as `from_raw_buf`, as well as
-/// not being able to provide a non-aliasing guarantee of the returned mutable
-/// slice.
-#[inline]
-#[unstable(feature = "core")]
-#[deprecated(since = "1.0.0",
- reason = "use from_raw_parts_mut")]
-pub unsafe fn from_raw_mut_buf<'a, T>(p: &'a *mut T, len: usize) -> &'a mut [T] {
- transmute(RawSlice { data: *p, len: len })
-}
-
//
// Submodules
//
use clone::Clone;
use cmp::{self, Eq};
use default::Default;
-use error::Error;
use fmt;
use iter::ExactSizeIterator;
use iter::{Map, Iterator, DoubleEndedIterator};
use marker::Sized;
use mem;
-#[allow(deprecated)]
-use num::Int;
use ops::{Fn, FnMut, FnOnce};
use option::Option::{self, None, Some};
use raw::{Repr, Slice};
}
}
-#[stable(feature = "rust1", since = "1.0.0")]
-impl Error for ParseBoolError {
- fn description(&self) -> &str { "failed to parse bool" }
-}
-
/*
Section: Creating a string
*/
mem::transmute(v)
}
-/// Constructs a static string slice from a given raw pointer.
-///
-/// This function will read memory starting at `s` until it finds a 0, and then
-/// transmute the memory up to that point as a string slice, returning the
-/// corresponding `&'static str` value.
-///
-/// This function is unsafe because the caller must ensure the C string itself
-/// has the static lifetime and that the memory `s` is valid up to and including
-/// the first null byte.
-///
-/// # Panics
-///
-/// This function will panic if the string pointed to by `s` is not valid UTF-8.
-#[unstable(feature = "core")]
-#[deprecated(since = "1.0.0",
- reason = "use std::ffi::c_str_to_bytes + str::from_utf8")]
-pub unsafe fn from_c_str(s: *const i8) -> &'static str {
- let s = s as *const u8;
- let mut len: usize = 0;
- while *s.offset(len as isize) != 0 {
- len += 1;
- }
- let v: &'static [u8] = ::mem::transmute(Slice { data: s, len: len });
- from_utf8(v).ok().expect("from_c_str passed invalid utf-8 data")
-}
-
-/// Something that can be used to compare against a character
-#[unstable(feature = "core")]
-#[deprecated(since = "1.0.0",
- reason = "use `Pattern` instead")]
-// NB: Rather than removing it, make it private and move it into self::pattern
-pub trait CharEq {
- /// Determine if the splitter should split at the given character
- fn matches(&mut self, char) -> bool;
- /// Indicate if this is only concerned about ASCII characters,
- /// which can allow for a faster implementation.
- fn only_ascii(&self) -> bool;
-}
-
-#[allow(deprecated) /* for CharEq */ ]
-impl CharEq for char {
- #[inline]
- fn matches(&mut self, c: char) -> bool { *self == c }
-
- #[inline]
- fn only_ascii(&self) -> bool { (*self as u32) < 128 }
-}
-
-#[allow(deprecated) /* for CharEq */ ]
-impl<F> CharEq for F where F: FnMut(char) -> bool {
- #[inline]
- fn matches(&mut self, c: char) -> bool { (*self)(c) }
-
- #[inline]
- fn only_ascii(&self) -> bool { false }
-}
-
-#[allow(deprecated) /* for CharEq */ ]
-impl<'a> CharEq for &'a [char] {
- #[inline]
- #[allow(deprecated) /* for CharEq */ ]
- fn matches(&mut self, c: char) -> bool {
- self.iter().any(|&m| { let mut m = m; m.matches(c) })
- }
-
- #[inline]
- #[allow(deprecated) /* for CharEq */ ]
- fn only_ascii(&self) -> bool {
- self.iter().all(|m| m.only_ascii())
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl Error for Utf8Error {
- fn description(&self) -> &str {
- match *self {
- Utf8Error::TooShort => "invalid utf-8: not enough bytes",
- Utf8Error::InvalidByte(..) => "invalid utf-8: corrupt contents",
- }
- }
-}
-
#[stable(feature = "rust1", since = "1.0.0")]
impl fmt::Display for Utf8Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
/// splitting at most `count` times.
struct CharSplitsN<'a, P: Pattern<'a>> {
iter: CharSplits<'a, P>,
- /// The number of splits remaining
+ /// The number of items remaining
count: usize,
}
#[inline]
fn next(&mut self) -> Option<&'a str> {
- if self.count != 0 {
- self.count -= 1;
- self.iter.next()
- } else {
- self.iter.get_end()
+ match self.count {
+ 0 => None,
+ 1 => { self.count = 0; self.iter.get_end() }
+ _ => { self.count -= 1; self.iter.next() }
}
}
}
#[inline]
fn next(&mut self) -> Option<&'a str> {
- if self.count != 0 {
- self.count -= 1;
- self.iter.next()
- } else {
- self.iter.get_remainder()
+ match self.count {
+ 0 => None,
+ 1 => { self.count -= 1; self.iter.get_remainder() }
+ _ => { self.count -= 1; self.iter.next() }
}
}
}
#[allow(dead_code)]
#[allow(deprecated)]
fn maximal_suffix(arr: &[u8], reversed: bool) -> (usize, usize) {
- let mut left: usize = -1; // Corresponds to i in the paper
+ let mut left: usize = !0; // Corresponds to i in the paper
let mut right = 0; // Corresponds to j in the paper
let mut offset = 1; // Corresponds to k in the paper
let mut period = 1; // Corresponds to p in the paper
}
}
-/// An iterator over the substrings of a string separated by a given
-/// search string
-#[unstable(feature = "core")]
-#[deprecated(since = "1.0.0", reason = "use `Split` with a `&str`")]
-pub struct SplitStr<'a, P: Pattern<'a>>(Split<'a, P>);
-#[allow(deprecated)]
-impl<'a, P: Pattern<'a>> Iterator for SplitStr<'a, P> {
- type Item = &'a str;
-
- #[inline]
- #[allow(deprecated)]
- fn next(&mut self) -> Option<&'a str> {
- Iterator::next(&mut self.0)
- }
-}
-
impl<'a, 'b> OldMatchIndices<'a, 'b> {
#[inline]
#[allow(dead_code)]
/// Struct that contains a `char` and the index of the first byte of
/// the next `char` in a string. This can be used as a data structure
/// for iterating over the UTF-8 bytes of a string.
-#[derive(Copy)]
+#[derive(Copy, Clone)]
#[unstable(feature = "str_char",
reason = "existence of this struct is uncertain as it is frequently \
able to be replaced with char.len_utf8() and/or \
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>;
fn lines<'a>(&'a self) -> Lines<'a>;
fn lines_any<'a>(&'a self) -> LinesAny<'a>;
fn char_len(&self) -> usize;
MatchIndices(pat.into_searcher(self))
}
- #[inline]
- #[allow(deprecated) /* for SplitStr */ ]
- fn split_str<'a, P: Pattern<'a>>(&'a self, pat: P) -> SplitStr<'a, P> {
- SplitStr(self.split(pat))
- }
-
#[inline]
fn lines(&self) -> Lines {
Lines { inner: self.split_terminator('\n').0 }
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![allow(deprecated) /* for CharEq */ ]
-
use prelude::*;
-use super::CharEq;
// Pattern
// Impl for a CharEq wrapper
+#[doc(hidden)]
+trait CharEq {
+ fn matches(&mut self, char) -> bool;
+ fn only_ascii(&self) -> bool;
+}
+
+impl CharEq for char {
+ #[inline]
+ fn matches(&mut self, c: char) -> bool { *self == c }
+
+ #[inline]
+ fn only_ascii(&self) -> bool { (*self as u32) < 128 }
+}
+
+impl<F> CharEq for F where F: FnMut(char) -> bool {
+ #[inline]
+ fn matches(&mut self, c: char) -> bool { (*self)(c) }
+
+ #[inline]
+ fn only_ascii(&self) -> bool { false }
+}
+
+impl<'a> CharEq for &'a [char] {
+ #[inline]
+ fn matches(&mut self, c: char) -> bool {
+ self.iter().any(|&m| { let mut m = m; m.matches(c) })
+ }
+
+ #[inline]
+ fn only_ascii(&self) -> bool {
+ self.iter().all(|m| m.only_ascii())
+ }
+}
+
struct CharEqPattern<C: CharEq>(C);
struct CharEqSearcher<'a, C: CharEq> {
}
}
-macro_rules! associated_items {
- ($t:ty, $s:ident, $e:expr) => {
- // FIXME: #22463
- //type Searcher = $t;
-
- fn into_searcher(self, haystack: &'a str) -> $t {
- let $s = self;
- $e.into_searcher(haystack)
+macro_rules! char_eq_pattern_impl {
+ ($wrapper:ty, $wrapper_ident:ident) => {
+ fn into_searcher(self, haystack: &'a str) -> $wrapper {
+ $wrapper_ident(CharEqPattern(self).into_searcher(haystack))
}
-
#[inline]
fn is_contained_in(self, haystack: &'a str) -> bool {
- let $s = self;
- $e.is_contained_in(haystack)
+ CharEqPattern(self).is_contained_in(haystack)
}
-
#[inline]
fn is_prefix_of(self, haystack: &'a str) -> bool {
- let $s = self;
- $e.is_prefix_of(haystack)
+ CharEqPattern(self).is_prefix_of(haystack)
}
-
- // FIXME: #21750
- /*#[inline]
+ #[inline]
fn is_suffix_of(self, haystack: &'a str) -> bool
- where $t: ReverseSearcher<'a>
+ where $wrapper: ReverseSearcher<'a>
{
- let $s = self;
- $e.is_suffix_of(haystack)
- }*/
+ CharEqPattern(self).is_suffix_of(haystack)
+ }
}
}
-// CharEq delegation impls
+// Pattern for char
-/// Searches for chars that are equal to a given char
impl<'a> Pattern<'a> for char {
- type Searcher = <CharEqPattern<Self> as Pattern<'a>>::Searcher;
- associated_items!(<CharEqPattern<Self> as Pattern<'a>>::Searcher,
- s, CharEqPattern(s));
+ type Searcher = CharSearcher<'a>;
+ char_eq_pattern_impl!(CharSearcher<'a>, CharSearcher);
+}
+
+pub struct CharSearcher<'a>(CharEqSearcher<'a, char>);
+
+unsafe impl<'a> Searcher<'a> for CharSearcher<'a> {
+ #[inline]
+ fn haystack(&self) -> &'a str { self.0.haystack() }
+ #[inline]
+ fn next(&mut self) -> SearchStep { self.0.next() }
+}
+unsafe impl<'a> ReverseSearcher<'a> for CharSearcher<'a> {
+ #[inline]
+ fn next_back(&mut self) -> SearchStep { self.0.next_back() }
}
+impl<'a> DoubleEndedSearcher<'a> for CharSearcher<'a> {}
+
+// Pattern for &[char]
-/// Searches for chars that are equal to any of the chars in the array
impl<'a, 'b> Pattern<'a> for &'b [char] {
- type Searcher = <CharEqPattern<Self> as Pattern<'a>>::Searcher;
- associated_items!(<CharEqPattern<Self> as Pattern<'a>>::Searcher,
- s, CharEqPattern(s));
+ type Searcher = CharSliceSearcher<'a, 'b>;
+ char_eq_pattern_impl!(CharSliceSearcher<'a, 'b>, CharSliceSearcher);
}
-/// 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));
+pub struct CharSliceSearcher<'a, 'b>(CharEqSearcher<'a, &'b [char]>);
+
+unsafe impl<'a, 'b> Searcher<'a> for CharSliceSearcher<'a, 'b> {
+ #[inline]
+ fn haystack(&self) -> &'a str { self.0.haystack() }
+ #[inline]
+ fn next(&mut self) -> SearchStep { self.0.next() }
+}
+unsafe impl<'a, 'b> ReverseSearcher<'a> for CharSliceSearcher<'a, 'b> {
+ #[inline]
+ fn next_back(&mut self) -> SearchStep { self.0.next_back() }
+}
+impl<'a, 'b> DoubleEndedSearcher<'a> for CharSliceSearcher<'a, 'b> {}
+
+// Pattern for predicates
+
+impl<'a, F: FnMut(char) -> bool> Pattern<'a> for F {
+ type Searcher = CharPredSearcher<'a, F>;
+ char_eq_pattern_impl!(CharPredSearcher<'a, F>, CharPredSearcher);
+}
+
+pub struct CharPredSearcher<'a, F: FnMut(char) -> bool>(CharEqSearcher<'a, F>);
+
+unsafe impl<'a, F> Searcher<'a> for CharPredSearcher<'a, F>
+ where F: FnMut(char) -> bool
+{
+ #[inline]
+ fn haystack(&self) -> &'a str { self.0.haystack() }
+ #[inline]
+ fn next(&mut self) -> SearchStep { self.0.next() }
+}
+unsafe impl<'a, F> ReverseSearcher<'a> for CharPredSearcher<'a, F>
+ where F: FnMut(char) -> bool
+{
+ #[inline]
+ fn next_back(&mut self) -> SearchStep { self.0.next_back() }
}
+impl<'a, F> DoubleEndedSearcher<'a> for CharPredSearcher<'a, F>
+ where F: FnMut(char) -> bool
+{}
-/// 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));
+// Pattern for &&str
+
+impl<'a, 'b> Pattern<'a> for &'b &'b str {
+ type Searcher = <&'b str as Pattern<'a>>::Searcher;
+ #[inline]
+ 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)
+ }
+ #[inline]
+ fn is_suffix_of(self, haystack: &'a str) -> bool {
+ (*self).is_suffix_of(haystack)
+ }
}
fn no_mut_then_imm_borrow() {
let x = RefCell::new(0);
let _b1 = x.borrow_mut();
- assert!(x.try_borrow().is_none());
assert_eq!(x.borrow_state(), BorrowState::Writing);
}
fn no_imm_then_borrow_mut() {
let x = RefCell::new(0);
let _b1 = x.borrow();
- assert!(x.try_borrow_mut().is_none());
assert_eq!(x.borrow_state(), BorrowState::Reading);
}
let x = RefCell::new(0);
assert_eq!(x.borrow_state(), BorrowState::Unused);
let _b1 = x.borrow_mut();
- assert!(x.try_borrow_mut().is_none());
assert_eq!(x.borrow_state(), BorrowState::Writing);
}
{
let _b2 = x.borrow();
}
- assert!(x.try_borrow_mut().is_none());
+ assert_eq!(x.borrow_state(), BorrowState::Reading);
}
#[test]
let x = RefCell::new(0);
{
let b1 = x.borrow();
- assert!(x.try_borrow_mut().is_none());
+ assert_eq!(x.borrow_state(), BorrowState::Reading);
{
let _b2 = clone_ref(&b1);
- assert!(x.try_borrow_mut().is_none());
+ assert_eq!(x.borrow_state(), BorrowState::Reading);
}
- assert!(x.try_borrow_mut().is_none());
+ assert_eq!(x.borrow_state(), BorrowState::Reading);
}
- assert!(x.try_borrow_mut().is_some());
+ assert_eq!(x.borrow_state(), BorrowState::Unused);
}
#[test]
+++ /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.
-
-#![allow(deprecated)]
-
-use core::finally::{try_finally, Finally};
-use std::thread;
-
-#[test]
-fn test_success() {
- let mut i = 0;
- try_finally(
- &mut i, (),
- |i, ()| {
- *i = 10;
- },
- |i| {
- assert!(!thread::panicking());
- assert_eq!(*i, 10);
- *i = 20;
- });
- assert_eq!(i, 20);
-}
-
-#[test]
-#[should_panic]
-fn test_fail() {
- let mut i = 0;
- try_finally(
- &mut i, (),
- |i, ()| {
- *i = 10;
- panic!();
- },
- |i| {
- assert!(thread::panicking());
- assert_eq!(*i, 10);
- })
-}
-
-#[test]
-fn test_retval() {
- let mut closure = || 10;
- // FIXME(#16640) `: i32` annotation shouldn't be necessary
- let i: i32 = closure.finally(|| { });
- assert_eq!(i, 10);
-}
-
-#[test]
-fn test_compact() {
- fn do_some_fallible_work() {}
- fn but_always_run_this_function() { }
- let mut f = do_some_fallible_work;
- f.finally(but_always_run_this_function);
-}
assert!(format!("{:>8x}", 10) == " a");
assert!(format!("{:#08x}", 10) == "0x00000a");
assert!(format!("{:08}", -10) == "-0000010");
- assert!(format!("{:x}", -1u8) == "ff");
- assert!(format!("{:X}", -1u8) == "FF");
- assert!(format!("{:b}", -1u8) == "11111111");
- assert!(format!("{:o}", -1u8) == "377");
- assert!(format!("{:#x}", -1u8) == "0xff");
- assert!(format!("{:#X}", -1u8) == "0xFF");
- assert!(format!("{:#b}", -1u8) == "0b11111111");
- assert!(format!("{:#o}", -1u8) == "0o377");
+ assert!(format!("{:x}", !0u8) == "ff");
+ assert!(format!("{:X}", !0u8) == "FF");
+ assert!(format!("{:b}", !0u8) == "11111111");
+ assert!(format!("{:o}", !0u8) == "377");
+ assert!(format!("{:#x}", !0u8) == "0xff");
+ assert!(format!("{:#X}", !0u8) == "0xFF");
+ assert!(format!("{:#b}", !0u8) == "0b11111111");
+ assert!(format!("{:#o}", !0u8) == "0o377");
}
#[test]
#[test]
fn test_counter_from_iter() {
- let it = count(0, 5).take(10);
+ let it = (0..).step_by(5).take(10);
let xs: Vec<isize> = FromIterator::from_iter(it);
assert_eq!(xs, [0, 5, 10, 15, 20, 25, 30, 35, 40, 45]);
}
}
assert_eq!(i, expected.len());
- let ys = count(30, 10).take(4);
+ let ys = (30..).step_by(10).take(4);
let it = xs.iter().cloned().chain(ys);
let mut i = 0;
for x in it {
#[test]
fn test_filter_map() {
- let it = count(0, 1).take(10)
+ let it = (0..).step_by(1).take(10)
.filter_map(|x| if x % 2 == 0 { Some(x*x) } else { None });
assert_eq!(it.collect::<Vec<usize>>(), [0*0, 2*2, 4*4, 6*6, 8*8]);
}
fn test_iterator_flat_map() {
let xs = [0, 3, 6];
let ys = [0, 1, 2, 3, 4, 5, 6, 7, 8];
- let it = xs.iter().flat_map(|&x| count(x, 1).take(3));
+ let it = xs.iter().flat_map(|&x| (x..).step_by(1).take(3));
let mut i = 0;
for x in it {
assert_eq!(x, ys[i]);
#[test]
fn test_cycle() {
let cycle_len = 3;
- let it = count(0, 1).take(cycle_len).cycle();
+ let it = (0..).step_by(1).take(cycle_len).cycle();
assert_eq!(it.size_hint(), (usize::MAX, None));
for (i, x) in it.take(100).enumerate() {
assert_eq!(i % cycle_len, x);
}
- let mut it = count(0, 1).take(0).cycle();
+ let mut it = (0..).step_by(1).take(0).cycle();
assert_eq!(it.size_hint(), (0, Some(0)));
assert_eq!(it.next(), None);
}
#[test]
fn test_iterator_size_hint() {
- let c = count(0, 1);
+ let c = (0..).step_by(1);
let v: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
let v2 = &[10, 11, 12];
let vi = v.iter();
mod cell;
mod char;
mod cmp;
-mod finally;
mod fmt;
mod hash;
mod iter;
}
unsafe {
- assert_eq!([76], transmute::<_, Vec<u8>>("L".to_string()));
+ assert_eq!(transmute::<_, Vec<u8>>("L".to_string()), [76]);
}
}
#[test]
fn test_count_zeros() {
- assert!(A.count_zeros() == BITS - 3);
- assert!(B.count_zeros() == BITS - 2);
- assert!(C.count_zeros() == BITS - 5);
+ assert!(A.count_zeros() == BITS as u32 - 3);
+ assert!(B.count_zeros() == BITS as u32 - 2);
+ assert!(C.count_zeros() == BITS as u32 - 5);
}
#[test]
fn test_overflows() {
assert!(MAX > 0);
assert!(MIN <= 0);
- assert!(MIN + MAX + 1 == 0);
+ assert!((MIN + MAX).wrapping_add(1) == 0);
}
#[test]
#[test]
fn test_count_zeros() {
- assert!(A.count_zeros() == BITS - 3);
- assert!(B.count_zeros() == BITS - 2);
- assert!(C.count_zeros() == BITS - 5);
+ assert!(A.count_zeros() == BITS as u32 - 3);
+ assert!(B.count_zeros() == BITS as u32 - 2);
+ assert!(C.count_zeros() == BITS as u32 - 5);
}
#[test]
fn test_rsplitn_char_iterator() {
let data = "\nMäry häd ä little lämb\nLittle lämb\n";
- let mut split: Vec<&str> = data.rsplitn(3, ' ').collect();
+ let mut split: Vec<&str> = data.rsplitn(4, ' ').collect();
split.reverse();
assert_eq!(split, ["\nMäry häd ä", "little", "lämb\nLittle", "lämb\n"]);
- let mut split: Vec<&str> = data.rsplitn(3, |c: char| c == ' ').collect();
+ let mut split: Vec<&str> = data.rsplitn(4, |c: char| c == ' ').collect();
split.reverse();
assert_eq!(split, ["\nMäry häd ä", "little", "lämb\nLittle", "lämb\n"]);
// Unicode
- let mut split: Vec<&str> = data.rsplitn(3, 'ä').collect();
+ let mut split: Vec<&str> = data.rsplitn(4, 'ä').collect();
split.reverse();
assert_eq!(split, ["\nMäry häd ", " little l", "mb\nLittle l", "mb\n"]);
- let mut split: Vec<&str> = data.rsplitn(3, |c: char| c == 'ä').collect();
+ let mut split: Vec<&str> = data.rsplitn(4, |c: char| c == 'ä').collect();
split.reverse();
assert_eq!(split, ["\nMäry häd ", " little l", "mb\nLittle l", "mb\n"]);
}
#[test]
fn contains_weird_cases() {
- assert!("* \t".contains_char(' '));
- assert!(!"* \t".contains_char('?'));
- assert!(!"* \t".contains_char('\u{1F4A9}'));
+ assert!("* \t".contains(' '));
+ assert!(!"* \t".contains('?'));
+ assert!(!"* \t".contains('\u{1F4A9}'));
}
#[test]
make_test!(chars_count, s, s.chars().count());
make_test!(contains_bang_str, s, s.contains("!"));
- make_test!(contains_bang_char, s, s.contains_char('!'));
+ make_test!(contains_bang_char, s, s.contains('!'));
make_test!(match_indices_a_str, s, s.match_indices("a").count());
- make_test!(split_str_a_str, s, s.split_str("a").count());
+ make_test!(split_a_str, s, s.split("a").count());
make_test!(trim_ascii_char, s, {
use std::ascii::AsciiExt;
make_test!(find_underscore_char, s, s.find('_'));
make_test!(rfind_underscore_char, s, s.rfind('_'));
- make_test!(find_underscore_str, s, s.find_str("_"));
+ make_test!(find_underscore_str, s, s.find("_"));
make_test!(find_zzz_char, s, s.find('\u{1F4A4}'));
make_test!(rfind_zzz_char, s, s.rfind('\u{1F4A4}'));
- make_test!(find_zzz_str, s, s.find_str("\u{1F4A4}"));
+ make_test!(find_zzz_str, s, s.find("\u{1F4A4}"));
make_test!(split_space_char, s, s.split(' ').count());
make_test!(split_terminator_space_char, s, s.split_terminator(' ').count());
make_test!(splitn_space_char, s, s.splitn(10, ' ').count());
make_test!(rsplitn_space_char, s, s.rsplitn(10, ' ').count());
- make_test!(split_str_space_str, s, s.split_str(" ").count());
- make_test!(split_str_ad_str, s, s.split_str("ad").count());
+ make_test!(split_space_str, s, s.split(" ").count());
+ make_test!(split_ad_str, s, s.split("ad").count());
}
/// A piece is a portion of the format string which represents the next part
/// to emit. These are emitted as a stream by the `Parser` class.
-#[derive(Copy, PartialEq)]
+#[derive(Copy, Clone, PartialEq)]
pub enum Piece<'a> {
/// A literal string which should directly be emitted
String(&'a str),
}
/// Representation of an argument specification.
-#[derive(Copy, PartialEq)]
+#[derive(Copy, Clone, PartialEq)]
pub struct Argument<'a> {
/// Where to find this argument
pub position: Position<'a>,
}
/// Specification for the formatting of an argument in the format string.
-#[derive(Copy, PartialEq)]
+#[derive(Copy, Clone, PartialEq)]
pub struct FormatSpec<'a> {
/// Optionally specified character to fill alignment with
pub fill: Option<char>,
}
/// Enum describing where an argument for a format can be located.
-#[derive(Copy, PartialEq)]
+#[derive(Copy, Clone, PartialEq)]
pub enum Position<'a> {
/// The argument will be in the next position. This is the default.
ArgumentNext,
}
/// Enum of alignments which are supported.
-#[derive(Copy, PartialEq)]
+#[derive(Copy, Clone, PartialEq)]
pub enum Alignment {
/// The value will be aligned to the left.
AlignLeft,
/// Various flags which can be applied to format strings. The meaning of these
/// flags is defined by the formatters themselves.
-#[derive(Copy, PartialEq)]
+#[derive(Copy, Clone, PartialEq)]
pub enum Flag {
/// A `+` will be used to denote positive numbers.
FlagSignPlus,
/// A count is used for the precision and width parameters of an integer, and
/// can reference either an argument or a literal integer.
-#[derive(Copy, PartialEq)]
+#[derive(Copy, Clone, PartialEq)]
pub enum Count<'a> {
/// The count is specified explicitly.
CountIs(usize),
fn same(fmt: &'static str, p: &[Piece<'static>]) {
let parser = Parser::new(fmt);
- assert!(p == parser.collect::<Vec<Piece<'static>>>());
+ assert!(parser.collect::<Vec<Piece<'static>>>() == p);
}
fn fmtdflt() -> FormatSpec<'static> {
}
/// The type of failure that occurred.
-#[derive(Copy, PartialEq, Eq, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
#[allow(missing_docs)]
pub enum FailType {
ArgumentMissing_,
line
}
-#[derive(Copy)]
+#[derive(Copy, Clone)]
enum SplitWithinState {
A, // leading whitespace, initial state
B, // words
C, // internal and trailing whitespace
}
-#[derive(Copy)]
+#[derive(Copy, Clone)]
enum Whitespace {
Ws, // current char is whitespace
Cr // current char is not whitespace
}
-#[derive(Copy)]
+#[derive(Copy, Clone)]
enum LengthLimit {
UnderLim, // current char makes current substring still fit in limit
OverLim // current char makes current substring no longer fit in limit
//!
//! fn edges(&'a self) -> dot::Edges<'a,Ed> {
//! let &Edges(ref edges) = self;
-//! edges.as_slice().into_cow()
+//! (&edges[..]).into_cow()
//! }
//!
//! fn source(&self, e: &Ed) -> Nd { let &(s,_) = e; s }
fn target(&'a self, edge: &E) -> N;
}
-#[derive(Copy, PartialEq, Eq, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum RenderOption {
NoEdgeLabels,
NoNodeLabels,
pub type rlim_t = u64;
#[repr(C)]
- #[derive(Copy)] pub struct glob_t {
+ #[derive(Copy, Clone)] pub struct glob_t {
pub gl_pathc: size_t,
pub gl_pathv: *mut *mut c_char,
pub gl_offs: size_t,
}
#[repr(C)]
- #[derive(Copy)] pub struct timeval {
+ #[derive(Copy, Clone)] pub struct timeval {
pub tv_sec: time_t,
pub tv_usec: suseconds_t,
}
#[repr(C)]
- #[derive(Copy)] pub struct timespec {
+ #[derive(Copy, Clone)] pub struct timespec {
pub tv_sec: time_t,
pub tv_nsec: c_long,
}
- #[derive(Copy)] pub enum timezone {}
+ pub enum timezone {}
pub type sighandler_t = size_t;
#[repr(C)]
- #[derive(Copy)]
+ #[derive(Copy, Clone)]
pub struct rlimit {
pub rlim_cur: rlim_t,
pub rlim_max: rlim_t,
// This is also specified in POSIX 2001, but only has two fields. All implementors
// implement BSD 4.3 version.
#[repr(C)]
- #[derive(Copy)]
+ #[derive(Copy, Clone)]
pub struct rusage {
pub ru_utime: timeval,
pub ru_stime: timeval,
pub type in_port_t = u16;
pub type in_addr_t = u32;
#[repr(C)]
- #[derive(Copy)] pub struct sockaddr {
+ #[derive(Copy, Clone)] pub struct sockaddr {
pub sa_family: sa_family_t,
pub sa_data: [u8; 14],
}
#[cfg(target_pointer_width = "64")]
pub __ss_pad2: [u8; 128 - 2 * 8],
}
+ impl ::core::clone::Clone for sockaddr_storage {
+ fn clone(&self) -> sockaddr_storage { *self }
+ }
#[repr(C)]
- #[derive(Copy)] pub struct sockaddr_in {
+ #[derive(Copy, Clone)] pub struct sockaddr_in {
pub sin_family: sa_family_t,
pub sin_port: in_port_t,
pub sin_addr: in_addr,
pub sin_zero: [u8; 8],
}
#[repr(C)]
- #[derive(Copy)] pub struct in_addr {
+ #[derive(Copy, Clone)] pub struct in_addr {
pub s_addr: in_addr_t,
}
#[repr(C)]
- #[derive(Copy)] pub struct sockaddr_in6 {
+ #[derive(Copy, Clone)] pub struct sockaddr_in6 {
pub sin6_family: sa_family_t,
pub sin6_port: in_port_t,
pub sin6_flowinfo: u32,
pub sin6_scope_id: u32,
}
#[repr(C)]
- #[derive(Copy)] pub struct in6_addr {
+ #[derive(Copy, Clone)] pub struct in6_addr {
pub s6_addr: [u16; 8]
}
#[repr(C)]
- #[derive(Copy)] pub struct ip_mreq {
+ #[derive(Copy, Clone)] pub struct ip_mreq {
pub imr_multiaddr: in_addr,
pub imr_interface: in_addr,
}
#[repr(C)]
- #[derive(Copy)] pub struct ip6_mreq {
+ #[derive(Copy, Clone)] pub struct ip6_mreq {
pub ipv6mr_multiaddr: in6_addr,
pub ipv6mr_interface: c_uint,
}
#[repr(C)]
- #[derive(Copy)] pub struct addrinfo {
+ #[derive(Copy, Clone)] pub struct addrinfo {
pub ai_flags: c_int,
pub ai_family: c_int,
pub ai_socktype: c_int,
pub sun_family: sa_family_t,
pub sun_path: [c_char; 108]
}
+ impl ::core::clone::Clone for sockaddr_un {
+ fn clone(&self) -> sockaddr_un { *self }
+ }
#[repr(C)]
- #[derive(Copy)] pub struct ifaddrs {
+ #[derive(Copy, Clone)] pub struct ifaddrs {
pub ifa_next: *mut ifaddrs,
pub ifa_name: *mut c_char,
pub ifa_flags: c_uint,
pub type blkcnt_t = i32;
#[repr(C)]
- #[derive(Copy)] pub struct stat {
+ #[derive(Copy, Clone)] pub struct stat {
pub st_dev: dev_t,
pub __pad1: c_short,
pub st_ino: ino_t,
}
#[repr(C)]
- #[derive(Copy)] pub struct utimbuf {
+ #[derive(Copy, Clone)] pub struct utimbuf {
pub actime: time_t,
pub modtime: time_t,
}
#[repr(C)]
- #[derive(Copy)] pub struct pthread_attr_t {
+ #[derive(Copy, Clone)] pub struct pthread_attr_t {
pub __size: [u32; 9]
}
}
pub type blkcnt_t = u32;
#[repr(C)]
- #[derive(Copy)] pub struct stat {
+ #[derive(Copy, Clone)] pub struct stat {
pub st_dev: c_ulonglong,
pub __pad0: [c_uchar; 4],
pub __st_ino: ino_t,
}
#[repr(C)]
- #[derive(Copy)] pub struct utimbuf {
+ #[derive(Copy, Clone)] pub struct utimbuf {
pub actime: time_t,
pub modtime: time_t,
}
#[repr(C)]
- #[derive(Copy)] pub struct pthread_attr_t {
+ #[derive(Copy, Clone)] pub struct pthread_attr_t {
pub __size: [u32; 9]
}
}
pub type blkcnt_t = i32;
#[repr(C)]
- #[derive(Copy)] pub struct stat {
+ #[derive(Copy, Clone)] pub struct stat {
pub st_dev: c_ulong,
pub st_pad1: [c_long; 3],
pub st_ino: ino_t,
}
#[repr(C)]
- #[derive(Copy)] pub struct utimbuf {
+ #[derive(Copy, Clone)] pub struct utimbuf {
pub actime: time_t,
pub modtime: time_t,
}
#[repr(C)]
- #[derive(Copy)] pub struct pthread_attr_t {
+ #[derive(Copy, Clone)] pub struct pthread_attr_t {
pub __size: [u32; 9]
}
}
pub mod extra {
use types::os::arch::c95::{c_ushort, c_int, c_uchar};
#[repr(C)]
- #[derive(Copy)] pub struct sockaddr_ll {
+ #[derive(Copy, Clone)] pub struct sockaddr_ll {
pub sll_family: c_ushort,
pub sll_protocol: c_ushort,
pub sll_ifindex: c_int,
pub type blkcnt_t = i64;
#[repr(C)]
- #[derive(Copy)] pub struct stat {
+ #[derive(Copy, Clone)] pub struct stat {
pub st_dev: dev_t,
pub st_ino: ino_t,
pub st_nlink: nlink_t,
}
#[repr(C)]
- #[derive(Copy)] pub struct utimbuf {
+ #[derive(Copy, Clone)] pub struct utimbuf {
pub actime: time_t,
pub modtime: time_t,
}
#[repr(C)]
- #[derive(Copy)] pub struct pthread_attr_t {
+ #[derive(Copy, Clone)] pub struct pthread_attr_t {
pub __size: [u64; 7]
}
}
pub type blkcnt_t = i64;
#[repr(C)]
- #[derive(Copy)] pub struct stat {
+ #[derive(Copy, Clone)] pub struct stat {
pub st_dev: dev_t,
pub st_ino: ino_t,
pub st_mode: mode_t,
}
#[repr(C)]
- #[derive(Copy)] pub struct utimbuf {
+ #[derive(Copy, Clone)] pub struct utimbuf {
pub actime: time_t,
pub modtime: time_t,
}
#[repr(C)]
- #[derive(Copy)] pub struct pthread_attr_t {
+ #[derive(Copy, Clone)] pub struct pthread_attr_t {
pub __size: [u64; 8]
}
}
}
pub mod extra {
use types::os::arch::c95::{c_ushort, c_int, c_uchar};
- #[derive(Copy)] pub struct sockaddr_ll {
+ #[derive(Copy, Clone)] pub struct sockaddr_ll {
pub sll_family: c_ushort,
pub sll_protocol: c_ushort,
pub sll_ifindex: c_int,
pub type rlim_t = i64;
#[repr(C)]
- #[derive(Copy)] pub struct glob_t {
+ #[derive(Copy, Clone)] pub struct glob_t {
pub gl_pathc: size_t,
pub __unused1: size_t,
pub gl_offs: size_t,
}
#[repr(C)]
- #[derive(Copy)] pub struct timeval {
+ #[derive(Copy, Clone)] pub struct timeval {
pub tv_sec: time_t,
pub tv_usec: suseconds_t,
}
#[repr(C)]
- #[derive(Copy)] pub struct timespec {
+ #[derive(Copy, Clone)] pub struct timespec {
pub tv_sec: time_t,
pub tv_nsec: c_long,
}
- #[derive(Copy)] pub enum timezone {}
+ pub enum timezone {}
pub type sighandler_t = size_t;
#[repr(C)]
- #[derive(Copy)]
+ #[derive(Copy, Clone)]
pub struct rlimit {
pub rlim_cur: rlim_t,
pub rlim_max: rlim_t,
use types::os::common::posix01::timeval;
use types::os::arch::c95::c_long;
#[repr(C)]
- #[derive(Copy)]
+ #[derive(Copy, Clone)]
pub struct rusage {
pub ru_utime: timeval,
pub ru_stime: timeval,
pub type in_port_t = u16;
pub type in_addr_t = u32;
#[repr(C)]
- #[derive(Copy)] pub struct sockaddr {
+ #[derive(Copy, Clone)] pub struct sockaddr {
pub sa_len: u8,
pub sa_family: sa_family_t,
pub sa_data: [u8; 14],
pub __ss_align: i64,
pub __ss_pad2: [u8; 112],
}
+ impl ::core::clone::Clone for sockaddr_storage {
+ fn clone(&self) -> sockaddr_storage { *self }
+ }
#[repr(C)]
- #[derive(Copy)] pub struct sockaddr_in {
+ #[derive(Copy, Clone)] pub struct sockaddr_in {
pub sin_len: u8,
pub sin_family: sa_family_t,
pub sin_port: in_port_t,
pub sin_zero: [u8; 8],
}
#[repr(C)]
- #[derive(Copy)] pub struct in_addr {
+ #[derive(Copy, Clone)] pub struct in_addr {
pub s_addr: in_addr_t,
}
#[repr(C)]
- #[derive(Copy)] pub struct sockaddr_in6 {
+ #[derive(Copy, Clone)] pub struct sockaddr_in6 {
pub sin6_len: u8,
pub sin6_family: sa_family_t,
pub sin6_port: in_port_t,
pub sin6_scope_id: u32,
}
#[repr(C)]
- #[derive(Copy)] pub struct in6_addr {
+ #[derive(Copy, Clone)] pub struct in6_addr {
pub s6_addr: [u16; 8]
}
#[repr(C)]
- #[derive(Copy)] pub struct ip_mreq {
+ #[derive(Copy, Clone)] pub struct ip_mreq {
pub imr_multiaddr: in_addr,
pub imr_interface: in_addr,
}
#[repr(C)]
- #[derive(Copy)] pub struct ip6_mreq {
+ #[derive(Copy, Clone)] pub struct ip6_mreq {
pub ipv6mr_multiaddr: in6_addr,
pub ipv6mr_interface: c_uint,
}
#[repr(C)]
- #[derive(Copy)] pub struct addrinfo {
+ #[derive(Copy, Clone)] pub struct addrinfo {
pub ai_flags: c_int,
pub ai_family: c_int,
pub ai_socktype: c_int,
pub sun_family: sa_family_t,
pub sun_path: [c_char; 104]
}
+ impl ::core::clone::Clone for sockaddr_un {
+ fn clone(&self) -> sockaddr_un { *self }
+ }
#[repr(C)]
- #[derive(Copy)] pub struct ifaddrs {
+ #[derive(Copy, Clone)] pub struct ifaddrs {
pub ifa_next: *mut ifaddrs,
pub ifa_name: *mut c_char,
pub ifa_flags: c_uint,
pub type blkcnt_t = i64;
pub type fflags_t = u32;
#[repr(C)]
- #[derive(Copy)] pub struct stat {
+ #[derive(Copy, Clone)] pub struct stat {
pub st_dev: dev_t,
pub st_ino: ino_t,
pub st_mode: mode_t,
}
#[repr(C)]
- #[derive(Copy)] pub struct utimbuf {
+ #[derive(Copy, Clone)] pub struct utimbuf {
pub actime: time_t,
pub modtime: time_t,
}
pub type rlim_t = i64;
#[repr(C)]
- #[derive(Copy)] pub struct glob_t {
+ #[derive(Copy, Clone)] pub struct glob_t {
pub gl_pathc: size_t,
pub __unused1: size_t,
pub gl_offs: size_t,
}
#[repr(C)]
- #[derive(Copy)] pub struct timeval {
+ #[derive(Copy, Clone)] pub struct timeval {
pub tv_sec: time_t,
pub tv_usec: suseconds_t,
}
#[repr(C)]
- #[derive(Copy)] pub struct timespec {
+ #[derive(Copy, Clone)] pub struct timespec {
pub tv_sec: time_t,
pub tv_nsec: c_long,
}
- #[derive(Copy)] pub enum timezone {}
+ pub enum timezone {}
pub type sighandler_t = size_t;
#[repr(C)]
- #[derive(Copy)]
+ #[derive(Copy, Clone)]
pub struct rlimit {
pub rlim_cur: rlim_t,
pub rlim_max: rlim_t,
use types::os::common::posix01::timeval;
use types::os::arch::c95::c_long;
#[repr(C)]
- #[derive(Copy)]
+ #[derive(Copy, Clone)]
pub struct rusage {
pub ru_utime: timeval,
pub ru_stime: timeval,
pub type in_port_t = u16;
pub type in_addr_t = u32;
#[repr(C)]
- #[derive(Copy)] pub struct sockaddr {
+ #[derive(Copy, Clone)] pub struct sockaddr {
pub sa_len: u8,
pub sa_family: sa_family_t,
pub sa_data: [u8; 14],
pub __ss_align: i64,
pub __ss_pad2: [u8; 112],
}
+ impl ::core::clone::Clone for sockaddr_storage {
+ fn clone(&self) -> sockaddr_storage { *self }
+ }
#[repr(C)]
- #[derive(Copy)] pub struct sockaddr_in {
+ #[derive(Copy, Clone)] pub struct sockaddr_in {
pub sin_len: u8,
pub sin_family: sa_family_t,
pub sin_port: in_port_t,
pub sin_zero: [u8; 8],
}
#[repr(C)]
- #[derive(Copy)] pub struct in_addr {
+ #[derive(Copy, Clone)] pub struct in_addr {
pub s_addr: in_addr_t,
}
#[repr(C)]
- #[derive(Copy)] pub struct sockaddr_in6 {
+ #[derive(Copy, Clone)] pub struct sockaddr_in6 {
pub sin6_len: u8,
pub sin6_family: sa_family_t,
pub sin6_port: in_port_t,
pub sin6_scope_id: u32,
}
#[repr(C)]
- #[derive(Copy)] pub struct in6_addr {
+ #[derive(Copy, Clone)] pub struct in6_addr {
pub s6_addr: [u16; 8]
}
#[repr(C)]
- #[derive(Copy)] pub struct ip_mreq {
+ #[derive(Copy, Clone)] pub struct ip_mreq {
pub imr_multiaddr: in_addr,
pub imr_interface: in_addr,
}
#[repr(C)]
- #[derive(Copy)] pub struct ip6_mreq {
+ #[derive(Copy, Clone)] pub struct ip6_mreq {
pub ipv6mr_multiaddr: in6_addr,
pub ipv6mr_interface: c_uint,
}
#[repr(C)]
- #[derive(Copy)] pub struct addrinfo {
+ #[derive(Copy, Clone)] pub struct addrinfo {
pub ai_flags: c_int,
pub ai_family: c_int,
pub ai_socktype: c_int,
pub sun_family: sa_family_t,
pub sun_path: [c_char; 104]
}
+ impl ::core::clone::Clone for sockaddr_un {
+ fn clone(&self) -> sockaddr_un { *self }
+ }
#[repr(C)]
- #[derive(Copy)] pub struct ifaddrs {
+ #[derive(Copy, Clone)] pub struct ifaddrs {
pub ifa_next: *mut ifaddrs,
pub ifa_name: *mut c_char,
pub ifa_flags: c_uint,
pub type fflags_t = u32;
#[repr(C)]
- #[derive(Copy)] pub struct stat {
+ #[derive(Copy, Clone)] pub struct stat {
pub st_ino: ino_t,
pub st_nlink: nlink_t,
pub st_dev: dev_t,
pub st_qspare2: int64_t,
}
#[repr(C)]
- #[derive(Copy)] pub struct utimbuf {
+ #[derive(Copy, Clone)] pub struct utimbuf {
pub actime: time_t,
pub modtime: time_t,
}
#[cfg(target_os = "bitrig")]
#[repr(C)]
- #[derive(Copy)] pub struct glob_t {
+ #[derive(Copy, Clone)] pub struct glob_t {
pub gl_pathc: c_int,
pub gl_matchc: c_int,
pub gl_offs: c_int,
#[cfg(target_os = "openbsd")]
#[repr(C)]
- #[derive(Copy)] pub struct glob_t {
+ #[derive(Copy, Clone)] pub struct glob_t {
pub gl_pathc: c_int,
pub __unused1: c_int,
pub gl_offs: c_int,
}
#[repr(C)]
- #[derive(Copy)] pub struct timeval {
+ #[derive(Copy, Clone)] pub struct timeval {
pub tv_sec: time_t,
pub tv_usec: suseconds_t,
}
#[repr(C)]
- #[derive(Copy)] pub struct timespec {
+ #[derive(Copy, Clone)] pub struct timespec {
pub tv_sec: time_t,
pub tv_nsec: c_long,
}
- #[derive(Copy)] pub enum timezone {}
+ pub enum timezone {}
pub type sighandler_t = size_t;
#[repr(C)]
- #[derive(Copy)]
+ #[derive(Copy, Clone)]
pub struct rlimit {
pub rlim_cur: rlim_t,
pub rlim_max: rlim_t,
use types::os::common::posix01::timeval;
use types::os::arch::c95::c_long;
#[repr(C)]
- #[derive(Copy)]
+ #[derive(Copy, Clone)]
pub struct rusage {
pub ru_utime: timeval,
pub ru_stime: timeval,
pub type in_port_t = u16;
pub type in_addr_t = u32;
#[repr(C)]
- #[derive(Copy)] pub struct sockaddr {
+ #[derive(Copy, Clone)] pub struct sockaddr {
pub sa_len: u8,
pub sa_family: sa_family_t,
pub sa_data: [u8; 14],
pub __ss_pad2: i64,
pub __ss_pad3: [u8; 240],
}
+ impl ::core::clone::Clone for sockaddr_storage {
+ fn clone(&self) -> sockaddr_storage { *self }
+ }
#[repr(C)]
- #[derive(Copy)] pub struct sockaddr_in {
+ #[derive(Copy, Clone)] pub struct sockaddr_in {
pub sin_len: u8,
pub sin_family: sa_family_t,
pub sin_port: in_port_t,
pub sin_zero: [u8; 8],
}
#[repr(C)]
- #[derive(Copy)] pub struct in_addr {
+ #[derive(Copy, Clone)] pub struct in_addr {
pub s_addr: in_addr_t,
}
#[repr(C)]
- #[derive(Copy)] pub struct sockaddr_in6 {
+ #[derive(Copy, Clone)] pub struct sockaddr_in6 {
pub sin6_len: u8,
pub sin6_family: sa_family_t,
pub sin6_port: in_port_t,
pub sin6_scope_id: u32,
}
#[repr(C)]
- #[derive(Copy)] pub struct in6_addr {
+ #[derive(Copy, Clone)] pub struct in6_addr {
pub s6_addr: [u16; 8]
}
#[repr(C)]
- #[derive(Copy)] pub struct ip_mreq {
+ #[derive(Copy, Clone)] pub struct ip_mreq {
pub imr_multiaddr: in_addr,
pub imr_interface: in_addr,
}
#[repr(C)]
- #[derive(Copy)] pub struct ip6_mreq {
+ #[derive(Copy, Clone)] pub struct ip6_mreq {
pub ipv6mr_multiaddr: in6_addr,
pub ipv6mr_interface: c_uint,
}
#[repr(C)]
- #[derive(Copy)] pub struct addrinfo {
+ #[derive(Copy, Clone)] pub struct addrinfo {
pub ai_flags: c_int,
pub ai_family: c_int,
pub ai_socktype: c_int,
pub sun_family: sa_family_t,
pub sun_path: [c_char; 104]
}
+ impl ::core::clone::Clone for sockaddr_un {
+ fn clone(&self) -> sockaddr_un { *self }
+ }
#[repr(C)]
- #[derive(Copy)] pub struct ifaddrs {
+ #[derive(Copy, Clone)] pub struct ifaddrs {
pub ifa_next: *mut ifaddrs,
pub ifa_name: *mut c_char,
pub ifa_flags: c_uint,
pub type fflags_t = u32; // type not declared, but struct stat have u_int32_t
#[repr(C)]
- #[derive(Copy)] pub struct stat {
+ #[derive(Copy, Clone)] pub struct stat {
pub st_mode: mode_t,
pub st_dev: dev_t,
pub st_ino: ino_t,
pub st_birthtime_nsec: c_long,
}
#[repr(C)]
- #[derive(Copy)] pub struct utimbuf {
+ #[derive(Copy, Clone)] pub struct utimbuf {
pub actime: time_t,
pub modtime: time_t,
}
// pub Note: this is the struct called stat64 in Windows. Not stat,
// nor stati64.
#[repr(C)]
- #[derive(Copy)] pub struct stat {
+ #[derive(Copy, Clone)] pub struct stat {
pub st_dev: dev_t,
pub st_ino: ino_t,
pub st_mode: u16,
// note that this is called utimbuf64 in Windows
#[repr(C)]
- #[derive(Copy)] pub struct utimbuf {
+ #[derive(Copy, Clone)] pub struct utimbuf {
pub actime: time64_t,
pub modtime: time64_t,
}
#[repr(C)]
- #[derive(Copy)] pub struct timeval {
+ #[derive(Copy, Clone)] pub struct timeval {
pub tv_sec: c_long,
pub tv_usec: c_long,
}
#[repr(C)]
- #[derive(Copy)] pub struct timespec {
+ #[derive(Copy, Clone)] pub struct timespec {
pub tv_sec: time_t,
pub tv_nsec: c_long,
}
- #[derive(Copy)] pub enum timezone {}
+ pub enum timezone {}
}
pub mod bsd44 {
pub type in_port_t = u16;
pub type in_addr_t = u32;
#[repr(C)]
- #[derive(Copy)] pub struct sockaddr {
+ #[derive(Copy, Clone)] pub struct sockaddr {
pub sa_family: sa_family_t,
pub sa_data: [u8; 14],
}
pub __ss_align: i64,
pub __ss_pad2: [u8; 112],
}
+ impl ::core::clone::Clone for sockaddr_storage {
+ fn clone(&self) -> sockaddr_storage { *self }
+ }
#[repr(C)]
- #[derive(Copy)] pub struct sockaddr_in {
+ #[derive(Copy, Clone)] pub struct sockaddr_in {
pub sin_family: sa_family_t,
pub sin_port: in_port_t,
pub sin_addr: in_addr,
pub sin_zero: [u8; 8],
}
#[repr(C)]
- #[derive(Copy)] pub struct in_addr {
+ #[derive(Copy, Clone)] pub struct in_addr {
pub s_addr: in_addr_t,
}
#[repr(C)]
- #[derive(Copy)] pub struct sockaddr_in6 {
+ #[derive(Copy, Clone)] pub struct sockaddr_in6 {
pub sin6_family: sa_family_t,
pub sin6_port: in_port_t,
pub sin6_flowinfo: u32,
pub sin6_scope_id: u32,
}
#[repr(C)]
- #[derive(Copy)] pub struct in6_addr {
+ #[derive(Copy, Clone)] pub struct in6_addr {
pub s6_addr: [u16; 8]
}
#[repr(C)]
- #[derive(Copy)] pub struct ip_mreq {
+ #[derive(Copy, Clone)] pub struct ip_mreq {
pub imr_multiaddr: in_addr,
pub imr_interface: in_addr,
}
#[repr(C)]
- #[derive(Copy)] pub struct ip6_mreq {
+ #[derive(Copy, Clone)] pub struct ip6_mreq {
pub ipv6mr_multiaddr: in6_addr,
pub ipv6mr_interface: c_uint,
}
#[repr(C)]
- #[derive(Copy)] pub struct addrinfo {
+ #[derive(Copy, Clone)] pub struct addrinfo {
pub ai_flags: c_int,
pub ai_family: c_int,
pub ai_socktype: c_int,
pub sun_family: sa_family_t,
pub sun_path: [c_char; 108]
}
+ impl ::core::clone::Clone for sockaddr_un {
+ fn clone(&self) -> sockaddr_un { *self }
+ }
}
}
pub type LPCH = *mut CHAR;
#[repr(C)]
- #[derive(Copy)] pub struct SECURITY_ATTRIBUTES {
+ #[derive(Copy, Clone)] pub struct SECURITY_ATTRIBUTES {
pub nLength: DWORD,
pub lpSecurityDescriptor: LPVOID,
pub bInheritHandle: BOOL,
pub type int64 = i64;
#[repr(C)]
- #[derive(Copy)] pub struct STARTUPINFO {
+ #[derive(Copy, Clone)] pub struct STARTUPINFO {
pub cb: DWORD,
pub lpReserved: LPWSTR,
pub lpDesktop: LPWSTR,
pub type LPSTARTUPINFO = *mut STARTUPINFO;
#[repr(C)]
- #[derive(Copy)] pub struct PROCESS_INFORMATION {
+ #[derive(Copy, Clone)] pub struct PROCESS_INFORMATION {
pub hProcess: HANDLE,
pub hThread: HANDLE,
pub dwProcessId: DWORD,
pub type LPPROCESS_INFORMATION = *mut PROCESS_INFORMATION;
#[repr(C)]
- #[derive(Copy)] pub struct SYSTEM_INFO {
+ #[derive(Copy, Clone)] pub struct SYSTEM_INFO {
pub wProcessorArchitecture: WORD,
pub wReserved: WORD,
pub dwPageSize: DWORD,
pub type LPSYSTEM_INFO = *mut SYSTEM_INFO;
#[repr(C)]
- #[derive(Copy)] pub struct MEMORY_BASIC_INFORMATION {
+ #[derive(Copy, Clone)] pub struct MEMORY_BASIC_INFORMATION {
pub BaseAddress: LPVOID,
pub AllocationBase: LPVOID,
pub AllocationProtect: DWORD,
pub type LPMEMORY_BASIC_INFORMATION = *mut MEMORY_BASIC_INFORMATION;
#[repr(C)]
- #[derive(Copy)] pub struct OVERLAPPED {
+ #[derive(Copy, Clone)] pub struct OVERLAPPED {
pub Internal: *mut c_ulong,
pub InternalHigh: *mut c_ulong,
pub Offset: DWORD,
pub type LPOVERLAPPED = *mut OVERLAPPED;
#[repr(C)]
- #[derive(Copy)] pub struct FILETIME {
+ #[derive(Copy, Clone)] pub struct FILETIME {
pub dwLowDateTime: DWORD,
pub dwHighDateTime: DWORD,
}
pub type LPFILETIME = *mut FILETIME;
#[repr(C)]
- #[derive(Copy)] pub struct GUID {
+ #[derive(Copy, Clone)] pub struct GUID {
pub Data1: DWORD,
pub Data2: WORD,
pub Data3: WORD,
}
#[repr(C)]
- #[derive(Copy)] pub struct WSAPROTOCOLCHAIN {
+ #[derive(Copy, Clone)] pub struct WSAPROTOCOLCHAIN {
pub ChainLen: c_int,
pub ChainEntries: [DWORD; MAX_PROTOCOL_CHAIN as usize],
}
pub dwProviderReserved: DWORD,
pub szProtocol: [u8; WSAPROTOCOL_LEN as usize + 1],
}
+ impl ::core::clone::Clone for WSAPROTOCOL_INFO {
+ fn clone(&self) -> WSAPROTOCOL_INFO { *self }
+ }
pub type LPWSAPROTOCOL_INFO = *mut WSAPROTOCOL_INFO;
pub cFileName: [wchar_t; 260], // #define MAX_PATH 260
pub cAlternateFileName: [wchar_t; 14],
}
+ impl ::core::clone::Clone for WIN32_FIND_DATAW {
+ fn clone(&self) -> WIN32_FIND_DATAW { *self }
+ }
pub type LPWIN32_FIND_DATAW = *mut WIN32_FIND_DATAW;
}
pub type rlim_t = u64;
#[repr(C)]
- #[derive(Copy)] pub struct glob_t {
+ #[derive(Copy, Clone)] pub struct glob_t {
pub gl_pathc: size_t,
pub __unused1: c_int,
pub gl_offs: size_t,
}
#[repr(C)]
- #[derive(Copy)] pub struct timeval {
+ #[derive(Copy, Clone)] pub struct timeval {
pub tv_sec: time_t,
pub tv_usec: suseconds_t,
}
#[repr(C)]
- #[derive(Copy)] pub struct timespec {
+ #[derive(Copy, Clone)] pub struct timespec {
pub tv_sec: time_t,
pub tv_nsec: c_long,
}
- #[derive(Copy)] pub enum timezone {}
+ pub enum timezone {}
pub type sighandler_t = size_t;
#[repr(C)]
- #[derive(Copy)]
+ #[derive(Copy, Clone)]
pub struct rlimit {
pub rlim_cur: rlim_t,
pub rlim_max: rlim_t,
use types::os::common::posix01::timeval;
use types::os::arch::c95::c_long;
#[repr(C)]
- #[derive(Copy)]
+ #[derive(Copy, Clone)]
pub struct rusage {
pub ru_utime: timeval,
pub ru_stime: timeval,
pub type in_port_t = u16;
pub type in_addr_t = u32;
#[repr(C)]
- #[derive(Copy)] pub struct sockaddr {
+ #[derive(Copy, Clone)] pub struct sockaddr {
pub sa_len: u8,
pub sa_family: sa_family_t,
pub sa_data: [u8; 14],
pub __ss_align: i64,
pub __ss_pad2: [u8; 112],
}
+ impl ::core::clone::Clone for sockaddr_storage {
+ fn clone(&self) -> sockaddr_storage { *self }
+ }
#[repr(C)]
- #[derive(Copy)] pub struct sockaddr_in {
+ #[derive(Copy, Clone)] pub struct sockaddr_in {
pub sin_len: u8,
pub sin_family: sa_family_t,
pub sin_port: in_port_t,
}
#[repr(C)]
- #[derive(Copy)] pub struct in_addr {
+ #[derive(Copy, Clone)] pub struct in_addr {
pub s_addr: in_addr_t,
}
#[repr(C)]
- #[derive(Copy)] pub struct sockaddr_in6 {
+ #[derive(Copy, Clone)] pub struct sockaddr_in6 {
pub sin6_len: u8,
pub sin6_family: sa_family_t,
pub sin6_port: in_port_t,
}
#[repr(C)]
- #[derive(Copy)] pub struct in6_addr {
+ #[derive(Copy, Clone)] pub struct in6_addr {
pub s6_addr: [u16; 8]
}
#[repr(C)]
- #[derive(Copy)] pub struct ip_mreq {
+ #[derive(Copy, Clone)] pub struct ip_mreq {
pub imr_multiaddr: in_addr,
pub imr_interface: in_addr,
}
#[repr(C)]
- #[derive(Copy)] pub struct ip6_mreq {
+ #[derive(Copy, Clone)] pub struct ip6_mreq {
pub ipv6mr_multiaddr: in6_addr,
pub ipv6mr_interface: c_uint,
}
#[repr(C)]
- #[derive(Copy)] pub struct addrinfo {
+ #[derive(Copy, Clone)] pub struct addrinfo {
pub ai_flags: c_int,
pub ai_family: c_int,
pub ai_socktype: c_int,
pub sun_family: sa_family_t,
pub sun_path: [c_char; 104]
}
+ impl ::core::clone::Clone for sockaddr_un {
+ fn clone(&self) -> sockaddr_un { *self }
+ }
#[repr(C)]
- #[derive(Copy)] pub struct ifaddrs {
+ #[derive(Copy, Clone)] pub struct ifaddrs {
pub ifa_next: *mut ifaddrs,
pub ifa_name: *mut c_char,
pub ifa_flags: c_uint,
pub type blkcnt_t = i64;
#[repr(C)]
- #[derive(Copy)] pub struct stat {
+ #[derive(Copy, Clone)] pub struct stat {
pub st_dev: dev_t,
pub st_mode: mode_t,
pub st_nlink: nlink_t,
}
#[repr(C)]
- #[derive(Copy)] pub struct utimbuf {
+ #[derive(Copy, Clone)] pub struct utimbuf {
pub actime: time_t,
pub modtime: time_t,
}
pub __sig: c_long,
pub __opaque: [c_char; 36]
}
+ impl ::core::clone::Clone for pthread_attr_t {
+ fn clone(&self) -> pthread_attr_t { *self }
+ }
}
pub mod posix08 {
}
}
pub mod extra {
#[repr(C)]
- #[derive(Copy)] pub struct mach_timebase_info {
+ #[derive(Copy, Clone)] pub struct mach_timebase_info {
pub numer: u32,
pub denom: u32,
}
pub type blkcnt_t = i64;
#[repr(C)]
- #[derive(Copy)] pub struct stat {
+ #[derive(Copy, Clone)] pub struct stat {
pub st_dev: dev_t,
pub st_mode: mode_t,
pub st_nlink: nlink_t,
}
#[repr(C)]
- #[derive(Copy)] pub struct utimbuf {
+ #[derive(Copy, Clone)] pub struct utimbuf {
pub actime: time_t,
pub modtime: time_t,
}
pub __sig: c_long,
pub __opaque: [c_char; 56]
}
+ impl ::core::clone::Clone for pthread_attr_t {
+ fn clone(&self) -> pthread_attr_t { *self }
+ }
}
pub mod posix08 {
}
}
pub mod extra {
#[repr(C)]
- #[derive(Copy)] pub struct mach_timebase_info {
+ #[derive(Copy, Clone)] pub struct mach_timebase_info {
pub numer: u32,
pub denom: u32,
}
pub const ERROR_IO_PENDING: c_int = 997;
pub const ERROR_FILE_INVALID : c_int = 1006;
pub const ERROR_NOT_FOUND: c_int = 1168;
- pub const INVALID_HANDLE_VALUE: HANDLE = -1 as HANDLE;
+ pub const INVALID_HANDLE_VALUE: HANDLE = !0 as HANDLE;
pub const DELETE : DWORD = 0x00010000;
pub const READ_CONTROL : DWORD = 0x00020000;
pub const WAIT_ABANDONED : DWORD = 0x00000080;
pub const WAIT_OBJECT_0 : DWORD = 0x00000000;
pub const WAIT_TIMEOUT : DWORD = 0x00000102;
- pub const WAIT_FAILED : DWORD = -1;
+ pub const WAIT_FAILED : DWORD = !0;
pub const DUPLICATE_CLOSE_SOURCE : DWORD = 0x00000001;
pub const DUPLICATE_SAME_ACCESS : DWORD = 0x00000002;
- pub const INFINITE : DWORD = -1;
+ pub const INFINITE : DWORD = !0;
pub const STILL_ACTIVE : DWORD = 259;
pub const MEM_COMMIT : DWORD = 0x00001000;
pub const MAP_FIXED : c_int = 0x0010;
pub const MAP_ANON : c_int = 0x0020;
- pub const MAP_FAILED : *mut c_void = -1 as *mut c_void;
+ pub const MAP_FAILED : *mut c_void = !0 as *mut c_void;
pub const MCL_CURRENT : c_int = 0x0001;
pub const MCL_FUTURE : c_int = 0x0002;
pub const MAP_FIXED : c_int = 0x0010;
pub const MAP_ANON : c_int = 0x0800;
- pub const MAP_FAILED : *mut c_void = -1 as *mut c_void;
+ pub const MAP_FAILED : *mut c_void = !0 as *mut c_void;
pub const MCL_CURRENT : c_int = 0x0001;
pub const MCL_FUTURE : c_int = 0x0002;
pub const MAP_FIXED : c_int = 0x0010;
pub const MAP_ANON : c_int = 0x1000;
- pub const MAP_FAILED : *mut c_void = -1 as *mut c_void;
+ pub const MAP_FAILED : *mut c_void = !0 as *mut c_void;
pub const MCL_CURRENT : c_int = 0x0001;
pub const MCL_FUTURE : c_int = 0x0002;
pub const MAP_FIXED : c_int = 0x0010;
pub const MAP_ANON : c_int = 0x1000;
- pub const MAP_FAILED : *mut c_void = -1 as *mut c_void;
+ pub const MAP_FAILED : *mut c_void = !0 as *mut c_void;
pub const MCL_CURRENT : c_int = 0x0001;
pub const MCL_FUTURE : c_int = 0x0002;
pub const MAP_FIXED : c_int = 0x0010;
pub const MAP_ANON : c_int = 0x1000;
- pub const MAP_FAILED : *mut c_void = -1 as *mut c_void;
+ pub const MAP_FAILED : *mut c_void = !0 as *mut c_void;
pub const MCL_CURRENT : c_int = 0x0001;
pub const MCL_FUTURE : c_int = 0x0002;
struct DefaultLogger { handle: Stderr }
/// Wraps the log level with fmt implementations.
-#[derive(Copy, PartialEq, PartialOrd, Debug)]
+#[derive(Copy, Clone, PartialEq, PartialOrd, Debug)]
pub struct LogLevel(pub u32);
impl fmt::Display for LogLevel {
}
#[doc(hidden)]
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub struct LogLocation {
pub module_path: &'static str,
pub file: &'static str,
for word in &mut key {
*word = other.gen();
}
- SeedableRng::from_seed(key.as_slice())
+ SeedableRng::from_seed(&key[..])
}
}
/// Generate Normal Random
/// Samples*](http://www.doornik.com/research/ziggurat.pdf). Nuffield
/// College, Oxford
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub struct Exp1(pub f64);
// This could be done via `-rng.gen::<f64>().ln()` but that is slower.
/// let v = exp.ind_sample(&mut rand::thread_rng());
/// println!("{} is from a Exp(2) distribution", v);
/// ```
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub struct Exp {
/// `lambda` stored as `1/lambda`, since this is what we scale by.
lambda_inverse: f64
}
#[test] #[should_panic]
fn test_weighted_choice_weight_overflows() {
- let x = (-1) as usize / 2; // x + x + 2 is the overflow
+ let x = (!0) as usize / 2; // x + x + 2 is the overflow
WeightedChoice::new(&mut [Weighted { weight: x, item: 0 },
Weighted { weight: 1, item: 1 },
Weighted { weight: x, item: 2 },
/// Generate Normal Random
/// Samples*](http://www.doornik.com/research/ziggurat.pdf). Nuffield
/// College, Oxford
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub struct StandardNormal(pub f64);
impl Rand for StandardNormal {
/// let v = normal.ind_sample(&mut rand::thread_rng());
/// println!("{} is from a N(2, 9) distribution", v)
/// ```
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub struct Normal {
mean: f64,
std_dev: f64,
/// let v = log_normal.ind_sample(&mut rand::thread_rng());
/// println!("{} is from an ln N(2, 9) distribution", v)
/// ```
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub struct LogNormal {
norm: Normal
}
///
/// let mut v = [0; 13579];
/// thread_rng().fill_bytes(&mut v);
- /// println!("{:?}", v.as_slice());
+ /// println!("{:?}", &v[..]);
/// ```
fn fill_bytes(&mut self, dest: &mut [u8]) {
// this could, in theory, be done by transmuting dest to a
/// let mut rng = thread_rng();
/// let mut y = [1, 2, 3];
/// rng.shuffle(&mut y);
- /// println!("{:?}", y.as_slice());
+ /// println!("{:?}", y);
/// rng.shuffle(&mut y);
- /// println!("{:?}", y.as_slice());
+ /// println!("{:?}", y);
/// ```
fn shuffle<T>(&mut self, values: &mut [T]) {
let mut i = values.len();
/// Reseed an RNG using a `Default` instance. This reseeds by
/// replacing the RNG with the result of a `Default::default` call.
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub struct ReseedWithDefault;
impl<R: Rng + Default> Reseeder<R> for ReseedWithDefault {
html_root_url = "http://doc.rust-lang.org/nightly/",
html_playground_url = "http://play.rust-lang.org/")]
-#![feature(io)]
#![feature(core)]
#![feature(rustc_private)]
#![feature(staged_api)]
pub doc: Doc<'a>,
}
-#[derive(Copy, Debug)]
+#[derive(Copy, Clone, Debug)]
pub enum EbmlEncoderTag {
// tags 00..1f are reserved for auto-serialization.
// first NUM_IMPLICIT_TAGS tags are implicitly sized and lengths are not encoded.
)
}
- #[derive(Copy)]
+ #[derive(Copy, Clone)]
pub struct Res {
pub val: usize,
pub next: usize
} else if 0x100 <= n && n < NUM_TAGS {
w.write_all(&[0xf0 | (n >> 8) as u8, n as u8])
} else {
- Err(io::Error::new(io::ErrorKind::Other, "invalid tag",
- Some(n.to_string())))
+ Err(io::Error::new(io::ErrorKind::Other,
+ &format!("invalid tag: {}", n)[..]))
}
}
4 => w.write_all(&[0x10 | ((n >> 24) as u8), (n >> 16) as u8,
(n >> 8) as u8, n as u8]),
_ => Err(io::Error::new(io::ErrorKind::Other,
- "isize too big", Some(n.to_string())))
+ &format!("isize too big: {}", n)[..]))
}
}
if n < 0x4000 { return write_sized_vuint(w, n, 2); }
if n < 0x200000 { return write_sized_vuint(w, n, 3); }
if n < 0x10000000 { return write_sized_vuint(w, n, 4); }
- Err(io::Error::new(io::ErrorKind::Other, "isize too big",
- Some(n.to_string())))
+ Err(io::Error::new(io::ErrorKind::Other,
+ &format!("isize too big: {}", n)[..]))
}
impl<'a> Encoder<'a> {
self.wr_tagged_raw_u32(EsSub32 as usize, v)
} else {
Err(io::Error::new(io::ErrorKind::Other,
- "length or variant id too big",
- Some(v.to_string())))
+ &format!("length or variant id too big: {}",
+ v)[..]))
}
}
E0019,
E0020,
E0022,
+ E0079, // enum variant: expected signed integer constant
+ E0080, // enum variant: constant evaluation error
E0109,
E0110,
E0133,
E0313, // lifetime of borrowed pointer outlives lifetime of captured variable
E0314, // closure outlives stack frame
E0315, // cannot invoke closure outside of its lifetime
- E0316 // nested quantification of lifetimes
+ E0316, // nested quantification of lifetimes
+ E0370 // discriminant overflow
}
__build_diagnostic_array! { DIAGNOSTICS }
#![feature(unsafe_destructor)]
#![feature(staged_api)]
#![feature(std_misc)]
-#![feature(io)]
#![feature(path_ext)]
#![feature(str_words)]
#![feature(str_char)]
-#![feature(convert)]
#![feature(into_cow)]
#![feature(slice_patterns)]
#![cfg_attr(test, feature(test))]
pub mod traits;
pub mod ty;
pub mod ty_fold;
+ pub mod ty_match;
+ pub mod ty_relate;
pub mod ty_walk;
pub mod weak_lang_items;
}
}
/// Does nothing as a lint pass, but registers some `Lint`s
/// which are used by other parts of the compiler.
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub struct HardwiredLints;
impl LintPass for HardwiredLints {
GatherNodeLevels};
/// Specification of a single lint.
-#[derive(Copy, Debug)]
+#[derive(Copy, Clone, Debug)]
pub struct Lint {
/// A string identifier for the lint.
///
pub const tag_items_data_item_reexport_name: usize = 0x48;
// used to encode crate_ctxt side tables
-#[derive(Copy, PartialEq, FromPrimitive)]
+#[derive(Copy, Clone, PartialEq, FromPrimitive)]
#[repr(usize)]
pub enum astencode_tag { // Reserves 0x50 -- 0x6f
tag_ast = 0x50,
use std::collections::hash_map::HashMap;
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub struct MethodInfo {
pub name: ast::Name,
pub def_id: ast::DefId,
use std::io::{Cursor, SeekFrom};
use syntax::abi;
use syntax::ast::{self, DefId, NodeId};
-use syntax::ast_map::{PathElem, PathElems};
-use syntax::ast_map;
+use syntax::ast_map::{self, LinkedPath, PathElem, PathElems};
use syntax::ast_util::*;
use syntax::ast_util;
use syntax::attr;
&krate.module,
&[],
ast::CRATE_NODE_ID,
- [].iter().cloned().chain(None),
+ [].iter().cloned().chain(LinkedPath::empty()),
syntax::parse::token::special_idents::invalid,
ast::Public);
}
// Encode reexports for the root module.
- encode_reexports(ecx, rbml_w, 0, [].iter().cloned().chain(None));
+ encode_reexports(ecx, rbml_w, 0, [].iter().cloned().chain(LinkedPath::empty()));
rbml_w.end_tag();
rbml_w.end_tag();
use util::fs as myfs;
use session::search_paths::{SearchPaths, PathKind};
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub enum FileMatch {
FileMatches,
FileDoesntMatch,
// def-id will depend on where it originated from. Therefore, the conversion
// function is given an indicator of the source of the def-id. See
// astencode.rs for more information.
-#[derive(Copy, Debug)]
+#[derive(Copy, Clone, Debug)]
pub enum DefIdSource {
// Identifies a struct, trait, enum, etc.
NominalType,
})
}
- if let Some(ty) = tcx.node_types.borrow().get(&id) {
+ if let Some(ty) = tcx.node_types().get(&id) {
rbml_w.tag(c::tag_table_node_type, |rbml_w| {
rbml_w.id(id);
rbml_w.emit_ty(ecx, *ty);
let ty = val_dsr.read_ty(dcx);
debug!("inserting ty for node {}: {}",
id, ty_to_string(dcx.tcx, ty));
- dcx.tcx.node_types.borrow_mut().insert(id, ty);
+ dcx.tcx.node_type_insert(id, ty);
}
c::tag_table_item_subst => {
let item_substs = ty::ItemSubsts {
loop_scopes: Vec<LoopScope>,
}
-#[derive(Copy)]
+#[derive(Copy, Clone)]
struct LoopScope {
loop_id: ast::NodeId, // id of loop/while node
continue_index: CFGIndex, // where to go on a `loop`
pub exit: CFGIndex,
}
-#[derive(Copy, PartialEq)]
+#[derive(Copy, Clone, PartialEq)]
pub enum CFGNodeData {
AST(ast::NodeId),
Entry,
}
}
-#[derive(Copy, Eq, PartialEq)]
+#[derive(Copy, Clone, Eq, PartialEq)]
enum Mode {
Const,
Static,
Normal, Loop, Closure
}
-#[derive(Copy)]
+#[derive(Copy, Clone)]
struct CheckLoopVisitor<'a> {
sess: &'a Session,
cx: Context
NotUseful
}
-#[derive(Copy)]
+#[derive(Copy, Clone)]
enum WitnessPreference {
ConstructWitness,
LeaveOutWitness
pub use self::const_val::*;
+use self::ErrKind::*;
+
use metadata::csearch;
use middle::{astencode, def};
use middle::pat_util::def_to_path;
use syntax::ast::{self, Expr};
use syntax::codemap::Span;
+use syntax::feature_gate;
use syntax::parse::token::InternedString;
use syntax::ptr::P;
use syntax::{ast_map, ast_util, codemap};
use std::borrow::{Cow, IntoCow};
use std::num::wrapping::OverflowingOps;
+use std::num::ToPrimitive;
use std::cmp::Ordering;
use std::collections::hash_map::Entry::Vacant;
use std::{i8, i16, i32, i64};
NotOnStruct,
NotOnTuple,
+ NegateWithOverflow(i64),
AddiWithOverflow(i64, i64),
SubiWithOverflow(i64, i64),
MuliWithOverflow(i64, i64),
DivideWithOverflow,
ModuloByZero,
ModuloWithOverflow,
+ ShiftLeftWithOverflow,
+ ShiftRightWithOverflow,
MissingStructField,
NonConstPath,
ExpectedConstTuple,
impl ConstEvalErr {
pub fn description(&self) -> Cow<str> {
use self::ErrKind::*;
+
match self.kind {
CannotCast => "can't cast this type".into_cow(),
CannotCastTo(s) => format!("can't cast this type to {}", s).into_cow(),
NotOnStruct => "not on struct".into_cow(),
NotOnTuple => "not on tuple".into_cow(),
+ NegateWithOverflow(..) => "attempted to negate with overflow".into_cow(),
AddiWithOverflow(..) => "attempted to add with overflow".into_cow(),
SubiWithOverflow(..) => "attempted to sub with overflow".into_cow(),
MuliWithOverflow(..) => "attempted to mul with overflow".into_cow(),
DivideWithOverflow => "attempted to divide with overflow".into_cow(),
ModuloByZero => "attempted remainder with a divisor of zero".into_cow(),
ModuloWithOverflow => "attempted remainder with overflow".into_cow(),
+ ShiftLeftWithOverflow => "attempted left shift with overflow".into_cow(),
+ ShiftRightWithOverflow => "attempted right shift with overflow".into_cow(),
MissingStructField => "nonexistent struct field".into_cow(),
NonConstPath => "non-constant path in constant expr".into_cow(),
ExpectedConstTuple => "expected constant tuple".into_cow(),
}
}
+pub type EvalResult = Result<const_val, ConstEvalErr>;
+pub type CastResult = Result<const_val, ErrKind>;
+
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub enum IntTy { I8, I16, I32, I64 }
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub enum UintTy { U8, U16, U32, U64 }
+
+impl IntTy {
+ pub fn from(tcx: &ty::ctxt, t: ast::IntTy) -> IntTy {
+ let t = if let ast::TyIs = t {
+ tcx.sess.target.int_type
+ } else {
+ t
+ };
+ match t {
+ ast::TyIs => unreachable!(),
+ ast::TyI8 => IntTy::I8,
+ ast::TyI16 => IntTy::I16,
+ ast::TyI32 => IntTy::I32,
+ ast::TyI64 => IntTy::I64,
+ }
+ }
+}
+
+impl UintTy {
+ pub fn from(tcx: &ty::ctxt, t: ast::UintTy) -> UintTy {
+ let t = if let ast::TyUs = t {
+ tcx.sess.target.uint_type
+ } else {
+ t
+ };
+ match t {
+ ast::TyUs => unreachable!(),
+ ast::TyU8 => UintTy::U8,
+ ast::TyU16 => UintTy::U16,
+ ast::TyU32 => UintTy::U32,
+ ast::TyU64 => UintTy::U64,
+ }
+ }
+}
+
macro_rules! signal {
- ($e:expr, $ctor:ident) => {
- return Err(ConstEvalErr { span: $e.span, kind: ErrKind::$ctor })
+ ($e:expr, $exn:expr) => {
+ return Err(ConstEvalErr { span: $e.span, kind: $exn })
+ }
+}
+
+// The const_{int,uint}_checked_{neg,add,sub,mul,div,shl,shr} family
+// of functions catch and signal overflow errors during constant
+// evaluation.
+//
+// They all take the operator's arguments (`a` and `b` if binary), the
+// overall expression (`e`) and, if available, whole expression's
+// concrete type (`opt_ety`).
+//
+// If the whole expression's concrete type is None, then this is a
+// constant evaluation happening before type check (e.g. in the check
+// to confirm that a pattern range's left-side is not greater than its
+// right-side). We do not do arithmetic modulo the type's bitwidth in
+// such a case; we just do 64-bit arithmetic and assume that later
+// passes will do it again with the type information, and thus do the
+// overflow checks then.
+
+pub fn const_int_checked_neg<'a>(
+ a: i64, e: &'a Expr, opt_ety: Option<IntTy>) -> EvalResult {
+
+ let (min,max) = match opt_ety {
+ // (-i8::MIN is itself not an i8, etc, but this is an easy way
+ // to allow literals to pass the check. Of course that does
+ // not work for i64::MIN.)
+ Some(IntTy::I8) => (-(i8::MAX as i64), -(i8::MIN as i64)),
+ Some(IntTy::I16) => (-(i16::MAX as i64), -(i16::MIN as i64)),
+ Some(IntTy::I32) => (-(i32::MAX as i64), -(i32::MIN as i64)),
+ None | Some(IntTy::I64) => (-i64::MAX, -(i64::MIN+1)),
};
- ($e:expr, $ctor:ident($($arg:expr),*)) => {
- return Err(ConstEvalErr { span: $e.span, kind: ErrKind::$ctor($($arg),*) })
+ let oflo = a < min || a > max;
+ if oflo {
+ signal!(e, NegateWithOverflow(a));
+ } else {
+ Ok(const_int(-a))
+ }
+}
+
+pub fn const_uint_checked_neg<'a>(
+ a: u64, _e: &'a Expr, _opt_ety: Option<UintTy>) -> EvalResult {
+ // This always succeeds, and by definition, returns `(!a)+1`.
+ Ok(const_uint((!a).wrapping_add(1)))
+}
+
+macro_rules! overflow_checking_body {
+ ($a:ident, $b:ident, $ety:ident, $overflowing_op:ident,
+ lhs: $to_8_lhs:ident $to_16_lhs:ident $to_32_lhs:ident,
+ rhs: $to_8_rhs:ident $to_16_rhs:ident $to_32_rhs:ident $to_64_rhs:ident,
+ $EnumTy:ident $T8: ident $T16: ident $T32: ident $T64: ident,
+ $result_type: ident) => { {
+ let (a,b,opt_ety) = ($a,$b,$ety);
+ match opt_ety {
+ Some($EnumTy::$T8) => match (a.$to_8_lhs(), b.$to_8_rhs()) {
+ (Some(a), Some(b)) => {
+ let (a, oflo) = a.$overflowing_op(b);
+ (a as $result_type, oflo)
+ }
+ (None, _) | (_, None) => (0, true)
+ },
+ Some($EnumTy::$T16) => match (a.$to_16_lhs(), b.$to_16_rhs()) {
+ (Some(a), Some(b)) => {
+ let (a, oflo) = a.$overflowing_op(b);
+ (a as $result_type, oflo)
+ }
+ (None, _) | (_, None) => (0, true)
+ },
+ Some($EnumTy::$T32) => match (a.$to_32_lhs(), b.$to_32_rhs()) {
+ (Some(a), Some(b)) => {
+ let (a, oflo) = a.$overflowing_op(b);
+ (a as $result_type, oflo)
+ }
+ (None, _) | (_, None) => (0, true)
+ },
+ None | Some($EnumTy::$T64) => match b.$to_64_rhs() {
+ Some(b) => a.$overflowing_op(b),
+ None => (0, true),
+ }
+ }
+ } }
+}
+
+macro_rules! int_arith_body {
+ ($a:ident, $b:ident, $ety:ident, $overflowing_op:ident) => {
+ overflow_checking_body!(
+ $a, $b, $ety, $overflowing_op,
+ lhs: to_i8 to_i16 to_i32,
+ rhs: to_i8 to_i16 to_i32 to_i64, IntTy I8 I16 I32 I64, i64)
+ }
+}
+
+macro_rules! uint_arith_body {
+ ($a:ident, $b:ident, $ety:ident, $overflowing_op:ident) => {
+ overflow_checking_body!(
+ $a, $b, $ety, $overflowing_op,
+ lhs: to_u8 to_u16 to_u32,
+ rhs: to_u8 to_u16 to_u32 to_u64, UintTy U8 U16 U32 U64, u64)
+ }
+}
+
+macro_rules! int_shift_body {
+ ($a:ident, $b:ident, $ety:ident, $overflowing_op:ident) => {
+ overflow_checking_body!(
+ $a, $b, $ety, $overflowing_op,
+ lhs: to_i8 to_i16 to_i32,
+ rhs: to_u32 to_u32 to_u32 to_u32, IntTy I8 I16 I32 I64, i64)
}
}
-fn checked_add_int(e: &Expr, a: i64, b: i64) -> Result<const_val, ConstEvalErr> {
- let (ret, oflo) = a.overflowing_add(b);
- if !oflo { Ok(const_int(ret)) } else { signal!(e, AddiWithOverflow(a, b)) }
+macro_rules! uint_shift_body {
+ ($a:ident, $b:ident, $ety:ident, $overflowing_op:ident) => {
+ overflow_checking_body!(
+ $a, $b, $ety, $overflowing_op,
+ lhs: to_u8 to_u16 to_u32,
+ rhs: to_u32 to_u32 to_u32 to_u32, UintTy U8 U16 U32 U64, u64)
+ }
}
-fn checked_sub_int(e: &Expr, a: i64, b: i64) -> Result<const_val, ConstEvalErr> {
- let (ret, oflo) = a.overflowing_sub(b);
- if !oflo { Ok(const_int(ret)) } else { signal!(e, SubiWithOverflow(a, b)) }
+
+macro_rules! pub_fn_checked_op {
+ {$fn_name:ident ($a:ident : $a_ty:ty, $b:ident : $b_ty:ty,.. $WhichTy:ident) {
+ $ret_oflo_body:ident $overflowing_op:ident
+ $const_ty:ident $signal_exn:expr
+ }} => {
+ pub fn $fn_name<'a>($a: $a_ty,
+ $b: $b_ty,
+ e: &'a Expr,
+ opt_ety: Option<$WhichTy>) -> EvalResult {
+ let (ret, oflo) = $ret_oflo_body!($a, $b, opt_ety, $overflowing_op);
+ if !oflo { Ok($const_ty(ret)) } else { signal!(e, $signal_exn) }
+ }
+ }
}
-fn checked_mul_int(e: &Expr, a: i64, b: i64) -> Result<const_val, ConstEvalErr> {
- let (ret, oflo) = a.overflowing_mul(b);
- if !oflo { Ok(const_int(ret)) } else { signal!(e, MuliWithOverflow(a, b)) }
+
+pub_fn_checked_op!{ const_int_checked_add(a: i64, b: i64,.. IntTy) {
+ int_arith_body overflowing_add const_int AddiWithOverflow(a, b)
+}}
+
+pub_fn_checked_op!{ const_int_checked_sub(a: i64, b: i64,.. IntTy) {
+ int_arith_body overflowing_sub const_int SubiWithOverflow(a, b)
+}}
+
+pub_fn_checked_op!{ const_int_checked_mul(a: i64, b: i64,.. IntTy) {
+ int_arith_body overflowing_mul const_int MuliWithOverflow(a, b)
+}}
+
+pub fn const_int_checked_div<'a>(
+ a: i64, b: i64, e: &'a Expr, opt_ety: Option<IntTy>) -> EvalResult {
+ if b == 0 { signal!(e, DivideByZero); }
+ let (ret, oflo) = int_arith_body!(a, b, opt_ety, overflowing_div);
+ if !oflo { Ok(const_int(ret)) } else { signal!(e, DivideWithOverflow) }
}
-fn checked_add_uint(e: &Expr, a: u64, b: u64) -> Result<const_val, ConstEvalErr> {
- let (ret, oflo) = a.overflowing_add(b);
- if !oflo { Ok(const_uint(ret)) } else { signal!(e, AdduWithOverflow(a, b)) }
+pub fn const_int_checked_rem<'a>(
+ a: i64, b: i64, e: &'a Expr, opt_ety: Option<IntTy>) -> EvalResult {
+ if b == 0 { signal!(e, ModuloByZero); }
+ let (ret, oflo) = int_arith_body!(a, b, opt_ety, overflowing_rem);
+ if !oflo { Ok(const_int(ret)) } else { signal!(e, ModuloWithOverflow) }
}
-fn checked_sub_uint(e: &Expr, a: u64, b: u64) -> Result<const_val, ConstEvalErr> {
- let (ret, oflo) = a.overflowing_sub(b);
- if !oflo { Ok(const_uint(ret)) } else { signal!(e, SubuWithOverflow(a, b)) }
+
+pub_fn_checked_op!{ const_int_checked_shl(a: i64, b: i64,.. IntTy) {
+ int_shift_body overflowing_shl const_int ShiftLeftWithOverflow
+}}
+
+pub_fn_checked_op!{ const_int_checked_shl_via_uint(a: i64, b: u64,.. IntTy) {
+ int_shift_body overflowing_shl const_int ShiftLeftWithOverflow
+}}
+
+pub_fn_checked_op!{ const_int_checked_shr(a: i64, b: i64,.. IntTy) {
+ int_shift_body overflowing_shr const_int ShiftRightWithOverflow
+}}
+
+pub_fn_checked_op!{ const_int_checked_shr_via_uint(a: i64, b: u64,.. IntTy) {
+ int_shift_body overflowing_shr const_int ShiftRightWithOverflow
+}}
+
+pub_fn_checked_op!{ const_uint_checked_add(a: u64, b: u64,.. UintTy) {
+ uint_arith_body overflowing_add const_uint AdduWithOverflow(a, b)
+}}
+
+pub_fn_checked_op!{ const_uint_checked_sub(a: u64, b: u64,.. UintTy) {
+ uint_arith_body overflowing_sub const_uint SubuWithOverflow(a, b)
+}}
+
+pub_fn_checked_op!{ const_uint_checked_mul(a: u64, b: u64,.. UintTy) {
+ uint_arith_body overflowing_mul const_uint MuluWithOverflow(a, b)
+}}
+
+pub fn const_uint_checked_div<'a>(
+ a: u64, b: u64, e: &'a Expr, opt_ety: Option<UintTy>) -> EvalResult {
+ if b == 0 { signal!(e, DivideByZero); }
+ let (ret, oflo) = uint_arith_body!(a, b, opt_ety, overflowing_div);
+ if !oflo { Ok(const_uint(ret)) } else { signal!(e, DivideWithOverflow) }
}
-fn checked_mul_uint(e: &Expr, a: u64, b: u64) -> Result<const_val, ConstEvalErr> {
- let (ret, oflo) = a.overflowing_mul(b);
- if !oflo { Ok(const_uint(ret)) } else { signal!(e, MuluWithOverflow(a, b)) }
+
+pub fn const_uint_checked_rem<'a>(
+ a: u64, b: u64, e: &'a Expr, opt_ety: Option<UintTy>) -> EvalResult {
+ if b == 0 { signal!(e, ModuloByZero); }
+ let (ret, oflo) = uint_arith_body!(a, b, opt_ety, overflowing_rem);
+ if !oflo { Ok(const_uint(ret)) } else { signal!(e, ModuloWithOverflow) }
}
+pub_fn_checked_op!{ const_uint_checked_shl(a: u64, b: u64,.. UintTy) {
+ uint_shift_body overflowing_shl const_uint ShiftLeftWithOverflow
+}}
+
+pub_fn_checked_op!{ const_uint_checked_shl_via_int(a: u64, b: i64,.. UintTy) {
+ uint_shift_body overflowing_shl const_uint ShiftLeftWithOverflow
+}}
+
+pub_fn_checked_op!{ const_uint_checked_shr(a: u64, b: u64,.. UintTy) {
+ uint_shift_body overflowing_shr const_uint ShiftRightWithOverflow
+}}
+
+pub_fn_checked_op!{ const_uint_checked_shr_via_int(a: u64, b: i64,.. UintTy) {
+ uint_shift_body overflowing_shr const_uint ShiftRightWithOverflow
+}}
pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
e: &Expr,
- ty_hint: Option<Ty<'tcx>>)
- -> Result<const_val, ConstEvalErr> {
+ ty_hint: Option<Ty<'tcx>>) -> EvalResult {
fn fromb(b: bool) -> const_val { const_int(b as i64) }
let ety = ty_hint.or_else(|| ty::expr_ty_opt(tcx, e));
+ // If type of expression itself is int or uint, normalize in these
+ // bindings so that isize/usize is mapped to a type with an
+ // inherently known bitwidth.
+ let expr_int_type = ety.and_then(|ty| {
+ if let ty::ty_int(t) = ty.sty {
+ Some(IntTy::from(tcx, t)) } else { None }
+ });
+ let expr_uint_type = ety.and_then(|ty| {
+ if let ty::ty_uint(t) = ty.sty {
+ Some(UintTy::from(tcx, t)) } else { None }
+ });
+
let result = match e.node {
ast::ExprUnary(ast::UnNeg, ref inner) => {
match try!(eval_const_expr_partial(tcx, &**inner, ety)) {
const_float(f) => const_float(-f),
- const_int(i) => const_int(-i),
- const_uint(i) => const_uint(-i),
+ const_int(n) => try!(const_int_checked_neg(n, e, expr_int_type)),
+ const_uint(i) => {
+ if !tcx.sess.features.borrow().negate_unsigned {
+ feature_gate::emit_feature_err(
+ &tcx.sess.parse_sess.span_diagnostic,
+ "negate_unsigned",
+ e.span,
+ "unary negation of unsigned integers may be removed in the future");
+ }
+ try!(const_uint_checked_neg(i, e, expr_uint_type))
+ }
const_str(_) => signal!(e, NegateOnString),
const_bool(_) => signal!(e, NegateOnBoolean),
const_binary(_) => signal!(e, NegateOnBinary),
}
}
(const_int(a), const_int(b)) => {
- let is_a_min_value = || {
- let int_ty = match ty::expr_ty_opt(tcx, e).map(|ty| &ty.sty) {
- Some(&ty::ty_int(int_ty)) => int_ty,
- _ => return false
- };
- let int_ty = if let ast::TyIs = int_ty {
- tcx.sess.target.int_type
- } else {
- int_ty
- };
- match int_ty {
- ast::TyI8 => (a as i8) == i8::MIN,
- ast::TyI16 => (a as i16) == i16::MIN,
- ast::TyI32 => (a as i32) == i32::MIN,
- ast::TyI64 => (a as i64) == i64::MIN,
- ast::TyIs => unreachable!()
- }
- };
match op.node {
- ast::BiAdd => try!(checked_add_int(e, a, b)),
- ast::BiSub => try!(checked_sub_int(e, a, b)),
- ast::BiMul => try!(checked_mul_int(e, a, b)),
- ast::BiDiv => {
- if b == 0 {
- signal!(e, DivideByZero);
- } else if b == -1 && is_a_min_value() {
- signal!(e, DivideWithOverflow);
- } else {
- const_int(a / b)
- }
- }
- ast::BiRem => {
- if b == 0 {
- signal!(e, ModuloByZero)
- } else if b == -1 && is_a_min_value() {
- signal!(e, ModuloWithOverflow)
- } else {
- const_int(a % b)
- }
- }
+ ast::BiAdd => try!(const_int_checked_add(a,b,e,expr_int_type)),
+ ast::BiSub => try!(const_int_checked_sub(a,b,e,expr_int_type)),
+ ast::BiMul => try!(const_int_checked_mul(a,b,e,expr_int_type)),
+ ast::BiDiv => try!(const_int_checked_div(a,b,e,expr_int_type)),
+ ast::BiRem => try!(const_int_checked_rem(a,b,e,expr_int_type)),
ast::BiAnd | ast::BiBitAnd => const_int(a & b),
ast::BiOr | ast::BiBitOr => const_int(a | b),
ast::BiBitXor => const_int(a ^ b),
- ast::BiShl => const_int(a << b as usize),
- ast::BiShr => const_int(a >> b as usize),
+ ast::BiShl => try!(const_int_checked_shl(a,b,e,expr_int_type)),
+ ast::BiShr => try!(const_int_checked_shr(a,b,e,expr_int_type)),
ast::BiEq => fromb(a == b),
ast::BiLt => fromb(a < b),
ast::BiLe => fromb(a <= b),
}
(const_uint(a), const_uint(b)) => {
match op.node {
- ast::BiAdd => try!(checked_add_uint(e, a, b)),
- ast::BiSub => try!(checked_sub_uint(e, a, b)),
- ast::BiMul => try!(checked_mul_uint(e, a, b)),
- ast::BiDiv if b == 0 => signal!(e, DivideByZero),
- ast::BiDiv => const_uint(a / b),
- ast::BiRem if b == 0 => signal!(e, ModuloByZero),
- ast::BiRem => const_uint(a % b),
+ ast::BiAdd => try!(const_uint_checked_add(a,b,e,expr_uint_type)),
+ ast::BiSub => try!(const_uint_checked_sub(a,b,e,expr_uint_type)),
+ ast::BiMul => try!(const_uint_checked_mul(a,b,e,expr_uint_type)),
+ ast::BiDiv => try!(const_uint_checked_div(a,b,e,expr_uint_type)),
+ ast::BiRem => try!(const_uint_checked_rem(a,b,e,expr_uint_type)),
ast::BiAnd | ast::BiBitAnd => const_uint(a & b),
ast::BiOr | ast::BiBitOr => const_uint(a | b),
ast::BiBitXor => const_uint(a ^ b),
- ast::BiShl => const_uint(a << b as usize),
- ast::BiShr => const_uint(a >> b as usize),
+ ast::BiShl => try!(const_uint_checked_shl(a,b,e,expr_uint_type)),
+ ast::BiShr => try!(const_uint_checked_shr(a,b,e,expr_uint_type)),
ast::BiEq => fromb(a == b),
ast::BiLt => fromb(a < b),
ast::BiLe => fromb(a <= b),
// shifts can have any integral type as their rhs
(const_int(a), const_uint(b)) => {
match op.node {
- ast::BiShl => const_int(a << b as usize),
- ast::BiShr => const_int(a >> b as usize),
+ ast::BiShl => try!(const_int_checked_shl_via_uint(a,b,e,expr_int_type)),
+ ast::BiShr => try!(const_int_checked_shr_via_uint(a,b,e,expr_int_type)),
_ => signal!(e, InvalidOpForIntUint(op.node)),
}
}
(const_uint(a), const_int(b)) => {
match op.node {
- ast::BiShl => const_uint(a << b as usize),
- ast::BiShr => const_uint(a >> b as usize),
+ ast::BiShl => try!(const_uint_checked_shl_via_int(a,b,e,expr_uint_type)),
+ ast::BiShr => try!(const_uint_checked_shr_via_int(a,b,e,expr_uint_type)),
_ => signal!(e, InvalidOpForUintInt(op.node)),
}
}
tcx.sess.span_fatal(target_ty.span,
"target type not found for const cast")
});
+
// Prefer known type to noop, but always have a type hint.
+ //
+ // FIXME (#23833): the type-hint can cause problems,
+ // e.g. `(i8::MAX + 1_i8) as u32` feeds in `u32` as result
+ // type to the sum, and thus no overflow is signaled.
let base_hint = ty::expr_ty_opt(tcx, &**base).unwrap_or(ety);
let val = try!(eval_const_expr_partial(tcx, &**base, Some(base_hint)));
- match cast_const(val, ety) {
+ match cast_const(tcx, val, ety) {
Ok(val) => val,
Err(kind) => return Err(ConstEvalErr { span: e.span, kind: kind }),
}
Ok(result)
}
-fn cast_const(val: const_val, ty: Ty) -> Result<const_val, ErrKind> {
- macro_rules! define_casts {
- ($($ty_pat:pat => (
- $intermediate_ty:ty,
- $const_type:ident,
- $target_ty:ty
- )),*) => (match ty.sty {
- $($ty_pat => {
- match val {
- const_bool(b) => Ok($const_type(b as $intermediate_ty as $target_ty)),
- const_uint(u) => Ok($const_type(u as $intermediate_ty as $target_ty)),
- const_int(i) => Ok($const_type(i as $intermediate_ty as $target_ty)),
- const_float(f) => Ok($const_type(f as $intermediate_ty as $target_ty)),
- _ => Err(ErrKind::CannotCastTo(stringify!($const_type))),
- }
- },)*
- _ => Err(ErrKind::CannotCast),
- })
+fn cast_const<'tcx>(tcx: &ty::ctxt<'tcx>, val: const_val, ty: Ty) -> CastResult {
+ macro_rules! convert_val {
+ ($intermediate_ty:ty, $const_type:ident, $target_ty:ty) => {
+ match val {
+ const_bool(b) => Ok($const_type(b as $intermediate_ty as $target_ty)),
+ const_uint(u) => Ok($const_type(u as $intermediate_ty as $target_ty)),
+ const_int(i) => Ok($const_type(i as $intermediate_ty as $target_ty)),
+ const_float(f) => Ok($const_type(f as $intermediate_ty as $target_ty)),
+ _ => Err(ErrKind::CannotCastTo(stringify!($const_type))),
+ }
+ }
+ }
+
+ // Issue #23890: If isize/usize, then dispatch to appropriate target representation type
+ match (&ty.sty, tcx.sess.target.int_type, tcx.sess.target.uint_type) {
+ (&ty::ty_int(ast::TyIs), ast::TyI32, _) => return convert_val!(i32, const_int, i64),
+ (&ty::ty_int(ast::TyIs), ast::TyI64, _) => return convert_val!(i64, const_int, i64),
+ (&ty::ty_int(ast::TyIs), _, _) => panic!("unexpected target.int_type"),
+
+ (&ty::ty_uint(ast::TyUs), _, ast::TyU32) => return convert_val!(u32, const_uint, u64),
+ (&ty::ty_uint(ast::TyUs), _, ast::TyU64) => return convert_val!(u64, const_uint, u64),
+ (&ty::ty_uint(ast::TyUs), _, _) => panic!("unexpected target.uint_type"),
+
+ _ => {}
}
- define_casts!{
- ty::ty_int(ast::TyIs) => (isize, const_int, i64),
- ty::ty_int(ast::TyI8) => (i8, const_int, i64),
- ty::ty_int(ast::TyI16) => (i16, const_int, i64),
- ty::ty_int(ast::TyI32) => (i32, const_int, i64),
- ty::ty_int(ast::TyI64) => (i64, const_int, i64),
- ty::ty_uint(ast::TyUs) => (usize, const_uint, u64),
- ty::ty_uint(ast::TyU8) => (u8, const_uint, u64),
- ty::ty_uint(ast::TyU16) => (u16, const_uint, u64),
- ty::ty_uint(ast::TyU32) => (u32, const_uint, u64),
- ty::ty_uint(ast::TyU64) => (u64, const_uint, u64),
- ty::ty_float(ast::TyF32) => (f32, const_float, f64),
- ty::ty_float(ast::TyF64) => (f64, const_float, f64)
+ match ty.sty {
+ ty::ty_int(ast::TyIs) => unreachable!(),
+ ty::ty_uint(ast::TyUs) => unreachable!(),
+
+ ty::ty_int(ast::TyI8) => convert_val!(i8, const_int, i64),
+ ty::ty_int(ast::TyI16) => convert_val!(i16, const_int, i64),
+ ty::ty_int(ast::TyI32) => convert_val!(i32, const_int, i64),
+ ty::ty_int(ast::TyI64) => convert_val!(i64, const_int, i64),
+
+ ty::ty_uint(ast::TyU8) => convert_val!(u8, const_uint, u64),
+ ty::ty_uint(ast::TyU16) => convert_val!(u16, const_uint, u64),
+ ty::ty_uint(ast::TyU32) => convert_val!(u32, const_uint, u64),
+ ty::ty_uint(ast::TyU64) => convert_val!(u64, const_uint, u64),
+
+ ty::ty_float(ast::TyF32) => convert_val!(f32, const_float, f64),
+ ty::ty_float(ast::TyF64) => convert_val!(f64, const_float, f64),
+ _ => Err(ErrKind::CannotCast),
}
}
use syntax::print::{pp, pprust};
use util::nodemap::NodeMap;
-#[derive(Copy, Debug)]
+#[derive(Copy, Clone, Debug)]
pub enum EntryOrExit {
Entry,
Exit,
pprust::NodeIdent(_) | pprust::NodeName(_) => 0,
pprust::NodeExpr(expr) => expr.id,
pprust::NodeBlock(blk) => blk.id,
- pprust::NodeItem(_) => 0,
+ pprust::NodeItem(_) | pprust::NodeSubItem(_) => 0,
pprust::NodePat(pat) => pat.id
};
oper: O,
id_range: IdRange,
bits_per_id: usize) -> DataFlowContext<'a, 'tcx, O> {
- let words_per_id = (bits_per_id + usize::BITS as usize - 1) / usize::BITS as usize;
+ let words_per_id = (bits_per_id + usize::BITS - 1) / usize::BITS;
let num_nodes = cfg.graph.all_nodes().len();
debug!("DataFlowContext::new(analysis_name: {}, id_range={:?}, \
for (word_index, &word) in words.iter().enumerate() {
if word != 0 {
- let base_index = word_index * usize::BITS as usize;
+ let base_index = word_index * usize::BITS;
for offset in 0..usize::BITS {
let bit = 1 << offset;
if (word & bit) != 0 {
fn set_bit(words: &mut [usize], bit: usize) -> bool {
debug!("set_bit: words={} bit={}",
mut_bits_to_string(words), bit_str(bit));
- let word = bit / usize::BITS as usize;
- let bit_in_word = bit % usize::BITS as usize;
+ let word = bit / usize::BITS;
+ let bit_in_word = bit % usize::BITS;
let bit_mask = 1 << bit_in_word;
debug!("word={} bit_in_word={} bit_mask={}", word, bit_in_word, word);
let oldv = words[word];
/// <T as Trait>::AssocX::AssocY::MethodOrAssocType
/// ^~~~~~~~~~~~~~ ^~~~~~~~~~~~~~~~~~~~~~~~~
/// base_def depth = 2
-#[derive(Copy, Debug)]
+#[derive(Copy, Clone, Debug)]
pub struct PathResolution {
pub base_def: Def,
pub last_private: LastPrivate,
pub fn def_id(&self) -> ast::DefId {
self.full_def().def_id()
}
+
+ pub fn new(base_def: Def,
+ last_private: LastPrivate,
+ depth: usize)
+ -> PathResolution {
+ PathResolution {
+ base_def: base_def,
+ last_private: last_private,
+ depth: depth,
+ }
+ }
}
// Definition mapping
// within.
pub type ExportMap = NodeMap<Vec<Export>>;
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub struct Export {
pub name: ast::Name, // The name of the target.
pub def_id: ast::DefId, // The definition of the target.
use syntax::visit;
use syntax::visit::Visitor;
-#[derive(Copy, PartialEq)]
+#[derive(Copy, Clone, PartialEq)]
enum UnsafeContext {
SafeContext,
UnsafeFn,
mode: MutateMode);
}
-#[derive(Copy, PartialEq, Debug)]
+#[derive(Copy, Clone, PartialEq, Debug)]
pub enum LoanCause {
ClosureCapture(Span),
AddrOf,
MatchDiscriminant
}
-#[derive(Copy, PartialEq, Debug)]
+#[derive(Copy, Clone, PartialEq, Debug)]
pub enum ConsumeMode {
Copy, // reference to x where x has a type that copies
Move(MoveReason), // reference to x where x has a type that moves
}
-#[derive(Copy, PartialEq, Debug)]
+#[derive(Copy, Clone, PartialEq, Debug)]
pub enum MoveReason {
DirectRefMove,
PatBindingMove,
CaptureMove,
}
-#[derive(Copy, PartialEq, Debug)]
+#[derive(Copy, Clone, PartialEq, Debug)]
pub enum MatchMode {
NonBindingMatch,
BorrowingMatch,
MovingMatch,
}
-#[derive(Copy, PartialEq, Debug)]
+#[derive(Copy, Clone, PartialEq, Debug)]
enum TrackMatchMode {
Unknown,
Definite(MatchMode),
}
}
-#[derive(Copy, PartialEq, Debug)]
+#[derive(Copy, Clone, PartialEq, Debug)]
pub enum MutateMode {
Init,
JustWrite, // x = y
WriteAndRead, // x += y
}
-#[derive(Copy)]
+#[derive(Copy, Clone)]
enum OverloadedCallType {
FnOverloadedCall,
FnMutOverloadedCall,
#[allow(non_upper_case_globals)]
pub const InvalidNodeIndex: NodeIndex = NodeIndex(usize::MAX);
-#[derive(Copy, PartialEq, Debug)]
+#[derive(Copy, Clone, PartialEq, Debug)]
pub struct EdgeIndex(pub usize);
#[allow(non_upper_case_globals)]
pub const InvalidEdgeIndex: EdgeIndex = EdgeIndex(usize::MAX);
// Use a private field here to guarantee no more instances are created:
-#[derive(Copy, Debug)]
+#[derive(Copy, Clone, Debug)]
pub struct Direction { repr: usize }
#[allow(non_upper_case_globals)]
pub const Outgoing: Direction = Direction { repr: 0 };
//! In particular, it might be enough to say (A,B) are bivariant for
//! all (A,B).
-use middle::ty::BuiltinBounds;
+use super::combine::{self, CombineFields};
+use super::type_variable::{BiTo};
+
use middle::ty::{self, Ty};
use middle::ty::TyVar;
-use middle::infer::combine::*;
-use middle::infer::cres;
-use middle::infer::type_variable::BiTo;
-use util::ppaux::Repr;
+use middle::ty_relate::{Relate, RelateResult, TypeRelation};
+use util::ppaux::{Repr};
-pub struct Bivariate<'f, 'tcx: 'f> {
- fields: CombineFields<'f, 'tcx>
+pub struct Bivariate<'a, 'tcx: 'a> {
+ fields: CombineFields<'a, 'tcx>
}
-#[allow(non_snake_case)]
-pub fn Bivariate<'f, 'tcx>(cf: CombineFields<'f, 'tcx>) -> Bivariate<'f, 'tcx> {
- Bivariate { fields: cf }
+impl<'a, 'tcx> Bivariate<'a, 'tcx> {
+ pub fn new(fields: CombineFields<'a, 'tcx>) -> Bivariate<'a, 'tcx> {
+ Bivariate { fields: fields }
+ }
}
-impl<'f, 'tcx> Combine<'tcx> for Bivariate<'f, 'tcx> {
- fn tag(&self) -> String { "Bivariate".to_string() }
- fn fields<'a>(&'a self) -> &'a CombineFields<'a, 'tcx> { &self.fields }
+impl<'a, 'tcx> TypeRelation<'a, 'tcx> for Bivariate<'a, 'tcx> {
+ fn tag(&self) -> &'static str { "Bivariate" }
- fn tys_with_variance(&self, v: ty::Variance, a: Ty<'tcx>, b: Ty<'tcx>)
- -> cres<'tcx, Ty<'tcx>>
- {
- match v {
- ty::Invariant => self.equate().tys(a, b),
- ty::Covariant => self.tys(a, b),
- ty::Contravariant => self.tys(a, b),
- ty::Bivariant => self.tys(a, b),
- }
- }
+ fn tcx(&self) -> &'a ty::ctxt<'tcx> { self.fields.tcx() }
- fn regions_with_variance(&self, v: ty::Variance, a: ty::Region, b: ty::Region)
- -> cres<'tcx, ty::Region>
- {
- match v {
- ty::Invariant => self.equate().regions(a, b),
- ty::Covariant => self.regions(a, b),
- ty::Contravariant => self.regions(a, b),
- ty::Bivariant => self.regions(a, b),
- }
- }
+ fn a_is_expected(&self) -> bool { self.fields.a_is_expected }
- fn regions(&self, a: ty::Region, _: ty::Region) -> cres<'tcx, ty::Region> {
- Ok(a)
- }
-
- fn builtin_bounds(&self,
- a: BuiltinBounds,
- b: BuiltinBounds)
- -> cres<'tcx, BuiltinBounds>
+ fn relate_with_variance<T:Relate<'a,'tcx>>(&mut self,
+ variance: ty::Variance,
+ a: &T,
+ b: &T)
+ -> RelateResult<'tcx, T>
{
- if a != b {
- Err(ty::terr_builtin_bounds(expected_found(self, a, b)))
- } else {
- Ok(a)
+ match variance {
+ // If we have Foo<A> and Foo is invariant w/r/t A,
+ // and we want to assert that
+ //
+ // Foo<A> <: Foo<B> ||
+ // Foo<B> <: Foo<A>
+ //
+ // then still A must equal B.
+ ty::Invariant => self.relate(a, b),
+
+ ty::Covariant => self.relate(a, b),
+ ty::Bivariant => self.relate(a, b),
+ ty::Contravariant => self.relate(a, b),
}
}
- fn tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, Ty<'tcx>> {
+ fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
debug!("{}.tys({}, {})", self.tag(),
a.repr(self.fields.infcx.tcx), b.repr(self.fields.infcx.tcx));
if a == b { return Ok(a); }
}
_ => {
- super_tys(self, a, b)
+ combine::super_combine_tys(self.fields.infcx, self, a, b)
}
}
}
- fn binders<T>(&self, a: &ty::Binder<T>, b: &ty::Binder<T>) -> cres<'tcx, ty::Binder<T>>
- where T : Combineable<'tcx>
+ fn regions(&mut self, a: ty::Region, _: ty::Region) -> RelateResult<'tcx, ty::Region> {
+ Ok(a)
+ }
+
+ fn binders<T>(&mut self, a: &ty::Binder<T>, b: &ty::Binder<T>)
+ -> RelateResult<'tcx, ty::Binder<T>>
+ where T: Relate<'a,'tcx>
{
let a1 = ty::erase_late_bound_regions(self.tcx(), a);
let b1 = ty::erase_late_bound_regions(self.tcx(), b);
- let c = try!(Combineable::combine(self, &a1, &b1));
+ let c = try!(self.relate(&a1, &b1));
Ok(ty::Binder(c))
}
}
use super::glb::Glb;
use super::lub::Lub;
use super::sub::Sub;
-use super::unify::InferCtxtMethodsForSimplyUnifiableTypes;
-use super::{InferCtxt, cres};
+use super::{InferCtxt};
use super::{MiscVariable, TypeTrace};
use super::type_variable::{RelationDir, BiTo, EqTo, SubtypeOf, SupertypeOf};
-use middle::subst;
-use middle::subst::{ErasedRegions, NonerasedRegions, Substs};
-use middle::ty::{FloatVar, FnSig, IntVar, TyVar};
+use middle::ty::{TyVar};
use middle::ty::{IntType, UintType};
-use middle::ty::BuiltinBounds;
use middle::ty::{self, Ty};
use middle::ty_fold;
use middle::ty_fold::{TypeFolder, TypeFoldable};
+use middle::ty_relate::{self, Relate, RelateResult, TypeRelation};
use util::ppaux::Repr;
-use std::rc::Rc;
-use syntax::ast::Unsafety;
use syntax::ast;
-use syntax::abi;
use syntax::codemap::Span;
-pub trait Combine<'tcx> : Sized {
- fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx> { self.infcx().tcx }
- fn tag(&self) -> String;
-
- fn fields<'a>(&'a self) -> &'a CombineFields<'a, 'tcx>;
-
- fn infcx<'a>(&'a self) -> &'a InferCtxt<'a, 'tcx> { self.fields().infcx }
- fn a_is_expected(&self) -> bool { self.fields().a_is_expected }
- fn trace(&self) -> TypeTrace<'tcx> { self.fields().trace.clone() }
- fn equate<'a>(&'a self) -> Equate<'a, 'tcx> { self.fields().equate() }
- fn bivariate<'a>(&'a self) -> Bivariate<'a, 'tcx> { self.fields().bivariate() }
-
- fn sub<'a>(&'a self) -> Sub<'a, 'tcx> { self.fields().sub() }
- fn lub<'a>(&'a self) -> Lub<'a, 'tcx> { Lub(self.fields().clone()) }
- fn glb<'a>(&'a self) -> Glb<'a, 'tcx> { Glb(self.fields().clone()) }
-
- fn mts(&self, a: &ty::mt<'tcx>, b: &ty::mt<'tcx>) -> cres<'tcx, ty::mt<'tcx>> {
- debug!("{}.mts({}, {})",
- self.tag(),
- a.repr(self.tcx()),
- b.repr(self.tcx()));
-
- if a.mutbl != b.mutbl {
- Err(ty::terr_mutability)
- } else {
- let mutbl = a.mutbl;
- let variance = match mutbl {
- ast::MutImmutable => ty::Covariant,
- ast::MutMutable => ty::Invariant,
- };
- let ty = try!(self.tys_with_variance(variance, a.ty, b.ty));
- Ok(ty::mt {ty: ty, mutbl: mutbl})
- }
- }
-
- fn tys_with_variance(&self, variance: ty::Variance, a: Ty<'tcx>, b: Ty<'tcx>)
- -> cres<'tcx, Ty<'tcx>>;
-
- fn tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, Ty<'tcx>>;
-
- fn regions_with_variance(&self, variance: ty::Variance, a: ty::Region, b: ty::Region)
- -> cres<'tcx, ty::Region>;
-
- fn regions(&self, a: ty::Region, b: ty::Region) -> cres<'tcx, ty::Region>;
-
- fn substs(&self,
- item_def_id: ast::DefId,
- a_subst: &subst::Substs<'tcx>,
- b_subst: &subst::Substs<'tcx>)
- -> cres<'tcx, subst::Substs<'tcx>>
- {
- debug!("substs: item_def_id={} a_subst={} b_subst={}",
- item_def_id.repr(self.infcx().tcx),
- a_subst.repr(self.infcx().tcx),
- b_subst.repr(self.infcx().tcx));
-
- let variances = if self.infcx().tcx.variance_computed.get() {
- Some(ty::item_variances(self.infcx().tcx, item_def_id))
- } else {
- None
- };
- self.substs_variances(variances.as_ref().map(|v| &**v), a_subst, b_subst)
- }
-
- fn substs_variances(&self,
- variances: Option<&ty::ItemVariances>,
- a_subst: &subst::Substs<'tcx>,
- b_subst: &subst::Substs<'tcx>)
- -> cres<'tcx, subst::Substs<'tcx>>
- {
- let mut substs = subst::Substs::empty();
-
- for &space in &subst::ParamSpace::all() {
- let a_tps = a_subst.types.get_slice(space);
- let b_tps = b_subst.types.get_slice(space);
- let t_variances = variances.map(|v| v.types.get_slice(space));
- let tps = try!(relate_type_params(self, t_variances, a_tps, b_tps));
- substs.types.replace(space, tps);
- }
-
- match (&a_subst.regions, &b_subst.regions) {
- (&ErasedRegions, _) | (_, &ErasedRegions) => {
- substs.regions = ErasedRegions;
- }
-
- (&NonerasedRegions(ref a), &NonerasedRegions(ref b)) => {
- for &space in &subst::ParamSpace::all() {
- let a_regions = a.get_slice(space);
- let b_regions = b.get_slice(space);
- let r_variances = variances.map(|v| v.regions.get_slice(space));
- let regions = try!(relate_region_params(self,
- r_variances,
- a_regions,
- b_regions));
- substs.mut_regions().replace(space, regions);
- }
- }
- }
-
- return Ok(substs);
-
- fn relate_type_params<'tcx, C: Combine<'tcx>>(this: &C,
- variances: Option<&[ty::Variance]>,
- a_tys: &[Ty<'tcx>],
- b_tys: &[Ty<'tcx>])
- -> cres<'tcx, Vec<Ty<'tcx>>>
- {
- if a_tys.len() != b_tys.len() {
- return Err(ty::terr_ty_param_size(expected_found(this,
- a_tys.len(),
- b_tys.len())));
- }
-
- (0.. a_tys.len()).map(|i| {
- let a_ty = a_tys[i];
- let b_ty = b_tys[i];
- let v = variances.map_or(ty::Invariant, |v| v[i]);
- this.tys_with_variance(v, a_ty, b_ty)
- }).collect()
- }
-
- fn relate_region_params<'tcx, C: Combine<'tcx>>(this: &C,
- variances: Option<&[ty::Variance]>,
- a_rs: &[ty::Region],
- b_rs: &[ty::Region])
- -> cres<'tcx, Vec<ty::Region>>
- {
- let tcx = this.infcx().tcx;
- let num_region_params = a_rs.len();
-
- debug!("relate_region_params(\
- a_rs={}, \
- b_rs={},
- variances={})",
- a_rs.repr(tcx),
- b_rs.repr(tcx),
- variances.repr(tcx));
-
- assert_eq!(num_region_params,
- variances.map_or(num_region_params,
- |v| v.len()));
-
- assert_eq!(num_region_params, b_rs.len());
-
- (0..a_rs.len()).map(|i| {
- let a_r = a_rs[i];
- let b_r = b_rs[i];
- let variance = variances.map_or(ty::Invariant, |v| v[i]);
- this.regions_with_variance(variance, a_r, b_r)
- }).collect()
- }
- }
-
- fn bare_fn_tys(&self, a: &ty::BareFnTy<'tcx>,
- b: &ty::BareFnTy<'tcx>) -> cres<'tcx, ty::BareFnTy<'tcx>> {
- let unsafety = try!(self.unsafeties(a.unsafety, b.unsafety));
- let abi = try!(self.abi(a.abi, b.abi));
- let sig = try!(self.binders(&a.sig, &b.sig));
- Ok(ty::BareFnTy {unsafety: unsafety,
- abi: abi,
- sig: sig})
- }
-
- fn fn_sigs(&self, a: &ty::FnSig<'tcx>, b: &ty::FnSig<'tcx>) -> cres<'tcx, ty::FnSig<'tcx>> {
- if a.variadic != b.variadic {
- return Err(ty::terr_variadic_mismatch(expected_found(self, a.variadic, b.variadic)));
- }
-
- let inputs = try!(argvecs(self,
- &a.inputs,
- &b.inputs));
-
- let output = try!(match (a.output, b.output) {
- (ty::FnConverging(a_ty), ty::FnConverging(b_ty)) =>
- Ok(ty::FnConverging(try!(self.tys(a_ty, b_ty)))),
- (ty::FnDiverging, ty::FnDiverging) =>
- Ok(ty::FnDiverging),
- (a, b) =>
- Err(ty::terr_convergence_mismatch(
- expected_found(self, a != ty::FnDiverging, b != ty::FnDiverging))),
- });
-
- return Ok(ty::FnSig {inputs: inputs,
- output: output,
- variadic: a.variadic});
-
-
- fn argvecs<'tcx, C>(combiner: &C,
- a_args: &[Ty<'tcx>],
- b_args: &[Ty<'tcx>])
- -> cres<'tcx, Vec<Ty<'tcx>>>
- where C: Combine<'tcx> {
- if a_args.len() == b_args.len() {
- a_args.iter().zip(b_args.iter())
- .map(|(a, b)| combiner.args(*a, *b)).collect()
- } else {
- Err(ty::terr_arg_count)
- }
- }
- }
-
- fn args(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, Ty<'tcx>> {
- self.tys_with_variance(ty::Contravariant, a, b).and_then(|t| Ok(t))
- }
-
- fn unsafeties(&self, a: Unsafety, b: Unsafety) -> cres<'tcx, Unsafety> {
- if a != b {
- Err(ty::terr_unsafety_mismatch(expected_found(self, a, b)))
- } else {
- Ok(a)
- }
- }
-
- fn abi(&self, a: abi::Abi, b: abi::Abi) -> cres<'tcx, abi::Abi> {
- if a == b {
- Ok(a)
- } else {
- Err(ty::terr_abi_mismatch(expected_found(self, a, b)))
- }
- }
-
- fn projection_tys(&self,
- a: &ty::ProjectionTy<'tcx>,
- b: &ty::ProjectionTy<'tcx>)
- -> cres<'tcx, ty::ProjectionTy<'tcx>>
- {
- if a.item_name != b.item_name {
- Err(ty::terr_projection_name_mismatched(
- expected_found(self, a.item_name, b.item_name)))
- } else {
- let trait_ref = try!(self.trait_refs(&*a.trait_ref, &*b.trait_ref));
- Ok(ty::ProjectionTy { trait_ref: Rc::new(trait_ref), item_name: a.item_name })
- }
- }
-
- fn projection_predicates(&self,
- a: &ty::ProjectionPredicate<'tcx>,
- b: &ty::ProjectionPredicate<'tcx>)
- -> cres<'tcx, ty::ProjectionPredicate<'tcx>>
- {
- let projection_ty = try!(self.projection_tys(&a.projection_ty, &b.projection_ty));
- let ty = try!(self.tys(a.ty, b.ty));
- Ok(ty::ProjectionPredicate { projection_ty: projection_ty, ty: ty })
- }
-
- fn projection_bounds(&self,
- a: &Vec<ty::PolyProjectionPredicate<'tcx>>,
- b: &Vec<ty::PolyProjectionPredicate<'tcx>>)
- -> cres<'tcx, Vec<ty::PolyProjectionPredicate<'tcx>>>
- {
- // To be compatible, `a` and `b` must be for precisely the
- // same set of traits and item names. We always require that
- // projection bounds lists are sorted by trait-def-id and item-name,
- // so we can just iterate through the lists pairwise, so long as they are the
- // same length.
- if a.len() != b.len() {
- Err(ty::terr_projection_bounds_length(expected_found(self, a.len(), b.len())))
- } else {
- a.iter()
- .zip(b.iter())
- .map(|(a, b)| self.binders(a, b))
- .collect()
- }
- }
-
- fn existential_bounds(&self,
- a: &ty::ExistentialBounds<'tcx>,
- b: &ty::ExistentialBounds<'tcx>)
- -> cres<'tcx, ty::ExistentialBounds<'tcx>>
- {
- let r = try!(self.regions_with_variance(ty::Contravariant, a.region_bound, b.region_bound));
- let nb = try!(self.builtin_bounds(a.builtin_bounds, b.builtin_bounds));
- let pb = try!(self.projection_bounds(&a.projection_bounds, &b.projection_bounds));
- Ok(ty::ExistentialBounds { region_bound: r,
- builtin_bounds: nb,
- projection_bounds: pb })
- }
-
- fn builtin_bounds(&self,
- a: BuiltinBounds,
- b: BuiltinBounds)
- -> cres<'tcx, BuiltinBounds>
- {
- // Two sets of builtin bounds are only relatable if they are
- // precisely the same (but see the coercion code).
- if a != b {
- Err(ty::terr_builtin_bounds(expected_found(self, a, b)))
- } else {
- Ok(a)
- }
- }
-
- fn trait_refs(&self,
- a: &ty::TraitRef<'tcx>,
- b: &ty::TraitRef<'tcx>)
- -> cres<'tcx, ty::TraitRef<'tcx>>
- {
- // Different traits cannot be related
- if a.def_id != b.def_id {
- Err(ty::terr_traits(expected_found(self, a.def_id, b.def_id)))
- } else {
- let substs = try!(self.substs(a.def_id, a.substs, b.substs));
- Ok(ty::TraitRef { def_id: a.def_id, substs: self.tcx().mk_substs(substs) })
- }
- }
-
- fn binders<T>(&self, a: &ty::Binder<T>, b: &ty::Binder<T>) -> cres<'tcx, ty::Binder<T>>
- where T : Combineable<'tcx>;
- // this must be overridden to do correctly, so as to account for higher-ranked
- // behavior
-}
-
-pub trait Combineable<'tcx> : Repr<'tcx> + TypeFoldable<'tcx> {
- fn combine<C:Combine<'tcx>>(combiner: &C, a: &Self, b: &Self) -> cres<'tcx, Self>;
-}
-
-impl<'tcx,T> Combineable<'tcx> for Rc<T>
- where T : Combineable<'tcx>
-{
- fn combine<C>(combiner: &C,
- a: &Rc<T>,
- b: &Rc<T>)
- -> cres<'tcx, Rc<T>>
- where C: Combine<'tcx> {
- Ok(Rc::new(try!(Combineable::combine(combiner, &**a, &**b))))
- }
-}
-
-impl<'tcx> Combineable<'tcx> for ty::TraitRef<'tcx> {
- fn combine<C>(combiner: &C,
- a: &ty::TraitRef<'tcx>,
- b: &ty::TraitRef<'tcx>)
- -> cres<'tcx, ty::TraitRef<'tcx>>
- where C: Combine<'tcx> {
- combiner.trait_refs(a, b)
- }
-}
-
-impl<'tcx> Combineable<'tcx> for Ty<'tcx> {
- fn combine<C>(combiner: &C,
- a: &Ty<'tcx>,
- b: &Ty<'tcx>)
- -> cres<'tcx, Ty<'tcx>>
- where C: Combine<'tcx> {
- combiner.tys(*a, *b)
- }
-}
-
-impl<'tcx> Combineable<'tcx> for ty::ProjectionPredicate<'tcx> {
- fn combine<C>(combiner: &C,
- a: &ty::ProjectionPredicate<'tcx>,
- b: &ty::ProjectionPredicate<'tcx>)
- -> cres<'tcx, ty::ProjectionPredicate<'tcx>>
- where C: Combine<'tcx> {
- combiner.projection_predicates(a, b)
- }
-}
-
-impl<'tcx> Combineable<'tcx> for ty::FnSig<'tcx> {
- fn combine<C>(combiner: &C,
- a: &ty::FnSig<'tcx>,
- b: &ty::FnSig<'tcx>)
- -> cres<'tcx, ty::FnSig<'tcx>>
- where C: Combine<'tcx> {
- combiner.fn_sigs(a, b)
- }
-}
-
#[derive(Clone)]
pub struct CombineFields<'a, 'tcx: 'a> {
pub infcx: &'a InferCtxt<'a, 'tcx>,
pub trace: TypeTrace<'tcx>,
}
-pub fn expected_found<'tcx, C, T>(this: &C,
- a: T,
- b: T)
- -> ty::expected_found<T>
- where C: Combine<'tcx> {
- if this.a_is_expected() {
- ty::expected_found {expected: a, found: b}
- } else {
- ty::expected_found {expected: b, found: a}
- }
-}
-
-pub fn super_tys<'tcx, C>(this: &C,
- a: Ty<'tcx>,
- b: Ty<'tcx>)
- -> cres<'tcx, Ty<'tcx>>
- where C: Combine<'tcx> {
- let tcx = this.infcx().tcx;
- let a_sty = &a.sty;
- let b_sty = &b.sty;
- debug!("super_tys: a_sty={:?} b_sty={:?}", a_sty, b_sty);
- return match (a_sty, b_sty) {
- // The "subtype" ought to be handling cases involving var:
- (&ty::ty_infer(TyVar(_)), _)
- | (_, &ty::ty_infer(TyVar(_))) =>
- tcx.sess.bug(
- &format!("{}: bot and var types should have been handled ({},{})",
- this.tag(),
- a.repr(this.infcx().tcx),
- b.repr(this.infcx().tcx))),
-
- (&ty::ty_err, _) | (_, &ty::ty_err) => Ok(tcx.types.err),
+pub fn super_combine_tys<'a,'tcx:'a,R>(infcx: &InferCtxt<'a, 'tcx>,
+ relation: &mut R,
+ a: Ty<'tcx>,
+ b: Ty<'tcx>)
+ -> RelateResult<'tcx, Ty<'tcx>>
+ where R: TypeRelation<'a,'tcx>
+{
+ let a_is_expected = relation.a_is_expected();
+ match (&a.sty, &b.sty) {
// Relate integral variables to other types
- (&ty::ty_infer(IntVar(a_id)), &ty::ty_infer(IntVar(b_id))) => {
- try!(this.infcx().simple_vars(this.a_is_expected(),
- a_id, b_id));
+ (&ty::ty_infer(ty::IntVar(a_id)), &ty::ty_infer(ty::IntVar(b_id))) => {
+ try!(infcx.int_unification_table
+ .borrow_mut()
+ .unify_var_var(a_id, b_id)
+ .map_err(|e| int_unification_error(a_is_expected, e)));
Ok(a)
}
- (&ty::ty_infer(IntVar(v_id)), &ty::ty_int(v)) => {
- unify_integral_variable(this, this.a_is_expected(),
- v_id, IntType(v))
+ (&ty::ty_infer(ty::IntVar(v_id)), &ty::ty_int(v)) => {
+ unify_integral_variable(infcx, a_is_expected, v_id, IntType(v))
}
- (&ty::ty_int(v), &ty::ty_infer(IntVar(v_id))) => {
- unify_integral_variable(this, !this.a_is_expected(),
- v_id, IntType(v))
+ (&ty::ty_int(v), &ty::ty_infer(ty::IntVar(v_id))) => {
+ unify_integral_variable(infcx, !a_is_expected, v_id, IntType(v))
}
- (&ty::ty_infer(IntVar(v_id)), &ty::ty_uint(v)) => {
- unify_integral_variable(this, this.a_is_expected(),
- v_id, UintType(v))
+ (&ty::ty_infer(ty::IntVar(v_id)), &ty::ty_uint(v)) => {
+ unify_integral_variable(infcx, a_is_expected, v_id, UintType(v))
}
- (&ty::ty_uint(v), &ty::ty_infer(IntVar(v_id))) => {
- unify_integral_variable(this, !this.a_is_expected(),
- v_id, UintType(v))
+ (&ty::ty_uint(v), &ty::ty_infer(ty::IntVar(v_id))) => {
+ unify_integral_variable(infcx, !a_is_expected, v_id, UintType(v))
}
// Relate floating-point variables to other types
- (&ty::ty_infer(FloatVar(a_id)), &ty::ty_infer(FloatVar(b_id))) => {
- try!(this.infcx().simple_vars(this.a_is_expected(), a_id, b_id));
+ (&ty::ty_infer(ty::FloatVar(a_id)), &ty::ty_infer(ty::FloatVar(b_id))) => {
+ try!(infcx.float_unification_table
+ .borrow_mut()
+ .unify_var_var(a_id, b_id)
+ .map_err(|e| float_unification_error(relation.a_is_expected(), e)));
Ok(a)
}
- (&ty::ty_infer(FloatVar(v_id)), &ty::ty_float(v)) => {
- unify_float_variable(this, this.a_is_expected(), v_id, v)
- }
- (&ty::ty_float(v), &ty::ty_infer(FloatVar(v_id))) => {
- unify_float_variable(this, !this.a_is_expected(), v_id, v)
+ (&ty::ty_infer(ty::FloatVar(v_id)), &ty::ty_float(v)) => {
+ unify_float_variable(infcx, a_is_expected, v_id, v)
}
-
- (&ty::ty_char, _)
- | (&ty::ty_bool, _)
- | (&ty::ty_int(_), _)
- | (&ty::ty_uint(_), _)
- | (&ty::ty_float(_), _) => {
- if a == b {
- Ok(a)
- } else {
- Err(ty::terr_sorts(expected_found(this, a, b)))
- }
+ (&ty::ty_float(v), &ty::ty_infer(ty::FloatVar(v_id))) => {
+ unify_float_variable(infcx, !a_is_expected, v_id, v)
}
- (&ty::ty_param(ref a_p), &ty::ty_param(ref b_p)) if
- a_p.idx == b_p.idx && a_p.space == b_p.space => Ok(a),
-
- (&ty::ty_enum(a_id, a_substs), &ty::ty_enum(b_id, b_substs))
- if a_id == b_id => {
- let substs = try!(this.substs(a_id, a_substs, b_substs));
- Ok(ty::mk_enum(tcx, a_id, tcx.mk_substs(substs)))
+ // All other cases of inference are errors
+ (&ty::ty_infer(_), _) |
+ (_, &ty::ty_infer(_)) => {
+ Err(ty::terr_sorts(ty_relate::expected_found(relation, &a, &b)))
}
- (&ty::ty_trait(ref a_), &ty::ty_trait(ref b_)) => {
- debug!("Trying to match traits {:?} and {:?}", a, b);
- let principal = try!(this.binders(&a_.principal, &b_.principal));
- let bounds = try!(this.existential_bounds(&a_.bounds, &b_.bounds));
- Ok(ty::mk_trait(tcx, principal, bounds))
- }
-
- (&ty::ty_struct(a_id, a_substs), &ty::ty_struct(b_id, b_substs))
- if a_id == b_id => {
- let substs = try!(this.substs(a_id, a_substs, b_substs));
- Ok(ty::mk_struct(tcx, a_id, tcx.mk_substs(substs)))
- }
-
- (&ty::ty_closure(a_id, a_substs),
- &ty::ty_closure(b_id, b_substs))
- if a_id == b_id => {
- // All ty_closure types with the same id represent
- // the (anonymous) type of the same closure expression. So
- // all of their regions should be equated.
- let substs = try!(this.substs_variances(None, a_substs, b_substs));
- Ok(ty::mk_closure(tcx, a_id, tcx.mk_substs(substs)))
- }
- (&ty::ty_uniq(a_inner), &ty::ty_uniq(b_inner)) => {
- let typ = try!(this.tys(a_inner, b_inner));
- Ok(ty::mk_uniq(tcx, typ))
- }
-
- (&ty::ty_ptr(ref a_mt), &ty::ty_ptr(ref b_mt)) => {
- let mt = try!(this.mts(a_mt, b_mt));
- Ok(ty::mk_ptr(tcx, mt))
- }
-
- (&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));
- let mt = try!(this.mts(a_mt, b_mt));
- Ok(ty::mk_rptr(tcx, tcx.mk_region(r), mt))
- }
-
- (&ty::ty_vec(a_t, Some(sz_a)), &ty::ty_vec(b_t, Some(sz_b))) => {
- this.tys(a_t, b_t).and_then(|t| {
- if sz_a == sz_b {
- Ok(ty::mk_vec(tcx, t, Some(sz_a)))
- } else {
- Err(ty::terr_fixed_array_size(expected_found(this, sz_a, sz_b)))
- }
- })
- }
-
- (&ty::ty_vec(a_t, sz_a), &ty::ty_vec(b_t, sz_b)) => {
- this.tys(a_t, b_t).and_then(|t| {
- if sz_a == sz_b {
- Ok(ty::mk_vec(tcx, t, sz_a))
- } else {
- Err(ty::terr_sorts(expected_found(this, a, b)))
- }
- })
- }
-
- (&ty::ty_str, &ty::ty_str) => Ok(ty::mk_str(tcx)),
-
- (&ty::ty_tup(ref as_), &ty::ty_tup(ref bs)) => {
- if as_.len() == bs.len() {
- as_.iter().zip(bs.iter())
- .map(|(a, b)| this.tys(*a, *b))
- .collect::<Result<_, _>>()
- .map(|ts| ty::mk_tup(tcx, ts))
- } else if as_.len() != 0 && bs.len() != 0 {
- Err(ty::terr_tuple_size(
- expected_found(this, as_.len(), bs.len())))
- } else {
- Err(ty::terr_sorts(expected_found(this, a, b)))
- }
- }
-
- (&ty::ty_bare_fn(a_opt_def_id, a_fty), &ty::ty_bare_fn(b_opt_def_id, b_fty))
- if a_opt_def_id == b_opt_def_id =>
- {
- let fty = try!(this.bare_fn_tys(a_fty, b_fty));
- Ok(ty::mk_bare_fn(tcx, a_opt_def_id, tcx.mk_bare_fn(fty)))
- }
-
- (&ty::ty_projection(ref a_data), &ty::ty_projection(ref b_data)) => {
- let projection_ty = try!(this.projection_tys(a_data, b_data));
- Ok(ty::mk_projection(tcx, projection_ty.trait_ref, projection_ty.item_name))
- }
-
- _ => Err(ty::terr_sorts(expected_found(this, a, b))),
- };
-
- fn unify_integral_variable<'tcx, C>(this: &C,
- vid_is_expected: bool,
- vid: ty::IntVid,
- val: ty::IntVarValue)
- -> cres<'tcx, Ty<'tcx>>
- where C: Combine<'tcx> {
- try!(this.infcx().simple_var_t(vid_is_expected, vid, val));
- match val {
- IntType(v) => Ok(ty::mk_mach_int(this.tcx(), v)),
- UintType(v) => Ok(ty::mk_mach_uint(this.tcx(), v)),
+ _ => {
+ ty_relate::super_relate_tys(relation, a, b)
}
}
+}
- fn unify_float_variable<'tcx, C>(this: &C,
- vid_is_expected: bool,
- vid: ty::FloatVid,
- val: ast::FloatTy)
- -> cres<'tcx, Ty<'tcx>>
- where C: Combine<'tcx> {
- try!(this.infcx().simple_var_t(vid_is_expected, vid, val));
- Ok(ty::mk_mach_float(this.tcx(), val))
+fn unify_integral_variable<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
+ vid_is_expected: bool,
+ vid: ty::IntVid,
+ val: ty::IntVarValue)
+ -> RelateResult<'tcx, Ty<'tcx>>
+{
+ try!(infcx
+ .int_unification_table
+ .borrow_mut()
+ .unify_var_value(vid, val)
+ .map_err(|e| int_unification_error(vid_is_expected, e)));
+ match val {
+ IntType(v) => Ok(ty::mk_mach_int(infcx.tcx, v)),
+ UintType(v) => Ok(ty::mk_mach_uint(infcx.tcx, v)),
}
}
-impl<'f, 'tcx> CombineFields<'f, 'tcx> {
- pub fn switch_expected(&self) -> CombineFields<'f, 'tcx> {
+fn unify_float_variable<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
+ vid_is_expected: bool,
+ vid: ty::FloatVid,
+ val: ast::FloatTy)
+ -> RelateResult<'tcx, Ty<'tcx>>
+{
+ try!(infcx
+ .float_unification_table
+ .borrow_mut()
+ .unify_var_value(vid, val)
+ .map_err(|e| float_unification_error(vid_is_expected, e)));
+ Ok(ty::mk_mach_float(infcx.tcx, val))
+}
+
+impl<'a, 'tcx> CombineFields<'a, 'tcx> {
+ pub fn tcx(&self) -> &'a ty::ctxt<'tcx> {
+ self.infcx.tcx
+ }
+
+ pub fn switch_expected(&self) -> CombineFields<'a, 'tcx> {
CombineFields {
a_is_expected: !self.a_is_expected,
..(*self).clone()
}
}
- fn equate(&self) -> Equate<'f, 'tcx> {
- Equate((*self).clone())
+ pub fn equate(&self) -> Equate<'a, 'tcx> {
+ Equate::new(self.clone())
+ }
+
+ pub fn bivariate(&self) -> Bivariate<'a, 'tcx> {
+ Bivariate::new(self.clone())
+ }
+
+ pub fn sub(&self) -> Sub<'a, 'tcx> {
+ Sub::new(self.clone())
}
- fn bivariate(&self) -> Bivariate<'f, 'tcx> {
- Bivariate((*self).clone())
+ pub fn lub(&self) -> Lub<'a, 'tcx> {
+ Lub::new(self.clone())
}
- fn sub(&self) -> Sub<'f, 'tcx> {
- Sub((*self).clone())
+ pub fn glb(&self) -> Glb<'a, 'tcx> {
+ Glb::new(self.clone())
}
pub fn instantiate(&self,
a_ty: Ty<'tcx>,
dir: RelationDir,
b_vid: ty::TyVid)
- -> cres<'tcx, ()>
+ -> RelateResult<'tcx, ()>
{
let tcx = self.infcx.tcx;
let mut stack = Vec::new();
// relations wind up attributed to the same spans. We need
// to associate causes/spans with each of the relations in
// the stack to get this right.
- match dir {
- BiTo => try!(self.bivariate().tys(a_ty, b_ty)),
-
- EqTo => try!(self.equate().tys(a_ty, b_ty)),
-
- SubtypeOf => try!(self.sub().tys(a_ty, b_ty)),
-
- SupertypeOf => try!(self.sub().tys_with_variance(ty::Contravariant, a_ty, b_ty)),
- };
+ try!(match dir {
+ BiTo => self.bivariate().relate(&a_ty, &b_ty),
+ EqTo => self.equate().relate(&a_ty, &b_ty),
+ SubtypeOf => self.sub().relate(&a_ty, &b_ty),
+ SupertypeOf => self.sub().relate_with_variance(ty::Contravariant, &a_ty, &b_ty),
+ });
}
Ok(())
ty: Ty<'tcx>,
for_vid: ty::TyVid,
make_region_vars: bool)
- -> cres<'tcx, Ty<'tcx>>
+ -> RelateResult<'tcx, Ty<'tcx>>
{
let mut generalize = Generalizer {
infcx: self.infcx,
self.infcx.next_region_var(MiscVariable(self.span))
}
}
+
+pub trait RelateResultCompare<'tcx, T> {
+ fn compare<F>(&self, t: T, f: F) -> RelateResult<'tcx, T> where
+ F: FnOnce() -> ty::type_err<'tcx>;
+}
+
+impl<'tcx, T:Clone + PartialEq> RelateResultCompare<'tcx, T> for RelateResult<'tcx, T> {
+ fn compare<F>(&self, t: T, f: F) -> RelateResult<'tcx, T> where
+ F: FnOnce() -> ty::type_err<'tcx>,
+ {
+ self.clone().and_then(|s| {
+ if s == t {
+ self.clone()
+ } else {
+ Err(f())
+ }
+ })
+ }
+}
+
+fn int_unification_error<'tcx>(a_is_expected: bool, v: (ty::IntVarValue, ty::IntVarValue))
+ -> ty::type_err<'tcx>
+{
+ let (a, b) = v;
+ ty::terr_int_mismatch(ty_relate::expected_found_bool(a_is_expected, &a, &b))
+}
+
+fn float_unification_error<'tcx>(a_is_expected: bool,
+ v: (ast::FloatTy, ast::FloatTy))
+ -> ty::type_err<'tcx>
+{
+ let (a, b) = v;
+ ty::terr_float_mismatch(ty_relate::expected_found_bool(a_is_expected, &a, &b))
+}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use super::combine::{self, CombineFields};
+use super::higher_ranked::HigherRankedRelations;
+use super::{Subtype};
+use super::type_variable::{EqTo};
+
use middle::ty::{self, Ty};
use middle::ty::TyVar;
-use middle::infer::combine::*;
-use middle::infer::cres;
-use middle::infer::Subtype;
-use middle::infer::type_variable::EqTo;
-use util::ppaux::Repr;
+use middle::ty_relate::{Relate, RelateResult, TypeRelation};
+use util::ppaux::{Repr};
-pub struct Equate<'f, 'tcx: 'f> {
- fields: CombineFields<'f, 'tcx>
+pub struct Equate<'a, 'tcx: 'a> {
+ fields: CombineFields<'a, 'tcx>
}
-#[allow(non_snake_case)]
-pub fn Equate<'f, 'tcx>(cf: CombineFields<'f, 'tcx>) -> Equate<'f, 'tcx> {
- Equate { fields: cf }
+impl<'a, 'tcx> Equate<'a, 'tcx> {
+ pub fn new(fields: CombineFields<'a, 'tcx>) -> Equate<'a, 'tcx> {
+ Equate { fields: fields }
+ }
}
-impl<'f, 'tcx> Combine<'tcx> for Equate<'f, 'tcx> {
- fn tag(&self) -> String { "Equate".to_string() }
- fn fields<'a>(&'a self) -> &'a CombineFields<'a, 'tcx> { &self.fields }
+impl<'a, 'tcx> TypeRelation<'a,'tcx> for Equate<'a, 'tcx> {
+ fn tag(&self) -> &'static str { "Equate" }
- fn tys_with_variance(&self, _: ty::Variance, a: Ty<'tcx>, b: Ty<'tcx>)
- -> cres<'tcx, Ty<'tcx>>
- {
- // Once we're equating, it doesn't matter what the variance is.
- self.tys(a, b)
- }
+ fn tcx(&self) -> &'a ty::ctxt<'tcx> { self.fields.tcx() }
- fn regions_with_variance(&self, _: ty::Variance, a: ty::Region, b: ty::Region)
- -> cres<'tcx, ty::Region>
- {
- // Once we're equating, it doesn't matter what the variance is.
- self.regions(a, b)
- }
+ fn a_is_expected(&self) -> bool { self.fields.a_is_expected }
- fn regions(&self, a: ty::Region, b: ty::Region) -> cres<'tcx, ty::Region> {
- debug!("{}.regions({}, {})",
- self.tag(),
- a.repr(self.fields.infcx.tcx),
- b.repr(self.fields.infcx.tcx));
- self.infcx().region_vars.make_eqregion(Subtype(self.trace()), a, b);
- Ok(a)
+ fn relate_with_variance<T:Relate<'a,'tcx>>(&mut self,
+ _: ty::Variance,
+ a: &T,
+ b: &T)
+ -> RelateResult<'tcx, T>
+ {
+ self.relate(a, b)
}
- fn tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, Ty<'tcx>> {
+ fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
debug!("{}.tys({}, {})", self.tag(),
a.repr(self.fields.infcx.tcx), b.repr(self.fields.infcx.tcx));
if a == b { return Ok(a); }
}
_ => {
- super_tys(self, a, b)
+ combine::super_combine_tys(self.fields.infcx, self, a, b)
}
}
}
- fn binders<T>(&self, a: &ty::Binder<T>, b: &ty::Binder<T>) -> cres<'tcx, ty::Binder<T>>
- where T : Combineable<'tcx>
+ fn regions(&mut self, a: ty::Region, b: ty::Region) -> RelateResult<'tcx, ty::Region> {
+ debug!("{}.regions({}, {})",
+ self.tag(),
+ a.repr(self.fields.infcx.tcx),
+ b.repr(self.fields.infcx.tcx));
+ let origin = Subtype(self.fields.trace.clone());
+ self.fields.infcx.region_vars.make_eqregion(origin, a, b);
+ Ok(a)
+ }
+
+ fn binders<T>(&mut self, a: &ty::Binder<T>, b: &ty::Binder<T>)
+ -> RelateResult<'tcx, ty::Binder<T>>
+ where T: Relate<'a, 'tcx>
{
- try!(self.sub().binders(a, b));
- self.sub().binders(b, a)
+ try!(self.fields.higher_ranked_sub(a, b));
+ self.fields.higher_ranked_sub(b, a)
}
}
use std::collections::hash_map::{self, Entry};
use super::InferCtxt;
-use super::unify::InferCtxtMethodsForSimplyUnifiableTypes;
+use super::unify::ToType;
pub struct TypeFreshener<'a, 'tcx:'a> {
infcx: &'a InferCtxt<'a, 'tcx>,
}
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
+ let tcx = self.infcx.tcx;
+
match t.sty {
ty::ty_infer(ty::TyVar(v)) => {
- self.freshen(self.infcx.type_variables.borrow().probe(v),
- ty::TyVar(v),
- ty::FreshTy)
+ self.freshen(
+ self.infcx.type_variables.borrow().probe(v),
+ ty::TyVar(v),
+ ty::FreshTy)
}
ty::ty_infer(ty::IntVar(v)) => {
- self.freshen(self.infcx.probe_var(v),
- ty::IntVar(v),
- ty::FreshIntTy)
+ self.freshen(
+ self.infcx.int_unification_table.borrow_mut()
+ .probe(v)
+ .map(|v| v.to_type(tcx)),
+ ty::IntVar(v),
+ ty::FreshIntTy)
}
ty::ty_infer(ty::FloatVar(v)) => {
- self.freshen(self.infcx.probe_var(v),
- ty::FloatVar(v),
- ty::FreshIntTy)
+ self.freshen(
+ self.infcx.float_unification_table.borrow_mut()
+ .probe(v)
+ .map(|v| v.to_type(tcx)),
+ ty::FloatVar(v),
+ ty::FreshIntTy)
}
ty::ty_infer(ty::FreshTy(c)) |
ty::ty_infer(ty::FreshIntTy(c)) => {
if c >= self.freshen_count {
- self.tcx().sess.bug(
+ tcx.sess.bug(
&format!("Encountered a freshend type with id {} \
but our counter is only at {}",
c,
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use super::combine::*;
-use super::lattice::*;
+use super::combine::CombineFields;
use super::higher_ranked::HigherRankedRelations;
-use super::cres;
+use super::InferCtxt;
+use super::lattice::{self, LatticeDir};
use super::Subtype;
use middle::ty::{self, Ty};
+use middle::ty_relate::{Relate, RelateResult, TypeRelation};
use util::ppaux::Repr;
/// "Greatest lower bound" (common subtype)
-pub struct Glb<'f, 'tcx: 'f> {
- fields: CombineFields<'f, 'tcx>
+pub struct Glb<'a, 'tcx: 'a> {
+ fields: CombineFields<'a, 'tcx>
}
-#[allow(non_snake_case)]
-pub fn Glb<'f, 'tcx>(cf: CombineFields<'f, 'tcx>) -> Glb<'f, 'tcx> {
- Glb { fields: cf }
+impl<'a, 'tcx> Glb<'a, 'tcx> {
+ pub fn new(fields: CombineFields<'a, 'tcx>) -> Glb<'a, 'tcx> {
+ Glb { fields: fields }
+ }
}
-impl<'f, 'tcx> Combine<'tcx> for Glb<'f, 'tcx> {
- fn tag(&self) -> String { "Glb".to_string() }
- fn fields<'a>(&'a self) -> &'a CombineFields<'a, 'tcx> { &self.fields }
+impl<'a, 'tcx> TypeRelation<'a, 'tcx> for Glb<'a, 'tcx> {
+ fn tag(&self) -> &'static str { "Glb" }
+
+ fn tcx(&self) -> &'a ty::ctxt<'tcx> { self.fields.tcx() }
+
+ fn a_is_expected(&self) -> bool { self.fields.a_is_expected }
- fn tys_with_variance(&self, v: ty::Variance, a: Ty<'tcx>, b: Ty<'tcx>)
- -> cres<'tcx, Ty<'tcx>>
+ fn relate_with_variance<T:Relate<'a,'tcx>>(&mut self,
+ variance: ty::Variance,
+ a: &T,
+ b: &T)
+ -> RelateResult<'tcx, T>
{
- match v {
- ty::Invariant => self.equate().tys(a, b),
- ty::Covariant => self.tys(a, b),
- ty::Bivariant => self.bivariate().tys(a, b),
- ty::Contravariant => self.lub().tys(a, b),
+ match variance {
+ ty::Invariant => self.fields.equate().relate(a, b),
+ ty::Covariant => self.relate(a, b),
+ ty::Bivariant => self.fields.bivariate().relate(a, b),
+ ty::Contravariant => self.fields.lub().relate(a, b),
}
}
- fn regions_with_variance(&self, v: ty::Variance, a: ty::Region, b: ty::Region)
- -> cres<'tcx, ty::Region>
- {
- match v {
- ty::Invariant => self.equate().regions(a, b),
- ty::Covariant => self.regions(a, b),
- ty::Bivariant => self.bivariate().regions(a, b),
- ty::Contravariant => self.lub().regions(a, b),
- }
+ fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
+ lattice::super_lattice_tys(self, a, b)
}
- fn regions(&self, a: ty::Region, b: ty::Region) -> cres<'tcx, ty::Region> {
+ fn regions(&mut self, a: ty::Region, b: ty::Region) -> RelateResult<'tcx, ty::Region> {
debug!("{}.regions({}, {})",
self.tag(),
a.repr(self.fields.infcx.tcx),
b.repr(self.fields.infcx.tcx));
- Ok(self.fields.infcx.region_vars.glb_regions(Subtype(self.trace()), a, b))
+ let origin = Subtype(self.fields.trace.clone());
+ Ok(self.fields.infcx.region_vars.glb_regions(origin, a, b))
}
- fn tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, Ty<'tcx>> {
- super_lattice_tys(self, a, b)
+ fn binders<T>(&mut self, a: &ty::Binder<T>, b: &ty::Binder<T>)
+ -> RelateResult<'tcx, ty::Binder<T>>
+ where T: Relate<'a, 'tcx>
+ {
+ self.fields.higher_ranked_glb(a, b)
}
+}
- fn binders<T>(&self, a: &ty::Binder<T>, b: &ty::Binder<T>) -> cres<'tcx, ty::Binder<T>>
- where T : Combineable<'tcx>
- {
- self.higher_ranked_glb(a, b)
+impl<'a, 'tcx> LatticeDir<'a,'tcx> for Glb<'a, 'tcx> {
+ fn infcx(&self) -> &'a InferCtxt<'a,'tcx> {
+ self.fields.infcx
+ }
+
+ fn relate_bound(&self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> {
+ let mut sub = self.fields.sub();
+ try!(sub.relate(&v, &a));
+ try!(sub.relate(&v, &b));
+ Ok(())
}
}
//! Helper routines for higher-ranked things. See the `doc` module at
//! the end of the file for details.
-use super::{CombinedSnapshot, cres, InferCtxt, HigherRankedType, SkolemizationMap};
-use super::combine::{Combine, Combineable};
+use super::{CombinedSnapshot, InferCtxt, HigherRankedType, SkolemizationMap};
+use super::combine::CombineFields;
use middle::subst;
use middle::ty::{self, Binder};
use middle::ty_fold::{self, TypeFoldable};
+use middle::ty_relate::{Relate, RelateResult, TypeRelation};
use syntax::codemap::Span;
use util::nodemap::{FnvHashMap, FnvHashSet};
use util::ppaux::Repr;
-pub trait HigherRankedRelations<'tcx> {
- fn higher_ranked_sub<T>(&self, a: &Binder<T>, b: &Binder<T>) -> cres<'tcx, Binder<T>>
- where T : Combineable<'tcx>;
+pub trait HigherRankedRelations<'a,'tcx> {
+ fn higher_ranked_sub<T>(&self, a: &Binder<T>, b: &Binder<T>) -> RelateResult<'tcx, Binder<T>>
+ where T: Relate<'a,'tcx>;
- fn higher_ranked_lub<T>(&self, a: &Binder<T>, b: &Binder<T>) -> cres<'tcx, Binder<T>>
- where T : Combineable<'tcx>;
+ fn higher_ranked_lub<T>(&self, a: &Binder<T>, b: &Binder<T>) -> RelateResult<'tcx, Binder<T>>
+ where T: Relate<'a,'tcx>;
- fn higher_ranked_glb<T>(&self, a: &Binder<T>, b: &Binder<T>) -> cres<'tcx, Binder<T>>
- where T : Combineable<'tcx>;
+ fn higher_ranked_glb<T>(&self, a: &Binder<T>, b: &Binder<T>) -> RelateResult<'tcx, Binder<T>>
+ where T: Relate<'a,'tcx>;
}
trait InferCtxtExt {
-> Vec<ty::RegionVid>;
}
-impl<'tcx,C> HigherRankedRelations<'tcx> for C
- where C : Combine<'tcx>
-{
+impl<'a,'tcx> HigherRankedRelations<'a,'tcx> for CombineFields<'a,'tcx> {
fn higher_ranked_sub<T>(&self, a: &Binder<T>, b: &Binder<T>)
- -> cres<'tcx, Binder<T>>
- where T : Combineable<'tcx>
+ -> RelateResult<'tcx, Binder<T>>
+ where T: Relate<'a,'tcx>
{
+ let tcx = self.infcx.tcx;
+
debug!("higher_ranked_sub(a={}, b={})",
- a.repr(self.tcx()), b.repr(self.tcx()));
+ a.repr(tcx), b.repr(tcx));
// Rather than checking the subtype relationship between `a` and `b`
// as-is, we need to do some extra work here in order to make sure
// Start a snapshot so we can examine "all bindings that were
// created as part of this type comparison".
- return self.infcx().try(|snapshot| {
+ return self.infcx.commit_if_ok(|snapshot| {
// First, we instantiate each bound region in the subtype with a fresh
// region variable.
let (a_prime, _) =
- self.infcx().replace_late_bound_regions_with_fresh_var(
- self.trace().origin.span(),
+ self.infcx.replace_late_bound_regions_with_fresh_var(
+ self.trace.origin.span(),
HigherRankedType,
a);
// Second, we instantiate each bound region in the supertype with a
// fresh concrete region.
let (b_prime, skol_map) =
- self.infcx().skolemize_late_bound_regions(b, snapshot);
+ self.infcx.skolemize_late_bound_regions(b, snapshot);
- debug!("a_prime={}", a_prime.repr(self.tcx()));
- debug!("b_prime={}", b_prime.repr(self.tcx()));
+ debug!("a_prime={}", a_prime.repr(tcx));
+ debug!("b_prime={}", b_prime.repr(tcx));
// Compare types now that bound regions have been replaced.
- let result = try!(Combineable::combine(self, &a_prime, &b_prime));
+ let result = try!(self.sub().relate(&a_prime, &b_prime));
// Presuming type comparison succeeds, we need to check
// that the skolemized regions do not "leak".
- match leak_check(self.infcx(), &skol_map, snapshot) {
+ match leak_check(self.infcx, &skol_map, snapshot) {
Ok(()) => { }
Err((skol_br, tainted_region)) => {
- if self.a_is_expected() {
+ if self.a_is_expected {
debug!("Not as polymorphic!");
return Err(ty::terr_regions_insufficiently_polymorphic(skol_br,
tainted_region));
}
debug!("higher_ranked_sub: OK result={}",
- result.repr(self.tcx()));
+ result.repr(tcx));
Ok(ty::Binder(result))
});
}
- fn higher_ranked_lub<T>(&self, a: &Binder<T>, b: &Binder<T>) -> cres<'tcx, Binder<T>>
- where T : Combineable<'tcx>
+ fn higher_ranked_lub<T>(&self, a: &Binder<T>, b: &Binder<T>) -> RelateResult<'tcx, Binder<T>>
+ where T: Relate<'a,'tcx>
{
// Start a snapshot so we can examine "all bindings that were
// created as part of this type comparison".
- return self.infcx().try(|snapshot| {
+ return self.infcx.commit_if_ok(|snapshot| {
// Instantiate each bound region with a fresh region variable.
- let span = self.trace().origin.span();
+ let span = self.trace.origin.span();
let (a_with_fresh, a_map) =
- self.infcx().replace_late_bound_regions_with_fresh_var(
+ self.infcx.replace_late_bound_regions_with_fresh_var(
span, HigherRankedType, a);
let (b_with_fresh, _) =
- self.infcx().replace_late_bound_regions_with_fresh_var(
+ self.infcx.replace_late_bound_regions_with_fresh_var(
span, HigherRankedType, b);
// Collect constraints.
let result0 =
- try!(Combineable::combine(self, &a_with_fresh, &b_with_fresh));
+ try!(self.lub().relate(&a_with_fresh, &b_with_fresh));
let result0 =
- self.infcx().resolve_type_vars_if_possible(&result0);
+ self.infcx.resolve_type_vars_if_possible(&result0);
debug!("lub result0 = {}", result0.repr(self.tcx()));
// Generalize the regions appearing in result0 if possible
- let new_vars = self.infcx().region_vars_confined_to_snapshot(snapshot);
- let span = self.trace().origin.span();
+ let new_vars = self.infcx.region_vars_confined_to_snapshot(snapshot);
+ let span = self.trace.origin.span();
let result1 =
fold_regions_in(
self.tcx(),
&result0,
- |r, debruijn| generalize_region(self.infcx(), span, snapshot, debruijn,
+ |r, debruijn| generalize_region(self.infcx, span, snapshot, debruijn,
&new_vars, &a_map, r));
debug!("lub({},{}) = {}",
}
}
- fn higher_ranked_glb<T>(&self, a: &Binder<T>, b: &Binder<T>) -> cres<'tcx, Binder<T>>
- where T : Combineable<'tcx>
+ fn higher_ranked_glb<T>(&self, a: &Binder<T>, b: &Binder<T>) -> RelateResult<'tcx, Binder<T>>
+ where T: Relate<'a,'tcx>
{
- debug!("{}.higher_ranked_glb({}, {})",
- self.tag(), a.repr(self.tcx()), b.repr(self.tcx()));
+ debug!("higher_ranked_glb({}, {})",
+ a.repr(self.tcx()), b.repr(self.tcx()));
// Make a snapshot so we can examine "all bindings that were
// created as part of this type comparison".
- return self.infcx().try(|snapshot| {
+ return self.infcx.commit_if_ok(|snapshot| {
// Instantiate each bound region with a fresh region variable.
let (a_with_fresh, a_map) =
- self.infcx().replace_late_bound_regions_with_fresh_var(
- self.trace().origin.span(), HigherRankedType, a);
+ self.infcx.replace_late_bound_regions_with_fresh_var(
+ self.trace.origin.span(), HigherRankedType, a);
let (b_with_fresh, b_map) =
- self.infcx().replace_late_bound_regions_with_fresh_var(
- self.trace().origin.span(), HigherRankedType, b);
+ self.infcx.replace_late_bound_regions_with_fresh_var(
+ self.trace.origin.span(), HigherRankedType, b);
let a_vars = var_ids(self, &a_map);
let b_vars = var_ids(self, &b_map);
// Collect constraints.
let result0 =
- try!(Combineable::combine(self, &a_with_fresh, &b_with_fresh));
+ try!(self.glb().relate(&a_with_fresh, &b_with_fresh));
let result0 =
- self.infcx().resolve_type_vars_if_possible(&result0);
+ self.infcx.resolve_type_vars_if_possible(&result0);
debug!("glb result0 = {}", result0.repr(self.tcx()));
// Generalize the regions appearing in result0 if possible
- let new_vars = self.infcx().region_vars_confined_to_snapshot(snapshot);
- let span = self.trace().origin.span();
+ let new_vars = self.infcx.region_vars_confined_to_snapshot(snapshot);
+ let span = self.trace.origin.span();
let result1 =
fold_regions_in(
self.tcx(),
&result0,
- |r, debruijn| generalize_region(self.infcx(), span, snapshot, debruijn,
+ |r, debruijn| generalize_region(self.infcx, span, snapshot, debruijn,
&new_vars,
&a_map, &a_vars, &b_vars,
r));
}
}
-fn var_ids<'tcx, T: Combine<'tcx>>(combiner: &T,
- map: &FnvHashMap<ty::BoundRegion, ty::Region>)
- -> Vec<ty::RegionVid> {
- map.iter().map(|(_, r)| match *r {
- ty::ReInfer(ty::ReVar(r)) => { r }
- r => {
- combiner.infcx().tcx.sess.span_bug(
- combiner.trace().origin.span(),
- &format!("found non-region-vid: {:?}", r));
- }
- }).collect()
+fn var_ids<'a, 'tcx>(fields: &CombineFields<'a, 'tcx>,
+ map: &FnvHashMap<ty::BoundRegion, ty::Region>)
+ -> Vec<ty::RegionVid> {
+ map.iter()
+ .map(|(_, r)| match *r {
+ ty::ReInfer(ty::ReVar(r)) => { r }
+ r => {
+ fields.tcx().sess.span_bug(
+ fields.trace.origin.span(),
+ &format!("found non-region-vid: {:?}", r));
+ }
+ })
+ .collect()
}
fn is_var_in_set(new_vars: &[ty::RegionVid], r: ty::Region) -> bool {
unbound_value: &T,
mut fldr: F)
-> T
- where T : Combineable<'tcx>,
- F : FnMut(ty::Region, ty::DebruijnIndex) -> ty::Region,
+ where T: TypeFoldable<'tcx>,
+ F: FnMut(ty::Region, ty::DebruijnIndex) -> ty::Region,
{
unbound_value.fold_with(&mut ty_fold::RegionFolder::new(tcx, &mut |region, current_depth| {
// we should only be encountering "escaping" late-bound regions here,
//! over a `LatticeValue`, which is a value defined with respect to
//! a lattice.
-use super::*;
-use super::combine::*;
-use super::glb::Glb;
-use super::lub::Lub;
+use super::combine;
+use super::InferCtxt;
use middle::ty::TyVar;
use middle::ty::{self, Ty};
+use middle::ty_relate::{RelateResult, TypeRelation};
use util::ppaux::Repr;
-pub trait LatticeDir<'tcx> {
+pub trait LatticeDir<'f,'tcx> : TypeRelation<'f,'tcx> {
+ fn infcx(&self) -> &'f InferCtxt<'f, 'tcx>;
+
// Relates the type `v` to `a` and `b` such that `v` represents
// the LUB/GLB of `a` and `b` as appropriate.
- fn relate_bound(&self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, ()>;
-}
-
-impl<'a, 'tcx> LatticeDir<'tcx> for Lub<'a, 'tcx> {
- fn relate_bound(&self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, ()> {
- let sub = self.sub();
- try!(sub.tys(a, v));
- try!(sub.tys(b, v));
- Ok(())
- }
-}
-
-impl<'a, 'tcx> LatticeDir<'tcx> for Glb<'a, 'tcx> {
- fn relate_bound(&self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, ()> {
- let sub = self.sub();
- try!(sub.tys(v, a));
- try!(sub.tys(v, b));
- Ok(())
- }
+ fn relate_bound(&self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()>;
}
-pub fn super_lattice_tys<'tcx, L:LatticeDir<'tcx>+Combine<'tcx>>(this: &L,
- a: Ty<'tcx>,
- b: Ty<'tcx>)
- -> cres<'tcx, Ty<'tcx>>
+pub fn super_lattice_tys<'a,'tcx,L:LatticeDir<'a,'tcx>>(this: &mut L,
+ a: Ty<'tcx>,
+ b: Ty<'tcx>)
+ -> RelateResult<'tcx, Ty<'tcx>>
+ where 'tcx: 'a
{
debug!("{}.lattice_tys({}, {})",
this.tag(),
- a.repr(this.infcx().tcx),
- b.repr(this.infcx().tcx));
+ a.repr(this.tcx()),
+ b.repr(this.tcx()));
if a == b {
return Ok(a);
}
_ => {
- super_tys(this, a, b)
+ combine::super_combine_tys(this.infcx(), this, a, b)
}
}
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use super::combine::*;
+use super::combine::CombineFields;
use super::higher_ranked::HigherRankedRelations;
-use super::lattice::*;
-use super::cres;
+use super::InferCtxt;
+use super::lattice::{self, LatticeDir};
use super::Subtype;
use middle::ty::{self, Ty};
+use middle::ty_relate::{Relate, RelateResult, TypeRelation};
use util::ppaux::Repr;
/// "Least upper bound" (common supertype)
-pub struct Lub<'f, 'tcx: 'f> {
- fields: CombineFields<'f, 'tcx>
+pub struct Lub<'a, 'tcx: 'a> {
+ fields: CombineFields<'a, 'tcx>
}
-#[allow(non_snake_case)]
-pub fn Lub<'f, 'tcx>(cf: CombineFields<'f, 'tcx>) -> Lub<'f, 'tcx> {
- Lub { fields: cf }
+impl<'a, 'tcx> Lub<'a, 'tcx> {
+ pub fn new(fields: CombineFields<'a, 'tcx>) -> Lub<'a, 'tcx> {
+ Lub { fields: fields }
+ }
}
-impl<'f, 'tcx> Combine<'tcx> for Lub<'f, 'tcx> {
- fn tag(&self) -> String { "Lub".to_string() }
- fn fields<'a>(&'a self) -> &'a CombineFields<'a, 'tcx> { &self.fields }
+impl<'a, 'tcx> TypeRelation<'a, 'tcx> for Lub<'a, 'tcx> {
+ fn tag(&self) -> &'static str { "Lub" }
+
+ fn tcx(&self) -> &'a ty::ctxt<'tcx> { self.fields.tcx() }
+
+ fn a_is_expected(&self) -> bool { self.fields.a_is_expected }
- fn tys_with_variance(&self, v: ty::Variance, a: Ty<'tcx>, b: Ty<'tcx>)
- -> cres<'tcx, Ty<'tcx>>
+ fn relate_with_variance<T:Relate<'a,'tcx>>(&mut self,
+ variance: ty::Variance,
+ a: &T,
+ b: &T)
+ -> RelateResult<'tcx, T>
{
- match v {
- ty::Invariant => self.equate().tys(a, b),
- ty::Covariant => self.tys(a, b),
- ty::Bivariant => self.bivariate().tys(a, b),
- ty::Contravariant => self.glb().tys(a, b),
+ match variance {
+ ty::Invariant => self.fields.equate().relate(a, b),
+ ty::Covariant => self.relate(a, b),
+ ty::Bivariant => self.fields.bivariate().relate(a, b),
+ ty::Contravariant => self.fields.glb().relate(a, b),
}
}
- fn regions_with_variance(&self, v: ty::Variance, a: ty::Region, b: ty::Region)
- -> cres<'tcx, ty::Region>
- {
- match v {
- ty::Invariant => self.equate().regions(a, b),
- ty::Covariant => self.regions(a, b),
- ty::Bivariant => self.bivariate().regions(a, b),
- ty::Contravariant => self.glb().regions(a, b),
- }
+ fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
+ lattice::super_lattice_tys(self, a, b)
}
- fn regions(&self, a: ty::Region, b: ty::Region) -> cres<'tcx, ty::Region> {
+ fn regions(&mut self, a: ty::Region, b: ty::Region) -> RelateResult<'tcx, ty::Region> {
debug!("{}.regions({}, {})",
self.tag(),
a.repr(self.tcx()),
b.repr(self.tcx()));
- Ok(self.infcx().region_vars.lub_regions(Subtype(self.trace()), a, b))
+ let origin = Subtype(self.fields.trace.clone());
+ Ok(self.fields.infcx.region_vars.lub_regions(origin, a, b))
}
- fn tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, Ty<'tcx>> {
- super_lattice_tys(self, a, b)
+ fn binders<T>(&mut self, a: &ty::Binder<T>, b: &ty::Binder<T>)
+ -> RelateResult<'tcx, ty::Binder<T>>
+ where T: Relate<'a, 'tcx>
+ {
+ self.fields.higher_ranked_lub(a, b)
}
+}
- fn binders<T>(&self, a: &ty::Binder<T>, b: &ty::Binder<T>) -> cres<'tcx, ty::Binder<T>>
- where T : Combineable<'tcx>
- {
- self.higher_ranked_lub(a, b)
+impl<'a, 'tcx> LatticeDir<'a,'tcx> for Lub<'a, 'tcx> {
+ fn infcx(&self) -> &'a InferCtxt<'a,'tcx> {
+ self.fields.infcx
+ }
+
+ fn relate_bound(&self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> {
+ let mut sub = self.fields.sub();
+ try!(sub.relate(&a, &v));
+ try!(sub.relate(&b, &v));
+ Ok(())
}
}
+
use middle::ty::replace_late_bound_regions;
use middle::ty::{self, Ty};
use middle::ty_fold::{TypeFolder, TypeFoldable};
-use std::cell::RefCell;
+use middle::ty_relate::{Relate, RelateResult, TypeRelation};
+use std::cell::{RefCell};
use std::fmt;
use std::rc::Rc;
use syntax::ast;
use util::ppaux::ty_to_string;
use util::ppaux::{Repr, UserString};
-use self::combine::{Combine, Combineable, CombineFields};
+use self::combine::CombineFields;
use self::region_inference::{RegionVarBindings, RegionSnapshot};
-use self::equate::Equate;
-use self::sub::Sub;
-use self::lub::Lub;
-use self::unify::{UnificationTable, InferCtxtMethodsForSimplyUnifiableTypes};
+use self::unify::{ToType, UnificationTable};
use self::error_reporting::ErrorReporting;
pub mod bivariate;
pub mod unify;
pub type Bound<T> = Option<T>;
-
-pub type cres<'tcx, T> = Result<T,ty::type_err<'tcx>>; // "combine result"
-pub type ures<'tcx> = cres<'tcx, ()>; // "unify result"
+pub type UnitResult<'tcx> = RelateResult<'tcx, ()>; // "unify result"
pub type fres<T> = Result<T, fixup_err>; // "fixup result"
pub struct InferCtxt<'a, 'tcx: 'a> {
///
/// See `error_reporting.rs` for more details
#[derive(Clone, Debug)]
-pub enum RegionVariableOrigin<'tcx> {
+pub enum RegionVariableOrigin {
// Region variables created for ill-categorized reasons,
// mostly indicates places in need of refactoring
MiscVariable(Span),
Autoref(Span),
// Regions created as part of an automatic coercion
- Coercion(TypeTrace<'tcx>),
+ Coercion(Span),
// Region variables created as the values for early-bound regions
EarlyBoundRegion(Span, ast::Name),
BoundRegionInCoherence(ast::Name),
}
-#[derive(Copy, Debug)]
+#[derive(Copy, Clone, Debug)]
pub enum fixup_err {
unresolved_int_ty(IntVid),
unresolved_float_ty(FloatVid),
values: Types(expected_found(a_is_expected, a, b))
};
- let result =
- cx.commit_if_ok(|| cx.lub(a_is_expected, trace.clone()).tys(a, b));
+ let result = cx.commit_if_ok(|_| cx.lub(a_is_expected, trace.clone()).relate(&a, &b));
match result {
Ok(t) => t,
Err(ref err) => {
origin: TypeOrigin,
a: Ty<'tcx>,
b: Ty<'tcx>)
- -> ures<'tcx>
+ -> UnitResult<'tcx>
{
debug!("mk_subty({} <: {})", a.repr(cx.tcx), b.repr(cx.tcx));
- cx.commit_if_ok(|| {
- cx.sub_types(a_is_expected, origin, a, b)
- })
+ cx.sub_types(a_is_expected, origin, a, b)
}
pub fn can_mk_subty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>,
a: Ty<'tcx>,
b: Ty<'tcx>)
- -> ures<'tcx> {
+ -> UnitResult<'tcx> {
debug!("can_mk_subty({} <: {})", a.repr(cx.tcx), b.repr(cx.tcx));
cx.probe(|_| {
let trace = TypeTrace {
origin: Misc(codemap::DUMMY_SP),
values: Types(expected_found(true, a, b))
};
- cx.sub(true, trace).tys(a, b).to_ures()
+ cx.sub(true, trace).relate(&a, &b).map(|_| ())
})
}
-pub fn can_mk_eqty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> ures<'tcx>
+pub fn can_mk_eqty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, a: Ty<'tcx>, b: Ty<'tcx>)
+ -> UnitResult<'tcx>
{
cx.can_equate(&a, &b)
}
origin: TypeOrigin,
a: Ty<'tcx>,
b: Ty<'tcx>)
- -> ures<'tcx>
+ -> UnitResult<'tcx>
{
debug!("mk_eqty({} <: {})", a.repr(cx.tcx), b.repr(cx.tcx));
- cx.commit_if_ok(
- || cx.eq_types(a_is_expected, origin, a, b))
+ cx.commit_if_ok(|_| cx.eq_types(a_is_expected, origin, a, b))
}
pub fn mk_sub_poly_trait_refs<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>,
origin: TypeOrigin,
a: ty::PolyTraitRef<'tcx>,
b: ty::PolyTraitRef<'tcx>)
- -> ures<'tcx>
+ -> UnitResult<'tcx>
{
debug!("mk_sub_trait_refs({} <: {})",
a.repr(cx.tcx), b.repr(cx.tcx));
- cx.commit_if_ok(
- || cx.sub_poly_trait_refs(a_is_expected, origin, a.clone(), b.clone()))
+ cx.commit_if_ok(|_| cx.sub_poly_trait_refs(a_is_expected, origin, a.clone(), b.clone()))
}
fn expected_found<T>(a_is_expected: bool,
}
}
-trait then<'tcx> {
- fn then<T, F>(&self, f: F) -> Result<T, ty::type_err<'tcx>> where
- T: Clone,
- F: FnOnce() -> Result<T, ty::type_err<'tcx>>;
-}
-
-impl<'tcx> then<'tcx> for ures<'tcx> {
- fn then<T, F>(&self, f: F) -> Result<T, ty::type_err<'tcx>> where
- T: Clone,
- F: FnOnce() -> Result<T, ty::type_err<'tcx>>,
- {
- self.and_then(move |_| f())
- }
-}
-
-trait ToUres<'tcx> {
- fn to_ures(&self) -> ures<'tcx>;
-}
-
-impl<'tcx, T> ToUres<'tcx> for cres<'tcx, T> {
- fn to_ures(&self) -> ures<'tcx> {
- match *self {
- Ok(ref _v) => Ok(()),
- Err(ref e) => Err((*e))
- }
- }
-}
-
-trait CresCompare<'tcx, T> {
- fn compare<F>(&self, t: T, f: F) -> cres<'tcx, T> where
- F: FnOnce() -> ty::type_err<'tcx>;
-}
-
-impl<'tcx, T:Clone + PartialEq> CresCompare<'tcx, T> for cres<'tcx, T> {
- fn compare<F>(&self, t: T, f: F) -> cres<'tcx, T> where
- F: FnOnce() -> ty::type_err<'tcx>,
- {
- (*self).clone().and_then(move |s| {
- if s == t {
- (*self).clone()
- } else {
- Err(f())
- }
- })
- }
-}
-
-pub fn uok<'tcx>() -> ures<'tcx> {
- Ok(())
-}
-
#[must_use = "once you start a snapshot, you should always consume it"]
pub struct CombinedSnapshot {
type_snapshot: type_variable::Snapshot,
use middle::ty::UnconstrainedNumeric::{Neither, UnconstrainedInt, UnconstrainedFloat};
match ty.sty {
ty::ty_infer(ty::IntVar(vid)) => {
- match self.int_unification_table.borrow_mut().get(self.tcx, vid).value {
- None => UnconstrainedInt,
- _ => Neither,
+ if self.int_unification_table.borrow_mut().has_value(vid) {
+ Neither
+ } else {
+ UnconstrainedInt
}
},
ty::ty_infer(ty::FloatVar(vid)) => {
- match self.float_unification_table.borrow_mut().get(self.tcx, vid).value {
- None => return UnconstrainedFloat,
- _ => Neither,
+ if self.float_unification_table.borrow_mut().has_value(vid) {
+ Neither
+ } else {
+ UnconstrainedFloat
}
},
_ => Neither,
}
}
- pub fn combine_fields<'b>(&'b self, a_is_expected: bool, trace: TypeTrace<'tcx>)
- -> CombineFields<'b, 'tcx> {
+ fn combine_fields(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>)
+ -> CombineFields<'a, 'tcx> {
CombineFields {infcx: self,
a_is_expected: a_is_expected,
trace: trace}
}
- pub fn equate<'b>(&'b self, a_is_expected: bool, trace: TypeTrace<'tcx>)
- -> Equate<'b, 'tcx> {
- Equate(self.combine_fields(a_is_expected, trace))
+ // public so that it can be used from the rustc_driver unit tests
+ pub fn equate(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>)
+ -> equate::Equate<'a, 'tcx>
+ {
+ self.combine_fields(a_is_expected, trace).equate()
}
- pub fn sub<'b>(&'b self, a_is_expected: bool, trace: TypeTrace<'tcx>)
- -> Sub<'b, 'tcx> {
- Sub(self.combine_fields(a_is_expected, trace))
+ // public so that it can be used from the rustc_driver unit tests
+ pub fn sub(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>)
+ -> sub::Sub<'a, 'tcx>
+ {
+ self.combine_fields(a_is_expected, trace).sub()
}
- pub fn lub<'b>(&'b self, a_is_expected: bool, trace: TypeTrace<'tcx>)
- -> Lub<'b, 'tcx> {
- Lub(self.combine_fields(a_is_expected, trace))
+ // public so that it can be used from the rustc_driver unit tests
+ pub fn lub(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>)
+ -> lub::Lub<'a, 'tcx>
+ {
+ self.combine_fields(a_is_expected, trace).lub()
+ }
+
+ // public so that it can be used from the rustc_driver unit tests
+ pub fn glb(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>)
+ -> glb::Glb<'a, 'tcx>
+ {
+ self.combine_fields(a_is_expected, trace).glb()
}
fn start_snapshot(&self) -> CombinedSnapshot {
r
}
- /// Execute `f` and commit the bindings if successful
+ /// Execute `f` and commit the bindings if closure `f` returns `Ok(_)`
pub fn commit_if_ok<T, E, F>(&self, f: F) -> Result<T, E> where
- F: FnOnce() -> Result<T, E>
+ F: FnOnce(&CombinedSnapshot) -> Result<T, E>
{
- self.commit_unconditionally(move || self.try(move |_| f()))
+ debug!("commit_if_ok()");
+ let snapshot = self.start_snapshot();
+ let r = f(&snapshot);
+ debug!("commit_if_ok() -- r.is_ok() = {}", r.is_ok());
+ match r {
+ Ok(_) => { self.commit_from(snapshot); }
+ Err(_) => { self.rollback_to(snapshot); }
+ }
+ r
}
/// Execute `f` and commit only the region bindings if successful.
float_snapshot,
region_vars_snapshot } = self.start_snapshot();
- let r = self.try(move |_| f());
+ let r = self.commit_if_ok(|_| f());
// Roll back any non-region bindings - they should be resolved
// inside `f`, with, e.g. `resolve_type_vars_if_possible`.
r
}
- /// Execute `f`, unroll bindings on panic
- pub fn try<T, E, F>(&self, f: F) -> Result<T, E> where
- F: FnOnce(&CombinedSnapshot) -> Result<T, E>
- {
- debug!("try()");
- let snapshot = self.start_snapshot();
- let r = f(&snapshot);
- debug!("try() -- r.is_ok() = {}", r.is_ok());
- match r {
- Ok(_) => {
- self.commit_from(snapshot);
- }
- Err(_) => {
- self.rollback_to(snapshot);
- }
- }
- r
- }
-
/// Execute `f` then unroll any bindings it creates
pub fn probe<R, F>(&self, f: F) -> R where
F: FnOnce(&CombinedSnapshot) -> R,
origin: TypeOrigin,
a: Ty<'tcx>,
b: Ty<'tcx>)
- -> ures<'tcx>
+ -> UnitResult<'tcx>
{
debug!("sub_types({} <: {})", a.repr(self.tcx), b.repr(self.tcx));
- self.commit_if_ok(|| {
+ self.commit_if_ok(|_| {
let trace = TypeTrace::types(origin, a_is_expected, a, b);
- self.sub(a_is_expected, trace).tys(a, b).to_ures()
+ self.sub(a_is_expected, trace).relate(&a, &b).map(|_| ())
})
}
origin: TypeOrigin,
a: Ty<'tcx>,
b: Ty<'tcx>)
- -> ures<'tcx>
+ -> UnitResult<'tcx>
{
- self.commit_if_ok(|| {
+ self.commit_if_ok(|_| {
let trace = TypeTrace::types(origin, a_is_expected, a, b);
- self.equate(a_is_expected, trace).tys(a, b).to_ures()
+ self.equate(a_is_expected, trace).relate(&a, &b).map(|_| ())
})
}
origin: TypeOrigin,
a: Rc<ty::TraitRef<'tcx>>,
b: Rc<ty::TraitRef<'tcx>>)
- -> ures<'tcx>
+ -> UnitResult<'tcx>
{
debug!("sub_trait_refs({} <: {})",
a.repr(self.tcx),
b.repr(self.tcx));
- self.commit_if_ok(|| {
+ self.commit_if_ok(|_| {
let trace = TypeTrace {
origin: origin,
values: TraitRefs(expected_found(a_is_expected, a.clone(), b.clone()))
};
- self.sub(a_is_expected, trace).trait_refs(&*a, &*b).to_ures()
+ self.sub(a_is_expected, trace).relate(&*a, &*b).map(|_| ())
})
}
origin: TypeOrigin,
a: ty::PolyTraitRef<'tcx>,
b: ty::PolyTraitRef<'tcx>)
- -> ures<'tcx>
+ -> UnitResult<'tcx>
{
debug!("sub_poly_trait_refs({} <: {})",
a.repr(self.tcx),
b.repr(self.tcx));
- self.commit_if_ok(|| {
+ self.commit_if_ok(|_| {
let trace = TypeTrace {
origin: origin,
values: PolyTraitRefs(expected_found(a_is_expected, a.clone(), b.clone()))
};
- self.sub(a_is_expected, trace).binders(&a, &b).to_ures()
+ self.sub(a_is_expected, trace).relate(&a, &b).map(|_| ())
})
}
pub fn leak_check(&self,
skol_map: &SkolemizationMap,
snapshot: &CombinedSnapshot)
- -> ures<'tcx>
+ -> UnitResult<'tcx>
{
/*! See `higher_ranked::leak_check` */
pub fn equality_predicate(&self,
span: Span,
predicate: &ty::PolyEquatePredicate<'tcx>)
- -> ures<'tcx> {
- self.try(|snapshot| {
+ -> UnitResult<'tcx> {
+ self.commit_if_ok(|snapshot| {
let (ty::EquatePredicate(a, b), skol_map) =
self.skolemize_late_bound_regions(predicate, snapshot);
let origin = EquatePredicate(span);
pub fn region_outlives_predicate(&self,
span: Span,
predicate: &ty::PolyRegionOutlivesPredicate)
- -> ures<'tcx> {
- self.try(|snapshot| {
+ -> UnitResult<'tcx> {
+ self.commit_if_ok(|snapshot| {
let (ty::OutlivesPredicate(r_a, r_b), skol_map) =
self.skolemize_late_bound_regions(predicate, snapshot);
let origin = RelateRegionParamBound(span);
.new_key(None)
}
- pub fn next_region_var(&self, origin: RegionVariableOrigin<'tcx>) -> ty::Region {
+ pub fn next_region_var(&self, origin: RegionVariableOrigin) -> ty::Region {
ty::ReInfer(ty::ReVar(self.region_vars.new_region_var(origin)))
}
}
ty::ty_infer(ty::IntVar(v)) => {
- self.probe_var(v)
+ self.int_unification_table
+ .borrow_mut()
+ .probe(v)
+ .map(|v| v.to_type(self.tcx))
.unwrap_or(typ)
}
ty::ty_infer(ty::FloatVar(v)) => {
- self.probe_var(v)
+ self.float_unification_table
+ .borrow_mut()
+ .probe(v)
+ .map(|v| v.to_type(self.tcx))
.unwrap_or(typ)
}
self.region_vars.verify_generic_bound(origin, kind, a, bs);
}
- pub fn can_equate<T>(&self, a: &T, b: &T) -> ures<'tcx>
- where T : Combineable<'tcx> + Repr<'tcx>
+ pub fn can_equate<'b,T>(&'b self, a: &T, b: &T) -> UnitResult<'tcx>
+ where T: Relate<'b,'tcx> + Repr<'tcx>
{
debug!("can_equate({}, {})", a.repr(self.tcx), b.repr(self.tcx));
self.probe(|_| {
let e = self.tcx.types.err;
let trace = TypeTrace { origin: Misc(codemap::DUMMY_SP),
values: Types(expected_found(true, e, e)) };
- let eq = self.equate(true, trace);
- Combineable::combine(&eq, a, b)
- }).to_ures()
+ self.equate(true, trace).relate(a, b)
+ }).map(|_| ())
}
}
}
}
-impl<'tcx> RegionVariableOrigin<'tcx> {
+impl RegionVariableOrigin {
pub fn span(&self) -> Span {
match *self {
MiscVariable(a) => a,
PatternRegion(a) => a,
AddrOfRegion(a) => a,
Autoref(a) => a,
- Coercion(ref a) => a.span(),
+ Coercion(a) => a,
EarlyBoundRegion(a, _) => a,
LateBoundRegion(a, _, _) => a,
BoundRegionInCoherence(_) => codemap::DUMMY_SP,
}
}
-impl<'tcx> Repr<'tcx> for RegionVariableOrigin<'tcx> {
+impl<'tcx> Repr<'tcx> for RegionVariableOrigin {
fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
match *self {
MiscVariable(a) => {
format!("AddrOfRegion({})", a.repr(tcx))
}
Autoref(a) => format!("Autoref({})", a.repr(tcx)),
- Coercion(ref a) => format!("Coercion({})", a.repr(tcx)),
+ Coercion(a) => format!("Coercion({})", a.repr(tcx)),
EarlyBoundRegion(a, b) => {
format!("EarlyBoundRegion({},{})", a.repr(tcx), b.repr(tcx))
}
the borrow expression, we must issue sufficient restrictions to ensure
that the pointee remains valid.
-## Adding closures
-
-The other significant complication to the region hierarchy is
-closures. I will describe here how closures should work, though some
-of the work to implement this model is ongoing at the time of this
-writing.
-
-The body of closures are type-checked along with the function that
-creates them. However, unlike other expressions that appear within the
-function body, it is not entirely obvious when a closure body executes
-with respect to the other expressions. This is because the closure
-body will execute whenever the closure is called; however, we can
-never know precisely when the closure will be called, especially
-without some sort of alias analysis.
-
-However, we can place some sort of limits on when the closure
-executes. In particular, the type of every closure `fn:'r K` includes
-a region bound `'r`. This bound indicates the maximum lifetime of that
-closure; once we exit that region, the closure cannot be called
-anymore. Therefore, we say that the lifetime of the closure body is a
-sublifetime of the closure bound, but the closure body itself is unordered
-with respect to other parts of the code.
-
-For example, consider the following fragment of code:
-
- 'a: {
- let closure: fn:'a() = || 'b: {
- 'c: ...
- };
- 'd: ...
- }
-
-Here we have four lifetimes, `'a`, `'b`, `'c`, and `'d`. The closure
-`closure` is bounded by the lifetime `'a`. The lifetime `'b` is the
-lifetime of the closure body, and `'c` is some statement within the
-closure body. Finally, `'d` is a statement within the outer block that
-created the closure.
-
-We can say that the closure body `'b` is a sublifetime of `'a` due to
-the closure bound. By the usual lexical scoping conventions, the
-statement `'c` is clearly a sublifetime of `'b`, and `'d` is a
-sublifetime of `'d`. However, there is no ordering between `'c` and
-`'d` per se (this kind of ordering between statements is actually only
-an issue for dataflow; passes like the borrow checker must assume that
-closures could execute at any time from the moment they are created
-until they go out of scope).
-
-### Complications due to closure bound inference
-
-There is only one problem with the above model: in general, we do not
-actually *know* the closure bounds during region inference! In fact,
-closure bounds are almost always region variables! This is very tricky
-because the inference system implicitly assumes that we can do things
-like compute the LUB of two scoped lifetimes without needing to know
-the values of any variables.
-
-Here is an example to illustrate the problem:
-
- fn identify<T>(x: T) -> T { x }
-
- fn foo() { // 'foo is the function body
- 'a: {
- let closure = identity(|| 'b: {
- 'c: ...
- });
- 'd: closure();
- }
- 'e: ...;
- }
-
-In this example, the closure bound is not explicit. At compile time,
-we will create a region variable (let's call it `V0`) to represent the
-closure bound.
-
-The primary difficulty arises during the constraint propagation phase.
-Imagine there is some variable with incoming edges from `'c` and `'d`.
-This means that the value of the variable must be `LUB('c,
-'d)`. However, without knowing what the closure bound `V0` is, we
-can't compute the LUB of `'c` and `'d`! Any we don't know the closure
-bound until inference is done.
-
-The solution is to rely on the fixed point nature of inference.
-Basically, when we must compute `LUB('c, 'd)`, we just use the current
-value for `V0` as the closure's bound. If `V0`'s binding should
-change, then we will do another round of inference, and the result of
-`LUB('c, 'd)` will change.
-
-One minor implication of this is that the graph does not in fact track
-the full set of dependencies between edges. We cannot easily know
-whether the result of a LUB computation will change, since there may
-be indirect dependencies on other variables that are not reflected on
-the graph. Therefore, we must *always* iterate over all edges when
-doing the fixed point calculation, not just those adjacent to nodes
-whose values have changed.
-
-Were it not for this requirement, we could in fact avoid fixed-point
-iteration altogether. In that universe, we could instead first
-identify and remove strongly connected components (SCC) in the graph.
-Note that such components must consist solely of region variables; all
-of these variables can effectively be unified into a single variable.
-Once SCCs are removed, we are left with a DAG. At this point, we
-could walk the DAG in topological order once to compute the expanding
-nodes, and again in reverse topological order to compute the
-contracting nodes. However, as I said, this does not work given the
-current treatment of closure bounds, but perhaps in the future we can
-address this problem somehow and make region inference somewhat more
-efficient. Note that this is solely a matter of performance, not
-expressiveness.
+## Modeling closures
+
+Integrating closures properly into the model is a bit of
+work-in-progress. In an ideal world, we would model closures as
+closely as possible after their desugared equivalents. That is, a
+closure type would be modeled as a struct, and the region hierarchy of
+different closure bodies would be completely distinct from all other
+fns. We are generally moving in that direction but there are
+complications in terms of the implementation.
+
+In practice what we currently do is somewhat different. The basis for
+the current approach is the observation that the only time that
+regions from distinct fn bodies interact with one another is through
+an upvar or the type of a fn parameter (since closures live in the fn
+body namespace, they can in fact have fn parameters whose types
+include regions from the surrounding fn body). For these cases, there
+are separate mechanisms which ensure that the regions that appear in
+upvars/parameters outlive the dynamic extent of each call to the
+closure:
+
+1. Types must outlive the region of any expression where they are used.
+ For a closure type `C` to outlive a region `'r`, that implies that the
+ types of all its upvars must outlive `'r`.
+2. Parameters must outlive the region of any fn that they are passed to.
+
+Therefore, we can -- sort of -- assume that any region from an
+enclosing fns is larger than any region from one of its enclosed
+fn. And that is precisely what we do: when building the region
+hierarchy, each region lives in its own distinct subtree, but if we
+are asked to compute the `LUB(r1, r2)` of two regions, and those
+regions are in disjoint subtrees, we compare the lexical nesting of
+the two regions.
+
+*Ideas for improving the situation:* (FIXME #3696) The correctness
+argument here is subtle and a bit hand-wavy. The ideal, as stated
+earlier, would be to model things in such a way that it corresponds
+more closely to the desugared code. The best approach for doing this
+is a bit unclear: it may in fact be possible to *actually* desugar
+before we start, but I don't think so. The main option that I've been
+thinking through is imposing a "view shift" as we enter the fn body,
+so that regions appearing in the types of fn parameters and upvars are
+translated from being regions in the outer fn into free region
+parameters, just as they would be if we applied the desugaring. The
+challenge here is that type inference may not have fully run, so the
+types may not be fully known: we could probably do this translation
+lazilly, as type variables are instantiated. We would also have to
+apply a kind of inverse translation to the return value. This would be
+a good idea anyway, as right now it is possible for free regions
+instantiated within the closure to leak into the parent: this
+currently leads to type errors, since those regions cannot outlive any
+expressions within the parent hierarchy. Much like the current
+handling of closures, there are no known cases where this leads to a
+type-checking accepting incorrect code (though it sometimes rejects
+what might be considered correct code; see rust-lang/rust#22557), but
+it still doesn't feel like the right approach.
### Skolemization
pub use self::VarValue::*;
use self::Classification::*;
-use super::cres;
use super::{RegionVariableOrigin, SubregionOrigin, TypeTrace, MiscVariable};
use middle::region;
use middle::ty::{BoundRegion, FreeRegion, Region, RegionVid};
use middle::ty::{ReEmpty, ReStatic, ReInfer, ReFree, ReEarlyBound};
use middle::ty::{ReLateBound, ReScope, ReVar, ReSkolemized, BrFresh};
+use middle::ty_relate::RelateResult;
use middle::graph;
use middle::graph::{Direction, NodeIndex};
use util::common::indenter;
Projection(ty::ProjectionTy<'tcx>),
}
-#[derive(Copy, PartialEq, Eq, Hash)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub struct TwoRegions {
a: Region,
b: Region,
}
-#[derive(Copy, PartialEq)]
+#[derive(Copy, Clone, PartialEq)]
pub enum UndoLogEntry {
OpenSnapshot,
CommitedSnapshot,
AddCombination(CombineMapType, TwoRegions)
}
-#[derive(Copy, PartialEq)]
+#[derive(Copy, Clone, PartialEq)]
pub enum CombineMapType {
Lub, Glb
}
/// Could not infer a value for `v` because `sub_r <= v` (due to
/// `sub_origin`) but `v <= sup_r` (due to `sup_origin`) and
/// `sub_r <= sup_r` does not hold.
- SubSupConflict(RegionVariableOrigin<'tcx>,
+ SubSupConflict(RegionVariableOrigin,
SubregionOrigin<'tcx>, Region,
SubregionOrigin<'tcx>, Region),
/// Could not infer a value for `v` because `v <= r1` (due to
/// `origin1`) and `v <= r2` (due to `origin2`) and
/// `r1` and `r2` have no intersection.
- SupSupConflict(RegionVariableOrigin<'tcx>,
+ SupSupConflict(RegionVariableOrigin,
SubregionOrigin<'tcx>, Region,
SubregionOrigin<'tcx>, Region),
/// more specific errors message by suggesting to the user where they
/// should put a lifetime. In those cases we process and put those errors
/// into `ProcessedErrors` before we do any reporting.
- ProcessedErrors(Vec<RegionVariableOrigin<'tcx>>,
+ ProcessedErrors(Vec<RegionVariableOrigin>,
Vec<(TypeTrace<'tcx>, ty::type_err<'tcx>)>,
Vec<SameRegions>),
}
pub struct RegionVarBindings<'a, 'tcx: 'a> {
tcx: &'a ty::ctxt<'tcx>,
- var_origins: RefCell<Vec<RegionVariableOrigin<'tcx>>>,
+ var_origins: RefCell<Vec<RegionVariableOrigin>>,
// Constraints of the form `A <= B` introduced by the region
// checker. Here at least one of `A` and `B` must be a region
len as u32
}
- pub fn new_region_var(&self, origin: RegionVariableOrigin<'tcx>) -> RegionVid {
+ pub fn new_region_var(&self, origin: RegionVariableOrigin) -> RegionVid {
let id = self.num_vars();
self.var_origins.borrow_mut().push(origin.clone());
let vid = RegionVid { index: id };
// at least as big as the block fr.scope_id". So, we can
// reasonably compare free regions and scopes:
let fr_scope = fr.scope.to_code_extent();
- match self.tcx.region_maps.nearest_common_ancestor(fr_scope, s_id) {
+ let r_id = self.tcx.region_maps.nearest_common_ancestor(fr_scope, s_id);
+
+ if r_id == fr_scope {
// if the free region's scope `fr.scope_id` is bigger than
// the scope region `s_id`, then the LUB is the free
// region itself:
- Some(r_id) if r_id == fr_scope => f,
-
+ f
+ } else {
// otherwise, we don't know what the free region is,
// so we must conservatively say the LUB is static:
- _ => ReStatic
+ ReStatic
}
}
// The region corresponding to an outer block is a
// subtype of the region corresponding to an inner
// block.
- match self.tcx.region_maps.nearest_common_ancestor(a_id, b_id) {
- Some(r_id) => ReScope(r_id),
- _ => ReStatic
- }
+ ReScope(self.tcx.region_maps.nearest_common_ancestor(a_id, b_id))
}
(ReFree(ref a_fr), ReFree(ref b_fr)) => {
/// regions are given as argument, in any order, a consistent result is returned.
fn lub_free_regions(&self,
a: &FreeRegion,
- b: &FreeRegion) -> ty::Region
+ b: &FreeRegion)
+ -> ty::Region
{
return match a.cmp(b) {
Less => helper(self, a, b),
fn glb_concrete_regions(&self,
a: Region,
b: Region)
- -> cres<'tcx, Region> {
+ -> RelateResult<'tcx, Region>
+ {
debug!("glb_concrete_regions({:?}, {:?})", a, b);
match (a, b) {
(ReLateBound(..), _) |
// is the scope `s_id`. Otherwise, as we do not know
// big the free region is precisely, the GLB is undefined.
let fr_scope = fr.scope.to_code_extent();
- match self.tcx.region_maps.nearest_common_ancestor(fr_scope, s_id) {
- Some(r_id) if r_id == fr_scope => Ok(s),
- _ => Err(ty::terr_regions_no_overlap(b, a))
+ if self.tcx.region_maps.nearest_common_ancestor(fr_scope, s_id) == fr_scope {
+ Ok(s)
+ } else {
+ Err(ty::terr_regions_no_overlap(b, a))
}
}
/// returned.
fn glb_free_regions(&self,
a: &FreeRegion,
- b: &FreeRegion) -> cres<'tcx, ty::Region>
+ b: &FreeRegion)
+ -> RelateResult<'tcx, ty::Region>
{
return match a.cmp(b) {
Less => helper(self, a, b),
fn helper<'a, 'tcx>(this: &RegionVarBindings<'a, 'tcx>,
a: &FreeRegion,
- b: &FreeRegion) -> cres<'tcx, ty::Region>
+ b: &FreeRegion) -> RelateResult<'tcx, ty::Region>
{
if this.tcx.region_maps.sub_free_region(*a, *b) {
Ok(ty::ReFree(*a))
region_a: ty::Region,
region_b: ty::Region,
scope_a: region::CodeExtent,
- scope_b: region::CodeExtent) -> cres<'tcx, Region>
+ scope_b: region::CodeExtent)
+ -> RelateResult<'tcx, Region>
{
// We want to generate the intersection of two
// scopes or two free regions. So, if one of
// it. Otherwise fail.
debug!("intersect_scopes(scope_a={:?}, scope_b={:?}, region_a={:?}, region_b={:?})",
scope_a, scope_b, region_a, region_b);
- match self.tcx.region_maps.nearest_common_ancestor(scope_a, scope_b) {
- Some(r_id) if scope_a == r_id => Ok(ReScope(scope_b)),
- Some(r_id) if scope_b == r_id => Ok(ReScope(scope_a)),
- _ => Err(ty::terr_regions_no_overlap(region_a, region_b))
+ let r_id = self.tcx.region_maps.nearest_common_ancestor(scope_a, scope_b);
+ if r_id == scope_a {
+ Ok(ReScope(scope_b))
+ } else if r_id == scope_b {
+ Ok(ReScope(scope_a))
+ } else {
+ Err(ty::terr_regions_no_overlap(region_a, region_b))
}
}
}
// ______________________________________________________________________
-#[derive(Copy, PartialEq, Debug)]
+#[derive(Copy, Clone, PartialEq, Debug)]
enum Classification { Expanding, Contracting }
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub enum VarValue { NoValue, Value(Region), ErrorValue }
struct VarData {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use super::combine::*;
-use super::cres;
+use super::combine::{self, CombineFields};
use super::higher_ranked::HigherRankedRelations;
use super::Subtype;
use super::type_variable::{SubtypeOf, SupertypeOf};
use middle::ty::{self, Ty};
use middle::ty::TyVar;
-use util::ppaux::Repr;
+use middle::ty_relate::{Relate, RelateResult, TypeRelation};
+use util::ppaux::{Repr};
/// "Greatest lower bound" (common subtype)
-pub struct Sub<'f, 'tcx: 'f> {
- fields: CombineFields<'f, 'tcx>
+pub struct Sub<'a, 'tcx: 'a> {
+ fields: CombineFields<'a, 'tcx>
}
-#[allow(non_snake_case)]
-pub fn Sub<'f, 'tcx>(cf: CombineFields<'f, 'tcx>) -> Sub<'f, 'tcx> {
- Sub { fields: cf }
+impl<'a, 'tcx> Sub<'a, 'tcx> {
+ pub fn new(f: CombineFields<'a, 'tcx>) -> Sub<'a, 'tcx> {
+ Sub { fields: f }
+ }
}
-impl<'f, 'tcx> Combine<'tcx> for Sub<'f, 'tcx> {
- fn tag(&self) -> String { "Sub".to_string() }
- fn fields<'a>(&'a self) -> &'a CombineFields<'a, 'tcx> { &self.fields }
-
- fn tys_with_variance(&self, v: ty::Variance, a: Ty<'tcx>, b: Ty<'tcx>)
- -> cres<'tcx, Ty<'tcx>>
- {
- match v {
- ty::Invariant => self.equate().tys(a, b),
- ty::Covariant => self.tys(a, b),
- ty::Bivariant => self.bivariate().tys(a, b),
- ty::Contravariant => Sub(self.fields.switch_expected()).tys(b, a),
- }
- }
+impl<'a, 'tcx> TypeRelation<'a, 'tcx> for Sub<'a, 'tcx> {
+ fn tag(&self) -> &'static str { "Sub" }
+ fn tcx(&self) -> &'a ty::ctxt<'tcx> { self.fields.infcx.tcx }
+ fn a_is_expected(&self) -> bool { self.fields.a_is_expected }
- fn regions_with_variance(&self, v: ty::Variance, a: ty::Region, b: ty::Region)
- -> cres<'tcx, ty::Region>
+ fn relate_with_variance<T:Relate<'a,'tcx>>(&mut self,
+ variance: ty::Variance,
+ a: &T,
+ b: &T)
+ -> RelateResult<'tcx, T>
{
- match v {
- ty::Invariant => self.equate().regions(a, b),
- ty::Covariant => self.regions(a, b),
- ty::Bivariant => self.bivariate().regions(a, b),
- ty::Contravariant => Sub(self.fields.switch_expected()).regions(b, a),
+ match variance {
+ ty::Invariant => self.fields.equate().relate(a, b),
+ ty::Covariant => self.relate(a, b),
+ ty::Bivariant => self.fields.bivariate().relate(a, b),
+ ty::Contravariant => self.fields.switch_expected().sub().relate(b, a),
}
}
- fn regions(&self, a: ty::Region, b: ty::Region) -> cres<'tcx, ty::Region> {
- debug!("{}.regions({}, {})",
- self.tag(),
- a.repr(self.tcx()),
- b.repr(self.tcx()));
- self.infcx().region_vars.make_subregion(Subtype(self.trace()), a, b);
- Ok(a)
- }
+ fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
+ debug!("{}.tys({}, {})", self.tag(), a.repr(self.tcx()), b.repr(self.tcx()));
- fn tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, Ty<'tcx>> {
- debug!("{}.tys({}, {})", self.tag(),
- a.repr(self.tcx()), b.repr(self.tcx()));
if a == b { return Ok(a); }
let infcx = self.fields.infcx;
}
(&ty::ty_infer(TyVar(a_id)), _) => {
try!(self.fields
- .switch_expected()
- .instantiate(b, SupertypeOf, a_id));
+ .switch_expected()
+ .instantiate(b, SupertypeOf, a_id));
Ok(a)
}
(_, &ty::ty_infer(TyVar(b_id))) => {
}
_ => {
- super_tys(self, a, b)
+ combine::super_combine_tys(self.fields.infcx, self, a, b)
}
}
}
- fn binders<T>(&self, a: &ty::Binder<T>, b: &ty::Binder<T>) -> cres<'tcx, ty::Binder<T>>
- where T : Combineable<'tcx>
+ fn regions(&mut self, a: ty::Region, b: ty::Region) -> RelateResult<'tcx, ty::Region> {
+ debug!("{}.regions({}, {})",
+ self.tag(),
+ a.repr(self.tcx()),
+ b.repr(self.tcx()));
+ let origin = Subtype(self.fields.trace.clone());
+ self.fields.infcx.region_vars.make_subregion(origin, a, b);
+ Ok(a)
+ }
+
+ fn binders<T>(&mut self, a: &ty::Binder<T>, b: &ty::Binder<T>)
+ -> RelateResult<'tcx, ty::Binder<T>>
+ where T: Relate<'a,'tcx>
{
- self.higher_ranked_sub(a, b)
+ self.fields.higher_ranked_sub(a, b)
}
}
type Relation = (RelationDir, ty::TyVid);
-#[derive(Copy, PartialEq, Debug)]
+#[derive(Copy, Clone, PartialEq, Debug)]
pub enum RelationDir {
SubtypeOf, SupertypeOf, EqTo, BiTo
}
use std::marker;
-use middle::ty::{expected_found, IntVarValue};
+use middle::ty::{IntVarValue};
use middle::ty::{self, Ty};
-use middle::infer::{uok, ures};
-use middle::infer::InferCtxt;
-use std::cell::RefCell;
use std::fmt::Debug;
use std::marker::PhantomData;
use syntax::ast;
pub trait UnifyKey : Clone + Debug + PartialEq {
type Value : UnifyValue;
- fn index(&self) -> usize;
+ fn index(&self) -> u32;
- fn from_index(u: usize) -> Self;
-
- // Given an inference context, returns the unification table
- // appropriate to this key type.
- fn unification_table<'v>(infcx: &'v InferCtxt)
- -> &'v RefCell<UnificationTable<Self>>;
+ fn from_index(u: u32) -> Self;
fn tag(k: Option<Self>) -> &'static str;
}
pub rank: usize,
}
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub struct Delegate<K>(PhantomData<K>);
// We can't use V:LatticeValue, much as I would like to,
pub fn new_key(&mut self, value: K::Value) -> K {
let index = self.values.push(Root(value, 0));
- let k = UnifyKey::from_index(index);
+ let k = UnifyKey::from_index(index as u32);
debug!("{}: created new key: {:?}",
UnifyKey::tag(None::<K>),
k);
k
}
- /// Find the root node for `vid`. This uses the standard union-find algorithm with path
- /// compression: http://en.wikipedia.org/wiki/Disjoint-set_data_structure
- pub fn get(&mut self, tcx: &ty::ctxt, vid: K) -> Node<K> {
- let index = vid.index();
+ /// Find the root node for `vid`. This uses the standard
+ /// union-find algorithm with path compression:
+ /// <http://en.wikipedia.org/wiki/Disjoint-set_data_structure>.
+ ///
+ /// NB. This is a building-block operation and you would probably
+ /// prefer to call `probe` below.
+ fn get(&mut self, vid: K) -> Node<K> {
+ let index = vid.index() as usize;
let value = (*self.values.get(index)).clone();
match value {
Redirect(redirect) => {
- let node: Node<K> = self.get(tcx, redirect.clone());
+ let node: Node<K> = self.get(redirect.clone());
if node.key != redirect {
// Path compression
self.values.set(index, Redirect(node.key.clone()));
}
fn is_root(&self, key: &K) -> bool {
- match *self.values.get(key.index()) {
+ let index = key.index() as usize;
+ match *self.values.get(index) {
Redirect(..) => false,
Root(..) => true,
}
}
- /// Sets the value for `vid` to `new_value`. `vid` MUST be a root node! Also, we must be in the
- /// middle of a snapshot.
- pub fn set<'tcx>(&mut self,
- _tcx: &ty::ctxt<'tcx>,
- key: K,
- new_value: VarValue<K>)
- {
+ /// Sets the value for `vid` to `new_value`. `vid` MUST be a root
+ /// node! This is an internal operation used to impl other things.
+ fn set(&mut self, key: K, new_value: VarValue<K>) {
assert!(self.is_root(&key));
debug!("Updating variable {:?} to {:?}",
key, new_value);
- self.values.set(key.index(), new_value);
+ let index = key.index() as usize;
+ self.values.set(index, new_value);
}
- /// Either redirects node_a to node_b or vice versa, depending on the relative rank. Returns
- /// the new root and rank. You should then update the value of the new root to something
- /// suitable.
- pub fn unify<'tcx>(&mut self,
- tcx: &ty::ctxt<'tcx>,
- node_a: &Node<K>,
- node_b: &Node<K>)
- -> (K, usize)
- {
+ /// Either redirects `node_a` to `node_b` or vice versa, depending
+ /// on the relative rank. The value associated with the new root
+ /// will be `new_value`.
+ ///
+ /// NB: This is the "union" operation of "union-find". It is
+ /// really more of a building block. If the values associated with
+ /// your key are non-trivial, you would probably prefer to call
+ /// `unify_var_var` below.
+ fn unify(&mut self, node_a: &Node<K>, node_b: &Node<K>, new_value: K::Value) {
debug!("unify(node_a(id={:?}, rank={:?}), node_b(id={:?}, rank={:?}))",
node_a.key,
node_a.rank,
node_b.key,
node_b.rank);
- if node_a.rank > node_b.rank {
+ let (new_root, new_rank) = if node_a.rank > node_b.rank {
// a has greater rank, so a should become b's parent,
// i.e., b should redirect to a.
- self.set(tcx, node_b.key.clone(), Redirect(node_a.key.clone()));
+ self.set(node_b.key.clone(), Redirect(node_a.key.clone()));
(node_a.key.clone(), node_a.rank)
} else if node_a.rank < node_b.rank {
// b has greater rank, so a should redirect to b.
- self.set(tcx, node_a.key.clone(), Redirect(node_b.key.clone()));
+ self.set(node_a.key.clone(), Redirect(node_b.key.clone()));
(node_b.key.clone(), node_b.rank)
} else {
// If equal, redirect one to the other and increment the
// other's rank.
assert_eq!(node_a.rank, node_b.rank);
- self.set(tcx, node_b.key.clone(), Redirect(node_a.key.clone()));
+ self.set(node_b.key.clone(), Redirect(node_a.key.clone()));
(node_a.key.clone(), node_a.rank + 1)
- }
+ };
+
+ self.set(new_root, Root(new_value, new_rank));
}
}
}
///////////////////////////////////////////////////////////////////////////
-// Code to handle simple keys like ints, floats---anything that
-// doesn't have a subtyping relationship we need to worry about.
-
-/// Indicates a type that does not have any kind of subtyping
-/// relationship.
-pub trait SimplyUnifiable<'tcx> : Clone + PartialEq + Debug {
- fn to_type(&self, tcx: &ty::ctxt<'tcx>) -> Ty<'tcx>;
- fn to_type_err(expected_found<Self>) -> ty::type_err<'tcx>;
-}
-
-pub fn err<'tcx, V:SimplyUnifiable<'tcx>>(a_is_expected: bool,
- a_t: V,
- b_t: V)
- -> ures<'tcx> {
- if a_is_expected {
- Err(SimplyUnifiable::to_type_err(
- ty::expected_found {expected: a_t, found: b_t}))
- } else {
- Err(SimplyUnifiable::to_type_err(
- ty::expected_found {expected: b_t, found: a_t}))
- }
-}
-
-pub trait InferCtxtMethodsForSimplyUnifiableTypes<'tcx,K,V>
- where K : UnifyKey<Value=Option<V>>,
- V : SimplyUnifiable<'tcx>,
- Option<V> : UnifyValue,
-{
- fn simple_vars(&self,
- a_is_expected: bool,
- a_id: K,
- b_id: K)
- -> ures<'tcx>;
- fn simple_var_t(&self,
- a_is_expected: bool,
- a_id: K,
- b: V)
- -> ures<'tcx>;
- fn probe_var(&self, a_id: K) -> Option<Ty<'tcx>>;
-}
-
-impl<'a,'tcx,V,K> InferCtxtMethodsForSimplyUnifiableTypes<'tcx,K,V> for InferCtxt<'a,'tcx>
- where K : UnifyKey<Value=Option<V>>,
- V : SimplyUnifiable<'tcx>,
- Option<V> : UnifyValue,
+// Code to handle keys which carry a value, like ints,
+// floats---anything that doesn't have a subtyping relationship we
+// need to worry about.
+
+impl<'tcx,K,V> UnificationTable<K>
+ where K: UnifyKey<Value=Option<V>>,
+ V: Clone+PartialEq,
+ Option<V>: UnifyValue,
{
- /// Unifies two simple keys. Because simple keys do not have any subtyping relationships, if
- /// both keys have already been associated with a value, then those two values must be the
- /// same.
- fn simple_vars(&self,
- a_is_expected: bool,
- a_id: K,
- b_id: K)
- -> ures<'tcx>
+ pub fn unify_var_var(&mut self,
+ a_id: K,
+ b_id: K)
+ -> Result<(),(V,V)>
{
- let tcx = self.tcx;
- let table = UnifyKey::unification_table(self);
- let node_a: Node<K> = table.borrow_mut().get(tcx, a_id);
- let node_b: Node<K> = table.borrow_mut().get(tcx, b_id);
+ let node_a = self.get(a_id);
+ let node_b = self.get(b_id);
let a_id = node_a.key.clone();
let b_id = node_b.key.clone();
- if a_id == b_id { return uok(); }
+ if a_id == b_id { return Ok(()); }
let combined = {
match (&node_a.value, &node_b.value) {
None
}
(&Some(ref v), &None) | (&None, &Some(ref v)) => {
- Some((*v).clone())
+ Some(v.clone())
}
(&Some(ref v1), &Some(ref v2)) => {
if *v1 != *v2 {
- return err(a_is_expected, (*v1).clone(), (*v2).clone())
+ return Err((v1.clone(), v2.clone()));
}
- Some((*v1).clone())
+ Some(v1.clone())
}
}
};
- let (new_root, new_rank) = table.borrow_mut().unify(tcx,
- &node_a,
- &node_b);
- table.borrow_mut().set(tcx, new_root, Root(combined, new_rank));
- return Ok(())
+ Ok(self.unify(&node_a, &node_b, combined))
}
/// Sets the value of the key `a_id` to `b`. Because simple keys do not have any subtyping
/// relationships, if `a_id` already has a value, it must be the same as `b`.
- fn simple_var_t(&self,
- a_is_expected: bool,
- a_id: K,
- b: V)
- -> ures<'tcx>
+ pub fn unify_var_value(&mut self,
+ a_id: K,
+ b: V)
+ -> Result<(),(V,V)>
{
- let tcx = self.tcx;
- let table = UnifyKey::unification_table(self);
- let node_a = table.borrow_mut().get(tcx, a_id);
+ let node_a = self.get(a_id);
let a_id = node_a.key.clone();
match node_a.value {
None => {
- table.borrow_mut().set(tcx, a_id, Root(Some(b), node_a.rank));
- return Ok(());
+ self.set(a_id, Root(Some(b), node_a.rank));
+ Ok(())
}
Some(ref a_t) => {
if *a_t == b {
- return Ok(());
+ Ok(())
} else {
- return err(a_is_expected, (*a_t).clone(), b);
+ Err((a_t.clone(), b))
}
}
}
}
- fn probe_var(&self, a_id: K) -> Option<Ty<'tcx>> {
- let tcx = self.tcx;
- let table = UnifyKey::unification_table(self);
- let node_a = table.borrow_mut().get(tcx, a_id);
- match node_a.value {
- None => None,
- Some(ref a_t) => Some(a_t.to_type(tcx))
- }
+ pub fn has_value(&mut self, id: K) -> bool {
+ self.get(id).value.is_some()
+ }
+
+ pub fn probe(&mut self, a_id: K) -> Option<V> {
+ self.get(a_id).value.clone()
}
}
// Integral type keys
+pub trait ToType<'tcx> {
+ fn to_type(&self, tcx: &ty::ctxt<'tcx>) -> Ty<'tcx>;
+}
+
impl UnifyKey for ty::IntVid {
type Value = Option<IntVarValue>;
-
- fn index(&self) -> usize { self.index as usize }
-
- fn from_index(i: usize) -> ty::IntVid { ty::IntVid { index: i as u32 } }
-
- fn unification_table<'v>(infcx: &'v InferCtxt) -> &'v RefCell<UnificationTable<ty::IntVid>> {
- return &infcx.int_unification_table;
- }
-
- fn tag(_: Option<ty::IntVid>) -> &'static str {
- "IntVid"
- }
+ fn index(&self) -> u32 { self.index }
+ fn from_index(i: u32) -> ty::IntVid { ty::IntVid { index: i } }
+ fn tag(_: Option<ty::IntVid>) -> &'static str { "IntVid" }
}
-impl<'tcx> SimplyUnifiable<'tcx> for IntVarValue {
+impl<'tcx> ToType<'tcx> for IntVarValue {
fn to_type(&self, tcx: &ty::ctxt<'tcx>) -> Ty<'tcx> {
match *self {
ty::IntType(i) => ty::mk_mach_int(tcx, i),
ty::UintType(i) => ty::mk_mach_uint(tcx, i),
}
}
-
- fn to_type_err(err: expected_found<IntVarValue>) -> ty::type_err<'tcx> {
- return ty::terr_int_mismatch(err);
- }
}
impl UnifyValue for Option<IntVarValue> { }
impl UnifyKey for ty::FloatVid {
type Value = Option<ast::FloatTy>;
-
- fn index(&self) -> usize { self.index as usize }
-
- fn from_index(i: usize) -> ty::FloatVid { ty::FloatVid { index: i as u32 } }
-
- fn unification_table<'v>(infcx: &'v InferCtxt) -> &'v RefCell<UnificationTable<ty::FloatVid>> {
- return &infcx.float_unification_table;
- }
-
- fn tag(_: Option<ty::FloatVid>) -> &'static str {
- "FloatVid"
- }
+ fn index(&self) -> u32 { self.index }
+ fn from_index(i: u32) -> ty::FloatVid { ty::FloatVid { index: i } }
+ fn tag(_: Option<ty::FloatVid>) -> &'static str { "FloatVid" }
}
impl UnifyValue for Option<ast::FloatTy> {
}
-impl<'tcx> SimplyUnifiable<'tcx> for ast::FloatTy {
+impl<'tcx> ToType<'tcx> for ast::FloatTy {
fn to_type(&self, tcx: &ty::ctxt<'tcx>) -> Ty<'tcx> {
ty::mk_mach_float(tcx, *self)
}
-
- fn to_type_err(err: expected_found<ast::FloatTy>) -> ty::type_err<'tcx> {
- ty::terr_float_mismatch(err)
- }
}
$( $variant:ident, $name:expr, $method:ident; )*
) => {
-#[derive(Copy, FromPrimitive, PartialEq, Eq, Hash)]
+#[derive(Copy, Clone, FromPrimitive, PartialEq, Eq, Hash)]
pub enum LangItem {
$($variant),*
}
WhileLoop(&'a Expr),
}
-#[derive(Copy, PartialEq)]
+#[derive(Copy, Clone, PartialEq)]
struct Variable(usize);
#[derive(Copy, PartialEq)]
}
}
-#[derive(Copy, PartialEq, Debug)]
+#[derive(Copy, Clone, PartialEq, Debug)]
enum LiveNodeKind {
FreeVarNode(Span),
ExprNode(Span),
var_nid: NodeId
}
-#[derive(Copy, Debug)]
+#[derive(Copy, Clone, Debug)]
struct LocalInfo {
id: NodeId,
ident: ast::Ident
}
-#[derive(Copy, Debug)]
+#[derive(Copy, Clone, Debug)]
enum VarKind {
Arg(NodeId, ast::Ident),
Local(LocalInfo),
}
}
-#[derive(Copy)]
+#[derive(Copy, Clone)]
struct Specials {
exit_ln: LiveNode,
fallthrough_ln: LiveNode,
// We pun on *T to mean both actual deref of a ptr as well
// as accessing of components:
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub enum deref_kind {
deref_ptr(PointerKind),
deref_interior(InteriorKind),
}
impl<'t,TYPER:'t> Copy for MemCategorizationContext<'t,TYPER> {}
+impl<'t,TYPER:'t> Clone for MemCategorizationContext<'t,TYPER> {
+ fn clone(&self) -> MemCategorizationContext<'t,TYPER> { *self }
+}
pub type McResult<T> = Result<T, ()>;
/// reexporting a public struct doesn't inline the doc).
pub type PublicItems = NodeSet;
-#[derive(Copy, Debug)]
+#[derive(Copy, Clone, Debug)]
pub enum LastPrivate {
LastMod(PrivateDep),
// `use` directives (imports) can refer to two separate definitions in the
type_used: ImportUse},
}
-#[derive(Copy, Debug)]
+#[derive(Copy, Clone, Debug)]
pub enum PrivateDep {
AllPublic,
DependsOn(ast::DefId),
}
// How an import is used.
-#[derive(Copy, PartialEq, Debug)]
+#[derive(Copy, Clone, PartialEq, Debug)]
pub enum ImportUse {
Unused, // The import is not used.
Used, // The import is used.
}
/// The region maps encode information about region relationships.
-///
-/// - `scope_map` maps from a scope id to the enclosing scope id; this is
-/// usually corresponding to the lexical nesting, though in the case of
-/// closures the parent scope is the innermost conditional expression or repeating
-/// block. (Note that the enclosing scope id for the block
-/// associated with a closure is the closure itself.)
-///
-/// - `var_map` maps from a variable or binding id to the block in which
-/// that variable is declared.
-///
-/// - `free_region_map` maps from a free region `a` to a list of free
-/// regions `bs` such that `a <= b for all b in bs`
-/// - the free region map is populated during type check as we check
-/// each function. See the function `relate_free_regions` for
-/// more information.
-///
-/// - `rvalue_scopes` includes entries for those expressions whose cleanup
-/// scope is larger than the default. The map goes from the expression
-/// id to the cleanup scope id. For rvalues not present in this table,
-/// the appropriate cleanup scope is the innermost enclosing statement,
-/// conditional expression, or repeating block (see `terminating_scopes`).
-///
-/// - `terminating_scopes` is a set containing the ids of each statement,
-/// or conditional/repeating expression. These scopes are calling "terminating
-/// scopes" because, when attempting to find the scope of a temporary, by
-/// default we search up the enclosing scopes until we encounter the
-/// terminating scope. A conditional/repeating
-/// expression is one which is not guaranteed to execute exactly once
-/// upon entering the parent scope. This could be because the expression
-/// only executes conditionally, such as the expression `b` in `a && b`,
-/// or because the expression may execute many times, such as a loop
-/// body. The reason that we distinguish such expressions is that, upon
-/// exiting the parent scope, we cannot statically know how many times
-/// the expression executed, and thus if the expression creates
-/// temporaries we cannot know statically how many such temporaries we
-/// would have to cleanup. Therefore we ensure that the temporaries never
-/// outlast the conditional/repeating expression, preventing the need
-/// for dynamic checks and/or arbitrary amounts of stack space.
pub struct RegionMaps {
+ /// `scope_map` maps from a scope id to the enclosing scope id;
+ /// this is usually corresponding to the lexical nesting, though
+ /// in the case of closures the parent scope is the innermost
+ /// conditional expression or repeating block. (Note that the
+ /// enclosing scope id for the block associated with a closure is
+ /// the closure itself.)
scope_map: RefCell<FnvHashMap<CodeExtent, CodeExtent>>,
+
+ /// `var_map` maps from a variable or binding id to the block in
+ /// which that variable is declared.
var_map: RefCell<NodeMap<CodeExtent>>,
+
+ /// `free_region_map` maps from a free region `a` to a list of
+ /// free regions `bs` such that `a <= b for all b in bs`
+ ///
+ /// NB. the free region map is populated during type check as we
+ /// check each function. See the function `relate_free_regions`
+ /// for more information.
free_region_map: RefCell<FnvHashMap<FreeRegion, Vec<FreeRegion>>>,
+
+ /// `rvalue_scopes` includes entries for those expressions whose cleanup scope is
+ /// larger than the default. The map goes from the expression id
+ /// to the cleanup scope id. For rvalues not present in this
+ /// table, the appropriate cleanup scope is the innermost
+ /// enclosing statement, conditional expression, or repeating
+ /// block (see `terminating_scopes`).
rvalue_scopes: RefCell<NodeMap<CodeExtent>>,
+
+ /// `terminating_scopes` is a set containing the ids of each
+ /// statement, or conditional/repeating expression. These scopes
+ /// are calling "terminating scopes" because, when attempting to
+ /// find the scope of a temporary, by default we search up the
+ /// enclosing scopes until we encounter the terminating scope. A
+ /// conditional/repeating expression is one which is not
+ /// guaranteed to execute exactly once upon entering the parent
+ /// scope. This could be because the expression only executes
+ /// conditionally, such as the expression `b` in `a && b`, or
+ /// because the expression may execute many times, such as a loop
+ /// body. The reason that we distinguish such expressions is that,
+ /// upon exiting the parent scope, we cannot statically know how
+ /// many times the expression executed, and thus if the expression
+ /// creates temporaries we cannot know statically how many such
+ /// temporaries we would have to cleanup. Therefore we ensure that
+ /// the temporaries never outlast the conditional/repeating
+ /// expression, preventing the need for dynamic checks and/or
+ /// arbitrary amounts of stack space.
terminating_scopes: RefCell<FnvHashSet<CodeExtent>>,
+
+ /// Encodes the hierarchy of fn bodies. Every fn body (including
+ /// closures) forms its own distinct region hierarchy, rooted in
+ /// the block that is the fn body. This map points from the id of
+ /// that root block to the id of the root block for the enclosing
+ /// fn, if any. Thus the map structures the fn bodies into a
+ /// hierarchy based on their lexical mapping. This is used to
+ /// handle the relationships between regions in a fn and in a
+ /// closure defined by that fn. See the "Modeling closures"
+ /// section of the README in middle::infer::region_inference for
+ /// more details.
+ fn_tree: RefCell<NodeMap<ast::NodeId>>,
}
/// Carries the node id for the innermost block or match expression,
/// for building up the `var_map` which maps ids to the blocks in
/// which they were declared.
-#[derive(PartialEq, Eq, Debug, Copy)]
+#[derive(PartialEq, Eq, Debug, Copy, Clone)]
enum InnermostDeclaringBlock {
None,
Block(ast::NodeId),
/// Contextual information for declarations introduced by a statement
/// (i.e. `let`). It carries node-id's for statement and enclosing
/// block both, as well as the statement's index within the block.
-#[derive(PartialEq, Eq, Debug, Copy)]
+#[derive(PartialEq, Eq, Debug, Copy, Clone)]
struct DeclaringStatementContext {
stmt_id: ast::NodeId,
block_id: ast::NodeId,
}
}
-#[derive(PartialEq, Eq, Debug, Copy)]
+#[derive(PartialEq, Eq, Debug, Copy, Clone)]
enum InnermostEnclosingExpr {
None,
Some(ast::NodeId),
}
}
-#[derive(Debug, Copy)]
+#[derive(Debug, Copy, Clone)]
pub struct Context {
+ /// the root of the current region tree. This is typically the id
+ /// of the innermost fn body. Each fn forms its own disjoint tree
+ /// in the region hierarchy. These fn bodies are themselves
+ /// arranged into a tree. See the "Modeling closures" section of
+ /// the README in middle::infer::region_inference for more
+ /// details.
+ root_id: Option<ast::NodeId>,
+
/// the scope that contains any new variables declared
var_parent: InnermostDeclaringBlock,
self.free_region_map.borrow_mut().insert(sub, vec!(sup));
}
+ /// Records that `sub_fn` is defined within `sup_fn`. These ids
+ /// should be the id of the block that is the fn body, which is
+ /// also the root of the region hierarchy for that fn.
+ fn record_fn_parent(&self, sub_fn: ast::NodeId, sup_fn: ast::NodeId) {
+ debug!("record_fn_parent(sub_fn={:?}, sup_fn={:?})", sub_fn, sup_fn);
+ assert!(sub_fn != sup_fn);
+ let previous = self.fn_tree.borrow_mut().insert(sub_fn, sup_fn);
+ assert!(previous.is_none());
+ }
+
+ fn fn_is_enclosed_by(&self, mut sub_fn: ast::NodeId, sup_fn: ast::NodeId) -> bool {
+ let fn_tree = self.fn_tree.borrow();
+ loop {
+ if sub_fn == sup_fn { return true; }
+ match fn_tree.get(&sub_fn) {
+ Some(&s) => { sub_fn = s; }
+ None => { return false; }
+ }
+ }
+ }
+
pub fn record_encl_scope(&self, sub: CodeExtent, sup: CodeExtent) {
debug!("record_encl_scope(sub={:?}, sup={:?})", sub, sup);
assert!(sub != sup);
self.scope_map.borrow_mut().insert(sub, sup);
}
- pub fn record_var_scope(&self, var: ast::NodeId, lifetime: CodeExtent) {
+ fn record_var_scope(&self, var: ast::NodeId, lifetime: CodeExtent) {
debug!("record_var_scope(sub={:?}, sup={:?})", var, lifetime);
assert!(var != lifetime.node_id());
self.var_map.borrow_mut().insert(var, lifetime);
}
- pub fn record_rvalue_scope(&self, var: ast::NodeId, lifetime: CodeExtent) {
+ fn record_rvalue_scope(&self, var: ast::NodeId, lifetime: CodeExtent) {
debug!("record_rvalue_scope(sub={:?}, sup={:?})", var, lifetime);
assert!(var != lifetime.node_id());
self.rvalue_scopes.borrow_mut().insert(var, lifetime);
/// Records that a scope is a TERMINATING SCOPE. Whenever we create automatic temporaries --
/// e.g. by an expression like `a().f` -- they will be freed within the innermost terminating
/// scope.
- pub fn mark_as_terminating_scope(&self, scope_id: CodeExtent) {
+ fn mark_as_terminating_scope(&self, scope_id: CodeExtent) {
debug!("record_terminating_scope(scope_id={:?})", scope_id);
self.terminating_scopes.borrow_mut().insert(scope_id);
}
pub fn nearest_common_ancestor(&self,
scope_a: CodeExtent,
scope_b: CodeExtent)
- -> Option<CodeExtent> {
- if scope_a == scope_b { return Some(scope_a); }
+ -> CodeExtent {
+ if scope_a == scope_b { return scope_a; }
let a_ancestors = ancestors_of(self, scope_a);
let b_ancestors = ancestors_of(self, scope_b);
let mut a_index = a_ancestors.len() - 1;
let mut b_index = b_ancestors.len() - 1;
- // Here, ~[ab]_ancestors is a vector going from narrow to broad.
+ // Here, [ab]_ancestors is a vector going from narrow to broad.
// The end of each vector will be the item where the scope is
// defined; if there are any common ancestors, then the tails of
// the vector will be the same. So basically we want to walk
// then the corresponding scope is a superscope of the other.
if a_ancestors[a_index] != b_ancestors[b_index] {
- return None;
+ // In this case, the two regions belong to completely
+ // different functions. Compare those fn for lexical
+ // nesting. The reasoning behind this is subtle. See the
+ // "Modeling closures" section of the README in
+ // middle::infer::region_inference for more details.
+ let a_root_scope = a_ancestors[a_index];
+ let b_root_scope = a_ancestors[a_index];
+ return match (a_root_scope, b_root_scope) {
+ (CodeExtent::DestructionScope(a_root_id),
+ CodeExtent::DestructionScope(b_root_id)) => {
+ if self.fn_is_enclosed_by(a_root_id, b_root_id) {
+ // `a` is enclosed by `b`, hence `b` is the ancestor of everything in `a`
+ scope_b
+ } else if self.fn_is_enclosed_by(b_root_id, a_root_id) {
+ // `b` is enclosed by `a`, hence `a` is the ancestor of everything in `b`
+ scope_a
+ } else {
+ // neither fn encloses the other
+ unreachable!()
+ }
+ }
+ _ => {
+ // root ids are always Misc right now
+ unreachable!()
+ }
+ };
}
loop {
// Loop invariant: a_ancestors[a_index] == b_ancestors[b_index]
// for all indices between a_index and the end of the array
- if a_index == 0 { return Some(scope_a); }
- if b_index == 0 { return Some(scope_b); }
+ if a_index == 0 { return scope_a; }
+ if b_index == 0 { return scope_b; }
a_index -= 1;
b_index -= 1;
if a_ancestors[a_index] != b_ancestors[b_index] {
- return Some(a_ancestors[a_index + 1]);
+ return a_ancestors[a_index + 1];
}
}
- fn ancestors_of(this: &RegionMaps, scope: CodeExtent)
- -> Vec<CodeExtent> {
+ fn ancestors_of(this: &RegionMaps, scope: CodeExtent) -> Vec<CodeExtent> {
// debug!("ancestors_of(scope={:?})", scope);
let mut result = vec!(scope);
let mut scope = scope;
let prev_cx = visitor.cx;
let blk_scope = CodeExtent::Misc(blk.id);
+
// If block was previously marked as a terminating scope during
// the recursive visit of its parent node in the AST, then we need
// to account for the destruction scope representing the extent of
// itself has returned.
visitor.cx = Context {
+ root_id: prev_cx.root_id,
var_parent: InnermostDeclaringBlock::Block(blk.id),
parent: InnermostEnclosingExpr::Some(blk.id),
};
record_superlifetime(
visitor, declaring.to_code_extent(), statement.span);
visitor.cx = Context {
+ root_id: prev_cx.root_id,
var_parent: InnermostDeclaringBlock::Statement(declaring),
parent: InnermostEnclosingExpr::Statement(declaring),
};
// Items create a new outer block scope as far as we're concerned.
let prev_cx = visitor.cx;
visitor.cx = Context {
+ root_id: None,
var_parent: InnermostDeclaringBlock::None,
parent: InnermostEnclosingExpr::None
};
}
fn resolve_fn(visitor: &mut RegionResolutionVisitor,
- fk: FnKind,
+ _: FnKind,
decl: &ast::FnDecl,
body: &ast::Block,
sp: Span,
let body_scope = CodeExtent::from_node_id(body.id);
visitor.region_maps.mark_as_terminating_scope(body_scope);
+
let dtor_scope = CodeExtent::DestructionScope(body.id);
visitor.region_maps.record_encl_scope(body_scope, dtor_scope);
+
record_superlifetime(visitor, dtor_scope, body.span);
+ if let Some(root_id) = visitor.cx.root_id {
+ visitor.region_maps.record_fn_parent(body.id, root_id);
+ }
+
let outer_cx = visitor.cx;
// The arguments and `self` are parented to the body of the fn.
visitor.cx = Context {
+ root_id: Some(body.id),
parent: InnermostEnclosingExpr::Some(body.id),
var_parent: InnermostDeclaringBlock::Block(body.id)
};
visit::walk_fn_decl(visitor, decl);
- // The body of the fn itself is either a root scope (top-level fn)
- // or it continues with the inherited scope (closures).
- match fk {
- visit::FkItemFn(..) | visit::FkMethod(..) => {
- visitor.cx = Context {
- parent: InnermostEnclosingExpr::None,
- var_parent: InnermostDeclaringBlock::None
- };
- visitor.visit_block(body);
- visitor.cx = outer_cx;
- }
- visit::FkFnBlock(..) => {
- // FIXME(#3696) -- at present we are place the closure body
- // within the region hierarchy exactly where it appears lexically.
- // This is wrong because the closure may live longer
- // than the enclosing expression. We should probably fix this,
- // but the correct fix is a bit subtle, and I am also not sure
- // that the present approach is unsound -- it may not permit
- // any illegal programs. See issue for more details.
- visitor.cx = outer_cx;
- visitor.visit_block(body);
- }
- }
+ // The body of the every fn is a root scope.
+ visitor.cx = Context {
+ root_id: Some(body.id),
+ parent: InnermostEnclosingExpr::None,
+ var_parent: InnermostDeclaringBlock::None
+ };
+ visitor.visit_block(body);
+
+ // Restore context we had at the start.
+ visitor.cx = outer_cx;
}
impl<'a, 'v> Visitor<'v> for RegionResolutionVisitor<'a> {
free_region_map: RefCell::new(FnvHashMap()),
rvalue_scopes: RefCell::new(NodeMap()),
terminating_scopes: RefCell::new(FnvHashSet()),
+ fn_tree: RefCell::new(NodeMap()),
};
{
let mut visitor = RegionResolutionVisitor {
sess: sess,
region_maps: &maps,
cx: Context {
+ root_id: None,
parent: InnermostEnclosingExpr::None,
var_parent: InnermostDeclaringBlock::None,
}
sess: sess,
region_maps: region_maps,
cx: Context {
+ root_id: None,
parent: InnermostEnclosingExpr::None,
var_parent: InnermostDeclaringBlock::None
}
use super::project;
use super::util;
-use middle::subst::{Subst, TypeSpace};
+use middle::subst::{Subst, Substs, TypeSpace};
use middle::ty::{self, ToPolyTraitRef, Ty};
use middle::infer::{self, InferCtxt};
-use std::collections::HashSet;
use std::rc::Rc;
use syntax::ast;
-use syntax::codemap::DUMMY_SP;
+use syntax::codemap::{DUMMY_SP, Span};
use util::ppaux::Repr;
+#[derive(Copy, Clone)]
+struct ParamIsLocal(bool);
+
/// True if there exist types that satisfy both of the two given impls.
pub fn overlapping_impls(infcx: &InferCtxt,
impl1_def_id: ast::DefId,
a_def_id.repr(selcx.tcx()),
b_def_id.repr(selcx.tcx()));
- let (a_trait_ref, a_obligations) = impl_trait_ref_and_oblig(selcx, a_def_id);
- let (b_trait_ref, b_obligations) = impl_trait_ref_and_oblig(selcx, b_def_id);
+ let (a_trait_ref, a_obligations) = impl_trait_ref_and_oblig(selcx,
+ a_def_id,
+ util::free_substs_for_impl);
+
+ let (b_trait_ref, b_obligations) = impl_trait_ref_and_oblig(selcx,
+ b_def_id,
+ util::fresh_type_vars_for_impl);
debug!("overlap: a_trait_ref={}", a_trait_ref.repr(selcx.tcx()));
+
debug!("overlap: b_trait_ref={}", b_trait_ref.repr(selcx.tcx()));
// Does `a <: b` hold? If not, no overlap.
debug!("overlap: subtraitref check succeeded");
// Are any of the obligations unsatisfiable? If so, no overlap.
+ let tcx = selcx.tcx();
+ let infcx = selcx.infcx();
let opt_failing_obligation =
a_obligations.iter()
.chain(b_obligations.iter())
+ .map(|o| infcx.resolve_type_vars_if_possible(o))
.find(|o| !selcx.evaluate_obligation(o));
if let Some(failing_obligation) = opt_failing_obligation {
- debug!("overlap: obligation unsatisfiable {}", failing_obligation.repr(selcx.tcx()));
- return false;
+ debug!("overlap: obligation unsatisfiable {}", failing_obligation.repr(tcx));
+ return false
}
true
}
+pub fn trait_ref_is_knowable<'tcx>(tcx: &ty::ctxt<'tcx>, trait_ref: &ty::TraitRef<'tcx>) -> bool
+{
+ debug!("trait_ref_is_knowable(trait_ref={})", trait_ref.repr(tcx));
+
+ // if the orphan rules pass, that means that no ancestor crate can
+ // impl this, so it's up to us.
+ if orphan_check_trait_ref(tcx, trait_ref, ParamIsLocal(false)).is_ok() {
+ debug!("trait_ref_is_knowable: orphan check passed");
+ return true;
+ }
+
+ // if the trait is not marked fundamental, then it's always possible that
+ // an ancestor crate will impl this in the future, if they haven't
+ // already
+ if
+ trait_ref.def_id.krate != ast::LOCAL_CRATE &&
+ !ty::has_attr(tcx, trait_ref.def_id, "fundamental")
+ {
+ debug!("trait_ref_is_knowable: trait is neither local nor fundamental");
+ return false;
+ }
+
+ // find out when some downstream (or cousin) crate could impl this
+ // trait-ref, presuming that all the parameters were instantiated
+ // with downstream types. If not, then it could only be
+ // implemented by an upstream crate, which means that the impl
+ // must be visible to us, and -- since the trait is fundamental
+ // -- we can test.
+ orphan_check_trait_ref(tcx, trait_ref, ParamIsLocal(true)).is_err()
+}
+
+type SubstsFn = for<'a,'tcx> fn(infcx: &InferCtxt<'a, 'tcx>,
+ span: Span,
+ impl_def_id: ast::DefId)
+ -> Substs<'tcx>;
+
/// Instantiate fresh variables for all bound parameters of the impl
/// and return the impl trait ref with those variables substituted.
fn impl_trait_ref_and_oblig<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
- impl_def_id: ast::DefId)
+ impl_def_id: ast::DefId,
+ substs_fn: SubstsFn)
-> (Rc<ty::TraitRef<'tcx>>,
Vec<PredicateObligation<'tcx>>)
{
let impl_substs =
- &util::fresh_substs_for_impl(selcx.infcx(), DUMMY_SP, impl_def_id);
+ &substs_fn(selcx.infcx(), DUMMY_SP, impl_def_id);
let impl_trait_ref =
ty::impl_trait_ref(selcx.tcx(), impl_def_id).unwrap();
let impl_trait_ref =
impl_def_id: ast::DefId)
-> Result<(), OrphanCheckErr<'tcx>>
{
- debug!("impl_is_local({})", impl_def_id.repr(tcx));
+ debug!("orphan_check({})", impl_def_id.repr(tcx));
// We only except this routine to be invoked on implementations
// of a trait, not inherent implementations.
let trait_ref = ty::impl_trait_ref(tcx, impl_def_id).unwrap();
- debug!("trait_ref={}", trait_ref.repr(tcx));
+ debug!("orphan_check: trait_ref={}", trait_ref.repr(tcx));
// If the *trait* is local to the crate, ok.
if trait_ref.def_id.krate == ast::LOCAL_CRATE {
return Ok(());
}
+ orphan_check_trait_ref(tcx, &trait_ref, ParamIsLocal(false))
+}
+
+fn orphan_check_trait_ref<'tcx>(tcx: &ty::ctxt<'tcx>,
+ trait_ref: &ty::TraitRef<'tcx>,
+ param_is_local: ParamIsLocal)
+ -> Result<(), OrphanCheckErr<'tcx>>
+{
+ debug!("orphan_check_trait_ref(trait_ref={}, param_is_local={})",
+ trait_ref.repr(tcx), param_is_local.0);
+
// First, create an ordered iterator over all the type parameters to the trait, with the self
// type appearing first.
let input_tys = Some(trait_ref.self_ty());
let input_tys = input_tys.iter().chain(trait_ref.substs.types.get_slice(TypeSpace).iter());
- let mut input_tys = input_tys;
// Find the first input type that either references a type parameter OR
// some local type.
- match input_tys.find(|&&input_ty| references_local_or_type_parameter(tcx, input_ty)) {
- Some(&input_ty) => {
- // Within this first type, check that all type parameters are covered by a local
- // type constructor. Note that if there is no local type constructor, then any
- // type parameter at all will be an error.
- let covered_params = type_parameters_covered_by_ty(tcx, input_ty);
- let all_params = type_parameters_reachable_from_ty(input_ty);
- for ¶m in all_params.difference(&covered_params) {
- return Err(OrphanCheckErr::UncoveredTy(param));
+ for input_ty in input_tys {
+ if ty_is_local(tcx, input_ty, param_is_local) {
+ debug!("orphan_check_trait_ref: ty_is_local `{}`", input_ty.repr(tcx));
+
+ // First local input type. Check that there are no
+ // uncovered type parameters.
+ let uncovered_tys = uncovered_tys(tcx, input_ty, param_is_local);
+ for uncovered_ty in uncovered_tys {
+ if let Some(param) = uncovered_ty.walk().find(|t| is_type_parameter(t)) {
+ debug!("orphan_check_trait_ref: uncovered type `{}`", param.repr(tcx));
+ return Err(OrphanCheckErr::UncoveredTy(param));
+ }
}
+
+ // OK, found local type, all prior types upheld invariant.
+ return Ok(());
}
- None => {
- return Err(OrphanCheckErr::NoLocalInputType);
+
+ // Otherwise, enforce invariant that there are no type
+ // parameters reachable.
+ if !param_is_local.0 {
+ if let Some(param) = input_ty.walk().find(|t| is_type_parameter(t)) {
+ debug!("orphan_check_trait_ref: uncovered type `{}`", param.repr(tcx));
+ return Err(OrphanCheckErr::UncoveredTy(param));
+ }
}
}
- return Ok(());
+ // If we exit above loop, never found a local type.
+ debug!("orphan_check_trait_ref: no local type");
+ return Err(OrphanCheckErr::NoLocalInputType);
+}
+
+fn uncovered_tys<'tcx>(tcx: &ty::ctxt<'tcx>,
+ ty: Ty<'tcx>,
+ param_is_local: ParamIsLocal)
+ -> Vec<Ty<'tcx>>
+{
+ if ty_is_local_constructor(tcx, ty, param_is_local) {
+ vec![]
+ } else if fundamental_ty(tcx, ty) {
+ ty.walk_shallow()
+ .flat_map(|t| uncovered_tys(tcx, t, param_is_local).into_iter())
+ .collect()
+ } else {
+ vec![ty]
+ }
}
-fn ty_is_local_constructor<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool {
+fn is_type_parameter<'tcx>(ty: Ty<'tcx>) -> bool {
+ match ty.sty {
+ // FIXME(#20590) straighten story about projection types
+ ty::ty_projection(..) | ty::ty_param(..) => true,
+ _ => false,
+ }
+}
+
+fn ty_is_local<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>, param_is_local: ParamIsLocal) -> bool
+{
+ ty_is_local_constructor(tcx, ty, param_is_local) ||
+ fundamental_ty(tcx, ty) && ty.walk_shallow().any(|t| ty_is_local(tcx, t, param_is_local))
+}
+
+fn fundamental_ty<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool
+{
+ match ty.sty {
+ ty::ty_uniq(..) | ty::ty_rptr(..) =>
+ true,
+ ty::ty_enum(def_id, _) | ty::ty_struct(def_id, _) =>
+ ty::has_attr(tcx, def_id, "fundamental"),
+ ty::ty_trait(ref data) =>
+ ty::has_attr(tcx, data.principal_def_id(), "fundamental"),
+ _ =>
+ false
+ }
+}
+
+fn ty_is_local_constructor<'tcx>(tcx: &ty::ctxt<'tcx>,
+ ty: Ty<'tcx>,
+ param_is_local: ParamIsLocal)
+ -> bool
+{
debug!("ty_is_local_constructor({})", ty.repr(tcx));
match ty.sty {
ty::ty_ptr(..) |
ty::ty_rptr(..) |
ty::ty_tup(..) |
- ty::ty_param(..) |
+ ty::ty_infer(..) |
ty::ty_projection(..) => {
false
}
+ ty::ty_param(..) => {
+ param_is_local.0
+ }
+
ty::ty_enum(def_id, _) |
ty::ty_struct(def_id, _) => {
def_id.krate == ast::LOCAL_CRATE
}
ty::ty_closure(..) |
- ty::ty_infer(..) |
ty::ty_err => {
tcx.sess.bug(
&format!("ty_is_local invoked on unexpected type: {}",
}
}
-fn type_parameters_covered_by_ty<'tcx>(tcx: &ty::ctxt<'tcx>,
- ty: Ty<'tcx>)
- -> HashSet<Ty<'tcx>>
-{
- if ty_is_local_constructor(tcx, ty) {
- type_parameters_reachable_from_ty(ty)
- } else {
- ty.walk_children().flat_map(|t| type_parameters_covered_by_ty(tcx, t).into_iter()).collect()
- }
-}
-
-/// All type parameters reachable from `ty`
-fn type_parameters_reachable_from_ty<'tcx>(ty: Ty<'tcx>) -> HashSet<Ty<'tcx>> {
- ty.walk().filter(|&t| is_type_parameter(t)).collect()
-}
-
-fn references_local_or_type_parameter<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool {
- ty.walk().any(|ty| is_type_parameter(ty) || ty_is_local_constructor(tcx, ty))
-}
-fn is_type_parameter<'tcx>(ty: Ty<'tcx>) -> bool {
- match ty.sty {
- // FIXME(#20590) straighten story about projection types
- ty::ty_projection(..) | ty::ty_param(..) => true,
- _ => false,
- }
-}
obligation.repr(selcx.tcx()));
let infcx = selcx.infcx();
- infcx.try(|snapshot| {
+ infcx.commit_if_ok(|snapshot| {
let (skol_predicate, skol_map) =
infcx.skolemize_late_bound_regions(&obligation.predicate, snapshot);
}
}
+#[derive(Clone)]
pub struct Normalized<'tcx,T> {
pub value: T,
pub obligations: Vec<PredicateObligation<'tcx>>,
use self::BuiltinBoundConditions::*;
use self::EvaluationResult::*;
+use super::coherence;
use super::DerivedObligationCause;
use super::project;
use super::project::{normalize_with_depth, Normalized};
use middle::infer;
use middle::infer::{InferCtxt, TypeFreshener};
use middle::ty_fold::TypeFoldable;
+use middle::ty_match;
+use middle::ty_relate::TypeRelation;
use std::cell::RefCell;
-use std::collections::hash_map::HashMap;
use std::rc::Rc;
use syntax::{abi, ast};
use util::common::ErrorReported;
+use util::nodemap::FnvHashMap;
use util::ppaux::Repr;
pub struct SelectionContext<'cx, 'tcx:'cx> {
/// selection-context's freshener. Used to check for recursion.
fresh_trait_ref: ty::PolyTraitRef<'tcx>,
- previous: Option<&'prev TraitObligationStack<'prev, 'tcx>>
+ previous: TraitObligationStackList<'prev, 'tcx>,
}
#[derive(Clone)]
pub struct SelectionCache<'tcx> {
- hashmap: RefCell<HashMap<Rc<ty::TraitRef<'tcx>>,
- SelectionResult<'tcx, SelectionCandidate<'tcx>>>>,
+ hashmap: RefCell<FnvHashMap<Rc<ty::TraitRef<'tcx>>,
+ SelectionResult<'tcx, SelectionCandidate<'tcx>>>>,
}
pub enum MethodMatchResult {
MethodDidNotMatch,
}
-#[derive(Copy, Debug)]
+#[derive(Copy, Clone, Debug)]
pub enum MethodMatchedData {
// In the case of a precise match, we don't really need to store
// how the match was found. So don't.
debug!("select({})", obligation.repr(self.tcx()));
assert!(!obligation.predicate.has_escaping_regions());
- let stack = self.push_stack(None, obligation);
+ let stack = self.push_stack(TraitObligationStackList::empty(), obligation);
match try!(self.candidate_from_obligation(&stack)) {
None => {
self.consider_unification_despite_ambiguity(obligation);
debug!("evaluate_obligation({})",
obligation.repr(self.tcx()));
- self.evaluate_predicate_recursively(None, obligation).may_apply()
+ self.evaluate_predicate_recursively(TraitObligationStackList::empty(), obligation)
+ .may_apply()
}
fn evaluate_builtin_bound_recursively<'o>(&mut self,
match obligation {
Ok(obligation) => {
- self.evaluate_predicate_recursively(Some(previous_stack), &obligation)
+ self.evaluate_predicate_recursively(previous_stack.list(), &obligation)
}
Err(ErrorReported) => {
EvaluatedToOk
}
fn evaluate_predicates_recursively<'a,'o,I>(&mut self,
- stack: Option<&TraitObligationStack<'o, 'tcx>>,
+ stack: TraitObligationStackList<'o, 'tcx>,
predicates: I)
-> EvaluationResult<'tcx>
where I : Iterator<Item=&'a PredicateObligation<'tcx>>, 'tcx:'a
}
fn evaluate_predicate_recursively<'o>(&mut self,
- previous_stack: Option<&TraitObligationStack<'o, 'tcx>>,
+ previous_stack: TraitObligationStackList<'o, 'tcx>,
obligation: &PredicateObligation<'tcx>)
-> EvaluationResult<'tcx>
{
}
fn evaluate_obligation_recursively<'o>(&mut self,
- previous_stack: Option<&TraitObligationStack<'o, 'tcx>>,
+ previous_stack: TraitObligationStackList<'o, 'tcx>,
obligation: &TraitObligation<'tcx>)
-> EvaluationResult<'tcx>
{
debug!("evaluate_obligation_recursively({})",
obligation.repr(self.tcx()));
- let stack = self.push_stack(previous_stack.map(|x| x), obligation);
+ let stack = self.push_stack(previous_stack, obligation);
let result = self.evaluate_stack(&stack);
unbound_input_types &&
(self.intercrate ||
stack.iter().skip(1).any(
- |prev| stack.fresh_trait_ref.def_id() == prev.fresh_trait_ref.def_id()))
+ |prev| self.match_fresh_trait_refs(&stack.fresh_trait_ref,
+ &prev.fresh_trait_ref)))
{
debug!("evaluate_stack({}) --> unbound argument, recursion --> ambiguous",
stack.fresh_trait_ref.repr(self.tcx()));
obligation.recursion_depth + 1,
skol_map,
snapshot);
- self.winnow_selection(None, VtableImpl(vtable_impl)).may_apply()
+ self.winnow_selection(TraitObligationStackList::empty(),
+ VtableImpl(vtable_impl)).may_apply()
}
Err(()) => {
false
return Ok(Some(ErrorCandidate));
}
+ if !self.is_knowable(stack) {
+ debug!("intercrate not knowable");
+ return Ok(None);
+ }
+
let candidate_set = try!(self.assemble_candidates(stack));
if candidate_set.ambiguous {
Ok(Some(candidate))
}
+ fn is_knowable<'o>(&mut self,
+ stack: &TraitObligationStack<'o, 'tcx>)
+ -> bool
+ {
+ debug!("is_knowable(intercrate={})", self.intercrate);
+
+ if !self.intercrate {
+ return true;
+ }
+
+ let obligation = &stack.obligation;
+ let predicate = self.infcx().resolve_type_vars_if_possible(&obligation.predicate);
+
+ // ok to skip binder because of the nature of the
+ // trait-ref-is-knowable check, which does not care about
+ // bound regions
+ let trait_ref = &predicate.skip_binder().trait_ref;
+
+ coherence::trait_ref_is_knowable(self.tcx(), trait_ref)
+ }
+
fn pick_candidate_cache(&self) -> &SelectionCache<'tcx> {
// If there are any where-clauses in scope, then we always use
// a cache local to this particular scope. Otherwise, we
self.infcx().probe(move |_| {
match self.match_where_clause_trait_ref(stack.obligation, where_clause_trait_ref) {
Ok(obligations) => {
- self.evaluate_predicates_recursively(Some(stack), obligations.iter())
+ self.evaluate_predicates_recursively(stack.list(), obligations.iter())
}
Err(()) => {
EvaluatedToErr(Unimplemented)
return;
}
- self.infcx.try(|snapshot| {
+ self.infcx.commit_if_ok(|snapshot| {
let bound_self_ty =
self.infcx.resolve_type_vars_if_possible(&obligation.self_ty());
let (self_ty, _) =
let result = self.infcx.probe(|_| {
let candidate = (*candidate).clone();
match self.confirm_candidate(stack.obligation, candidate) {
- Ok(selection) => self.winnow_selection(Some(stack), selection),
+ Ok(selection) => self.winnow_selection(stack.list(),
+ selection),
Err(error) => EvaluatedToErr(error),
}
});
}
fn winnow_selection<'o>(&mut self,
- stack: Option<&TraitObligationStack<'o, 'tcx>>,
+ stack: TraitObligationStackList<'o,'tcx>,
selection: Selection<'tcx>)
-> EvaluationResult<'tcx>
{
// For each type, produce a vector of resulting obligations
let obligations: Result<Vec<Vec<_>>, _> = bound_types.iter().map(|nested_ty| {
- self.infcx.try(|snapshot| {
+ self.infcx.commit_if_ok(|snapshot| {
let (skol_ty, skol_map) =
self.infcx().skolemize_late_bound_regions(nested_ty, snapshot);
let Normalized { value: normalized_ty, mut obligations } =
obligation: &TraitObligation<'tcx>)
{
let _: Result<(),()> =
- self.infcx.try(|snapshot| {
+ self.infcx.commit_if_ok(|snapshot| {
let result =
self.match_projection_obligation_against_bounds_from_trait(obligation,
snapshot);
trait_def_id,
nested);
- let trait_obligations: Result<VecPerParamSpace<_>,()> = self.infcx.try(|snapshot| {
+ let trait_obligations: Result<VecPerParamSpace<_>,()> = self.infcx.commit_if_ok(|snapshot| {
let poly_trait_ref = obligation.predicate.to_poly_trait_ref();
let (trait_ref, skol_map) =
self.infcx().skolemize_late_bound_regions(&poly_trait_ref, snapshot);
// First, create the substitutions by matching the impl again,
// this time not in a probe.
- self.infcx.try(|snapshot| {
+ self.infcx.commit_if_ok(|snapshot| {
let (skol_obligation_trait_ref, skol_map) =
self.infcx().skolemize_late_bound_regions(&obligation.predicate, snapshot);
let substs =
return Err(());
}
- let impl_substs = util::fresh_substs_for_impl(self.infcx,
- obligation.cause.span,
- impl_def_id);
+ let impl_substs = util::fresh_type_vars_for_impl(self.infcx,
+ obligation.cause.span,
+ impl_def_id);
let impl_trait_ref = impl_trait_ref.subst(self.tcx(),
&impl_substs);
{
// Create fresh type variables for each type parameter declared
// on the impl etc.
- let impl_substs = util::fresh_substs_for_impl(self.infcx,
- obligation_cause.span,
- impl_def_id);
+ let impl_substs = util::fresh_type_vars_for_impl(self.infcx,
+ obligation_cause.span,
+ impl_def_id);
// Find the self type for the impl.
let impl_self_ty = ty::lookup_item_type(self.tcx(), impl_def_id).ty;
///////////////////////////////////////////////////////////////////////////
// Miscellany
+ fn match_fresh_trait_refs(&self,
+ previous: &ty::PolyTraitRef<'tcx>,
+ current: &ty::PolyTraitRef<'tcx>)
+ -> bool
+ {
+ let mut matcher = ty_match::Match::new(self.tcx());
+ matcher.relate(previous, current).is_ok()
+ }
+
fn push_stack<'o,'s:'o>(&mut self,
- previous_stack: Option<&'s TraitObligationStack<'s, 'tcx>>,
+ previous_stack: TraitObligationStackList<'s, 'tcx>,
obligation: &'o TraitObligation<'tcx>)
-> TraitObligationStack<'o, 'tcx>
{
TraitObligationStack {
obligation: obligation,
fresh_trait_ref: fresh_trait_ref,
- previous: previous_stack.map(|p| p), // FIXME variance
+ previous: previous_stack,
}
}
impl<'tcx> SelectionCache<'tcx> {
pub fn new() -> SelectionCache<'tcx> {
SelectionCache {
- hashmap: RefCell::new(HashMap::new())
+ hashmap: RefCell::new(FnvHashMap())
}
}
}
-impl<'o, 'tcx> TraitObligationStack<'o, 'tcx> {
- fn iter(&self) -> Option<&TraitObligationStack<'o, 'tcx>> {
- Some(self)
+impl<'o,'tcx> TraitObligationStack<'o,'tcx> {
+ fn list(&'o self) -> TraitObligationStackList<'o,'tcx> {
+ TraitObligationStackList::with(self)
}
+
+ fn iter(&'o self) -> TraitObligationStackList<'o,'tcx> {
+ self.list()
+ }
+}
+
+#[derive(Copy, Clone)]
+struct TraitObligationStackList<'o,'tcx:'o> {
+ head: Option<&'o TraitObligationStack<'o,'tcx>>
}
-impl<'o, 'tcx> Iterator for Option<&'o TraitObligationStack<'o, 'tcx>> {
+impl<'o,'tcx> TraitObligationStackList<'o,'tcx> {
+ fn empty() -> TraitObligationStackList<'o,'tcx> {
+ TraitObligationStackList { head: None }
+ }
+
+ fn with(r: &'o TraitObligationStack<'o,'tcx>) -> TraitObligationStackList<'o,'tcx> {
+ TraitObligationStackList { head: Some(r) }
+ }
+}
+
+impl<'o,'tcx> Iterator for TraitObligationStackList<'o,'tcx>{
type Item = &'o TraitObligationStack<'o,'tcx>;
- fn next(&mut self) -> Option<&'o TraitObligationStack<'o, 'tcx>> {
- match *self {
+ fn next(&mut self) -> Option<&'o TraitObligationStack<'o,'tcx>> {
+ match self.head {
Some(o) => {
*self = o.previous;
Some(o)
}
}
-impl<'o, 'tcx> Repr<'tcx> for TraitObligationStack<'o, 'tcx> {
+impl<'o,'tcx> Repr<'tcx> for TraitObligationStack<'o,'tcx> {
fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
format!("TraitObligationStack({})",
self.obligation.repr(tcx))
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use middle::region;
use middle::subst::{Substs, VecPerParamSpace};
use middle::infer::InferCtxt;
use middle::ty::{self, Ty, AsPredicate, ToPolyTraitRef};
}
}
-
///////////////////////////////////////////////////////////////////////////
// Other
///////////////////////////////////////////////////////////////////////////
// declared on the impl declaration e.g., `impl<A,B> for Box<[(A,B)]>`
// would return ($0, $1) where $0 and $1 are freshly instantiated type
// variables.
-pub fn fresh_substs_for_impl<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
- span: Span,
- impl_def_id: ast::DefId)
- -> Substs<'tcx>
+pub fn fresh_type_vars_for_impl<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
+ span: Span,
+ impl_def_id: ast::DefId)
+ -> Substs<'tcx>
{
let tcx = infcx.tcx;
let impl_generics = ty::lookup_item_type(tcx, impl_def_id).generics;
infcx.fresh_substs_for_generics(span, &impl_generics)
}
+// determine the `self` type, using fresh variables for all variables
+// declared on the impl declaration e.g., `impl<A,B> for Box<[(A,B)]>`
+// would return ($0, $1) where $0 and $1 are freshly instantiated type
+// variables.
+pub fn free_substs_for_impl<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
+ _span: Span,
+ impl_def_id: ast::DefId)
+ -> Substs<'tcx>
+{
+ let tcx = infcx.tcx;
+ let impl_generics = ty::lookup_item_type(tcx, impl_def_id).generics;
+
+ let some_types = impl_generics.types.map(|def| {
+ ty::mk_param_from_def(tcx, def)
+ });
+
+ let some_regions = impl_generics.regions.map(|def| {
+ // FIXME. This destruction scope information is pretty darn
+ // bogus; after all, the impl might not even be in this crate!
+ // But given what we do in coherence, it is harmless enough
+ // for now I think. -nmatsakis
+ let extent = region::DestructionScopeData::new(ast::DUMMY_NODE_ID);
+ ty::free_region_from_def(extent, def)
+ });
+
+ Substs::new(some_types, some_regions)
+}
+
impl<'tcx, N> fmt::Debug for VtableImplData<'tcx, N> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "VtableImpl({:?})", self.impl_def_id)
use middle::traits;
use middle::ty;
use middle::ty_fold::{self, TypeFoldable, TypeFolder};
-use middle::ty_walk::TypeWalker;
+use middle::ty_walk::{self, TypeWalker};
use util::ppaux::{note_and_explain_region, bound_region_ptr_to_string};
use util::ppaux::ty_to_string;
use util::ppaux::{Repr, UserString};
use arena::TypedArena;
use std::borrow::{Borrow, Cow};
-use std::cell::{Cell, RefCell};
+use std::cell::{Cell, RefCell, Ref};
use std::cmp;
use std::fmt;
use std::hash::{Hash, SipHasher, Hasher};
use std::mem;
+use std::num::ToPrimitive;
use std::ops;
use std::rc::Rc;
use std::vec::IntoIter;
use syntax::ast::{MutImmutable, MutMutable, Name, NamedField, NodeId};
use syntax::ast::{StmtExpr, StmtSemi, StructField, UnnamedField, Visibility};
use syntax::ast_util::{self, is_local, lit_is_str, local_def};
-use syntax::attr::{self, AttrMetaMethods};
+use syntax::attr::{self, AttrMetaMethods, SignedInt, UnsignedInt};
use syntax::codemap::Span;
use syntax::parse::token::{self, InternedString, special_idents};
-use syntax::{ast, ast_map};
+use syntax::print::pprust;
+use syntax::ptr::P;
+use syntax::ast;
+use syntax::ast_map::{self, LinkedPath};
pub type Disr = u64;
// Contains information needed to resolve types and (in the future) look up
// the types of AST nodes.
-#[derive(Copy, PartialEq, Eq, Hash)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub struct creader_cache_key {
pub cnum: CrateNum,
pub pos: usize,
/// will push one or more such restriction into the
/// `transmute_restrictions` vector during `intrinsicck`. They are
/// then checked during `trans` by the fn `check_intrinsics`.
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub struct TransmuteRestriction<'tcx> {
/// The span whence the restriction comes.
pub span: Span,
/// Stores the types for various nodes in the AST. Note that this table
/// is not guaranteed to be populated until after typeck. See
/// typeck::check::fn_ctxt for details.
- pub node_types: RefCell<NodeMap<Ty<'tcx>>>,
+ node_types: RefCell<NodeMap<Ty<'tcx>>>,
/// Stores the type parameters which were substituted to obtain the type
/// of this node. This only applies to nodes that refer to entities
pub const_qualif_map: RefCell<NodeMap<check_const::ConstQualif>>,
}
+impl<'tcx> ctxt<'tcx> {
+ pub fn node_types(&self) -> Ref<NodeMap<Ty<'tcx>>> { self.node_types.borrow() }
+ pub fn node_type_insert(&self, id: NodeId, ty: Ty<'tcx>) {
+ self.node_types.borrow_mut().insert(id, ty);
+ }
+}
+
// Flags that we track on types. These flags are propagated upwards
// through the type during type construction, so that we can quickly
// check whether the type has various kinds of types in it without
// variable names.
mod inner {
use middle::ty;
- #[derive(Copy)]
+ #[derive(Copy, Clone)]
struct DebugStat {
total: usize,
region_infer: usize,
TypeWalker::new(self)
}
- /// Iterator that walks types reachable from `self`, in
- /// depth-first order. Note that this is a shallow walk. For
- /// example:
- ///
- /// ```notrust
- /// isize => { }
- /// Foo<Bar<isize>> => { Bar<isize>, isize }
- /// [isize] => { isize }
- /// ```
- pub fn walk_children(&'tcx self) -> TypeWalker<'tcx> {
- // Walks type reachable from `self` but not `self
- let mut walker = self.walk();
- let r = walker.next();
- assert_eq!(r, Some(self));
- walker
+ /// Iterator that walks the immediate children of `self`. Hence
+ /// `Foo<Bar<i32>, u32>` yields the sequence `[Bar<i32>, u32]`
+ /// (but not `i32`, like `walk`).
+ pub fn walk_shallow(&'tcx self) -> IntoIter<Ty<'tcx>> {
+ ty_walk::walk_shallow(self)
}
pub fn as_opt_param_ty(&self) -> Option<ty::ParamTy> {
///
/// The ordering of the cases is significant. They are sorted so that cmp::max
/// will keep the "more erroneous" of two values.
-#[derive(Copy, PartialOrd, Ord, Eq, PartialEq, Debug)]
+#[derive(Copy, Clone, PartialOrd, Ord, Eq, PartialEq, Debug)]
pub enum Representability {
Representable,
ContainsRecursive,
/// two kinds of rvalues is an artifact of trans which reflects how we will
/// generate code for that kind of expression. See trans/expr.rs for more
/// information.
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub enum ExprKind {
LvalueExpr,
RvalueDpsExpr,
with_path(cx, id, |path| ast_map::path_to_string(path)).to_string()
}
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub enum DtorKind {
NoDtor,
TraitDtor(DefId, bool)
if id.krate == ast::LOCAL_CRATE {
cx.map.with_path(id.node, f)
} else {
- f(csearch::get_item_path(cx, id).iter().cloned().chain(None))
+ f(csearch::get_item_path(cx, id).iter().cloned().chain(LinkedPath::empty()))
}
}
}
}
+trait IntTypeExt {
+ fn to_ty<'tcx>(&self, cx: &ctxt<'tcx>) -> Ty<'tcx>;
+ fn i64_to_disr(&self, val: i64) -> Option<Disr>;
+ fn u64_to_disr(&self, val: u64) -> Option<Disr>;
+ fn disr_incr(&self, val: Disr) -> Option<Disr>;
+ fn disr_string(&self, val: Disr) -> String;
+ fn disr_wrap_incr(&self, val: Option<Disr>) -> Disr;
+}
+
+impl IntTypeExt for attr::IntType {
+ fn to_ty<'tcx>(&self, cx: &ctxt<'tcx>) -> Ty<'tcx> {
+ match *self {
+ SignedInt(ast::TyI8) => cx.types.i8,
+ SignedInt(ast::TyI16) => cx.types.i16,
+ SignedInt(ast::TyI32) => cx.types.i32,
+ SignedInt(ast::TyI64) => cx.types.i64,
+ SignedInt(ast::TyIs) => cx.types.isize,
+ UnsignedInt(ast::TyU8) => cx.types.u8,
+ UnsignedInt(ast::TyU16) => cx.types.u16,
+ UnsignedInt(ast::TyU32) => cx.types.u32,
+ UnsignedInt(ast::TyU64) => cx.types.u64,
+ UnsignedInt(ast::TyUs) => cx.types.usize,
+ }
+ }
+
+ fn i64_to_disr(&self, val: i64) -> Option<Disr> {
+ match *self {
+ SignedInt(ast::TyI8) => val.to_i8() .map(|v| v as Disr),
+ SignedInt(ast::TyI16) => val.to_i16() .map(|v| v as Disr),
+ SignedInt(ast::TyI32) => val.to_i32() .map(|v| v as Disr),
+ SignedInt(ast::TyI64) => val.to_i64() .map(|v| v as Disr),
+ UnsignedInt(ast::TyU8) => val.to_u8() .map(|v| v as Disr),
+ UnsignedInt(ast::TyU16) => val.to_u16() .map(|v| v as Disr),
+ UnsignedInt(ast::TyU32) => val.to_u32() .map(|v| v as Disr),
+ UnsignedInt(ast::TyU64) => val.to_u64() .map(|v| v as Disr),
+
+ UnsignedInt(ast::TyUs) |
+ SignedInt(ast::TyIs) => unreachable!(),
+ }
+ }
+
+ fn u64_to_disr(&self, val: u64) -> Option<Disr> {
+ match *self {
+ SignedInt(ast::TyI8) => val.to_i8() .map(|v| v as Disr),
+ SignedInt(ast::TyI16) => val.to_i16() .map(|v| v as Disr),
+ SignedInt(ast::TyI32) => val.to_i32() .map(|v| v as Disr),
+ SignedInt(ast::TyI64) => val.to_i64() .map(|v| v as Disr),
+ UnsignedInt(ast::TyU8) => val.to_u8() .map(|v| v as Disr),
+ UnsignedInt(ast::TyU16) => val.to_u16() .map(|v| v as Disr),
+ UnsignedInt(ast::TyU32) => val.to_u32() .map(|v| v as Disr),
+ UnsignedInt(ast::TyU64) => val.to_u64() .map(|v| v as Disr),
+
+ UnsignedInt(ast::TyUs) |
+ SignedInt(ast::TyIs) => unreachable!(),
+ }
+ }
+
+ fn disr_incr(&self, val: Disr) -> Option<Disr> {
+ macro_rules! add1 {
+ ($e:expr) => { $e.and_then(|v|v.checked_add(1)).map(|v| v as Disr) }
+ }
+ match *self {
+ // SignedInt repr means we *want* to reinterpret the bits
+ // treating the highest bit of Disr as a sign-bit, so
+ // cast to i64 before range-checking.
+ SignedInt(ast::TyI8) => add1!((val as i64).to_i8()),
+ SignedInt(ast::TyI16) => add1!((val as i64).to_i16()),
+ SignedInt(ast::TyI32) => add1!((val as i64).to_i32()),
+ SignedInt(ast::TyI64) => add1!(Some(val as i64)),
+
+ UnsignedInt(ast::TyU8) => add1!(val.to_u8()),
+ UnsignedInt(ast::TyU16) => add1!(val.to_u16()),
+ UnsignedInt(ast::TyU32) => add1!(val.to_u32()),
+ UnsignedInt(ast::TyU64) => add1!(Some(val)),
+
+ UnsignedInt(ast::TyUs) |
+ SignedInt(ast::TyIs) => unreachable!(),
+ }
+ }
+
+ // This returns a String because (1.) it is only used for
+ // rendering an error message and (2.) a string can represent the
+ // full range from `i64::MIN` through `u64::MAX`.
+ fn disr_string(&self, val: Disr) -> String {
+ match *self {
+ SignedInt(ast::TyI8) => format!("{}", val as i8 ),
+ SignedInt(ast::TyI16) => format!("{}", val as i16),
+ SignedInt(ast::TyI32) => format!("{}", val as i32),
+ SignedInt(ast::TyI64) => format!("{}", val as i64),
+ UnsignedInt(ast::TyU8) => format!("{}", val as u8 ),
+ UnsignedInt(ast::TyU16) => format!("{}", val as u16),
+ UnsignedInt(ast::TyU32) => format!("{}", val as u32),
+ UnsignedInt(ast::TyU64) => format!("{}", val as u64),
+
+ UnsignedInt(ast::TyUs) |
+ SignedInt(ast::TyIs) => unreachable!(),
+ }
+ }
+
+ fn disr_wrap_incr(&self, val: Option<Disr>) -> Disr {
+ macro_rules! add1 {
+ ($e:expr) => { ($e).wrapping_add(1) as Disr }
+ }
+ let val = val.unwrap_or(ty::INITIAL_DISCRIMINANT_VALUE);
+ match *self {
+ SignedInt(ast::TyI8) => add1!(val as i8 ),
+ SignedInt(ast::TyI16) => add1!(val as i16),
+ SignedInt(ast::TyI32) => add1!(val as i32),
+ SignedInt(ast::TyI64) => add1!(val as i64),
+ UnsignedInt(ast::TyU8) => add1!(val as u8 ),
+ UnsignedInt(ast::TyU16) => add1!(val as u16),
+ UnsignedInt(ast::TyU32) => add1!(val as u32),
+ UnsignedInt(ast::TyU64) => add1!(val as u64),
+
+ UnsignedInt(ast::TyUs) |
+ SignedInt(ast::TyIs) => unreachable!(),
+ }
+ }
+}
+
+/// Returns `(normalized_type, ty)`, where `normalized_type` is the
+/// IntType representation of one of {i64,i32,i16,i8,u64,u32,u16,u8},
+/// and `ty` is the original type (i.e. may include `isize` or
+/// `usize`).
+pub fn enum_repr_type<'tcx>(cx: &ctxt<'tcx>,
+ opt_hint: Option<&attr::ReprAttr>)
+ -> (attr::IntType, Ty<'tcx>)
+{
+ let repr_type = match opt_hint {
+ // Feed in the given type
+ Some(&attr::ReprInt(_, int_t)) => int_t,
+ // ... but provide sensible default if none provided
+ //
+ // NB. Historically `fn enum_variants` generate i64 here, while
+ // rustc_typeck::check would generate isize.
+ _ => SignedInt(ast::TyIs),
+ };
+
+ let repr_type_ty = repr_type.to_ty(cx);
+ let repr_type = match repr_type {
+ SignedInt(ast::TyIs) =>
+ SignedInt(cx.sess.target.int_type),
+ UnsignedInt(ast::TyUs) =>
+ UnsignedInt(cx.sess.target.uint_type),
+ other => other
+ };
+
+ (repr_type, repr_type_ty)
+}
+
+fn report_discrim_overflow(cx: &ctxt,
+ variant_span: Span,
+ variant_name: &str,
+ repr_type: attr::IntType,
+ prev_val: Disr) {
+ let computed_value = repr_type.disr_wrap_incr(Some(prev_val));
+ let computed_value = repr_type.disr_string(computed_value);
+ let prev_val = repr_type.disr_string(prev_val);
+ let repr_type = repr_type.to_ty(cx).user_string(cx);
+ span_err!(cx.sess, variant_span, E0370,
+ "enum discriminant overflowed on value after {}: {}; \
+ set explicitly via {} = {} if that is desired outcome",
+ prev_val, repr_type, variant_name, computed_value);
+}
+
+// This computes the discriminant values for the sequence of Variants
+// attached to a particular enum, taking into account the #[repr] (if
+// any) provided via the `opt_hint`.
+fn compute_enum_variants<'tcx>(cx: &ctxt<'tcx>,
+ vs: &'tcx [P<ast::Variant>],
+ opt_hint: Option<&attr::ReprAttr>)
+ -> Vec<Rc<ty::VariantInfo<'tcx>>> {
+ let mut variants: Vec<Rc<ty::VariantInfo>> = Vec::new();
+ let mut prev_disr_val: Option<ty::Disr> = None;
+
+ let (repr_type, repr_type_ty) = ty::enum_repr_type(cx, opt_hint);
+
+ for v in vs {
+ // If the discriminant value is specified explicitly in the
+ // enum, check whether the initialization expression is valid,
+ // otherwise use the last value plus one.
+ let current_disr_val;
+
+ // This closure marks cases where, when an error occurs during
+ // the computation, attempt to assign a (hopefully) fresh
+ // value to avoid spurious error reports downstream.
+ let attempt_fresh_value = move || -> Disr {
+ repr_type.disr_wrap_incr(prev_disr_val)
+ };
+
+ match v.node.disr_expr {
+ Some(ref e) => {
+ debug!("disr expr, checking {}", pprust::expr_to_string(&**e));
+
+ // check_expr (from check_const pass) doesn't guarantee
+ // that the expression is in a form that eval_const_expr can
+ // handle, so we may still get an internal compiler error
+ //
+ // pnkfelix: The above comment was transcribed from
+ // the version of this code taken from rustc_typeck.
+ // Presumably the implication is that we need to deal
+ // with such ICE's as they arise.
+ //
+ // Since this can be called from `ty::enum_variants`
+ // anyway, best thing is to make `eval_const_expr`
+ // more robust (on case-by-case basis).
+
+ match const_eval::eval_const_expr_partial(cx, &**e, Some(repr_type_ty)) {
+ Ok(const_eval::const_int(val)) => current_disr_val = val as Disr,
+ Ok(const_eval::const_uint(val)) => current_disr_val = val as Disr,
+ Ok(_) => {
+ span_err!(cx.sess, e.span, E0079,
+ "expected signed integer constant");
+ current_disr_val = attempt_fresh_value();
+ }
+ Err(ref err) => {
+ span_err!(cx.sess, err.span, E0080,
+ "constant evaluation error: {}",
+ err.description());
+ current_disr_val = attempt_fresh_value();
+ }
+ }
+ },
+ None => {
+ current_disr_val = match prev_disr_val {
+ Some(prev_disr_val) => {
+ if let Some(v) = repr_type.disr_incr(prev_disr_val) {
+ v
+ } else {
+ report_discrim_overflow(cx, v.span, v.node.name.as_str(),
+ repr_type, prev_disr_val);
+ attempt_fresh_value()
+ }
+ }
+ None => ty::INITIAL_DISCRIMINANT_VALUE
+ }
+ }
+ }
+
+ let variant_info = Rc::new(VariantInfo::from_ast_variant(cx, &**v, current_disr_val));
+ prev_disr_val = Some(current_disr_val);
+
+ variants.push(variant_info);
+ }
+
+ return variants;
+}
+
pub fn enum_variants<'tcx>(cx: &ctxt<'tcx>, id: ast::DefId)
-> Rc<Vec<Rc<VariantInfo<'tcx>>>> {
memoized(&cx.enum_var_cache, id, |id: ast::DefId| {
if ast::LOCAL_CRATE != id.krate {
Rc::new(csearch::get_enum_variants(cx, id))
} else {
- /*
- Although both this code and check_enum_variants in typeck/check
- call eval_const_expr, it should never get called twice for the same
- expr, since check_enum_variants also updates the enum_var_cache
- */
match cx.map.get(id.node) {
ast_map::NodeItem(ref item) => {
match item.node {
ast::ItemEnum(ref enum_definition, _) => {
- let mut last_discriminant: Option<Disr> = None;
- Rc::new(enum_definition.variants.iter().map(|variant| {
-
- let mut discriminant = INITIAL_DISCRIMINANT_VALUE;
- if let Some(ref e) = variant.node.disr_expr {
- // Preserve all values, and prefer signed.
- let ty = Some(cx.types.i64);
- match const_eval::eval_const_expr_partial(cx, &**e, ty) {
- Ok(const_eval::const_int(val)) => {
- discriminant = val as Disr;
- }
- Ok(const_eval::const_uint(val)) => {
- discriminant = val as Disr;
- }
- Ok(_) => {
- span_err!(cx.sess, e.span, E0304,
- "expected signed integer constant");
- }
- Err(err) => {
- span_err!(cx.sess, err.span, E0305,
- "constant evaluation error: {}",
- err.description());
- }
- }
- } else {
- if let Some(val) = last_discriminant {
- if let Some(v) = val.checked_add(1) {
- discriminant = v
- } else {
- cx.sess.span_err(
- variant.span,
- &format!("Discriminant overflowed!"));
- }
- } else {
- discriminant = INITIAL_DISCRIMINANT_VALUE;
- }
- }
-
- last_discriminant = Some(discriminant);
- Rc::new(VariantInfo::from_ast_variant(cx, &**variant,
- discriminant))
- }).collect())
+ Rc::new(compute_enum_variants(
+ cx,
+ &enum_definition.variants,
+ lookup_repr_hints(cx, id).get(0)))
}
_ => {
cx.sess.bug("enum_variants: id not bound to an enum")
"expected positive integer for repeat count, found {}",
found);
}
- Err(_) => {
+ Err(err) => {
+ let err_description = err.description();
let found = match count_expr.node {
ast::ExprPath(None, ast::Path {
global: false,
ref segments,
..
}) if segments.len() == 1 =>
- "variable",
+ format!("{}", "found variable"),
_ =>
- "non-constant expression"
+ format!("but {}", err_description),
};
span_err!(tcx.sess, count_expr.span, E0307,
- "expected constant integer for repeat count, found {}",
+ "expected constant integer for repeat count, {}",
found);
}
}
trait_ref.substs.clone().with_method(meth_tps, meth_regions)
}
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub enum CopyImplementationError {
FieldDoesNotImplementCopy(ast::Name),
VariantDoesNotImplementCopy(ast::Name),
use middle::ty::{self, Ty};
use middle::traits;
use std::rc::Rc;
+use syntax::abi;
+use syntax::ast;
use syntax::owned_slice::OwnedSlice;
use util::ppaux::Repr;
/// The TypeFoldable trait is implemented for every type that can be folded.
/// Basically, every type that has a corresponding method in TypeFolder.
-pub trait TypeFoldable<'tcx> {
+pub trait TypeFoldable<'tcx>: Repr<'tcx> + Clone {
fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self;
}
// can easily refactor the folding into the TypeFolder trait as
// needed.
-impl<'tcx> TypeFoldable<'tcx> for () {
- fn fold_with<F:TypeFolder<'tcx>>(&self, _: &mut F) -> () {
- ()
+macro_rules! CopyImpls {
+ ($($ty:ty),+) => {
+ $(
+ impl<'tcx> TypeFoldable<'tcx> for $ty {
+ fn fold_with<F:TypeFolder<'tcx>>(&self, _: &mut F) -> $ty {
+ *self
+ }
+ }
+ )+
}
}
+CopyImpls! { (), ast::Unsafety, abi::Abi }
+
impl<'tcx, T:TypeFoldable<'tcx>, U:TypeFoldable<'tcx>> TypeFoldable<'tcx> for (T, U) {
fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> (T, U) {
(self.0.fold_with(folder), self.1.fold_with(folder))
--- /dev/null
+// Copyright 2012 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 middle::ty::{self, Ty};
+use middle::ty_relate::{self, Relate, TypeRelation, RelateResult};
+use util::ppaux::Repr;
+
+/// A type "A" *matches* "B" if the fresh types in B could be
+/// substituted with values so as to make it equal to A. Matching is
+/// intended to be used only on freshened types, and it basically
+/// indicates if the non-freshened versions of A and B could have been
+/// unified.
+///
+/// It is only an approximation. If it yields false, unification would
+/// definitely fail, but a true result doesn't mean unification would
+/// succeed. This is because we don't track the "side-constraints" on
+/// type variables, nor do we track if the same freshened type appears
+/// more than once. To some extent these approximations could be
+/// fixed, given effort.
+///
+/// Like subtyping, matching is really a binary relation, so the only
+/// important thing about the result is Ok/Err. Also, matching never
+/// affects any type variables or unification state.
+pub struct Match<'a, 'tcx: 'a> {
+ tcx: &'a ty::ctxt<'tcx>
+}
+
+impl<'a, 'tcx> Match<'a, 'tcx> {
+ pub fn new(tcx: &'a ty::ctxt<'tcx>) -> Match<'a, 'tcx> {
+ Match { tcx: tcx }
+ }
+}
+
+impl<'a, 'tcx> TypeRelation<'a, 'tcx> for Match<'a, 'tcx> {
+ fn tag(&self) -> &'static str { "Match" }
+ fn tcx(&self) -> &'a ty::ctxt<'tcx> { self.tcx }
+ fn a_is_expected(&self) -> bool { true } // irrelevant
+
+ fn relate_with_variance<T:Relate<'a,'tcx>>(&mut self,
+ _: ty::Variance,
+ a: &T,
+ b: &T)
+ -> RelateResult<'tcx, T>
+ {
+ self.relate(a, b)
+ }
+
+ fn regions(&mut self, a: ty::Region, b: ty::Region) -> RelateResult<'tcx, ty::Region> {
+ debug!("{}.regions({}, {})",
+ self.tag(),
+ a.repr(self.tcx()),
+ b.repr(self.tcx()));
+ Ok(a)
+ }
+
+ fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
+ debug!("{}.tys({}, {})", self.tag(),
+ a.repr(self.tcx()), b.repr(self.tcx()));
+ if a == b { return Ok(a); }
+
+ match (&a.sty, &b.sty) {
+ (_, &ty::ty_infer(ty::FreshTy(_))) |
+ (_, &ty::ty_infer(ty::FreshIntTy(_))) => {
+ Ok(a)
+ }
+
+ (&ty::ty_infer(_), _) |
+ (_, &ty::ty_infer(_)) => {
+ Err(ty::terr_sorts(ty_relate::expected_found(self, &a, &b)))
+ }
+
+ (&ty::ty_err, _) | (_, &ty::ty_err) => {
+ Ok(self.tcx().types.err)
+ }
+
+ _ => {
+ ty_relate::super_relate_tys(self, a, b)
+ }
+ }
+ }
+
+ fn binders<T>(&mut self, a: &ty::Binder<T>, b: &ty::Binder<T>)
+ -> RelateResult<'tcx, ty::Binder<T>>
+ where T: Relate<'a,'tcx>
+ {
+ Ok(ty::Binder(try!(self.relate(a.skip_binder(), b.skip_binder()))))
+ }
+}
--- /dev/null
+// Copyright 2012-2013 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.
+
+//! Generalized type relating mechanism. A type relation R relates a
+//! pair of values (A, B). A and B are usually types or regions but
+//! can be other things. Examples of type relations are subtyping,
+//! type equality, etc.
+
+use middle::subst::{ErasedRegions, NonerasedRegions, ParamSpace, Substs};
+use middle::ty::{self, Ty};
+use middle::ty_fold::TypeFoldable;
+use std::rc::Rc;
+use syntax::abi;
+use syntax::ast;
+use util::ppaux::Repr;
+
+pub type RelateResult<'tcx, T> = Result<T, ty::type_err<'tcx>>;
+
+pub trait TypeRelation<'a,'tcx> : Sized {
+ fn tcx(&self) -> &'a ty::ctxt<'tcx>;
+
+ /// Returns a static string we can use for printouts.
+ fn tag(&self) -> &'static str;
+
+ /// Returns true if the value `a` is the "expected" type in the
+ /// relation. Just affects error messages.
+ fn a_is_expected(&self) -> bool;
+
+ /// Generic relation routine suitable for most anything.
+ fn relate<T:Relate<'a,'tcx>>(&mut self, a: &T, b: &T) -> RelateResult<'tcx, T> {
+ Relate::relate(self, a, b)
+ }
+
+ /// Switch variance for the purpose of relating `a` and `b`.
+ fn relate_with_variance<T:Relate<'a,'tcx>>(&mut self,
+ variance: ty::Variance,
+ a: &T,
+ b: &T)
+ -> RelateResult<'tcx, T>;
+
+ // Overrideable relations. You shouldn't typically call these
+ // directly, instead call `relate()`, which in turn calls
+ // these. This is both more uniform but also allows us to add
+ // additional hooks for other types in the future if needed
+ // without making older code, which called `relate`, obsolete.
+
+ fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>)
+ -> RelateResult<'tcx, Ty<'tcx>>;
+
+ fn regions(&mut self, a: ty::Region, b: ty::Region)
+ -> RelateResult<'tcx, ty::Region>;
+
+ fn binders<T>(&mut self, a: &ty::Binder<T>, b: &ty::Binder<T>)
+ -> RelateResult<'tcx, ty::Binder<T>>
+ where T: Relate<'a,'tcx>;
+}
+
+pub trait Relate<'a,'tcx>: TypeFoldable<'tcx> {
+ fn relate<R:TypeRelation<'a,'tcx>>(relation: &mut R,
+ a: &Self,
+ b: &Self)
+ -> RelateResult<'tcx, Self>;
+}
+
+///////////////////////////////////////////////////////////////////////////
+// Relate impls
+
+impl<'a,'tcx:'a> Relate<'a,'tcx> for ty::mt<'tcx> {
+ fn relate<R>(relation: &mut R,
+ a: &ty::mt<'tcx>,
+ b: &ty::mt<'tcx>)
+ -> RelateResult<'tcx, ty::mt<'tcx>>
+ where R: TypeRelation<'a,'tcx>
+ {
+ debug!("{}.mts({}, {})",
+ relation.tag(),
+ a.repr(relation.tcx()),
+ b.repr(relation.tcx()));
+ if a.mutbl != b.mutbl {
+ Err(ty::terr_mutability)
+ } else {
+ let mutbl = a.mutbl;
+ let variance = match mutbl {
+ ast::MutImmutable => ty::Covariant,
+ ast::MutMutable => ty::Invariant,
+ };
+ let ty = try!(relation.relate_with_variance(variance, &a.ty, &b.ty));
+ Ok(ty::mt {ty: ty, mutbl: mutbl})
+ }
+ }
+}
+
+// substitutions are not themselves relatable without more context,
+// but they is an important subroutine for things that ARE relatable,
+// like traits etc.
+fn relate_item_substs<'a,'tcx:'a,R>(relation: &mut R,
+ item_def_id: ast::DefId,
+ a_subst: &Substs<'tcx>,
+ b_subst: &Substs<'tcx>)
+ -> RelateResult<'tcx, Substs<'tcx>>
+ where R: TypeRelation<'a,'tcx>
+{
+ debug!("substs: item_def_id={} a_subst={} b_subst={}",
+ item_def_id.repr(relation.tcx()),
+ a_subst.repr(relation.tcx()),
+ b_subst.repr(relation.tcx()));
+
+ let variances;
+ let opt_variances = if relation.tcx().variance_computed.get() {
+ variances = ty::item_variances(relation.tcx(), item_def_id);
+ Some(&*variances)
+ } else {
+ None
+ };
+ relate_substs(relation, opt_variances, a_subst, b_subst)
+}
+
+fn relate_substs<'a,'tcx,R>(relation: &mut R,
+ variances: Option<&ty::ItemVariances>,
+ a_subst: &Substs<'tcx>,
+ b_subst: &Substs<'tcx>)
+ -> RelateResult<'tcx, Substs<'tcx>>
+ where R: TypeRelation<'a,'tcx>
+{
+ let mut substs = Substs::empty();
+
+ for &space in &ParamSpace::all() {
+ let a_tps = a_subst.types.get_slice(space);
+ let b_tps = b_subst.types.get_slice(space);
+ let t_variances = variances.map(|v| v.types.get_slice(space));
+ let tps = try!(relate_type_params(relation, t_variances, a_tps, b_tps));
+ substs.types.replace(space, tps);
+ }
+
+ match (&a_subst.regions, &b_subst.regions) {
+ (&ErasedRegions, _) | (_, &ErasedRegions) => {
+ substs.regions = ErasedRegions;
+ }
+
+ (&NonerasedRegions(ref a), &NonerasedRegions(ref b)) => {
+ for &space in &ParamSpace::all() {
+ let a_regions = a.get_slice(space);
+ let b_regions = b.get_slice(space);
+ let r_variances = variances.map(|v| v.regions.get_slice(space));
+ let regions = try!(relate_region_params(relation,
+ r_variances,
+ a_regions,
+ b_regions));
+ substs.mut_regions().replace(space, regions);
+ }
+ }
+ }
+
+ Ok(substs)
+}
+
+fn relate_type_params<'a,'tcx,R>(relation: &mut R,
+ variances: Option<&[ty::Variance]>,
+ a_tys: &[Ty<'tcx>],
+ b_tys: &[Ty<'tcx>])
+ -> RelateResult<'tcx, Vec<Ty<'tcx>>>
+ where R: TypeRelation<'a,'tcx>
+{
+ if a_tys.len() != b_tys.len() {
+ return Err(ty::terr_ty_param_size(expected_found(relation,
+ &a_tys.len(),
+ &b_tys.len())));
+ }
+
+ (0 .. a_tys.len())
+ .map(|i| {
+ let a_ty = a_tys[i];
+ let b_ty = b_tys[i];
+ let v = variances.map_or(ty::Invariant, |v| v[i]);
+ relation.relate_with_variance(v, &a_ty, &b_ty)
+ })
+ .collect()
+}
+
+fn relate_region_params<'a,'tcx:'a,R>(relation: &mut R,
+ variances: Option<&[ty::Variance]>,
+ a_rs: &[ty::Region],
+ b_rs: &[ty::Region])
+ -> RelateResult<'tcx, Vec<ty::Region>>
+ where R: TypeRelation<'a,'tcx>
+{
+ let tcx = relation.tcx();
+ let num_region_params = a_rs.len();
+
+ debug!("relate_region_params(a_rs={}, \
+ b_rs={}, variances={})",
+ a_rs.repr(tcx),
+ b_rs.repr(tcx),
+ variances.repr(tcx));
+
+ assert_eq!(num_region_params,
+ variances.map_or(num_region_params,
+ |v| v.len()));
+
+ assert_eq!(num_region_params, b_rs.len());
+
+ (0..a_rs.len())
+ .map(|i| {
+ let a_r = a_rs[i];
+ let b_r = b_rs[i];
+ let variance = variances.map_or(ty::Invariant, |v| v[i]);
+ relation.relate_with_variance(variance, &a_r, &b_r)
+ })
+ .collect()
+}
+
+impl<'a,'tcx:'a> Relate<'a,'tcx> for ty::BareFnTy<'tcx> {
+ fn relate<R>(relation: &mut R,
+ a: &ty::BareFnTy<'tcx>,
+ b: &ty::BareFnTy<'tcx>)
+ -> RelateResult<'tcx, ty::BareFnTy<'tcx>>
+ where R: TypeRelation<'a,'tcx>
+ {
+ let unsafety = try!(relation.relate(&a.unsafety, &b.unsafety));
+ let abi = try!(relation.relate(&a.abi, &b.abi));
+ let sig = try!(relation.relate(&a.sig, &b.sig));
+ Ok(ty::BareFnTy {unsafety: unsafety,
+ abi: abi,
+ sig: sig})
+ }
+}
+
+impl<'a,'tcx:'a> Relate<'a,'tcx> for ty::FnSig<'tcx> {
+ fn relate<R>(relation: &mut R,
+ a: &ty::FnSig<'tcx>,
+ b: &ty::FnSig<'tcx>)
+ -> RelateResult<'tcx, ty::FnSig<'tcx>>
+ where R: TypeRelation<'a,'tcx>
+ {
+ if a.variadic != b.variadic {
+ return Err(ty::terr_variadic_mismatch(
+ expected_found(relation, &a.variadic, &b.variadic)));
+ }
+
+ let inputs = try!(relate_arg_vecs(relation,
+ &a.inputs,
+ &b.inputs));
+
+ let output = try!(match (a.output, b.output) {
+ (ty::FnConverging(a_ty), ty::FnConverging(b_ty)) =>
+ Ok(ty::FnConverging(try!(relation.relate(&a_ty, &b_ty)))),
+ (ty::FnDiverging, ty::FnDiverging) =>
+ Ok(ty::FnDiverging),
+ (a, b) =>
+ Err(ty::terr_convergence_mismatch(
+ expected_found(relation, &(a != ty::FnDiverging), &(b != ty::FnDiverging)))),
+ });
+
+ return Ok(ty::FnSig {inputs: inputs,
+ output: output,
+ variadic: a.variadic});
+ }
+}
+
+fn relate_arg_vecs<'a,'tcx,R>(relation: &mut R,
+ a_args: &[Ty<'tcx>],
+ b_args: &[Ty<'tcx>])
+ -> RelateResult<'tcx, Vec<Ty<'tcx>>>
+ where R: TypeRelation<'a,'tcx>
+{
+ if a_args.len() != b_args.len() {
+ return Err(ty::terr_arg_count);
+ }
+
+ a_args.iter()
+ .zip(b_args.iter())
+ .map(|(a, b)| relation.relate_with_variance(ty::Contravariant, a, b))
+ .collect()
+}
+
+impl<'a,'tcx:'a> Relate<'a,'tcx> for ast::Unsafety {
+ fn relate<R>(relation: &mut R,
+ a: &ast::Unsafety,
+ b: &ast::Unsafety)
+ -> RelateResult<'tcx, ast::Unsafety>
+ where R: TypeRelation<'a,'tcx>
+ {
+ if a != b {
+ Err(ty::terr_unsafety_mismatch(expected_found(relation, a, b)))
+ } else {
+ Ok(*a)
+ }
+ }
+}
+
+impl<'a,'tcx:'a> Relate<'a,'tcx> for abi::Abi {
+ fn relate<R>(relation: &mut R,
+ a: &abi::Abi,
+ b: &abi::Abi)
+ -> RelateResult<'tcx, abi::Abi>
+ where R: TypeRelation<'a,'tcx>
+ {
+ if a == b {
+ Ok(*a)
+ } else {
+ Err(ty::terr_abi_mismatch(expected_found(relation, a, b)))
+ }
+ }
+}
+
+impl<'a,'tcx:'a> Relate<'a,'tcx> for ty::ProjectionTy<'tcx> {
+ fn relate<R>(relation: &mut R,
+ a: &ty::ProjectionTy<'tcx>,
+ b: &ty::ProjectionTy<'tcx>)
+ -> RelateResult<'tcx, ty::ProjectionTy<'tcx>>
+ where R: TypeRelation<'a,'tcx>
+ {
+ if a.item_name != b.item_name {
+ Err(ty::terr_projection_name_mismatched(
+ expected_found(relation, &a.item_name, &b.item_name)))
+ } else {
+ let trait_ref = try!(relation.relate(&*a.trait_ref, &*b.trait_ref));
+ Ok(ty::ProjectionTy { trait_ref: Rc::new(trait_ref), item_name: a.item_name })
+ }
+ }
+}
+
+impl<'a,'tcx:'a> Relate<'a,'tcx> for ty::ProjectionPredicate<'tcx> {
+ fn relate<R>(relation: &mut R,
+ a: &ty::ProjectionPredicate<'tcx>,
+ b: &ty::ProjectionPredicate<'tcx>)
+ -> RelateResult<'tcx, ty::ProjectionPredicate<'tcx>>
+ where R: TypeRelation<'a,'tcx>
+ {
+ let projection_ty = try!(relation.relate(&a.projection_ty, &b.projection_ty));
+ let ty = try!(relation.relate(&a.ty, &b.ty));
+ Ok(ty::ProjectionPredicate { projection_ty: projection_ty, ty: ty })
+ }
+}
+
+impl<'a,'tcx:'a> Relate<'a,'tcx> for Vec<ty::PolyProjectionPredicate<'tcx>> {
+ fn relate<R>(relation: &mut R,
+ a: &Vec<ty::PolyProjectionPredicate<'tcx>>,
+ b: &Vec<ty::PolyProjectionPredicate<'tcx>>)
+ -> RelateResult<'tcx, Vec<ty::PolyProjectionPredicate<'tcx>>>
+ where R: TypeRelation<'a,'tcx>
+ {
+ // To be compatible, `a` and `b` must be for precisely the
+ // same set of traits and item names. We always require that
+ // projection bounds lists are sorted by trait-def-id and item-name,
+ // so we can just iterate through the lists pairwise, so long as they are the
+ // same length.
+ if a.len() != b.len() {
+ Err(ty::terr_projection_bounds_length(expected_found(relation, &a.len(), &b.len())))
+ } else {
+ a.iter()
+ .zip(b.iter())
+ .map(|(a, b)| relation.relate(a, b))
+ .collect()
+ }
+ }
+}
+
+impl<'a,'tcx:'a> Relate<'a,'tcx> for ty::ExistentialBounds<'tcx> {
+ fn relate<R>(relation: &mut R,
+ a: &ty::ExistentialBounds<'tcx>,
+ b: &ty::ExistentialBounds<'tcx>)
+ -> RelateResult<'tcx, ty::ExistentialBounds<'tcx>>
+ where R: TypeRelation<'a,'tcx>
+ {
+ let r = try!(relation.relate_with_variance(ty::Contravariant,
+ &a.region_bound,
+ &b.region_bound));
+ let nb = try!(relation.relate(&a.builtin_bounds, &b.builtin_bounds));
+ let pb = try!(relation.relate(&a.projection_bounds, &b.projection_bounds));
+ Ok(ty::ExistentialBounds { region_bound: r,
+ builtin_bounds: nb,
+ projection_bounds: pb })
+ }
+}
+
+impl<'a,'tcx:'a> Relate<'a,'tcx> for ty::BuiltinBounds {
+ fn relate<R>(relation: &mut R,
+ a: &ty::BuiltinBounds,
+ b: &ty::BuiltinBounds)
+ -> RelateResult<'tcx, ty::BuiltinBounds>
+ where R: TypeRelation<'a,'tcx>
+ {
+ // Two sets of builtin bounds are only relatable if they are
+ // precisely the same (but see the coercion code).
+ if a != b {
+ Err(ty::terr_builtin_bounds(expected_found(relation, a, b)))
+ } else {
+ Ok(*a)
+ }
+ }
+}
+
+impl<'a,'tcx:'a> Relate<'a,'tcx> for ty::TraitRef<'tcx> {
+ fn relate<R>(relation: &mut R,
+ a: &ty::TraitRef<'tcx>,
+ b: &ty::TraitRef<'tcx>)
+ -> RelateResult<'tcx, ty::TraitRef<'tcx>>
+ where R: TypeRelation<'a,'tcx>
+ {
+ // Different traits cannot be related
+ if a.def_id != b.def_id {
+ Err(ty::terr_traits(expected_found(relation, &a.def_id, &b.def_id)))
+ } else {
+ let substs = try!(relate_item_substs(relation, a.def_id, a.substs, b.substs));
+ Ok(ty::TraitRef { def_id: a.def_id, substs: relation.tcx().mk_substs(substs) })
+ }
+ }
+}
+
+impl<'a,'tcx:'a> Relate<'a,'tcx> for Ty<'tcx> {
+ fn relate<R>(relation: &mut R,
+ a: &Ty<'tcx>,
+ b: &Ty<'tcx>)
+ -> RelateResult<'tcx, Ty<'tcx>>
+ where R: TypeRelation<'a,'tcx>
+ {
+ relation.tys(a, b)
+ }
+}
+
+/// The main "type relation" routine. Note that this does not handle
+/// inference artifacts, so you should filter those out before calling
+/// it.
+pub fn super_relate_tys<'a,'tcx:'a,R>(relation: &mut R,
+ a: Ty<'tcx>,
+ b: Ty<'tcx>)
+ -> RelateResult<'tcx, Ty<'tcx>>
+ where R: TypeRelation<'a,'tcx>
+{
+ let tcx = relation.tcx();
+ let a_sty = &a.sty;
+ let b_sty = &b.sty;
+ debug!("super_tys: a_sty={:?} b_sty={:?}", a_sty, b_sty);
+ match (a_sty, b_sty) {
+ (&ty::ty_infer(_), _) |
+ (_, &ty::ty_infer(_)) =>
+ {
+ // The caller should handle these cases!
+ tcx.sess.bug("var types encountered in super_relate_tys")
+ }
+
+ (&ty::ty_err, _) | (_, &ty::ty_err) =>
+ {
+ Ok(tcx.types.err)
+ }
+
+ (&ty::ty_char, _) |
+ (&ty::ty_bool, _) |
+ (&ty::ty_int(_), _) |
+ (&ty::ty_uint(_), _) |
+ (&ty::ty_float(_), _) |
+ (&ty::ty_str, _)
+ if a == b =>
+ {
+ Ok(a)
+ }
+
+ (&ty::ty_param(ref a_p), &ty::ty_param(ref b_p))
+ if a_p.idx == b_p.idx && a_p.space == b_p.space =>
+ {
+ Ok(a)
+ }
+
+ (&ty::ty_enum(a_id, a_substs), &ty::ty_enum(b_id, b_substs))
+ if a_id == b_id =>
+ {
+ let substs = try!(relate_item_substs(relation, a_id, a_substs, b_substs));
+ Ok(ty::mk_enum(tcx, a_id, tcx.mk_substs(substs)))
+ }
+
+ (&ty::ty_trait(ref a_), &ty::ty_trait(ref b_)) =>
+ {
+ let principal = try!(relation.relate(&a_.principal, &b_.principal));
+ let bounds = try!(relation.relate(&a_.bounds, &b_.bounds));
+ Ok(ty::mk_trait(tcx, principal, bounds))
+ }
+
+ (&ty::ty_struct(a_id, a_substs), &ty::ty_struct(b_id, b_substs))
+ if a_id == b_id =>
+ {
+ let substs = try!(relate_item_substs(relation, a_id, a_substs, b_substs));
+ Ok(ty::mk_struct(tcx, a_id, tcx.mk_substs(substs)))
+ }
+
+ (&ty::ty_closure(a_id, a_substs),
+ &ty::ty_closure(b_id, b_substs))
+ if a_id == b_id =>
+ {
+ // All ty_closure types with the same id represent
+ // the (anonymous) type of the same closure expression. So
+ // all of their regions should be equated.
+ let substs = try!(relate_substs(relation, None, a_substs, b_substs));
+ Ok(ty::mk_closure(tcx, a_id, tcx.mk_substs(substs)))
+ }
+
+ (&ty::ty_uniq(a_inner), &ty::ty_uniq(b_inner)) =>
+ {
+ let typ = try!(relation.relate(&a_inner, &b_inner));
+ Ok(ty::mk_uniq(tcx, typ))
+ }
+
+ (&ty::ty_ptr(ref a_mt), &ty::ty_ptr(ref b_mt)) =>
+ {
+ let mt = try!(relation.relate(a_mt, b_mt));
+ Ok(ty::mk_ptr(tcx, mt))
+ }
+
+ (&ty::ty_rptr(a_r, ref a_mt), &ty::ty_rptr(b_r, ref b_mt)) =>
+ {
+ let r = try!(relation.relate_with_variance(ty::Contravariant, a_r, b_r));
+ let mt = try!(relation.relate(a_mt, b_mt));
+ Ok(ty::mk_rptr(tcx, tcx.mk_region(r), mt))
+ }
+
+ (&ty::ty_vec(a_t, Some(sz_a)), &ty::ty_vec(b_t, Some(sz_b))) =>
+ {
+ let t = try!(relation.relate(&a_t, &b_t));
+ if sz_a == sz_b {
+ Ok(ty::mk_vec(tcx, t, Some(sz_a)))
+ } else {
+ Err(ty::terr_fixed_array_size(expected_found(relation, &sz_a, &sz_b)))
+ }
+ }
+
+ (&ty::ty_vec(a_t, None), &ty::ty_vec(b_t, None)) =>
+ {
+ let t = try!(relation.relate(&a_t, &b_t));
+ Ok(ty::mk_vec(tcx, t, None))
+ }
+
+ (&ty::ty_tup(ref as_), &ty::ty_tup(ref bs)) =>
+ {
+ if as_.len() == bs.len() {
+ let ts = try!(as_.iter()
+ .zip(bs.iter())
+ .map(|(a, b)| relation.relate(a, b))
+ .collect::<Result<_, _>>());
+ Ok(ty::mk_tup(tcx, ts))
+ } else if as_.len() != 0 && bs.len() != 0 {
+ Err(ty::terr_tuple_size(
+ expected_found(relation, &as_.len(), &bs.len())))
+ } else {
+ Err(ty::terr_sorts(expected_found(relation, &a, &b)))
+ }
+ }
+
+ (&ty::ty_bare_fn(a_opt_def_id, a_fty), &ty::ty_bare_fn(b_opt_def_id, b_fty))
+ if a_opt_def_id == b_opt_def_id =>
+ {
+ let fty = try!(relation.relate(a_fty, b_fty));
+ Ok(ty::mk_bare_fn(tcx, a_opt_def_id, tcx.mk_bare_fn(fty)))
+ }
+
+ (&ty::ty_projection(ref a_data), &ty::ty_projection(ref b_data)) =>
+ {
+ let projection_ty = try!(relation.relate(a_data, b_data));
+ Ok(ty::mk_projection(tcx, projection_ty.trait_ref, projection_ty.item_name))
+ }
+
+ _ =>
+ {
+ Err(ty::terr_sorts(expected_found(relation, &a, &b)))
+ }
+ }
+}
+
+impl<'a,'tcx:'a> Relate<'a,'tcx> for ty::Region {
+ fn relate<R>(relation: &mut R,
+ a: &ty::Region,
+ b: &ty::Region)
+ -> RelateResult<'tcx, ty::Region>
+ where R: TypeRelation<'a,'tcx>
+ {
+ relation.regions(*a, *b)
+ }
+}
+
+impl<'a,'tcx:'a,T> Relate<'a,'tcx> for ty::Binder<T>
+ where T: Relate<'a,'tcx>
+{
+ fn relate<R>(relation: &mut R,
+ a: &ty::Binder<T>,
+ b: &ty::Binder<T>)
+ -> RelateResult<'tcx, ty::Binder<T>>
+ where R: TypeRelation<'a,'tcx>
+ {
+ relation.binders(a, b)
+ }
+}
+
+impl<'a,'tcx:'a,T> Relate<'a,'tcx> for Rc<T>
+ where T: Relate<'a,'tcx>
+{
+ fn relate<R>(relation: &mut R,
+ a: &Rc<T>,
+ b: &Rc<T>)
+ -> RelateResult<'tcx, Rc<T>>
+ where R: TypeRelation<'a,'tcx>
+ {
+ let a: &T = a;
+ let b: &T = b;
+ Ok(Rc::new(try!(relation.relate(a, b))))
+ }
+}
+
+impl<'a,'tcx:'a,T> Relate<'a,'tcx> for Box<T>
+ where T: Relate<'a,'tcx>
+{
+ fn relate<R>(relation: &mut R,
+ a: &Box<T>,
+ b: &Box<T>)
+ -> RelateResult<'tcx, Box<T>>
+ where R: TypeRelation<'a,'tcx>
+ {
+ let a: &T = a;
+ let b: &T = b;
+ Ok(Box::new(try!(relation.relate(a, b))))
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////
+// Error handling
+
+pub fn expected_found<'a,'tcx,R,T>(relation: &mut R,
+ a: &T,
+ b: &T)
+ -> ty::expected_found<T>
+ where R: TypeRelation<'a,'tcx>, T: Clone
+{
+ expected_found_bool(relation.a_is_expected(), a, b)
+}
+
+pub fn expected_found_bool<T>(a_is_expected: bool,
+ a: &T,
+ b: &T)
+ -> ty::expected_found<T>
+ where T: Clone
+{
+ let a = a.clone();
+ let b = b.clone();
+ if a_is_expected {
+ ty::expected_found {expected: a, found: b}
+ } else {
+ ty::expected_found {expected: b, found: a}
+ }
+}
+
use middle::ty::{self, Ty};
use std::iter::Iterator;
+use std::vec::IntoIter;
pub struct TypeWalker<'tcx> {
stack: Vec<Ty<'tcx>>,
TypeWalker { stack: vec!(ty), last_subtree: 1, }
}
- fn push_subtypes(&mut self, parent_ty: Ty<'tcx>) {
- match parent_ty.sty {
- ty::ty_bool | ty::ty_char | ty::ty_int(_) | ty::ty_uint(_) | ty::ty_float(_) |
- ty::ty_str | ty::ty_infer(_) | ty::ty_param(_) | ty::ty_err => {
- }
- ty::ty_uniq(ty) | ty::ty_vec(ty, _) => {
- self.stack.push(ty);
- }
- ty::ty_ptr(ref mt) | ty::ty_rptr(_, ref mt) => {
- self.stack.push(mt.ty);
- }
- ty::ty_projection(ref data) => {
- self.push_reversed(data.trait_ref.substs.types.as_slice());
- }
- ty::ty_trait(box ty::TyTrait { ref principal, ref bounds }) => {
- self.push_reversed(principal.substs().types.as_slice());
- self.push_reversed(&bounds.projection_bounds.iter().map(|pred| {
- pred.0.ty
- }).collect::<Vec<_>>());
- }
- ty::ty_enum(_, ref substs) |
- ty::ty_struct(_, ref substs) |
- ty::ty_closure(_, ref substs) => {
- self.push_reversed(substs.types.as_slice());
- }
- ty::ty_tup(ref ts) => {
- self.push_reversed(ts);
- }
- ty::ty_bare_fn(_, ref ft) => {
- self.push_sig_subtypes(&ft.sig);
- }
- }
- }
-
- fn push_sig_subtypes(&mut self, sig: &ty::PolyFnSig<'tcx>) {
- match sig.0.output {
- ty::FnConverging(output) => { self.stack.push(output); }
- ty::FnDiverging => { }
- }
- self.push_reversed(&sig.0.inputs);
- }
-
- fn push_reversed(&mut self, tys: &[Ty<'tcx>]) {
- // We push slices on the stack in reverse order so as to
- // maintain a pre-order traversal. As of the time of this
- // writing, the fact that the traversal is pre-order is not
- // known to be significant to any code, but it seems like the
- // natural order one would expect (basically, the order of the
- // types as they are written).
- for &ty in tys.iter().rev() {
- self.stack.push(ty);
- }
- }
-
/// Skips the subtree of types corresponding to the last type
/// returned by `next()`.
///
}
Some(ty) => {
self.last_subtree = self.stack.len();
- self.push_subtypes(ty);
+ push_subtypes(&mut self.stack, ty);
debug!("next: stack={:?}", self.stack);
Some(ty)
}
}
}
}
+
+pub fn walk_shallow<'tcx>(ty: Ty<'tcx>) -> IntoIter<Ty<'tcx>> {
+ let mut stack = vec![];
+ push_subtypes(&mut stack, ty);
+ stack.into_iter()
+}
+
+fn push_subtypes<'tcx>(stack: &mut Vec<Ty<'tcx>>, parent_ty: Ty<'tcx>) {
+ match parent_ty.sty {
+ ty::ty_bool | ty::ty_char | ty::ty_int(_) | ty::ty_uint(_) | ty::ty_float(_) |
+ ty::ty_str | ty::ty_infer(_) | ty::ty_param(_) | ty::ty_err => {
+ }
+ ty::ty_uniq(ty) | ty::ty_vec(ty, _) => {
+ stack.push(ty);
+ }
+ ty::ty_ptr(ref mt) | ty::ty_rptr(_, ref mt) => {
+ stack.push(mt.ty);
+ }
+ ty::ty_projection(ref data) => {
+ push_reversed(stack, data.trait_ref.substs.types.as_slice());
+ }
+ ty::ty_trait(box ty::TyTrait { ref principal, ref bounds }) => {
+ push_reversed(stack, principal.substs().types.as_slice());
+ push_reversed(stack, &bounds.projection_bounds.iter().map(|pred| {
+ pred.0.ty
+ }).collect::<Vec<_>>());
+ }
+ ty::ty_enum(_, ref substs) |
+ ty::ty_struct(_, ref substs) |
+ ty::ty_closure(_, ref substs) => {
+ push_reversed(stack, substs.types.as_slice());
+ }
+ ty::ty_tup(ref ts) => {
+ push_reversed(stack, ts);
+ }
+ ty::ty_bare_fn(_, ref ft) => {
+ push_sig_subtypes(stack, &ft.sig);
+ }
+ }
+}
+
+fn push_sig_subtypes<'tcx>(stack: &mut Vec<Ty<'tcx>>, sig: &ty::PolyFnSig<'tcx>) {
+ match sig.0.output {
+ ty::FnConverging(output) => { stack.push(output); }
+ ty::FnDiverging => { }
+ }
+ push_reversed(stack, &sig.0.inputs);
+}
+
+fn push_reversed<'tcx>(stack: &mut Vec<Ty<'tcx>>, tys: &[Ty<'tcx>]) {
+ // We push slices on the stack in reverse order so as to
+ // maintain a pre-order traversal. As of the time of this
+ // writing, the fact that the traversal is pre-order is not
+ // known to be significant to any code, but it seems like the
+ // natural order one would expect (basically, the order of the
+ // types as they are written).
+ for &ty in tys.iter().rev() {
+ stack.push(ty);
+ }
+}
// users can have their own entry
// functions that don't start a
// scheduler
-#[derive(Copy, PartialEq)]
+#[derive(Copy, Clone, PartialEq)]
pub enum EntryFnType {
EntryMain,
EntryStart,
{
let mut op = $defaultfn();
for option in matches.opt_strs($prefix) {
- let mut iter = option.splitn(1, '=');
+ let mut iter = option.splitn(2, '=');
let key = iter.next().unwrap();
let value = iter.next();
let option_to_lookup = key.replace("-", "_");
}
let libs = matches.opt_strs("l").into_iter().map(|s| {
- let mut parts = s.splitn(1, '=');
+ let mut parts = s.splitn(2, '=');
let kind = parts.next().unwrap();
let (name, kind) = match (parts.next(), kind) {
(None, name) |
let mut externs = HashMap::new();
for arg in &matches.opt_strs("extern") {
- let mut parts = arg.splitn(1, '=');
+ let mut parts = arg.splitn(2, '=');
let name = match parts.next() {
Some(s) => s,
None => early_error("--extern value must not be empty"),
#[cfg(unix)]
pub fn path2cstr(p: &Path) -> CString {
use std::os::unix::prelude::*;
- use std::ffi::AsOsStr;
- CString::new(p.as_os_str().as_bytes()).unwrap()
+ use std::ffi::OsStr;
+ let p: &OsStr = p.as_ref();
+ CString::new(p.as_bytes()).unwrap()
}
#[cfg(windows)]
pub fn path2cstr(p: &Path) -> CString {
}
ty_infer(infer_ty) => infer_ty_to_string(cx, infer_ty),
ty_err => "[type error]".to_string(),
- ty_param(ref param_ty) => {
- if cx.sess.verbose() {
- param_ty.repr(cx)
- } else {
- param_ty.user_string(cx)
- }
- }
+ ty_param(ref param_ty) => param_ty.user_string(cx),
ty_enum(did, substs) | ty_struct(did, substs) => {
let base = ty::item_path_str(cx, did);
parameterized(cx, &base, substs, did, &[],
}
}
}
+
+impl<'tcx> Repr<'tcx> for ast::Unsafety {
+ fn repr(&self, _: &ctxt<'tcx>) -> String {
+ format!("{:?}", *self)
+ }
+}
// except according to those terms.
use std::io;
+use std::env;
#[allow(deprecated)] use std::old_path::{self, GenericPath};
#[allow(deprecated)] use std::old_io;
use std::path::{Path, PathBuf};
let old = old_path::Path::new(original.to_str().unwrap());
match old_realpath(&old) {
Ok(p) => Ok(PathBuf::from(p.as_str().unwrap())),
- Err(e) => Err(io::Error::new(io::ErrorKind::Other,
- "realpath error",
- Some(e.to_string())))
+ Err(e) => Err(io::Error::new(io::ErrorKind::Other, e))
}
}
#[allow(deprecated)]
fn old_realpath(original: &old_path::Path) -> old_io::IoResult<old_path::Path> {
use std::old_io::fs;
- use std::os;
const MAX_LINKS_FOLLOWED: usize = 256;
- let original = try!(os::getcwd()).join(original);
+ let original = old_path::Path::new(env::current_dir().unwrap()
+ .to_str().unwrap()).join(original);
// Right now lstat on windows doesn't work quite well
if cfg!(windows) {
#![feature(collections)]
#![feature(core)]
#![feature(old_fs)]
-#![feature(io)]
#![feature(old_io)]
#![feature(old_path)]
-#![feature(os)]
#![feature(rustc_private)]
#![feature(staged_api)]
#![feature(rand)]
#![feature(path_ext)]
-#![feature(std_misc)]
#![feature(step_by)]
-#![feature(convert)]
#![cfg_attr(test, feature(test, rand))]
extern crate syntax;
#![allow(deprecated)] // to_be32
-use std::iter::{range_step, repeat};
+use std::iter::repeat;
use std::num::Int;
use std::slice::bytes::{MutableByteVector, copy_memory};
use serialize::hex::ToHex;
// Putting the message schedule inside the same loop as the round calculations allows for
// the compiler to generate better code.
- for t in range_step(0, 48, 8) {
+ for t in (0..48).step_by(8) {
schedule_round!(t + 16);
schedule_round!(t + 17);
schedule_round!(t + 18);
sha2_round!(b, c, d, e, f, g, h, a, K32, t + 7);
}
- for t in range_step(48, 64, 8) {
+ for t in (48..64).step_by(8) {
sha2_round!(a, b, c, d, e, f, g, h, K32, t);
sha2_round!(h, a, b, c, d, e, f, g, K32, t + 1);
sha2_round!(g, h, a, b, c, d, e, f, K32, t + 2);
use self::Arch::*;
#[allow(non_camel_case_types)]
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub enum Arch {
Armv7,
Armv7s,
Ok(String::from_utf8(output.stdout).unwrap())
} else {
let error = String::from_utf8(output.stderr);
+ let error = format!("process exit with error: {}",
+ error.unwrap());
Err(io::Error::new(io::ErrorKind::Other,
- "process exit with error",
- error.ok()))
+ &error[..]))
}
});
use std::env;
use std::io::{self, Error, ErrorKind};
use std::fs;
-use std::path::{self, PathBuf, AsPath};
+use std::path::{self, PathBuf, Path};
use std::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>>(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);
}
Err(Error::new(ErrorKind::AlreadyExists,
- "too many temporary directories already exist",
- None))
+ "too many temporary directories already exist"))
}
/// Attempts to make a temporary directory inside of `env::temp_dir()` whose
}
}
-#[derive(Copy, PartialEq, Eq, Hash, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub enum LoanPathElem {
LpDeref(mc::PointerKind), // `*LV` in README.md
LpInterior(InteriorKind), // `LV.f` in README.md
code: bckerr_code
}
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub enum AliasableViolationKind {
MutabilityViolation,
BorrowViolation(euv::LoanCause)
}
-#[derive(Copy, Debug)]
+#[derive(Copy, Clone, Debug)]
pub enum MovedValueUseKind {
MovedInUse,
MovedInCapture,
const InvalidMovePathIndex: MovePathIndex = MovePathIndex(usize::MAX);
/// Index into `MoveData.moves`, used like a pointer
-#[derive(Copy, PartialEq)]
+#[derive(Copy, Clone, PartialEq)]
pub struct MoveIndex(usize);
impl MoveIndex {
pub next_sibling: MovePathIndex,
}
-#[derive(Copy, PartialEq, Debug)]
+#[derive(Copy, Clone, PartialEq, Debug)]
pub enum MoveKind {
Declared, // When declared, variables start out "moved".
MoveExpr, // Expression or binding that moves a variable
Captured // Closure creation that moves a value
}
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub struct Move {
/// Path being moved.
pub path: MovePathIndex,
pub next_move: MoveIndex
}
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub struct Assignment {
/// Path being assigned.
pub path: MovePathIndex,
pub span: Span,
}
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub struct VariantMatch {
/// downcast to the variant.
pub path: MovePathIndex,
use std::rc::Rc;
use std::borrow::IntoCow;
-#[derive(Debug, Copy)]
+#[derive(Debug, Copy, Clone)]
pub enum Variant {
Loans,
Moves,
#![feature(box_syntax)]
#![feature(collections)]
-#![feature(core)]
#![feature(libc)]
#![feature(quote)]
#![feature(rustc_diagnostic_macros)]
#![feature(unsafe_destructor)]
#![feature(staged_api)]
#![feature(exit_status)]
-#![feature(io)]
#![feature(set_stdio)]
#![feature(unicode)]
-#![feature(convert)]
extern crate arena;
extern crate flate;
}
// Whether to stop or continue compilation.
-#[derive(Copy, Debug, Eq, PartialEq)]
+#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum Compilation {
Stop,
Continue,
}
// CompilerCalls instance for a regular rustc build.
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub struct RustcDefaultCalls;
impl<'a> CompilerCalls<'a> for RustcDefaultCalls {
use std::path::PathBuf;
use std::str::FromStr;
-#[derive(Copy, PartialEq, Debug)]
+#[derive(Copy, Clone, PartialEq, Debug)]
pub enum PpSourceMode {
PpmNormal,
PpmEveryBodyLoops,
}
-#[derive(Copy, PartialEq, Debug)]
+#[derive(Copy, Clone, PartialEq, Debug)]
pub enum PpFlowGraphMode {
Default,
/// Drops the labels from the edges in the flowgraph output. This
/// have become a pain to maintain.
UnlabelledEdges,
}
-#[derive(Copy, PartialEq, Debug)]
+#[derive(Copy, Clone, PartialEq, Debug)]
pub enum PpMode {
PpmSource(PpSourceMode),
PpmFlowGraph(PpFlowGraphMode),
pub fn parse_pretty(sess: &Session,
name: &str,
extended: bool) -> (PpMode, Option<UserIdentifiedItem>) {
- let mut split = name.splitn(1, '=');
+ let mut split = name.splitn(2, '=');
let first = split.next().unwrap();
let opt_second = split.next();
let first = match (first, extended) {
try!(pp::space(&mut s.s));
s.synth_comment(item.id.to_string())
}
+ pprust::NodeSubItem(id) => {
+ try!(pp::space(&mut s.s));
+ s.synth_comment(id.to_string())
+ }
pprust::NodeBlock(blk) => {
try!(pp::space(&mut s.s));
s.synth_comment(format!("block {}", blk.id))
fn expand_err_details(r: io::Result<()>) -> io::Result<()> {
r.map_err(|ioerr| {
- io::Error::new(io::ErrorKind::Other, "graphviz::render failed",
- Some(ioerr.to_string()))
+ io::Error::new(io::ErrorKind::Other,
+ &format!("graphviz::render failed: {}", ioerr)[..])
})
}
}
use rustc_typeck::middle::subst;
use rustc_typeck::middle::subst::Subst;
use rustc_typeck::middle::ty::{self, Ty};
-use rustc_typeck::middle::infer::combine::Combine;
+use rustc_typeck::middle::ty_relate::TypeRelation;
use rustc_typeck::middle::infer;
use rustc_typeck::middle::infer::lub::Lub;
use rustc_typeck::middle::infer::glb::Glb;
pub fn sub(&self) -> Sub<'a, 'tcx> {
let trace = self.dummy_type_trace();
- Sub(self.infcx.combine_fields(true, trace))
+ self.infcx.sub(true, trace)
}
pub fn lub(&self) -> Lub<'a, 'tcx> {
let trace = self.dummy_type_trace();
- Lub(self.infcx.combine_fields(true, trace))
+ self.infcx.lub(true, trace)
}
pub fn glb(&self) -> Glb<'a, 'tcx> {
let trace = self.dummy_type_trace();
- Glb(self.infcx.combine_fields(true, trace))
+ self.infcx.glb(true, trace)
}
pub fn make_lub_ty(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) -> Ty<'tcx> {
- match self.lub().tys(t1, t2) {
+ match self.lub().relate(&t1, &t2) {
Ok(t) => t,
Err(ref e) => panic!("unexpected error computing LUB: {}",
ty::type_err_to_str(self.infcx.tcx, e))
/// Checks that `t1 <: t2` is true (this may register additional
/// region checks).
pub fn check_sub(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) {
- match self.sub().tys(t1, t2) {
+ match self.sub().relate(&t1, &t2) {
Ok(_) => { }
Err(ref e) => {
panic!("unexpected error computing sub({},{}): {}",
/// Checks that `t1 <: t2` is false (this may register additional
/// region checks).
pub fn check_not_sub(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) {
- match self.sub().tys(t1, t2) {
+ match self.sub().relate(&t1, &t2) {
Err(_) => { }
Ok(_) => {
panic!("unexpected success computing sub({},{})",
/// Checks that `LUB(t1,t2) == t_lub`
pub fn check_lub(&self, t1: Ty<'tcx>, t2: Ty<'tcx>, t_lub: Ty<'tcx>) {
- match self.lub().tys(t1, t2) {
+ match self.lub().relate(&t1, &t2) {
Ok(t) => {
self.assert_eq(t, t_lub);
}
self.ty_to_string(t1),
self.ty_to_string(t2),
self.ty_to_string(t_glb));
- match self.glb().tys(t1, t2) {
+ match self.glb().relate(&t1, &t2) {
Err(e) => {
panic!("unexpected error computing LUB: {:?}", e)
}
fn lub_returning_scope() {
test_env(EMPTY_SOURCE_STR,
errors(&["cannot infer an appropriate lifetime"]), |env| {
+ env.create_simple_region_hierarchy();
let t_rptr_scope10 = env.t_rptr_scope(10);
let t_rptr_scope11 = env.t_rptr_scope(11);
let tup2_ty = ty::mk_tup(tcx, vec!(tup1_ty, tup1_ty, uint_ty));
let uniq_ty = ty::mk_uniq(tcx, tup2_ty);
let walked: Vec<_> = uniq_ty.walk().collect();
- assert_eq!([uniq_ty,
- tup2_ty,
- tup1_ty, int_ty, uint_ty, int_ty, uint_ty,
- tup1_ty, int_ty, uint_ty, int_ty, uint_ty,
- uint_ty],
- walked);
+ assert_eq!(walked, [uniq_ty,
+ tup2_ty,
+ tup1_ty, int_ty, uint_ty, int_ty, uint_ty,
+ tup1_ty, int_ty, uint_ty, int_ty, uint_ty,
+ uint_ty]);
})
}
"suggest using `loop { }` instead of `while true { }`"
}
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub struct WhileTrue;
impl LintPass for WhileTrue {
"shift exceeds the type's number of bits"
}
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub struct TypeLimits {
/// Id of the last visited negated expression
negated_expr_id: ast::NodeId,
impl TypeLimits {
pub fn new() -> TypeLimits {
TypeLimits {
- negated_expr_id: -1,
+ negated_expr_id: !0,
}
}
}
}
}
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub struct ImproperCTypes;
impl LintPass for ImproperCTypes {
"use of owned (Box type) heap memory"
}
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub struct BoxPointers;
impl BoxPointers {
"detects attributes that were not used by the compiler"
}
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub struct UnusedAttributes;
impl LintPass for UnusedAttributes {
"path statements with no effect"
}
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub struct PathStatements;
impl LintPass for PathStatements {
"unused result of an expression in a statement"
}
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub struct UnusedResults;
impl LintPass for UnusedResults {
"types, variants, traits and type parameters should have camel case names"
}
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub struct NonCamelCaseTypes;
impl NonCamelCaseTypes {
"methods, functions, lifetime parameters and modules should have snake case names"
}
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub struct NonSnakeCase;
impl NonSnakeCase {
"static constants should have uppercase identifiers"
}
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub struct NonUpperCaseGlobals;
impl NonUpperCaseGlobals {
"`if`, `match`, `while` and `return` do not need parentheses"
}
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub struct UnusedParens;
impl UnusedParens {
"unnecessary braces around an imported item"
}
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub struct UnusedImportBraces;
impl LintPass for UnusedImportBraces {
"using `Struct { x: x }` instead of `Struct { x }`"
}
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub struct NonShorthandFieldPatterns;
impl LintPass for NonShorthandFieldPatterns {
"unnecessary use of an `unsafe` block"
}
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub struct UnusedUnsafe;
impl LintPass for UnusedUnsafe {
"usage of `unsafe` code"
}
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub struct UnsafeCode;
impl LintPass for UnsafeCode {
"detect mut variables which don't need to be mutable"
}
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub struct UnusedMut;
impl UnusedMut {
"detects unnecessary allocations that can be eliminated"
}
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub struct UnusedAllocation;
impl LintPass for UnusedAllocation {
"detects potentially-forgotten implementations of `Copy`"
}
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub struct MissingCopyImplementations;
impl LintPass for MissingCopyImplementations {
}
/// Checks for use of items with `#[deprecated]` attributes
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub struct Stability;
impl Stability {
"functions that cannot return without calling themselves"
}
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub struct UnconditionalRecursion;
"compiler plugin used as ordinary library in non-plugin crate"
}
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub struct PluginAsLibrary;
impl LintPass for PluginAsLibrary {
"const items will not have their symbols exported"
}
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub struct InvalidNoMangleItems;
impl LintPass for InvalidNoMangleItems {
}
/// Forbids using the `#[feature(...)]` attribute
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub struct UnstableFeatures;
declare_lint! {
#[cfg(unix)]
fn path2cstr(p: &Path) -> CString {
use std::os::unix::prelude::*;
- use std::ffi::AsOsStr;
- CString::new(p.as_os_str().as_bytes()).unwrap()
+ use std::ffi::OsStr;
+ let p: &OsStr = p.as_ref();
+ CString::new(p.as_bytes()).unwrap()
}
#[cfg(windows)]
fn path2cstr(p: &Path) -> CString {
use {ValueRef, TwineRef, DebugLocRef, DiagnosticInfoRef};
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub enum OptimizationDiagnosticKind {
OptimizationRemark,
OptimizationMissed,
}
#[allow(raw_pointer_derive)]
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub struct OptimizationDiagnostic {
pub kind: OptimizationDiagnosticKind,
pub pass_name: *const c_char,
}
}
+#[derive(Copy, Clone)]
pub struct InlineAsmDiagnostic {
pub cookie: c_uint,
pub message: TwineRef,
pub instruction: ValueRef,
}
-impl Copy for InlineAsmDiagnostic {}
-
impl InlineAsmDiagnostic {
unsafe fn unpack(di: DiagnosticInfoRef)
-> InlineAsmDiagnostic {
}
}
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub enum Diagnostic {
Optimization(OptimizationDiagnostic),
InlineAsm(InlineAsmDiagnostic),
#![feature(libc)]
#![feature(link_args)]
#![feature(staged_api)]
-#![cfg_attr(unix, feature(std_misc))]
extern crate libc;
#[macro_use] #[no_link] extern crate rustc_bitflags;
// Consts for the LLVM CallConv type, pre-cast to usize.
-#[derive(Copy, PartialEq)]
+#[derive(Copy, Clone, PartialEq)]
pub enum CallConv {
CCallConv = 0,
FastCallConv = 8,
X86_64_Win64 = 79,
}
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub enum Visibility {
LLVMDefaultVisibility = 0,
HiddenVisibility = 1,
// DLLExportLinkage, GhostLinkage and LinkOnceODRAutoHideLinkage.
// LinkerPrivateLinkage and LinkerPrivateWeakLinkage are not included either;
// they've been removed in upstream LLVM commit r203866.
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub enum Linkage {
ExternalLinkage = 0,
AvailableExternallyLinkage = 1,
}
#[repr(C)]
-#[derive(Copy, Debug)]
+#[derive(Copy, Clone, Debug)]
pub enum DiagnosticSeverity {
Error,
Warning,
#[repr(u64)]
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub enum OtherAttribute {
// The following are not really exposed in
// the LLVM c api so instead to add these
NonNullAttribute = 1 << 44,
}
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub enum SpecialAttribute {
DereferenceableAttribute(u64)
}
#[repr(C)]
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub enum AttributeSet {
ReturnIndex = 0,
FunctionIndex = !0
}
// enum for the LLVM IntPredicate type
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub enum IntPredicate {
IntEQ = 32,
IntNE = 33,
}
// enum for the LLVM RealPredicate type
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub enum RealPredicate {
RealPredicateFalse = 0,
RealOEQ = 1,
// The LLVM TypeKind type - must stay in sync with the def of
// LLVMTypeKind in llvm/include/llvm-c/Core.h
-#[derive(Copy, PartialEq, Debug)]
+#[derive(Copy, Clone, PartialEq, Debug)]
#[repr(C)]
pub enum TypeKind {
Void = 0,
}
#[repr(C)]
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub enum AtomicBinOp {
AtomicXchg = 0,
AtomicAdd = 1,
}
#[repr(C)]
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub enum AtomicOrdering {
NotAtomic = 0,
Unordered = 1,
// Consts for the LLVMCodeGenFileType type (in include/llvm/c/TargetMachine.h)
#[repr(C)]
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub enum FileType {
AssemblyFileType = 0,
ObjectFileType = 1
}
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub enum MetadataType {
MD_dbg = 0,
MD_tbaa = 1,
}
// Inline Asm Dialect
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub enum AsmDialect {
AD_ATT = 0,
AD_Intel = 1
}
-#[derive(Copy, PartialEq, Clone)]
+#[derive(Copy, Clone, PartialEq)]
#[repr(C)]
pub enum CodeGenOptLevel {
CodeGenLevelNone = 0,
CodeGenLevelAggressive = 3,
}
-#[derive(Copy, PartialEq)]
+#[derive(Copy, Clone, PartialEq)]
#[repr(C)]
pub enum RelocMode {
RelocDefault = 0,
}
#[repr(C)]
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub enum CodeGenModel {
CodeModelDefault = 0,
CodeModelJITDefault = 1,
}
#[repr(C)]
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub enum DiagnosticKind {
DK_InlineAsm = 0,
DK_StackSize,
pub type DIEnumerator = DIDescriptor;
pub type DITemplateTypeParameter = DIDescriptor;
- #[derive(Copy)]
+ #[derive(Copy, Clone)]
pub enum DIDescriptorFlags {
FlagPrivate = 1 << 0,
FlagProtected = 1 << 1,
pub fn LLVMIsAArgument(value_ref: ValueRef) -> ValueRef;
pub fn LLVMIsAAllocaInst(value_ref: ValueRef) -> ValueRef;
+ pub fn LLVMIsAConstantInt(value_ref: ValueRef) -> ValueRef;
pub fn LLVMInitializeX86TargetInfo();
pub fn LLVMInitializeX86Target();
// Specifies how duplicates should be handled when adding a child item if
// another item exists with the same name in some namespace.
-#[derive(Copy, PartialEq)]
+#[derive(Copy, Clone, PartialEq)]
enum DuplicateCheckingMode {
ForbidDuplicateModules,
ForbidDuplicateTypesAndModules,
OverwriteDuplicates
}
-#[derive(Copy, PartialEq)]
+#[derive(Copy, Clone, PartialEq)]
enum NamespaceError {
NoError,
ModuleError,
mod build_reduced_graph;
mod resolve_imports;
-#[derive(Copy)]
+#[derive(Copy, Clone)]
struct BindingInfo {
span: Span,
binding_mode: BindingMode,
// Map from the name in a pattern to its binding mode.
type BindingMap = HashMap<Name, BindingInfo>;
-#[derive(Copy, PartialEq)]
+#[derive(Copy, Clone, PartialEq)]
enum PatternBindingMode {
RefutableMode,
LocalIrrefutableMode,
ArgumentIrrefutableMode,
}
-#[derive(Copy, PartialEq, Eq, Hash, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
enum Namespace {
TypeNS,
ValueNS
}
enum NameDefinition {
- NoNameDefinition, //< The name was unbound.
- ChildNameDefinition(Def, LastPrivate), //< The name identifies an immediate child.
- ImportNameDefinition(Def, LastPrivate) //< The name identifies an import.
+ // The name was unbound.
+ NoNameDefinition,
+ // The name identifies an immediate child.
+ ChildNameDefinition(Def, LastPrivate),
+ // The name identifies an import.
+ ImportNameDefinition(Def, LastPrivate),
}
impl<'a, 'v, 'tcx> Visitor<'v> for Resolver<'a, 'tcx> {
TraitMethod(String),
}
-#[derive(Copy)]
+#[derive(Copy, Clone)]
enum TypeParameters<'a> {
NoTypeParameters,
HasTypeParameters(
// The rib kind controls the translation of local
// definitions (`DefLocal`) to upvars (`DefUpvar`).
-#[derive(Copy, Debug)]
+#[derive(Copy, Clone, Debug)]
enum RibKind {
// No translation needs to be applied.
NormalRibKind,
ConstantItemRibKind
}
-#[derive(Copy)]
+#[derive(Copy, Clone)]
enum UseLexicalScopeFlag {
DontUseLexicalScope,
UseLexicalScope
PrefixFound(Rc<Module>, usize)
}
-#[derive(Copy, PartialEq)]
+#[derive(Copy, Clone, PartialEq)]
enum NameSearchType {
/// We're doing a name search in order to resolve a `use` directive.
ImportSearch,
PathSearch,
}
-#[derive(Copy)]
+#[derive(Copy, Clone)]
enum BareIdentifierPatternResolution {
FoundStructOrEnumVariant(Def, LastPrivate),
FoundConst(Def, LastPrivate),
}
/// The type of module this is.
-#[derive(Copy, PartialEq, Debug)]
+#[derive(Copy, Clone, PartialEq, Debug)]
enum ModuleKind {
NormalModuleKind,
TraitModuleKind,
// The current self type if inside an impl (used for better errors).
current_self_type: Option<Ty>,
- // The ident for the keyword "self".
- self_name: Name,
- // The ident for the non-keyword "Self".
- type_self_name: Name,
-
// The idents for the primitive types.
primitive_type_table: PrimitiveTypeTable,
current_trait_ref: None,
current_self_type: None,
- self_name: special_names::self_,
- type_self_name: special_names::type_self,
-
primitive_type_table: PrimitiveTypeTable::new(),
def_map: RefCell::new(NodeMap()),
let mut self_type_rib = Rib::new(ItemRibKind);
// plain insert (no renaming, types are not currently hygienic....)
- let name = self.type_self_name;
+ let name = special_names::type_self;
self_type_rib.bindings.insert(name, DlDef(DefSelfTy(item.id)));
self.type_ribs.push(self_type_rib);
fn with_optional_trait_ref<T, F>(&mut self,
opt_trait_ref: Option<&TraitRef>,
- f: F) -> T where
- F: FnOnce(&mut Resolver) -> T,
+ f: F)
+ -> T
+ where F: FnOnce(&mut Resolver) -> T,
{
let mut new_val = None;
if let Some(trait_ref) = opt_trait_ref {
let span = path.span;
let segments = &path.segments[..path.segments.len()-path_depth];
- let mk_res = |(def, lp)| PathResolution {
- base_def: def,
- last_private: lp,
- depth: path_depth
- };
+ let mk_res = |(def, lp)| PathResolution::new(def, lp, path_depth);
if path.global {
let def = self.resolve_crate_relative_path(span, segments, namespace);
check_ribs,
span);
- if segments.len() > 1 {
- let def = self.resolve_module_relative_path(span, segments, namespace);
- match (def, unqualified_def) {
- (Some((ref d, _)), Some((ref ud, _))) if *d == *ud => {
- self.session
- .add_lint(lint::builtin::UNUSED_QUALIFICATIONS,
- id, span,
- "unnecessary qualification".to_string());
- }
- _ => ()
- }
+ if segments.len() <= 1 {
+ return unqualified_def.map(mk_res);
+ }
- def.map(mk_res)
- } else {
- unqualified_def.map(mk_res)
+ let def = self.resolve_module_relative_path(span, segments, namespace);
+ match (def, unqualified_def) {
+ (Some((ref d, _)), Some((ref ud, _))) if *d == *ud => {
+ self.session
+ .add_lint(lint::builtin::UNUSED_QUALIFICATIONS,
+ id, span,
+ "unnecessary qualification".to_string());
+ }
+ _ => {}
}
+
+ def.map(mk_res)
}
- // resolve a single identifier (used as a varref)
+ // Resolve a single identifier.
fn resolve_identifier(&mut self,
identifier: Ident,
namespace: Namespace,
match child_name_bindings.def_for_namespace(namespace) {
Some(def) => {
// Found it. Stop the search here.
- let p = child_name_bindings.defined_in_public_namespace(
- namespace);
+ let p = child_name_bindings.defined_in_public_namespace(namespace);
let lp = if p {LastMod(AllPublic)} else {
LastMod(DependsOn(def.def_id()))
};
let containing_module;
let last_private;
- let module = self.current_module.clone();
- match self.resolve_module_path(module,
+ let current_module = self.current_module.clone();
+ match self.resolve_module_path(current_module,
&module_path[..],
UseLexicalScope,
span,
match search_result {
Some(DlDef(def)) => {
- debug!("(resolving path in local ribs) resolved `{}` to \
- local: {:?}",
+ debug!("(resolving path in local ribs) resolved `{}` to local: {:?}",
token::get_ident(ident),
def);
Some(def)
panic!("unexpected indeterminate result");
}
Failed(err) => {
- match err {
- Some((span, msg)) =>
- self.resolve_error(span, &format!("failed to resolve. {}",
- msg)),
- None => ()
- }
-
debug!("(resolving item path by identifier in lexical scope) \
failed to resolve {}", token::get_name(name));
+
+ if let Some((span, msg)) = err {
+ self.resolve_error(span, &format!("failed to resolve. {}", msg))
+ }
+
return None;
}
}
}
} else {
match this.resolve_module_path(root,
- &name_path[..],
- UseLexicalScope,
- span,
- PathSearch) {
+ &name_path[..],
+ UseLexicalScope,
+ span,
+ PathSearch) {
Success((module, _)) => Some(module),
_ => None
}
false // Stop advancing
});
- if method_scope && &token::get_name(self.self_name)[..]
- == path_name {
+ if method_scope &&
+ &token::get_name(special_names::self_)[..] == path_name {
self.resolve_error(
expr.span,
"`self` is not available \
pub glob_map: Option<GlobMap>
}
-#[derive(PartialEq,Copy)]
+#[derive(PartialEq,Copy, Clone)]
pub enum MakeGlobMap {
Yes,
No
/// Contains data for specific types of import directives.
-#[derive(Copy,Debug)]
+#[derive(Copy, Clone,Debug)]
pub enum ImportDirectiveSubclass {
SingleImport(Name /* target */, Name /* source */),
GlobImport
#![feature(unicode)]
#![feature(path_ext)]
#![feature(fs)]
-#![feature(convert)]
#![feature(path_relative_from)]
#![allow(trivial_casts)]
let typ =
ppaux::ty_to_string(
&self.analysis.ty_cx,
- *self.analysis.ty_cx.node_types.borrow().get(&id).unwrap());
+ *self.analysis.ty_cx.node_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?)
self.fmt.formal_str(p.span,
let typ =
ppaux::ty_to_string(
&self.analysis.ty_cx,
- *self.analysis.ty_cx.node_types.borrow().get(&field.node.id).unwrap());
+ *self.analysis.ty_cx.node_types().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),
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 types = self.analysis.ty_cx.node_types();
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?).
})
}
-#[derive(Copy, Debug, Eq, PartialEq)]
+#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum Row {
Variable,
Enum,
use syntax::fold::Folder;
use syntax::ptr::P;
-#[derive(Copy, Debug)]
+#[derive(Copy, Clone, Debug)]
struct ConstantExpr<'a>(&'a ast::Expr);
impl<'a> ConstantExpr<'a> {
}
}
-#[derive(Copy, PartialEq)]
+#[derive(Copy, Clone, PartialEq)]
pub enum BranchKind {
NoBranch,
Single,
let bits = machine::llbitsize_of_real(bcx.ccx(), llty);
assert!(bits <= 64);
let bits = bits as usize;
- let mask = (-1u64 >> (64 - bits)) as Disr;
+ let mask = (!0u64 >> (64 - bits)) as Disr;
// For a (max) discr of -1, max will be `-1 as usize`, which overflows.
// However, that is fine here (it would still represent the full range),
if (max.wrapping_add(1)) & mask == min & mask {
use middle::lang_items::{LangItem, ExchangeMallocFnLangItem, StartFnLangItem};
use middle::weak_lang_items;
use middle::subst::{Subst, Substs};
-use middle::ty::{self, Ty, ClosureTyper};
+use middle::ty::{self, Ty, ClosureTyper, type_is_simd, simd_size};
use session::config::{self, NoDebugInfo};
use session::Session;
use trans::_match;
use trans::cleanup::CleanupMethods;
use trans::cleanup;
use trans::closure;
-use trans::common::{Block, C_bool, C_bytes_in_context, C_i32, C_integral};
+use trans::common::{Block, C_bool, C_bytes_in_context, C_i32, C_int, C_integral};
use trans::common::{C_null, C_struct_in_context, C_u64, C_u8, C_undef};
use trans::common::{CrateContext, ExternMap, FunctionContext};
use trans::common::{Result, NodeIdAndSpan};
let zero = C_integral(Type::uint_from_ty(cx.ccx(), t), 0, false);
(ICmp(cx, llvm::IntEQ, rhs, zero, debug_loc), false)
}
+ ty::ty_struct(_, _) if type_is_simd(cx.tcx(), rhs_t) => {
+ let mut res = C_bool(cx.ccx(), false);
+ for i in 0 .. simd_size(cx.tcx(), rhs_t) {
+ res = Or(cx, res,
+ IsNull(cx,
+ ExtractElement(cx, rhs, C_int(cx.ccx(), i as i64))), debug_loc);
+ }
+ (res, false)
+ }
_ => {
cx.sess().bug(&format!("fail-if-zero on unexpected type: {}",
ty_to_string(cx.tcx(), rhs_t)));
_ => unreachable!(),
};
let minus_one = ICmp(bcx, llvm::IntEQ, rhs,
- C_integral(llty, -1, false), debug_loc);
+ C_integral(llty, !0, false), debug_loc);
with_cond(bcx, minus_one, |bcx| {
let is_min = ICmp(bcx, llvm::IntEQ, lhs,
C_integral(llty, min, true), debug_loc);
common::validate_substs(param_substs);
debug!("new_fn_ctxt(path={}, id={}, param_substs={})",
- if id == -1 {
+ if id == !0 {
"".to_string()
} else {
ccx.tcx().map.path_to_string(id).to_string()
/// Enum describing the origin of an LLVM `Value`, for linkage purposes.
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub enum ValueOrigin {
/// The LLVM `Value` is in this context because the corresponding item was
/// assigned to the current compilation unit.
use trans::value::{Users, Value};
use std::iter::{Filter, Map};
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub struct BasicBlock(pub BasicBlockRef);
pub type Preds = Map<Filter<Users, fn(&Value) -> bool>, fn(Value) -> BasicBlock>;
use syntax::ast_map;
use syntax::ptr::P;
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub struct MethodData {
pub llfn: ValueRef,
pub llself: ValueRef,
bcx
}
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub enum AutorefArg {
DontAutorefArg,
DoAutorefArg(ast::NodeId)
cached_landing_pad: Option<BasicBlockRef>,
}
-#[derive(Copy, Debug)]
+#[derive(Copy, Clone, Debug)]
pub struct CustomScopeIndex {
index: usize
}
}
}
-#[derive(Copy, PartialEq, Debug)]
+#[derive(Copy, Clone, PartialEq, Debug)]
pub enum EarlyExitLabel {
UnwindExit,
ReturnExit,
LoopExit(ast::NodeId, usize)
}
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub struct CachedEarlyExit {
label: EarlyExitLabel,
cleanup_block: BasicBlockRef,
pub type CleanupObj<'tcx> = Box<Cleanup<'tcx>+'tcx>;
-#[derive(Copy, Debug)]
+#[derive(Copy, Clone, Debug)]
pub enum ScopeId {
AstScope(ast::NodeId),
CustomScope(CustomScopeIndex)
///////////////////////////////////////////////////////////////////////////
// Cleanup types
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub struct DropValue<'tcx> {
is_immediate: bool,
must_unwind: bool,
}
}
-#[derive(Copy, Debug)]
+#[derive(Copy, Clone, Debug)]
pub enum Heap {
HeapExchange
}
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub struct FreeValue<'tcx> {
ptr: ValueRef,
heap: Heap,
}
}
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub struct FreeSlice {
ptr: ValueRef,
size: ValueRef,
}
}
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub struct LifetimeEnd {
ptr: ValueRef,
}
*
*/
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub struct NodeIdAndSpan {
pub id: ast::NodeId,
pub span: Span,
}
}
+fn is_const_integral(v: ValueRef) -> bool {
+ unsafe {
+ !llvm::LLVMIsAConstantInt(v).is_null()
+ }
+}
+
+pub fn const_to_opt_int(v: ValueRef) -> Option<i64> {
+ unsafe {
+ if is_const_integral(v) {
+ Some(llvm::LLVMConstIntGetSExtValue(v))
+ } else {
+ None
+ }
+ }
+}
+
+pub fn const_to_opt_uint(v: ValueRef) -> Option<u64> {
+ unsafe {
+ if is_const_integral(v) {
+ Some(llvm::LLVMConstIntGetZExtValue(v))
+ } else {
+ None
+ }
+ }
+}
+
pub fn is_undef(val: ValueRef) -> bool {
unsafe {
llvm::LLVMIsUndef(val) != False
}
// Key used to lookup values supplied for type parameters in an expr.
-#[derive(Copy, PartialEq, Debug)]
+#[derive(Copy, Clone, PartialEq, Debug)]
pub enum ExprOrMethodCall {
// Type parameters for a path like `None::<int>`
ExprId(ast::NodeId),
use llvm::{ConstFCmp, ConstICmp, SetLinkage, SetUnnamedAddr};
use llvm::{InternalLinkage, ValueRef, Bool, True};
use middle::{check_const, const_eval, def};
+use middle::const_eval::{const_int_checked_neg, const_uint_checked_neg};
+use middle::const_eval::{const_int_checked_add, const_uint_checked_add};
+use middle::const_eval::{const_int_checked_sub, const_uint_checked_sub};
+use middle::const_eval::{const_int_checked_mul, const_uint_checked_mul};
+use middle::const_eval::{const_int_checked_div, const_uint_checked_div};
+use middle::const_eval::{const_int_checked_rem, const_uint_checked_rem};
+use middle::const_eval::{const_int_checked_shl, const_uint_checked_shl};
+use middle::const_eval::{const_int_checked_shr, const_uint_checked_shr};
use trans::{adt, closure, debuginfo, expr, inline, machine};
use trans::base::{self, push_ctxt};
use trans::common::*;
let csize = machine::llsize_of_alloc(cx, val_ty(llconst));
let tsize = machine::llsize_of_alloc(cx, llty);
if csize != tsize {
+ cx.sess().abort_if_errors();
unsafe {
// FIXME these values could use some context
llvm::LLVMDumpValue(llconst);
(llconst, ety_adjusted)
}
+fn check_unary_expr_validity(cx: &CrateContext, e: &ast::Expr, t: Ty,
+ te: ValueRef) {
+ // The only kind of unary expression that we check for validity
+ // here is `-expr`, to check if it "overflows" (e.g. `-i32::MIN`).
+ if let ast::ExprUnary(ast::UnNeg, ref inner_e) = e.node {
+
+ // An unfortunate special case: we parse e.g. -128 as a
+ // negation of the literal 128, which means if we're expecting
+ // a i8 (or if it was already suffixed, e.g. `-128_i8`), then
+ // 128 will have already overflowed to -128, and so then the
+ // constant evaluator thinks we're trying to negate -128.
+ //
+ // Catch this up front by looking for ExprLit directly,
+ // and just accepting it.
+ if let ast::ExprLit(_) = inner_e.node { return; }
+
+ let result = match t.sty {
+ ty::ty_int(int_type) => {
+ let input = match const_to_opt_int(te) {
+ Some(v) => v,
+ None => return,
+ };
+ const_int_checked_neg(
+ input, e, Some(const_eval::IntTy::from(cx.tcx(), int_type)))
+ }
+ ty::ty_uint(uint_type) => {
+ let input = match const_to_opt_uint(te) {
+ Some(v) => v,
+ None => return,
+ };
+ const_uint_checked_neg(
+ input, e, Some(const_eval::UintTy::from(cx.tcx(), uint_type)))
+ }
+ _ => return,
+ };
+
+ // We do not actually care about a successful result.
+ if let Err(err) = result {
+ cx.tcx().sess.span_err(e.span, &err.description());
+ }
+ }
+}
+
+fn check_binary_expr_validity(cx: &CrateContext, e: &ast::Expr, t: Ty,
+ te1: ValueRef, te2: ValueRef) {
+ let b = if let ast::ExprBinary(b, _, _) = e.node { b } else { return };
+
+ let result = match t.sty {
+ ty::ty_int(int_type) => {
+ let (lhs, rhs) = match (const_to_opt_int(te1),
+ const_to_opt_int(te2)) {
+ (Some(v1), Some(v2)) => (v1, v2),
+ _ => return,
+ };
+
+ let opt_ety = Some(const_eval::IntTy::from(cx.tcx(), int_type));
+ match b.node {
+ ast::BiAdd => const_int_checked_add(lhs, rhs, e, opt_ety),
+ ast::BiSub => const_int_checked_sub(lhs, rhs, e, opt_ety),
+ ast::BiMul => const_int_checked_mul(lhs, rhs, e, opt_ety),
+ ast::BiDiv => const_int_checked_div(lhs, rhs, e, opt_ety),
+ ast::BiRem => const_int_checked_rem(lhs, rhs, e, opt_ety),
+ ast::BiShl => const_int_checked_shl(lhs, rhs, e, opt_ety),
+ ast::BiShr => const_int_checked_shr(lhs, rhs, e, opt_ety),
+ _ => return,
+ }
+ }
+ ty::ty_uint(uint_type) => {
+ let (lhs, rhs) = match (const_to_opt_uint(te1),
+ const_to_opt_uint(te2)) {
+ (Some(v1), Some(v2)) => (v1, v2),
+ _ => return,
+ };
+
+ let opt_ety = Some(const_eval::UintTy::from(cx.tcx(), uint_type));
+ match b.node {
+ ast::BiAdd => const_uint_checked_add(lhs, rhs, e, opt_ety),
+ ast::BiSub => const_uint_checked_sub(lhs, rhs, e, opt_ety),
+ ast::BiMul => const_uint_checked_mul(lhs, rhs, e, opt_ety),
+ ast::BiDiv => const_uint_checked_div(lhs, rhs, e, opt_ety),
+ ast::BiRem => const_uint_checked_rem(lhs, rhs, e, opt_ety),
+ ast::BiShl => const_uint_checked_shl(lhs, rhs, e, opt_ety),
+ ast::BiShr => const_uint_checked_shr(lhs, rhs, e, opt_ety),
+ _ => return,
+ }
+ }
+ _ => return,
+ };
+ // We do not actually care about a successful result.
+ if let Err(err) = result {
+ cx.tcx().sess.span_err(e.span, &err.description());
+ }
+}
+
fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
e: &ast::Expr,
ety: Ty<'tcx>,
let signed = ty::type_is_signed(intype);
let (te2, _) = const_expr(cx, &**e2, param_substs);
- let te2 = base::cast_shift_const_rhs(b.node, te1, te2);
+
+ check_binary_expr_validity(cx, e, ty, te1, te2);
match b.node {
ast::BiAdd => {
ast::BiBitXor => llvm::LLVMConstXor(te1, te2),
ast::BiBitAnd => llvm::LLVMConstAnd(te1, te2),
ast::BiBitOr => llvm::LLVMConstOr(te1, te2),
- ast::BiShl => llvm::LLVMConstShl(te1, te2),
+ ast::BiShl => {
+ let te2 = base::cast_shift_const_rhs(b.node, te1, te2);
+ llvm::LLVMConstShl(te1, te2)
+ }
ast::BiShr => {
+ let te2 = base::cast_shift_const_rhs(b.node, te1, te2);
if signed { llvm::LLVMConstAShr(te1, te2) }
else { llvm::LLVMConstLShr(te1, te2) }
}
}
}
},
- ast::ExprUnary(u, ref e) => {
- let (te, ty) = const_expr(cx, &**e, param_substs);
+ ast::ExprUnary(u, ref inner_e) => {
+ let (te, ty) = const_expr(cx, &**inner_e, param_substs);
+
+ check_unary_expr_validity(cx, e, ty, te);
+
let is_float = ty::type_is_fp(ty);
match u {
ast::UnUniq | ast::UnDeref => {
ast::ExprRepeat(ref elem, ref count) => {
let unit_ty = ty::sequence_element_type(cx.tcx(), ety);
let llunitty = type_of::type_of(cx, unit_ty);
- let n = match const_eval::eval_const_expr_partial(cx.tcx(), &**count, None) {
- Ok(const_eval::const_int(i)) => i as usize,
- Ok(const_eval::const_uint(i)) => i as usize,
- _ => cx.sess().span_bug(count.span, "count must be integral const expression.")
- };
+ let n = ty::eval_repeat_count(cx.tcx(), count);
let unit_val = const_expr(cx, &**elem, param_substs).0;
let vs: Vec<_> = repeat(unit_val).take(n).collect();
if val_ty(unit_val) != llunitty {
CrateContext {
shared: shared,
local: self,
- index: -1 as usize,
+ index: !0 as usize,
}
}
}
let fcx = cx.fcx;
debug!("trans_stmt({})", s.repr(cx.tcx()));
+ if cx.unreachable.get() {
+ return cx;
+ }
+
if cx.sess().asm_comments() {
add_span_comment(cx, s.span, &s.repr(cx.tcx()));
}
pub fn trans_stmt_semi<'blk, 'tcx>(cx: Block<'blk, 'tcx>, e: &ast::Expr)
-> Block<'blk, 'tcx> {
let _icx = push_ctxt("trans_stmt_semi");
+
+ if cx.unreachable.get() {
+ return cx;
+ }
+
let ty = expr_ty(cx, e);
if cx.fcx.type_needs_drop(ty) {
expr::trans_to_lvalue(cx, e, "stmt").bcx
mut dest: expr::Dest)
-> Block<'blk, 'tcx> {
let _icx = push_ctxt("trans_block");
+
+ if bcx.unreachable.get() {
+ return bcx;
+ }
+
let fcx = bcx.fcx;
let mut bcx = bcx;
bcx.to_str(), if_id, bcx.expr_to_string(cond), thn.id,
dest.to_string(bcx.ccx()));
let _icx = push_ctxt("trans_if");
+
+ if bcx.unreachable.get() {
+ return bcx;
+ }
+
let mut bcx = bcx;
let cond_val = unpack_result!(bcx, expr::trans(bcx, cond).to_llbool());
body: &ast::Block)
-> Block<'blk, 'tcx> {
let _icx = push_ctxt("trans_while");
+
+ if bcx.unreachable.get() {
+ return bcx;
+ }
+
let fcx = bcx.fcx;
// bcx
body: &ast::Block)
-> Block<'blk, 'tcx> {
let _icx = push_ctxt("trans_loop");
+
+ if bcx.unreachable.get() {
+ return bcx;
+ }
+
let fcx = bcx.fcx;
// bcx
exit: usize)
-> Block<'blk, 'tcx> {
let _icx = push_ctxt("trans_break_cont");
- let fcx = bcx.fcx;
if bcx.unreachable.get() {
return bcx;
}
+ let fcx = bcx.fcx;
+
// Locate loop that we will break to
let loop_id = match opt_label {
None => fcx.top_loop_scope(),
retval_expr: Option<&ast::Expr>)
-> Block<'blk, 'tcx> {
let _icx = push_ctxt("trans_ret");
+
+ if bcx.unreachable.get() {
+ return bcx;
+ }
+
let fcx = bcx.fcx;
let mut bcx = bcx;
let dest = match (fcx.llretslotptr.get(), retval_expr) {
let ccx = bcx.ccx();
let _icx = push_ctxt("trans_fail_value");
+ if bcx.unreachable.get() {
+ return bcx;
+ }
+
let v_str = C_str_slice(ccx, fail_str);
let loc = bcx.sess().codemap().lookup_char_pos(call_info.span.lo);
let filename = token::intern_and_get_ident(&loc.file.name);
let ccx = bcx.ccx();
let _icx = push_ctxt("trans_fail_bounds_check");
+ if bcx.unreachable.get() {
+ return bcx;
+ }
+
// Extract the file/line from the span
let loc = bcx.sess().codemap().lookup_char_pos(call_info.span.lo);
let filename = token::intern_and_get_ident(&loc.file.name);
fn drop(&mut self) { }
}
-#[derive(Copy, PartialEq, Eq, Hash, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub enum RvalueMode {
/// `val` is a pointer to the actual value (and thus has type *T)
ByRef,
}
}
-#[derive(Copy)]
+#[derive(Copy, Clone)]
enum EnumDiscriminantInfo {
RegularDiscriminant(DIType),
OptimizedDiscriminant,
}
}
-#[derive(Copy, PartialEq)]
+#[derive(Copy, Clone, PartialEq)]
enum InternalDebugLocation {
KnownLocation { scope: DIScope, line: usize, col: usize },
UnknownLocation
fn assert_type_for_node_id(cx: &CrateContext,
node_id: ast::NodeId,
error_reporting_span: Span) {
- if !cx.tcx().node_types.borrow().contains_key(&node_id) {
+ if !cx.tcx().node_types().contains_key(&node_id) {
cx.sess().span_bug(error_reporting_span,
"debuginfo: Could not find type for node id!");
}
// These are passed around by the code generating functions to track the
// destination of a computation's value.
-#[derive(Copy, PartialEq)]
+#[derive(Copy, Clone, PartialEq)]
pub enum Dest {
SaveIn(ValueRef),
Ignore,
} else { llsrc };
}
-#[derive(Copy, PartialEq, Debug)]
+#[derive(Copy, Clone, PartialEq, Debug)]
pub enum cast_kind {
cast_pointer,
cast_integral,
mod llrepr;
mod cleanup;
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub struct ModuleTranslation {
pub llcx: ContextRef,
pub llmod: ModuleRef,
use syntax::ast;
use syntax::parse::token::InternedString;
-#[derive(Copy)]
+#[derive(Copy, Clone)]
struct VecTypes<'tcx> {
unit_ty: Ty<'tcx>,
llunit_ty: Type
use trans::common::Block;
use libc::c_uint;
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub struct Value(pub ValueRef);
macro_rules! opt_val { ($e:expr) => (
}
/// Wrapper for LLVM UseRef
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub struct Use(UseRef);
impl Use {
span: Span,
_trait_ref: Rc<ty::TraitRef<'tcx>>,
_item_name: ast::Name)
- -> Ty<'tcx>
- {
- span_err!(self.tcx().sess, span, E0213,
- "associated types are not accepted in this context");
-
- self.tcx().types.err
- }
+ -> Ty<'tcx>;
}
pub fn ast_region_to_region(tcx: &ty::ctxt, lifetime: &ast::Lifetime)
}
};
- let substs = ast_path_substs_for_ty(this, rscope,
- span, param_mode,
- &generics, item_segment);
+ let substs = ast_path_substs_for_ty(this,
+ rscope,
+ span,
+ param_mode,
+ &generics,
+ item_segment);
// FIXME(#12938): This is a hack until we have full support for DST.
if Some(did) == this.tcx().lang_items.owned_box() {
type_str, trait_str, name);
}
+// Create a type from a a path to an associated type.
+// For a path A::B::C::D, ty and ty_path_def are the type and def for A::B::C
+// and item_segment is the path segment for D. We return a type and a def for
+// the whole path.
+// Will fail except for T::A and Self::A; i.e., if ty/ty_path_def are not a type
+// parameter or Self.
fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>,
span: Span,
ty: Ty<'tcx>,
-> (Ty<'tcx>, def::Def)
{
let tcx = this.tcx();
- check_path_args(tcx, slice::ref_slice(item_segment), NO_TPS | NO_REGIONS);
let assoc_name = item_segment.identifier.name;
- let is_param = match (&ty.sty, ty_path_def) {
- (&ty::ty_param(_), def::DefTyParam(..)) |
- (&ty::ty_param(_), def::DefSelfTy(_)) => true,
- _ => false
- };
+ debug!("associated_path_def_to_ty: {}::{}", ty.repr(tcx), token::get_name(assoc_name));
- let ty_param_node_id = if is_param {
- ty_path_def.local_node_id()
- } else {
- report_ambiguous_associated_type(
- tcx, span, &ty.user_string(tcx), "Trait", &token::get_name(assoc_name));
- return (tcx.types.err, ty_path_def);
- };
+ check_path_args(tcx, slice::ref_slice(item_segment), NO_TPS | NO_REGIONS);
+
+ // Check that the path prefix given by ty/ty_path_def is a type parameter/Self.
+ match (&ty.sty, ty_path_def) {
+ (&ty::ty_param(_), def::DefTyParam(..)) |
+ (&ty::ty_param(_), def::DefSelfTy(_)) => {}
+ _ => {
+ report_ambiguous_associated_type(tcx,
+ span,
+ &ty.user_string(tcx),
+ "Trait",
+ &token::get_name(assoc_name));
+ return (tcx.types.err, ty_path_def);
+ }
+ }
+ let ty_param_node_id = ty_path_def.local_node_id();
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,
- Err(ErrorReported) => { return (tcx.types.err, ty_path_def); }
+ Err(ErrorReported) => {
+ return (tcx.types.err, ty_path_def);
+ }
};
- // ensure the super predicates and stop if we encountered an error
+ // Ensure the super predicates and stop if we encountered an error.
if bounds.iter().any(|b| this.ensure_super_predicates(span, b.def_id()).is_err()) {
return (this.tcx().types.err, ty_path_def);
}
+ // Check that there is exactly one way to find an associated type with the
+ // correct name.
let mut suitable_bounds: Vec<_> =
traits::transitive_bounds(tcx, &bounds)
.filter(|b| this.trait_defines_associated_type_named(b.def_id(), assoc_name))
// by type collection, which may be in progress at this point.
match this.tcx().map.expect_item(trait_did.node).node {
ast::ItemTrait(_, _, _, ref trait_items) => {
- let item = trait_items.iter().find(|i| i.ident.name == assoc_name)
+ let item = trait_items.iter()
+ .find(|i| i.ident.name == assoc_name)
.expect("missing associated type");
ast_util::local_def(item.id)
}
let item = trait_items.iter().find(|i| i.name() == assoc_name);
item.expect("missing associated type").def_id()
};
+
(ty, def::DefAssociatedTy(trait_did, item_did))
}
ty
} else {
let path_str = ty::item_path_str(tcx, trait_def_id);
- report_ambiguous_associated_type(
- tcx, span, "Type", &path_str, &token::get_ident(item_segment.identifier));
+ report_ambiguous_associated_type(tcx,
+ span,
+ "Type",
+ &path_str,
+ &token::get_ident(item_segment.identifier));
return tcx.types.err;
};
}
}
+// Note that both base_segments and assoc_segments may be empty, although not at
+// the same time.
pub fn finish_resolving_def_to_ty<'tcx>(this: &AstConv<'tcx>,
rscope: &RegionScope,
span: Span,
param_mode: PathParamMode,
- def: &mut def::Def,
+ def: &def::Def,
opt_self_ty: Option<Ty<'tcx>>,
- segments: &[ast::PathSegment],
+ base_segments: &[ast::PathSegment],
assoc_segments: &[ast::PathSegment])
-> Ty<'tcx> {
let tcx = this.tcx();
span,
param_mode,
trait_def_id,
- segments.last().unwrap(),
+ base_segments.last().unwrap(),
&mut projection_bounds);
- check_path_args(tcx, segments.init(), NO_TPS | NO_REGIONS);
- trait_ref_to_object_type(this, rscope, span, trait_ref,
- projection_bounds, &[])
+ check_path_args(tcx, base_segments.init(), NO_TPS | NO_REGIONS);
+ trait_ref_to_object_type(this,
+ rscope,
+ span,
+ trait_ref,
+ projection_bounds,
+ &[])
}
def::DefTy(did, _) | def::DefStruct(did) => {
- check_path_args(tcx, segments.init(), NO_TPS | NO_REGIONS);
+ check_path_args(tcx, base_segments.init(), NO_TPS | NO_REGIONS);
ast_path_to_ty(this, rscope, span,
param_mode, did,
- segments.last().unwrap())
+ base_segments.last().unwrap())
}
def::DefTyParam(space, index, _, name) => {
- check_path_args(tcx, segments, NO_TPS | NO_REGIONS);
+ check_path_args(tcx, base_segments, NO_TPS | NO_REGIONS);
ty::mk_param(tcx, space, index, name)
}
def::DefSelfTy(_) => {
- // n.b.: resolve guarantees that the this type only appears in a
+ // N.b.: resolve guarantees that the this type only appears in a
// trait, which we rely upon in various places when creating
- // substs
- check_path_args(tcx, segments, NO_TPS | NO_REGIONS);
+ // substs.
+ check_path_args(tcx, base_segments, NO_TPS | NO_REGIONS);
ty::mk_self_type(tcx)
}
def::DefAssociatedTy(trait_did, _) => {
- check_path_args(tcx, &segments[..segments.len()-2], NO_TPS | NO_REGIONS);
- qpath_to_ty(this, rscope, span, param_mode,
- opt_self_ty, trait_did,
- &segments[segments.len()-2],
- segments.last().unwrap())
+ check_path_args(tcx, &base_segments[..base_segments.len()-2], NO_TPS | NO_REGIONS);
+ qpath_to_ty(this,
+ rscope,
+ span,
+ param_mode,
+ opt_self_ty,
+ trait_did,
+ &base_segments[base_segments.len()-2],
+ base_segments.last().unwrap())
}
def::DefMod(id) => {
// Used as sentinel by callers to indicate the `<T>::A::B::C` form.
// FIXME(#22519) This part of the resolution logic should be
// avoided entirely for that form, once we stop needed a Def
// for `associated_path_def_to_ty`.
- if segments.is_empty() {
- opt_self_ty.expect("missing T in <T>::a::b::c")
- } else {
- span_err!(tcx.sess, span, E0247, "found module name used as a type: {}",
+
+ if !base_segments.is_empty() {
+ span_err!(tcx.sess,
+ span,
+ E0247,
+ "found module name used as a type: {}",
tcx.map.node_to_string(id.node));
return this.tcx().types.err;
}
+
+ opt_self_ty.expect("missing T in <T>::a::b::c")
}
def::DefPrimTy(prim_ty) => {
- prim_ty_to_ty(tcx, segments, prim_ty)
+ prim_ty_to_ty(tcx, base_segments, prim_ty)
}
_ => {
span_err!(tcx.sess, span, E0248,
// If any associated type segments remain, attempt to resolve them.
let mut ty = base_ty;
+ let mut def = *def;
for segment in assoc_segments {
if ty.sty == ty::ty_err {
break;
}
// This is pretty bad (it will fail except for T::A and Self::A).
- let (a_ty, a_def) = associated_path_def_to_ty(this, span,
- ty, *def, segment);
+ let (a_ty, a_def) = associated_path_def_to_ty(this,
+ span,
+ ty,
+ def,
+ segment);
ty = a_ty;
- *def = a_def;
+ def = a_def;
}
ty
}
tcx.sess.span_bug(ast_ty.span,
&format!("unbound path {}", ast_ty.repr(tcx)))
};
- let mut def = path_res.base_def;
+ let def = path_res.base_def;
let base_ty_end = path.segments.len() - path_res.depth;
let opt_self_ty = maybe_qself.as_ref().map(|qself| {
ast_ty_to_ty(this, rscope, &qself.ty)
});
- let ty = finish_resolving_def_to_ty(this, rscope, ast_ty.span,
- PathParamMode::Explicit, &mut def,
+ let ty = finish_resolving_def_to_ty(this,
+ rscope,
+ ast_ty.span,
+ PathParamMode::Explicit,
+ &def,
opt_self_ty,
&path.segments[..base_ty_end],
&path.segments[base_ty_end..]);
UnresolvedTypeAction::Error,
LvaluePreference::NoPreference,
|adj_ty, idx| {
- let autoderefref = ty::AutoDerefRef { autoderefs: idx, autoref: None };
- try_overloaded_call_step(fcx, call_expr, callee_expr,
- adj_ty, autoderefref)
+ try_overloaded_call_step(fcx, call_expr, callee_expr, adj_ty, idx)
});
match result {
call_expr: &'tcx ast::Expr,
callee_expr: &'tcx ast::Expr,
adjusted_ty: Ty<'tcx>,
- autoderefref: ty::AutoDerefRef<'tcx>)
+ autoderefs: usize)
-> Option<CallStep<'tcx>>
{
- debug!("try_overloaded_call_step(call_expr={}, adjusted_ty={}, autoderefref={})",
+ debug!("try_overloaded_call_step(call_expr={}, adjusted_ty={}, autoderefs={})",
call_expr.repr(fcx.tcx()),
adjusted_ty.repr(fcx.tcx()),
- autoderefref.repr(fcx.tcx()));
+ autoderefs);
+
+ let autoderefref = ty::AutoDerefRef { autoderefs: autoderefs, autoref: None };
// If the callee is a bare function or a closure, then we're all set.
match structurally_resolved_type(fcx, callee_expr.span, adjusted_ty).sty {
}
}
+ // Hack: we know that there are traits implementing Fn for &F
+ // where F:Fn and so forth. In the particular case of types
+ // like `x: &mut FnMut()`, if there is a call `x()`, we would
+ // normally translate to `FnMut::call_mut(&mut x, ())`, but
+ // that winds up requiring `mut x: &mut FnMut()`. A little
+ // over the top. The simplest fix by far is to just ignore
+ // this case and deref again, so we wind up with
+ // `FnMut::call_mut(&mut *x, ())`.
+ ty::ty_rptr(..) if autoderefs == 0 => {
+ return None;
+ }
+
_ => {}
}
use check::{autoderef, FnCtxt, NoPreference, PreferMutLvalue, UnresolvedTypeAction};
-use middle::infer::{self, cres, Coercion, TypeTrace};
-use middle::infer::combine::Combine;
-use middle::infer::sub::Sub;
+use middle::infer::{self, Coercion};
use middle::subst;
use middle::ty::{AutoPtr, AutoDerefRef, AdjustDerefRef, AutoUnsize, AutoUnsafe};
use middle::ty::{self, mt, Ty};
+use middle::ty_relate::RelateResult;
use util::common::indent;
use util::ppaux;
use util::ppaux::Repr;
struct Coerce<'a, 'tcx: 'a> {
fcx: &'a FnCtxt<'a, 'tcx>,
- trace: TypeTrace<'tcx>
+ origin: infer::TypeOrigin,
}
-type CoerceResult<'tcx> = cres<'tcx, Option<ty::AutoAdjustment<'tcx>>>;
+type CoerceResult<'tcx> = RelateResult<'tcx, Option<ty::AutoAdjustment<'tcx>>>;
impl<'f, 'tcx> Coerce<'f, 'tcx> {
fn tcx(&self) -> &ty::ctxt<'tcx> {
}
fn subtype(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> {
- let sub = Sub(self.fcx.infcx().combine_fields(false, self.trace.clone()));
- try!(sub.tys(a, b));
+ try!(self.fcx.infcx().sub_types(false, self.origin.clone(), a, b));
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));
+ fn outlives(&self,
+ origin: infer::SubregionOrigin<'tcx>,
+ a: ty::Region,
+ b: ty::Region)
+ -> RelateResult<'tcx, ()> {
+ infer::mk_subr(self.fcx.infcx(), origin, b, a);
Ok(())
}
_ => return self.subtype(a, b)
}
- let coercion = Coercion(self.trace.clone());
+ let coercion = Coercion(self.origin.span());
let r_borrow = self.fcx.infcx().next_region_var(coercion);
let autoref = Some(AutoPtr(r_borrow, mutbl_b, None));
}
let ty = ty::mk_rptr(self.tcx(), r_borrow,
mt {ty: inner_ty, mutbl: mutbl_b});
- if let Err(err) = self.fcx.infcx().try(|_| self.subtype(ty, b)) {
+ if let Err(err) = self.subtype(ty, b) {
if first_error.is_none() {
first_error = Some(err);
}
return Err(ty::terr_mutability);
}
- let coercion = Coercion(self.trace.clone());
+ let coercion = Coercion(self.origin.span());
let r_borrow = self.fcx.infcx().next_region_var(coercion);
let ty = ty::mk_rptr(self.tcx(),
self.tcx().mk_region(r_borrow),
ty::mt{ty: ty, mutbl: mt_b.mutbl});
- try!(self.fcx.infcx().try(|_| self.subtype(ty, b)));
+ try!(self.subtype(ty, b));
debug!("Success, coerced with AutoDerefRef(1, \
AutoPtr(AutoUnsize({:?})))", kind);
Ok(Some(AdjustDerefRef(AutoDerefRef {
let ty = ty::mk_ptr(self.tcx(),
ty::mt{ty: ty, mutbl: mt_b.mutbl});
- try!(self.fcx.infcx().try(|_| self.subtype(ty, b)));
+ try!(self.subtype(ty, b));
debug!("Success, coerced with AutoDerefRef(1, \
AutoPtr(AutoUnsize({:?})))", kind);
Ok(Some(AdjustDerefRef(AutoDerefRef {
match self.unsize_ty(t_a, t_b) {
Some((ty, kind)) => {
let ty = ty::mk_uniq(self.tcx(), ty);
- try!(self.fcx.infcx().try(|_| self.subtype(ty, b)));
+ try!(self.subtype(ty, b));
debug!("Success, coerced with AutoDerefRef(1, \
AutoUnsizeUniq({:?}))", kind);
Ok(Some(AdjustDerefRef(AutoDerefRef {
let ty_a1 = ty::mk_trait(tcx, data_a.principal.clone(), bounds_a1);
// relate `a1` to `b`
- let result = self.fcx.infcx().try(|_| {
+ let result = self.fcx.infcx().commit_if_ok(|_| {
// it's ok to upcast from Foo+'a to Foo+'b so long as 'a : 'b
- try!(self.outlives(data_a.bounds.region_bound,
+ try!(self.outlives(infer::RelateObjectBound(self.origin.span()),
+ data_a.bounds.region_bound,
data_b.bounds.region_bound));
self.subtype(ty_a1, ty_b)
});
let mut result = None;
let tps = ty_substs_a.iter().zip(ty_substs_b.iter()).enumerate();
for (i, (tp_a, tp_b)) in tps {
- if self.fcx.infcx().try(|_| self.subtype(*tp_a, *tp_b)).is_ok() {
+ if self.subtype(*tp_a, *tp_b).is_ok() {
continue;
}
match self.unsize_ty(*tp_a, *tp_b) {
let mut new_substs = substs_a.clone();
new_substs.types.get_mut_slice(subst::TypeSpace)[i] = new_tp;
let ty = ty::mk_struct(tcx, did_a, tcx.mk_substs(new_substs));
- if self.fcx.infcx().try(|_| self.subtype(ty, ty_b)).is_err() {
+ if self.subtype(ty, ty_b).is_err() {
debug!("Unsized type parameter '{}', but still \
could not match types {} and {}",
ppaux::ty_to_string(tcx, *tp_a),
expr: &ast::Expr,
a: Ty<'tcx>,
b: Ty<'tcx>)
- -> cres<'tcx, ()> {
+ -> RelateResult<'tcx, ()> {
debug!("mk_assignty({} -> {})", a.repr(fcx.tcx()), b.repr(fcx.tcx()));
let adjustment = try!(indent(|| {
- fcx.infcx().commit_if_ok(|| {
- let origin = infer::ExprAssignable(expr.span);
+ fcx.infcx().commit_if_ok(|_| {
Coerce {
fcx: fcx,
- trace: infer::TypeTrace::types(origin, false, a, b)
+ origin: infer::ExprAssignable(expr.span),
}.coerce(expr, a, b)
})
}));
let trait_fty = ty::mk_bare_fn(tcx, None, tcx.mk_bare_fn(trait_m.fty.clone()));
let trait_fty = trait_fty.subst(tcx, &trait_to_skol_substs);
- let err = infcx.try(|snapshot| {
+ let err = infcx.commit_if_ok(|snapshot| {
let origin = infer::MethodCompatCheck(impl_m_span);
let (impl_sig, _) =
ty::lookup_item_type(tcx, self_type_did);
let infcx = infer::new_infer_ctxt(tcx);
- infcx.try(|snapshot| {
+ infcx.commit_if_ok(|snapshot| {
let (named_type_to_skolem, skol_map) =
infcx.construct_skolemized_subst(named_type_generics, snapshot);
let named_type_skolem = named_type.subst(tcx, &named_type_to_skolem);
// A pared down enum describing just the places from which a method
// candidate can arise. Used for error reporting only.
-#[derive(Copy, PartialOrd, Ord, PartialEq, Eq)]
+#[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq)]
pub enum CandidateSource {
ImplSource(ast::DefId),
TraitSource(/* trait id */ ast::DefId),
AutoRef(ast::Mutability, Box<PickAdjustment>),
}
-#[derive(PartialEq, Eq, Copy)]
+#[derive(PartialEq, Eq, Copy, Clone)]
pub enum Mode {
// An expression of the form `receiver.method_name(...)`.
// Autoderefs are performed on `receiver`, lookup is done based on the
///////////////////////////////////////////////////////////////////////////
// MISCELLANY
- fn make_sub_ty(&self, sub: Ty<'tcx>, sup: Ty<'tcx>) -> infer::ures<'tcx> {
+ fn make_sub_ty(&self, sub: Ty<'tcx>, sup: Ty<'tcx>) -> infer::UnitResult<'tcx> {
self.infcx().sub_types(false, infer::Misc(DUMMY_SP), sub, sup)
}
}).2.is_some()
}
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub struct TraitInfo {
pub def_id: ast::DefId,
}
use check::_match::pat_ctxt;
use fmt_macros::{Parser, Piece, Position};
use middle::astconv_util::{check_path_args, NO_TPS, NO_REGIONS};
-use middle::{const_eval, def};
+use middle::def;
use middle::infer;
use middle::mem_categorization as mc;
use middle::mem_categorization::McResult;
use middle::region::{self, CodeExtent};
use middle::subst::{self, Subst, Substs, VecPerParamSpace, ParamSpace, TypeSpace};
use middle::traits;
-use middle::ty::{FnSig, GenericPredicates, VariantInfo, TypeScheme};
+use middle::ty::{FnSig, GenericPredicates, TypeScheme};
use middle::ty::{Disr, ParamTy, ParameterEnvironment};
use middle::ty::{self, HasProjectionTypes, RegionEscape, ToPolyTraitRef, Ty};
use middle::ty::liberate_late_bound_regions;
use syntax::ast::{self, DefId, Visibility};
use syntax::ast_util::{self, local_def};
use syntax::codemap::{self, Span};
+use syntax::feature_gate;
use syntax::owned_slice::OwnedSlice;
use syntax::parse::token;
use syntax::print::pprust;
/// When type-checking an expression, we propagate downward
/// whatever type hint we are able in the form of an `Expectation`.
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub enum Expectation<'tcx> {
/// We know nothing about what type this expression should have.
NoExpectation,
}
}
-#[derive(Copy, Debug, PartialEq, Eq)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum LvaluePreference {
PreferMutLvalue,
NoPreference
}
/// Whether `autoderef` requires types to resolve.
-#[derive(Copy, Debug, PartialEq, Eq)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum UnresolvedTypeAction {
/// Produce an error and return `ty_err` whenever a type cannot
/// be resolved (i.e. it is `ty_infer`).
tcx.lang_items.neg_trait(),
expr, &**oprnd, oprnd_t, unop);
}
+ if let ty::ty_uint(_) = oprnd_t.sty {
+ if !tcx.sess.features.borrow().negate_unsigned {
+ feature_gate::emit_feature_err(
+ &tcx.sess.parse_sess.span_diagnostic,
+ "negate_unsigned",
+ expr.span,
+ "unary negation of unsigned integers may be removed in the future");
+ }
+ }
}
}
}
&format!("unbound path {}", expr.repr(tcx)))
};
- let mut def = path_res.base_def;
+ let def = path_res.base_def;
if path_res.depth == 0 {
let (scheme, predicates) =
type_scheme_and_predicates_for_def(fcx, expr.span, def);
} else {
let ty_segments = path.segments.init();
let base_ty_end = path.segments.len() - path_res.depth;
- let ty = astconv::finish_resolving_def_to_ty(fcx, fcx, expr.span,
+ let ty = astconv::finish_resolving_def_to_ty(fcx,
+ fcx,
+ expr.span,
PathParamMode::Optional,
- &mut def,
+ &def,
opt_self_ty,
&ty_segments[..base_ty_end],
&ty_segments[base_ty_end..]);
fn do_check<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
vs: &'tcx [P<ast::Variant>],
id: ast::NodeId,
- hint: attr::ReprAttr)
- -> Vec<Rc<ty::VariantInfo<'tcx>>> {
+ hint: attr::ReprAttr) {
#![allow(trivial_numeric_casts)]
let rty = ty::node_id_to_type(ccx.tcx, id);
- let mut variants: Vec<Rc<ty::VariantInfo>> = Vec::new();
let mut disr_vals: Vec<ty::Disr> = Vec::new();
- let mut prev_disr_val: Option<ty::Disr> = None;
+ let inh = static_inherited_fields(ccx);
+ let fcx = blank_fn_ctxt(ccx, &inh, ty::FnConverging(rty), id);
+
+ let (_, repr_type_ty) = ty::enum_repr_type(ccx.tcx, Some(&hint));
for v in vs {
+ if let Some(ref e) = v.node.disr_expr {
+ check_const_with_ty(&fcx, e.span, e, repr_type_ty);
+ }
+ }
- // If the discriminant value is specified explicitly in the enum check whether the
- // initialization expression is valid, otherwise use the last value plus one.
- let mut current_disr_val = match prev_disr_val {
- Some(prev_disr_val) => {
- if let Some(v) = prev_disr_val.checked_add(1) {
- v
- } else {
- ty::INITIAL_DISCRIMINANT_VALUE
- }
- }
- None => ty::INITIAL_DISCRIMINANT_VALUE
- };
+ let def_id = local_def(id);
- match v.node.disr_expr {
- Some(ref e) => {
- debug!("disr expr, checking {}", pprust::expr_to_string(&**e));
+ // ty::enum_variants guards against discriminant overflows, so
+ // we need not check for that.
+ let variants = ty::enum_variants(ccx.tcx, def_id);
- let inh = static_inherited_fields(ccx);
- let fcx = blank_fn_ctxt(ccx, &inh, ty::FnConverging(rty), e.id);
- let declty = match hint {
- attr::ReprAny | attr::ReprPacked |
- attr::ReprExtern => fcx.tcx().types.isize,
-
- attr::ReprInt(_, attr::SignedInt(ity)) => {
- ty::mk_mach_int(fcx.tcx(), ity)
- }
- attr::ReprInt(_, attr::UnsignedInt(ity)) => {
- ty::mk_mach_uint(fcx.tcx(), ity)
- },
- };
- check_const_with_ty(&fcx, e.span, &**e, declty);
- // check_expr (from check_const pass) doesn't guarantee
- // that the expression is in a form that eval_const_expr can
- // handle, so we may still get an internal compiler error
-
- match const_eval::eval_const_expr_partial(ccx.tcx, &**e, Some(declty)) {
- Ok(const_eval::const_int(val)) => current_disr_val = val as Disr,
- Ok(const_eval::const_uint(val)) => current_disr_val = val as Disr,
- Ok(_) => {
- span_err!(ccx.tcx.sess, e.span, E0079,
- "expected signed integer constant");
- }
- Err(ref err) => {
- span_err!(ccx.tcx.sess, err.span, E0080,
- "constant evaluation error: {}",
- err.description());
- }
- }
- },
- None => ()
- };
+ for (v, variant) in vs.iter().zip(variants.iter()) {
+ let current_disr_val = variant.disr_val;
// Check for duplicate discriminant values
match disr_vals.iter().position(|&x| x == current_disr_val) {
}
}
disr_vals.push(current_disr_val);
-
- let variant_info = Rc::new(VariantInfo::from_ast_variant(ccx.tcx, &**v,
- current_disr_val));
- prev_disr_val = Some(current_disr_val);
-
- variants.push(variant_info);
}
-
- return variants;
}
let hint = *ty::lookup_repr_hints(ccx.tcx, ast::DefId { krate: ast::LOCAL_CRATE, node: id })
};
}
- let variants = do_check(ccx, vs, id, hint);
-
- // cache so that ty::enum_variants won't repeat this work
- ccx.tcx.enum_var_cache.borrow_mut().insert(local_def(id), Rc::new(variants));
+ do_check(ccx, vs, id, hint);
check_representable(ccx.tcx, sp, id, "enum");
debug!("projection_bounds: outlives={} (2)",
outlives.repr(tcx));
- let region_result = infcx.try(|_| {
+ let region_result = infcx.commit_if_ok(|_| {
let (outlives, _) =
infcx.replace_late_bound_regions_with_fresh_var(
span,
&fcx.inh.param_env.free_substs,
&trait_ref);
- if fcx.tcx().lang_items.copy_trait() == Some(trait_ref.def_id) {
- // This is checked in coherence.
- return
- }
-
// We are stricter on the trait-ref in an impl than the
// self-type. In particular, we enforce region
// relationships. The reason for this is that (at least
///////////////////////////////////////////////////////////////////////////
// Resolution reason.
-#[derive(Copy)]
+#[derive(Copy, Clone)]
enum ResolveReason {
ResolvingExpr(Span),
ResolvingLocal(Span),
use middle::ty::ty_projection;
use middle::ty;
use CrateCtxt;
-use middle::infer::combine::Combine;
use middle::infer::InferCtxt;
use middle::infer::new_infer_ctxt;
use std::collections::HashSet;
match traits::orphan_check(self.tcx, def_id) {
Ok(()) => { }
Err(traits::OrphanCheckErr::NoLocalInputType) => {
- if !ty::has_attr(self.tcx, trait_def_id, "old_orphan_check") {
- span_err!(
- self.tcx.sess, item.span, E0117,
- "the impl does not reference any \
- types defined in this crate; \
- only traits defined in the current crate can be \
- implemented for arbitrary types");
- return;
- }
+ span_err!(
+ self.tcx.sess, item.span, E0117,
+ "the impl does not reference any \
+ types defined in this crate; \
+ only traits defined in the current crate can be \
+ implemented for arbitrary types");
+ return;
}
Err(traits::OrphanCheckErr::UncoveredTy(param_ty)) => {
- if !ty::has_attr(self.tcx, trait_def_id, "old_orphan_check") {
- span_err!(self.tcx.sess, item.span, E0210,
- "type parameter `{}` must be used as the type parameter for \
- some local type (e.g. `MyStruct<T>`); only traits defined in \
- the current crate can be implemented for a type parameter",
- param_ty.user_string(self.tcx));
- return;
- }
+ span_err!(self.tcx.sess, item.span, E0210,
+ "type parameter `{}` must be used as the type parameter for \
+ some local type (e.g. `MyStruct<T>`); only traits defined in \
+ the current crate can be implemented for a type parameter",
+ param_ty.user_string(self.tcx));
+ return;
}
}
param_bounds: &'a (GetTypeParameterBounds<'tcx>+'a),
}
-#[derive(Copy, PartialEq, Eq)]
+#[derive(Copy, Clone, PartialEq, Eq)]
enum AstConvRequest {
GetItemTypeScheme(ast::DefId),
GetTraitDef(ast::DefId),
E0075,
E0076,
E0077,
- E0079,
- E0080,
E0081,
E0082,
E0083,
fn write_ty_to_tcx<'tcx>(tcx: &ty::ctxt<'tcx>, node_id: ast::NodeId, ty: Ty<'tcx>) {
debug!("write_ty_to_tcx({}, {})", node_id, ppaux::ty_to_string(tcx, ty));
assert!(!ty::type_needs_infer(ty));
- tcx.node_types.borrow_mut().insert(node_id, ty);
+ tcx.node_type_insert(node_id, ty);
}
fn write_substs_to_tcx<'tcx>(tcx: &ty::ctxt<'tcx>,
// A scope in which all regions must be explicitly named. This is used
// for types that appear in structs and so on.
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub struct ExplicitRscope;
impl RegionScope for ExplicitRscope {
type VarianceTermPtr<'a> = &'a VarianceTerm<'a>;
-#[derive(Copy, Debug)]
+#[derive(Copy, Clone, Debug)]
struct InferredIndex(usize);
-#[derive(Copy)]
+#[derive(Copy, Clone)]
enum VarianceTerm<'a> {
ConstantTerm(ty::Variance),
TransformTerm(VarianceTermPtr<'a>, VarianceTermPtr<'a>),
inferred_infos: Vec<InferredInfo<'a>> ,
}
-#[derive(Copy, Debug, PartialEq)]
+#[derive(Copy, Clone, Debug, PartialEq)]
enum ParamKind {
TypeParam,
RegionParam,
/// Declares that the variable `decl_id` appears in a location with
/// variance `variance`.
-#[derive(Copy)]
+#[derive(Copy, Clone)]
struct Constraint<'a> {
inferred: InferredIndex,
variance: &'a VarianceTerm<'a>,
};
match def {
- def::DefSelfTy(..) => {
+ def::DefSelfTy(..) if path.segments.len() == 1 => {
return Generic(token::get_name(special_idents::type_self.name).to_string());
}
def::DefPrimTy(p) => match p {
ast::TyFloat(ast::TyF32) => return Primitive(F32),
ast::TyFloat(ast::TyF64) => return Primitive(F64),
},
- def::DefTyParam(_, _, _, n) => return Generic(token::get_name(n).to_string()),
+ def::DefTyParam(_, _, _, n) => {
+ return Generic(token::get_name(n).to_string())
+ }
_ => {}
};
let did = register_def(&*cx, def);
#[cfg(unix)]
mod imp {
- use std::ffi::{AsOsStr, CString};
+ use std::ffi::{CString, OsStr};
use std::os::unix::prelude::*;
use std::path::Path;
use std::io;
impl Lock {
pub fn new(p: &Path) -> Lock {
- let buf = CString::new(p.as_os_str().as_bytes()).unwrap();
+ let os: &OsStr = p.as_ref();
+ let buf = CString::new(os.as_bytes()).unwrap();
let fd = unsafe {
libc::open(buf.as_ptr(), libc::O_RDWR | libc::O_CREAT,
libc::S_IRWXU)
#[cfg(windows)]
mod imp {
use libc;
- use std::ffi::AsOsStr;
use std::io;
use std::mem;
+ use std::ffi::OsStr;
use std::os::windows::prelude::*;
use std::path::Path;
use std::ptr;
impl Lock {
pub fn new(p: &Path) -> Lock {
- let mut p_16: Vec<_> = p.as_os_str().encode_wide().collect();
+ let os: &OsStr = p.as_ref();
+ let mut p_16: Vec<_> = os.encode_wide().collect();
p_16.push(0);
let handle = unsafe {
libc::CreateFileW(p_16.as_ptr(),
/// Helper to render an optional visibility with a space after it (if the
/// visibility is preset)
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub struct VisSpace(pub Option<ast::Visibility>);
/// Similarly to VisSpace, this structure is used to render a function style with a
/// space after it.
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub struct UnsafetySpace(pub ast::Unsafety);
/// Wrapper struct for properly emitting a method declaration.
pub struct Method<'a>(pub &'a clean::SelfTy, pub &'a clean::FnDecl);
/// Similar to VisSpace, but used for mutability
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub struct MutableSpace(pub clean::Mutability);
/// Similar to VisSpace, but used for mutability
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub struct RawMutableSpace(pub clean::Mutability);
/// Wrapper struct for properly emitting the stability level.
pub struct Stability<'a>(pub &'a Option<clean::Stability>);
// Helper structs for rendering items/sidebars and carrying along contextual
// information
-#[derive(Copy)]
+#[derive(Copy, Clone)]
struct Item<'a> {
cx: &'a Context,
item: &'a clean::Item,
#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(collections)]
-#![feature(core)]
#![feature(exit_status)]
#![feature(set_stdio)]
#![feature(libc)]
#![feature(file_path)]
#![feature(path_ext)]
#![feature(path_relative_from)]
-#![feature(convert)]
#![feature(slice_patterns)]
extern crate arena;
fn parse_externs(matches: &getopts::Matches) -> Result<core::Externs, String> {
let mut externs = HashMap::new();
for arg in &matches.opt_strs("extern") {
- let mut parts = arg.splitn(1, '=');
+ let mut parts = arg.splitn(2, '=');
let name = match parts.next() {
Some(s) => s,
None => {
#[derive(RustcEncodable, RustcDecodable, PartialEq, Eq)]
/// The counts for each stability level.
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub struct Counts {
pub deprecated: u64,
pub unstable: u64,
use std::process::Command;
use std::str;
use std::sync::{Arc, Mutex};
-use std::thunk::Thunk;
use testing;
use rustc_lint;
ignore: should_ignore,
should_panic: testing::ShouldPanic::No, // compiler failures are test failures
},
- testfn: testing::DynTestFn(Thunk::new(move|| {
+ testfn: testing::DynTestFn(Box::new(move|| {
runtest(&test,
&cratename,
libs,
}
/// Errors that can occur when decoding a hex encoded string
-#[derive(Copy, Debug)]
+#[derive(Copy, Clone, Debug)]
pub enum FromHexError {
/// The input contained a character not part of the hex format
InvalidHexCharacter(char, usize),
//! let encoded = json::encode(&object).unwrap();
//!
//! // Deserialize using `json::decode`
-//! let decoded: TestStruct = json::decode(encoded.as_slice()).unwrap();
+//! let decoded: TestStruct = json::decode(&encoded[..]).unwrap();
//! }
//! ```
//!
ApplicationError(string::String)
}
-#[derive(Copy, Debug)]
+#[derive(Copy, Clone, Debug)]
pub enum EncoderError {
FmtError(fmt::Error),
BadHashmapKey,
fn description(&self) -> &str { "encoder error" }
}
-impl std::error::FromError<fmt::Error> for EncoderError {
- fn from_error(err: fmt::Error) -> EncoderError { EncoderError::FmtError(err) }
+impl From<fmt::Error> for EncoderError {
+ fn from(err: fmt::Error) -> EncoderError { EncoderError::FmtError(err) }
}
pub type EncodeResult = Result<(), EncoderError>;
#![feature(std_misc)]
#![feature(unicode)]
#![feature(str_char)]
-#![feature(convert)]
#![cfg_attr(test, feature(test, old_io))]
// test harness access
}
}
- #[unstable(feature = "collections",
- reason = "matches entry v3 specification, waiting for dust to settle")]
+ #[stable(feature = "rust1", since = "1.0.0")]
/// Ensures a value is in the entry by inserting the default if empty, and returns
/// a mutable reference to the value in the entry.
pub fn or_insert(self, default: V) -> &'a mut V {
}
}
- #[unstable(feature = "collections",
- reason = "matches entry v3 specification, waiting for dust to settle")]
+ #[stable(feature = "rust1", since = "1.0.0")]
/// Ensures a value is in the entry by inserting the result of the default function if empty,
/// and returns a mutable reference to the value in the entry.
pub fn or_insert_with<F: FnOnce() -> V>(self, default: F) -> &'a mut V {
};
let v = hs.into_iter().collect::<Vec<char>>();
- assert!(['a', 'b'] == v || ['b', 'a'] == v);
+ assert!(v == ['a', 'b'] || v == ['b', 'a']);
}
#[test]
use clone::Clone;
use cmp;
use hash::{Hash, Hasher};
-use iter::{Iterator, ExactSizeIterator, count};
+use iter::{Iterator, ExactSizeIterator};
use marker::{Copy, Send, Sync, Sized, self};
use mem::{min_align_of, size_of};
use mem;
}
impl<K,V> Copy for RawBucket<K,V> {}
+impl<K,V> Clone for RawBucket<K,V> {
+ fn clone(&self) -> RawBucket<K, V> { *self }
+}
pub struct Bucket<K, V, M> {
raw: RawBucket<K, V>,
}
impl<K,V,M:Copy> Copy for Bucket<K,V,M> {}
+impl<K,V,M:Copy> Clone for Bucket<K,V,M> {
+ fn clone(&self) -> Bucket<K,V,M> { *self }
+}
pub struct EmptyBucket<K, V, M> {
raw: RawBucket<K, V>,
/// A hash that is not zero, since we use a hash of zero to represent empty
/// buckets.
-#[derive(PartialEq, Copy)]
+#[derive(PartialEq, Copy, Clone)]
pub struct SafeHash {
hash: u64,
}
use prelude::v1::*;
use env;
-use ffi::{AsOsStr, CString, OsString};
+use ffi::{CString, OsString};
use mem;
use path::{Path, PathBuf};
use ffi::{CStr, OsStr};
use str;
use libc;
- use os::unix::prelude::*;
use ptr;
pub fn open(filename: Option<&OsStr>) -> Result<*mut u8, String> {
use iter::IntoIterator;
use error::Error;
-use ffi::{OsString, AsOsStr};
+use ffi::{OsStr, OsString};
use fmt;
use io;
use path::{Path, PathBuf};
/// }
/// ```
#[stable(feature = "env", since = "1.0.0")]
-pub fn var<K: ?Sized>(key: &K) -> Result<String, VarError> where K: AsOsStr {
+pub fn var<K: ?Sized>(key: &K) -> Result<String, VarError> where K: AsRef<OsStr> {
match var_os(key) {
Some(s) => s.into_string().map_err(VarError::NotUnicode),
None => Err(VarError::NotPresent)
/// }
/// ```
#[stable(feature = "env", since = "1.0.0")]
-pub fn var_os<K: ?Sized>(key: &K) -> Option<OsString> where K: AsOsStr {
+pub fn var_os<K: ?Sized>(key: &K) -> Option<OsString> where K: AsRef<OsStr> {
let _g = ENV_LOCK.lock();
- os_imp::getenv(key.as_os_str())
+ os_imp::getenv(key.as_ref())
}
/// Possible errors from the `env::var` method.
/// ```
#[stable(feature = "env", since = "1.0.0")]
pub fn set_var<K: ?Sized, V: ?Sized>(k: &K, v: &V)
- where K: AsOsStr, V: AsOsStr
+ where K: AsRef<OsStr>, V: AsRef<OsStr>
{
let _g = ENV_LOCK.lock();
- os_imp::setenv(k.as_os_str(), v.as_os_str())
+ os_imp::setenv(k.as_ref(), v.as_ref())
}
-/// Remove a variable from the environment entirely.
+/// Remove an environment variable from the environment of the currently running process.
+///
+/// # Examples
+///
+/// ```
+/// use std::env;
+///
+/// let key = "KEY";
+/// env::set_var(key, "VALUE");
+/// assert_eq!(env::var(key), Ok("VALUE".to_string()));
+///
+/// env::remove_var(key);
+/// assert!(env::var(key).is_err());
+/// ```
#[stable(feature = "env", since = "1.0.0")]
-pub fn remove_var<K: ?Sized>(k: &K) where K: AsOsStr {
+pub fn remove_var<K: ?Sized>(k: &K) where K: AsRef<OsStr> {
let _g = ENV_LOCK.lock();
- os_imp::unsetenv(k.as_os_str())
+ os_imp::unsetenv(k.as_ref())
}
/// An iterator over `Path` instances for parsing an environment variable
/// }
/// ```
#[stable(feature = "env", since = "1.0.0")]
-pub fn split_paths<T: AsOsStr + ?Sized>(unparsed: &T) -> SplitPaths {
- SplitPaths { inner: os_imp::split_paths(unparsed.as_os_str()) }
+pub fn split_paths<T: AsRef<OsStr> + ?Sized>(unparsed: &T) -> SplitPaths {
+ SplitPaths { inner: os_imp::split_paths(unparsed.as_ref()) }
}
#[stable(feature = "env", since = "1.0.0")]
/// # Examples
///
/// ```
-/// # #![feature(convert)]
/// use std::env;
/// use std::path::PathBuf;
///
/// ```
#[stable(feature = "env", since = "1.0.0")]
pub fn join_paths<I, T>(paths: I) -> Result<OsString, JoinPathsError>
- where I: IntoIterator<Item=T>, T: AsOsStr
+ where I: IntoIterator<Item=T>, T: AsRef<OsStr>
{
os_imp::join_paths(paths.into_iter()).map_err(|e| {
JoinPathsError { inner: e }
/// On Windows, returns the value of, in order, the 'TMP', 'TEMP',
/// 'USERPROFILE' environment variable if any are set and not the empty
/// string. Otherwise, tmpdir returns the path to the Windows directory.
+///
+/// ```
+/// use std::env;
+/// use std::fs::File;
+///
+/// # fn foo() -> std::io::Result<()> {
+/// let mut dir = env::temp_dir();
+/// dir.push("foo.txt");
+///
+/// let f = try!(File::create(dir));
+/// # Ok(())
+/// # }
+/// ```
#[stable(feature = "env", since = "1.0.0")]
pub fn temp_dir() -> PathBuf {
os_imp::temp_dir()
#[stable(feature = "env", since = "1.0.0")]
pub const ARCH: &'static str = super::arch::ARCH;
+ /// The family of the operating system. In this case, `unix`.
#[stable(feature = "env", since = "1.0.0")]
pub const FAMILY: &'static str = super::os::FAMILY;
let mut rng = rand::thread_rng();
let n = format!("TEST{}", rng.gen_ascii_chars().take(10)
.collect::<String>());
- let n = OsString::from_string(n);
+ let n = OsString::from(n);
assert!(var_os(&n).is_none());
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 working with Errors.
+//!
+//! # The `Error` trait
+//!
+//! `Error` is a trait representing the basic expectations for error values,
+//! i.e. values of type `E` in `Result<T, E>`. At a minimum, errors must provide
+//! a description, but they may optionally provide additional detail (via
+//! `Display`) and cause chain information:
+//!
+//! ```
+//! use std::fmt::Display;
+//!
+//! trait Error: Display {
+//! fn description(&self) -> &str;
+//!
+//! fn cause(&self) -> Option<&Error> { None }
+//! }
+//! ```
+//!
+//! The `cause` method is generally used when errors cross "abstraction
+//! boundaries", i.e. when a one module must report an error that is "caused"
+//! by an error from a lower-level module. This setup makes it possible for the
+//! high-level module to provide its own errors that do not commit to any
+//! particular implementation, but also reveal some of its implementation for
+//! debugging via `cause` chains.
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+// A note about crates and the facade:
+//
+// Originally, the `Error` trait was defined in libcore, and the impls
+// were scattered about. However, coherence objected to this
+// arrangement, because to create the blanket impls for `Box` required
+// knowing that `&str: !Error`, and we have no means to deal with that
+// sort of conflict just now. Therefore, for the time being, we have
+// moved the `Error` trait into libstd. As we evolve a sol'n to the
+// coherence challenge (e.g., specialization, neg impls, etc) we can
+// reconsider what crate these items belong in.
+
+use boxed::Box;
+use convert::From;
+use fmt::{self, Debug, Display};
+use marker::Send;
+use num;
+use option::Option;
+use option::Option::None;
+use str;
+use string::{self, String};
+
+/// Base functionality for all errors in Rust.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub trait Error: Debug + Display {
+ /// 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 }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a, E: Error + 'a> From<E> for Box<Error + 'a> {
+ fn from(err: E) -> Box<Error + 'a> {
+ Box::new(err)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a, E: Error + Send + 'a> From<E> for Box<Error + Send + 'a> {
+ fn from(err: E) -> Box<Error + Send + 'a> {
+ Box::new(err)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a, 'b> From<&'b str> for Box<Error + Send + 'a> {
+ fn from(err: &'b str) -> Box<Error + Send + 'a> {
+ #[derive(Debug)]
+ struct StringError(String);
+
+ impl Error for StringError {
+ fn description(&self) -> &str { &self.0 }
+ }
+
+ impl Display for StringError {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ Display::fmt(&self.0, f)
+ }
+ }
+
+ Box::new(StringError(String::from_str(err)))
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Error for str::ParseBoolError {
+ fn description(&self) -> &str { "failed to parse bool" }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Error for str::Utf8Error {
+ fn description(&self) -> &str {
+ match *self {
+ str::Utf8Error::TooShort => "invalid utf-8: not enough bytes",
+ str::Utf8Error::InvalidByte(..) => "invalid utf-8: corrupt contents",
+ }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Error for num::ParseIntError {
+ fn description(&self) -> &str {
+ self.description()
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Error for num::ParseFloatError {
+ fn description(&self) -> &str {
+ self.description()
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Error for string::FromUtf8Error {
+ fn description(&self) -> &str {
+ "invalid utf-8"
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Error for string::FromUtf16Error {
+ fn description(&self) -> &str {
+ "invalid utf-16"
+ }
+}
+
#![unstable(feature = "std_misc")]
-use convert::Into;
+use convert::{Into, From};
use cmp::{PartialEq, Eq, PartialOrd, Ord, Ordering};
-use error::{Error, FromError};
+use error::Error;
use fmt;
use io;
use iter::Iterator;
#[stable(feature = "rust1", since = "1.0.0")]
pub struct NulError(usize, Vec<u8>);
-/// 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>;
-}
-
impl CString {
/// Create a new C-compatible string from a container of bytes.
///
}
}
- /// Create a new C-compatible string from a byte slice.
- ///
- /// This method will copy the data of the slice provided into a new
- /// allocation, ensuring that there is a trailing 0 byte.
- ///
- /// # Examples
- ///
- /// ```no_run
- /// # #![feature(libc)]
- /// extern crate libc;
- /// use std::ffi::CString;
- ///
- /// extern { fn puts(s: *const libc::c_char); }
- ///
- /// fn main() {
- /// let to_print = CString::new("Hello!").unwrap();
- /// unsafe {
- /// puts(to_print.as_ptr());
- /// }
- /// }
- /// ```
- ///
- /// # Panics
- ///
- /// This function will panic if the provided slice contains any
- /// interior nul bytes.
- #[unstable(feature = "std_misc")]
- #[deprecated(since = "1.0.0", reason = "use CString::new instead")]
- #[allow(deprecated)]
- pub fn from_slice(v: &[u8]) -> CString {
- CString::from_vec(v.to_vec())
- }
-
- /// Create a C-compatible string from a byte vector.
- ///
- /// This method will consume ownership of the provided vector, appending a 0
- /// byte to the end after verifying that there are no interior 0 bytes.
- ///
- /// # Panics
- ///
- /// This function will panic if the provided slice contains any
- /// interior nul bytes.
- #[unstable(feature = "std_misc")]
- #[deprecated(since = "1.0.0", reason = "use CString::new instead")]
- pub fn from_vec(v: Vec<u8>) -> CString {
- match v.iter().position(|x| *x == 0) {
- Some(i) => panic!("null byte found in slice at: {}", i),
- None => unsafe { CString::from_vec_unchecked(v) },
- }
- }
-
/// Create a C-compatible string from a byte vector without checking for
/// interior 0 bytes.
///
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl FromError<NulError> for io::Error {
- fn from_error(_: NulError) -> io::Error {
+impl From<NulError> for io::Error {
+ fn from(_: NulError) -> io::Error {
io::Error::new(io::ErrorKind::InvalidInput,
- "data provided contains a nul byte", None)
+ "data provided contains a nul byte")
}
}
#[stable(feature = "rust1", since = "1.0.0")]
#[allow(deprecated)]
-impl FromError<NulError> for old_io::IoError {
- fn from_error(_: NulError) -> old_io::IoError {
+impl From<NulError> for old_io::IoError {
+ fn from(_: NulError) -> old_io::IoError {
old_io::IoError {
kind: old_io::IoErrorKind::InvalidInput,
desc: "data provided contains a nul byte",
}
}
-/// Deprecated in favor of `CStr`
-#[unstable(feature = "std_misc")]
-#[deprecated(since = "1.0.0", reason = "use CStr::from_ptr(p).to_bytes() instead")]
-pub unsafe fn c_str_to_bytes<'a>(raw: &'a *const libc::c_char) -> &'a [u8] {
- let len = libc::strlen(*raw);
- slice::from_raw_parts(*(raw as *const _ as *const *const u8), len as usize)
-}
-
-/// Deprecated in favor of `CStr`
-#[unstable(feature = "std_misc")]
-#[deprecated(since = "1.0.0",
- reason = "use CStr::from_ptr(p).to_bytes_with_nul() instead")]
-pub unsafe fn c_str_to_bytes_with_nul<'a>(raw: &'a *const libc::c_char)
- -> &'a [u8] {
- let len = libc::strlen(*raw) + 1;
- 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 }
-}
-
#[cfg(test)]
mod tests {
use prelude::v1::*;
#![stable(feature = "rust1", since = "1.0.0")]
#[stable(feature = "rust1", since = "1.0.0")]
-pub use self::c_str::{CString, CStr};
-pub use self::c_str::{NulError, IntoBytes};
-#[allow(deprecated)]
-pub use self::c_str::c_str_to_bytes;
-#[allow(deprecated)]
-pub use self::c_str::c_str_to_bytes_with_nul;
+pub use self::c_str::{CString, CStr, NulError};
#[stable(feature = "rust1", since = "1.0.0")]
-pub use self::os_str::OsString;
-#[stable(feature = "rust1", since = "1.0.0")]
-pub use self::os_str::OsStr;
+pub use self::os_str::{OsString, OsStr};
mod c_str;
mod os_str;
//! for conversion to/from various other string types. Eventually these types
//! will offer a full-fledged string API.
-#![unstable(feature = "os",
+#![unstable(feature = "os_str",
reason = "recently added as part of path/io reform")]
use core::prelude::*;
use borrow::{Borrow, Cow, ToOwned};
+use ffi::CString;
use fmt::{self, Debug};
use mem;
use string::String;
use cmp;
use hash::{Hash, Hasher};
use old_path::{Path, GenericPath};
+use vec::Vec;
use sys::os_str::{Buf, Slice};
use sys_common::{AsInner, IntoInner, FromInner};
}
impl OsString {
- /// Constructs an `OsString` at no cost by consuming a `String`.
+ /// Constructs a new empty `OsString`.
#[stable(feature = "rust1", since = "1.0.0")]
- #[deprecated(since = "1.0.0", reason = "use `from` instead")]
- pub fn from_string(s: String) -> OsString {
- OsString::from(s)
+ pub fn new() -> OsString {
+ OsString { inner: Buf::from_string(String::new()) }
}
- /// Constructs an `OsString` by copying from a `&str` slice.
+ /// Construct an `OsString` from a byte sequence.
///
- /// 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::from(s)
+ /// # Platform behavior
+ ///
+ /// On Unix systems, any byte sequence can be successfully
+ /// converted into an `OsString`.
+ ///
+ /// On Windows system, only UTF-8 byte sequences will successfully
+ /// convert; non UTF-8 data will produce `None`.
+ #[unstable(feature = "convert", reason = "recently added")]
+ pub fn from_bytes<B>(bytes: B) -> Option<OsString> where B: Into<Vec<u8>> {
+ #[cfg(unix)]
+ fn from_bytes_inner(vec: Vec<u8>) -> Option<OsString> {
+ use os::unix::ffi::OsStringExt;
+ Some(OsString::from_vec(vec))
+ }
+
+ #[cfg(windows)]
+ fn from_bytes_inner(vec: Vec<u8>) -> Option<OsString> {
+ String::from_utf8(vec).ok().map(OsString::from)
+ }
+
+ from_bytes_inner(bytes.into())
}
- /// Constructs a new empty `OsString`.
+ /// Convert to an `OsStr` slice.
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn new() -> OsString {
- OsString { inner: Buf::from_string(String::new()) }
+ pub fn as_os_str(&self) -> &OsStr {
+ self
}
/// Convert the `OsString` into a `String` if it contains valid Unicode data.
self.inner.into_string().map_err(|buf| OsString { inner: buf} )
}
- /// Extend the string with the given `&OsStr` slice.
- #[deprecated(since = "1.0.0", reason = "renamed to `push`")]
- #[unstable(feature = "os")]
- pub fn push_os_str(&mut self, s: &OsStr) {
- self.inner.push_slice(&s.inner)
- }
-
/// Extend the string with the given `&OsStr` slice.
#[stable(feature = "rust1", since = "1.0.0")]
pub fn push<T: AsRef<OsStr>>(&mut self, s: T) {
}
impl OsStr {
+ /// Coerce into an `OsStr` slice.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn new<S: AsRef<OsStr> + ?Sized>(s: &S) -> &OsStr {
+ s.as_ref()
+ }
+
/// Coerce directly from a `&str` slice to a `&OsStr` slice.
#[stable(feature = "rust1", since = "1.0.0")]
+ #[deprecated(since = "1.0.0",
+ reason = "use `OsStr::new` instead")]
pub fn from_str(s: &str) -> &OsStr {
unsafe { mem::transmute(Slice::from_str(s)) }
}
OsString { inner: self.inner.to_owned() }
}
+ /// Yield this `OsStr` as a byte slice.
+ ///
+ /// # Platform behavior
+ ///
+ /// On Unix systems, this is a no-op.
+ ///
+ /// On Windows systems, this returns `None` unless the `OsStr` is
+ /// valid unicode, in which case it produces UTF-8-encoded
+ /// data. This may entail checking validity.
+ #[unstable(feature = "convert", reason = "recently added")]
+ pub fn to_bytes(&self) -> Option<&[u8]> {
+ if cfg!(windows) {
+ self.to_str().map(|s| s.as_bytes())
+ } else {
+ Some(self.bytes())
+ }
+ }
+
+ /// Create a `CString` containing this `OsStr` data.
+ ///
+ /// Fails if the `OsStr` contains interior nulls.
+ ///
+ /// This is a convenience for creating a `CString` from
+ /// `self.to_bytes()`, and inherits the platform behavior of the
+ /// `to_bytes` method.
+ #[unstable(feature = "convert", reason = "recently added")]
+ pub fn to_cstring(&self) -> Option<CString> {
+ self.to_bytes().and_then(|b| CString::new(b).ok())
+ }
+
/// Get the underlying byte representation.
///
/// Note: it is *crucial* that this API is private, to avoid
#[stable(feature = "rust1", since = "1.0.0")]
impl PartialEq<str> for OsStr {
fn eq(&self, other: &str) -> bool {
- *self == *OsStr::from_str(other)
+ *self == *OsStr::new(other)
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl PartialEq<OsStr> for str {
fn eq(&self, other: &OsStr) -> bool {
- *other == *OsStr::from_str(self)
+ *other == *OsStr::new(self)
}
}
impl PartialOrd<str> for OsStr {
#[inline]
fn partial_cmp(&self, other: &str) -> Option<cmp::Ordering> {
- self.partial_cmp(OsStr::from_str(other))
+ self.partial_cmp(OsStr::new(other))
}
}
#[deprecated(since = "1.0.0", reason = "trait is deprecated")]
impl AsOsStr for str {
fn as_os_str(&self) -> &OsStr {
- OsStr::from_str(self)
+ unsafe { mem::transmute(Slice::from_str(self)) }
}
}
#[deprecated(since = "1.0.0", reason = "trait is deprecated")]
impl AsOsStr for String {
fn as_os_str(&self) -> &OsStr {
- OsStr::from_str(&self[..])
+ unsafe { mem::transmute(Slice::from_str(self)) }
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl AsRef<OsStr> for str {
fn as_ref(&self) -> &OsStr {
- OsStr::from_str(self)
+ unsafe { mem::transmute(Slice::from_str(self)) }
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl AsRef<OsStr> for String {
fn as_ref(&self) -> &OsStr {
- OsStr::from_str(&self[..])
+ unsafe { mem::transmute(Slice::from_str(self)) }
}
}
--- /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.
+
+//! Filesystem manipulation operations
+//!
+//! This module contains basic methods to manipulate the contents of the local
+//! filesystem. All methods in this module represent cross-platform filesystem
+//! operations. Extra platform-specific functionality can be found in the
+//! extension traits of `std::os::$platform`.
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+use core::prelude::*;
+
+use io::{self, Error, ErrorKind, SeekFrom, Seek, Read, Write};
+use path::{Path, PathBuf};
+use sys::fs2 as fs_imp;
+use sys_common::{AsInnerMut, FromInner, AsInner};
+use vec::Vec;
+
+/// A reference to an open file on the filesystem.
+///
+/// An instance of a `File` can be read and/or written depending on what options
+/// it was opened with. Files also implement `Seek` to alter the logical cursor
+/// that the file contains internally.
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::io::prelude::*;
+/// use std::fs::File;
+///
+/// # fn foo() -> std::io::Result<()> {
+/// let mut f = try!(File::create("foo.txt"));
+/// try!(f.write_all(b"Hello, world!"));
+///
+/// let mut f = try!(File::open("foo.txt"));
+/// let mut s = String::new();
+/// try!(f.read_to_string(&mut s));
+/// assert_eq!(s, "Hello, world!");
+/// # Ok(())
+/// # }
+/// ```
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct File {
+ inner: fs_imp::File,
+ path: Option<PathBuf>,
+}
+
+/// Metadata information about a file.
+///
+/// This structure is returned from the `metadata` function or method and
+/// represents known metadata about a file such as its permissions, size,
+/// modification times, etc.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct Metadata(fs_imp::FileAttr);
+
+/// Iterator over the entries in a directory.
+///
+/// This iterator is returned from the `read_dir` function of this module and
+/// will yield instances of `io::Result<DirEntry>`. Through a `DirEntry`
+/// information like the entry's path and possibly other metadata can be
+/// learned.
+///
+/// # Failure
+///
+/// This `io::Result` will be an `Err` if there's some sort of intermittent
+/// IO error during iteration.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct ReadDir(fs_imp::ReadDir);
+
+/// Entries returned by the `ReadDir` iterator.
+///
+/// An instance of `DirEntry` represents an entry inside of a directory on the
+/// filesystem. Each entry can be inspected via methods to learn about the full
+/// path or possibly other metadata through per-platform extension traits.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct DirEntry(fs_imp::DirEntry);
+
+/// An iterator that recursively walks over the contents of a directory.
+#[unstable(feature = "fs_walk",
+ 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 struct WalkDir {
+ cur: Option<ReadDir>,
+ stack: Vec<io::Result<ReadDir>>,
+}
+
+/// Options and flags which can be used to configure how a file is opened.
+///
+/// This builder exposes the ability to configure how a `File` is opened and what operations are
+/// permitted on the open file. The `File::open` and `File::create` methods are aliases for
+/// commonly used options using this builder.
+///
+/// Generally speaking, when using `OpenOptions`, you'll first call `new()`, then chain calls to
+/// methods to set each option, then call `open()`, passing the path of the file you're trying to
+/// open. This will give you a [`io::Result`][result] with a [`File`][file] inside that you can
+/// further operate on.
+///
+/// [result]: ../io/type.Result.html
+/// [file]: struct.File.html
+///
+/// # Examples
+///
+/// Opening a file to read:
+///
+/// ```no_run
+/// use std::fs;
+/// use std::fs::OpenOptions;
+///
+/// let file = OpenOptions::new().read(true).open("foo.txt");
+/// ```
+///
+/// Opening a file for both reading and writing, as well as creating it if it doesn't exist:
+///
+/// ```
+/// use std::fs;
+/// use std::fs::OpenOptions;
+///
+/// let file = OpenOptions::new()
+/// .read(true)
+/// .write(true)
+/// .create(true)
+/// .open("foo.txt");
+/// ```
+#[derive(Clone)]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct OpenOptions(fs_imp::OpenOptions);
+
+/// Representation of the various permissions on a file.
+///
+/// This module only currently provides one bit of information, `readonly`,
+/// which is exposed on all currently supported platforms. Unix-specific
+/// functionality, such as mode bits, is available through the
+/// `os::unix::PermissionsExt` trait.
+#[derive(Clone, PartialEq, Eq, Debug)]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct Permissions(fs_imp::FilePermissions);
+
+impl File {
+ /// Attempts to open a file in read-only mode.
+ ///
+ /// See the `OpenOptions::open` method for more details.
+ ///
+ /// # Errors
+ ///
+ /// This function will return an error if `path` does not already exist.
+ /// Other errors may also be returned according to `OpenOptions::open`.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs::File;
+ ///
+ /// # fn foo() -> std::io::Result<()> {
+ /// let mut f = try!(File::open("foo.txt"));
+ /// # Ok(())
+ /// # }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn open<P: AsRef<Path>>(path: P) -> io::Result<File> {
+ OpenOptions::new().read(true).open(path)
+ }
+
+ /// Open a file in write-only mode.
+ ///
+ /// This function will create a file if it does not exist,
+ /// and will truncate it if it does.
+ ///
+ /// See the `OpenOptions::open` function for more details.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs::File;
+ ///
+ /// # fn foo() -> std::io::Result<()> {
+ /// let mut f = try!(File::create("foo.txt"));
+ /// # Ok(())
+ /// # }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn create<P: AsRef<Path>>(path: P) -> io::Result<File> {
+ OpenOptions::new().write(true).create(true).truncate(true).open(path)
+ }
+
+ /// Returns the original path that was used to open this file.
+ #[unstable(feature = "file_path",
+ reason = "this abstraction is imposed by this library instead \
+ of the underlying OS and may be removed")]
+ pub fn path(&self) -> Option<&Path> {
+ self.path.as_ref().map(|p| &**p)
+ }
+
+ /// Attempt to sync all OS-internal metadata to disk.
+ ///
+ /// This function will attempt to ensure that all in-core data reaches the
+ /// filesystem before returning.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs::File;
+ /// use std::io::prelude::*;
+ ///
+ /// # fn foo() -> std::io::Result<()> {
+ /// let mut f = try!(File::create("foo.txt"));
+ /// try!(f.write_all(b"Hello, world!"));
+ ///
+ /// try!(f.sync_all());
+ /// # Ok(())
+ /// # }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn sync_all(&self) -> io::Result<()> {
+ self.inner.fsync()
+ }
+
+ /// This function is similar to `sync_all`, except that it may not
+ /// synchronize file metadata to the filesystem.
+ ///
+ /// This is intended for use cases that must synchronize content, but don't
+ /// need the metadata on disk. The goal of this method is to reduce disk
+ /// operations.
+ ///
+ /// Note that some platforms may simply implement this in terms of
+ /// `sync_all`.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs::File;
+ /// use std::io::prelude::*;
+ ///
+ /// # fn foo() -> std::io::Result<()> {
+ /// let mut f = try!(File::create("foo.txt"));
+ /// try!(f.write_all(b"Hello, world!"));
+ ///
+ /// try!(f.sync_data());
+ /// # Ok(())
+ /// # }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn sync_data(&self) -> io::Result<()> {
+ self.inner.datasync()
+ }
+
+ /// Truncates or extends the underlying file, updating the size of
+ /// this file to become `size`.
+ ///
+ /// If the `size` is less than the current file's size, then the file will
+ /// be shrunk. If it is greater than the current file's size, then the file
+ /// will be extended to `size` and have all of the intermediate data filled
+ /// in with 0s.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs::File;
+ ///
+ /// # fn foo() -> std::io::Result<()> {
+ /// let mut f = try!(File::open("foo.txt"));
+ /// try!(f.set_len(0));
+ /// # Ok(())
+ /// # }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn set_len(&self, size: u64) -> io::Result<()> {
+ self.inner.truncate(size)
+ }
+
+ /// Queries metadata about the underlying file.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs::File;
+ ///
+ /// # fn foo() -> std::io::Result<()> {
+ /// let mut f = try!(File::open("foo.txt"));
+ /// let metadata = try!(f.metadata());
+ /// # Ok(())
+ /// # }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn metadata(&self) -> io::Result<Metadata> {
+ self.inner.file_attr().map(Metadata)
+ }
+}
+
+impl AsInner<fs_imp::File> for File {
+ fn as_inner(&self) -> &fs_imp::File { &self.inner }
+}
+impl FromInner<fs_imp::File> for File {
+ fn from_inner(f: fs_imp::File) -> File {
+ File { inner: f, path: None }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Read for File {
+ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+ self.inner.read(buf)
+ }
+}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Write for File {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ self.inner.write(buf)
+ }
+ fn flush(&mut self) -> io::Result<()> { self.inner.flush() }
+}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Seek for File {
+ fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
+ self.inner.seek(pos)
+ }
+}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a> Read for &'a File {
+ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+ self.inner.read(buf)
+ }
+}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a> Write for &'a File {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ self.inner.write(buf)
+ }
+ fn flush(&mut self) -> io::Result<()> { self.inner.flush() }
+}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a> Seek for &'a File {
+ fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
+ self.inner.seek(pos)
+ }
+}
+
+impl OpenOptions {
+ /// Creates a blank net set of options ready for configuration.
+ ///
+ /// All options are initially set to `false`.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs::OpenOptions;
+ ///
+ /// let file = OpenOptions::new().open("foo.txt");
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn new() -> OpenOptions {
+ OpenOptions(fs_imp::OpenOptions::new())
+ }
+
+ /// Set the option for read access.
+ ///
+ /// This option, when true, will indicate that the file should be
+ /// `read`-able if opened.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs::OpenOptions;
+ ///
+ /// let file = OpenOptions::new().read(true).open("foo.txt");
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn read(&mut self, read: bool) -> &mut OpenOptions {
+ self.0.read(read); self
+ }
+
+ /// Set the option for write access.
+ ///
+ /// This option, when true, will indicate that the file should be
+ /// `write`-able if opened.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs::OpenOptions;
+ ///
+ /// let file = OpenOptions::new().write(true).open("foo.txt");
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn write(&mut self, write: bool) -> &mut OpenOptions {
+ self.0.write(write); self
+ }
+
+ /// Set the option for the append mode.
+ ///
+ /// This option, when true, means that writes will append to a file instead
+ /// of overwriting previous contents.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs::OpenOptions;
+ ///
+ /// let file = OpenOptions::new().append(true).open("foo.txt");
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn append(&mut self, append: bool) -> &mut OpenOptions {
+ self.0.append(append); self
+ }
+
+ /// Set the option for truncating a previous file.
+ ///
+ /// If a file is successfully opened with this option set it will truncate
+ /// the file to 0 length if it already exists.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs::OpenOptions;
+ ///
+ /// let file = OpenOptions::new().truncate(true).open("foo.txt");
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn truncate(&mut self, truncate: bool) -> &mut OpenOptions {
+ self.0.truncate(truncate); self
+ }
+
+ /// Set the option for creating a new file.
+ ///
+ /// This option indicates whether a new file will be created if the file
+ /// does not yet already exist.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs::OpenOptions;
+ ///
+ /// let file = OpenOptions::new().create(true).open("foo.txt");
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn create(&mut self, create: bool) -> &mut OpenOptions {
+ self.0.create(create); self
+ }
+
+ /// Open a file at `path` with the options specified by `self`.
+ ///
+ /// # Errors
+ ///
+ /// This function will return an error under a number of different
+ /// circumstances, to include but not limited to:
+ ///
+ /// * Opening a file that does not exist with read access.
+ /// * Attempting to open a file with access that the user lacks
+ /// permissions for
+ /// * Filesystem-level errors (full disk, etc)
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs::OpenOptions;
+ ///
+ /// let file = OpenOptions::new().open("foo.txt");
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ 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: Some(path.to_path_buf()), inner: inner })
+ }
+}
+
+impl AsInnerMut<fs_imp::OpenOptions> for OpenOptions {
+ fn as_inner_mut(&mut self) -> &mut fs_imp::OpenOptions { &mut self.0 }
+}
+
+impl Metadata {
+ /// Returns whether this metadata is for a directory.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// # fn foo() -> std::io::Result<()> {
+ /// use std::fs;
+ ///
+ /// let metadata = try!(fs::metadata("foo.txt"));
+ ///
+ /// assert!(!metadata.is_dir());
+ /// # Ok(())
+ /// # }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn is_dir(&self) -> bool { self.0.is_dir() }
+
+ /// Returns whether this metadata is for a regular file.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// # fn foo() -> std::io::Result<()> {
+ /// use std::fs;
+ ///
+ /// let metadata = try!(fs::metadata("foo.txt"));
+ ///
+ /// assert!(metadata.is_file());
+ /// # Ok(())
+ /// # }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn is_file(&self) -> bool { self.0.is_file() }
+
+ /// Returns the size of the file, in bytes, this metadata is for.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// # fn foo() -> std::io::Result<()> {
+ /// use std::fs;
+ ///
+ /// let metadata = try!(fs::metadata("foo.txt"));
+ ///
+ /// assert_eq!(0, metadata.len());
+ /// # Ok(())
+ /// # }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn len(&self) -> u64 { self.0.size() }
+
+ /// Returns the permissions of the file this metadata is for.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// # fn foo() -> std::io::Result<()> {
+ /// use std::fs;
+ ///
+ /// let metadata = try!(fs::metadata("foo.txt"));
+ ///
+ /// assert!(!metadata.permissions().readonly());
+ /// # Ok(())
+ /// # }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn permissions(&self) -> Permissions {
+ Permissions(self.0.perm())
+ }
+
+ /// Returns the most recent access time for a file.
+ ///
+ /// The return value is in milliseconds since the epoch.
+ #[unstable(feature = "fs_time",
+ reason = "the return type of u64 is not quite appropriate for \
+ this method and may change if the standard library \
+ gains a type to represent a moment in time")]
+ pub fn accessed(&self) -> u64 { self.0.accessed() }
+
+ /// Returns the most recent modification time for a file.
+ ///
+ /// The return value is in milliseconds since the epoch.
+ #[unstable(feature = "fs_time",
+ reason = "the return type of u64 is not quite appropriate for \
+ this method and may change if the standard library \
+ gains a type to represent a moment in time")]
+ pub fn modified(&self) -> u64 { self.0.modified() }
+}
+
+impl Permissions {
+ /// Returns whether these permissions describe a readonly file.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::fs::File;
+ ///
+ /// # fn foo() -> std::io::Result<()> {
+ /// let mut f = try!(File::create("foo.txt"));
+ /// let metadata = try!(f.metadata());
+ ///
+ /// assert_eq!(false, metadata.permissions().readonly());
+ /// # Ok(())
+ /// # }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn readonly(&self) -> bool { self.0.readonly() }
+
+ /// Modify the readonly flag for this set of permissions.
+ ///
+ /// This operation does **not** modify the filesystem. To modify the
+ /// filesystem use the `fs::set_permissions` function.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::fs::File;
+ ///
+ /// # fn foo() -> std::io::Result<()> {
+ /// let mut f = try!(File::create("foo.txt"));
+ /// let metadata = try!(f.metadata());
+ /// let mut permissions = metadata.permissions();
+ ///
+ /// permissions.set_readonly(true);
+ ///
+ /// // filesystem doesn't change
+ /// assert_eq!(false, metadata.permissions().readonly());
+ ///
+ /// // just this particular `permissions`.
+ /// assert_eq!(true, permissions.readonly());
+ /// # Ok(())
+ /// # }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn set_readonly(&mut self, readonly: bool) {
+ self.0.set_readonly(readonly)
+ }
+}
+
+impl FromInner<fs_imp::FilePermissions> for Permissions {
+ fn from_inner(f: fs_imp::FilePermissions) -> Permissions {
+ Permissions(f)
+ }
+}
+
+impl AsInner<fs_imp::FilePermissions> for Permissions {
+ fn as_inner(&self) -> &fs_imp::FilePermissions { &self.0 }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Iterator for ReadDir {
+ type Item = io::Result<DirEntry>;
+
+ fn next(&mut self) -> Option<io::Result<DirEntry>> {
+ self.0.next().map(|entry| entry.map(DirEntry))
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl DirEntry {
+ /// Returns the full path to the file that this entry represents.
+ ///
+ /// The full path is created by joining the original path to `read_dir` or
+ /// `walk_dir` with the filename of this entry.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::fs;
+ /// # fn foo() -> std::io::Result<()> {
+ /// for entry in try!(fs::read_dir(".")) {
+ /// let dir = try!(entry);
+ /// println!("{:?}", dir.path());
+ /// }
+ /// # Ok(())
+ /// # }
+ /// ```
+ ///
+ /// This prints output like:
+ ///
+ /// ```text
+ /// "./whatever.txt"
+ /// "./foo.html"
+ /// "./hello_world.rs"
+ /// ```
+ ///
+ /// The exact text, of course, depends on what files you have in `.`.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn path(&self) -> PathBuf { self.0.path() }
+}
+
+/// Remove a file from the underlying filesystem.
+///
+/// Note that, just because an unlink call was successful, it is not
+/// guaranteed that a file is immediately deleted (e.g. depending on
+/// platform, other open file descriptors may prevent immediate removal).
+///
+/// # Errors
+///
+/// This function will return an error if `path` points to a directory, if the
+/// user lacks permissions to remove the file, or if some other filesystem-level
+/// error occurs.
+///
+/// # Examples
+///
+/// ```
+/// use std::fs;
+///
+/// # fn foo() -> std::io::Result<()> {
+/// try!(fs::remove_file("a.txt"));
+/// # Ok(())
+/// # }
+/// ```
+#[stable(feature = "rust1", since = "1.0.0")]
+pub fn remove_file<P: AsRef<Path>>(path: P) -> io::Result<()> {
+ fs_imp::unlink(path.as_ref())
+}
+
+/// Given a path, query the file system to get information about a file,
+/// directory, etc.
+///
+/// This function will traverse soft links to query information about the
+/// destination file.
+///
+/// # Examples
+///
+/// ```rust
+/// # fn foo() -> std::io::Result<()> {
+/// use std::fs;
+///
+/// let attr = try!(fs::metadata("/some/file/path.txt"));
+/// // inspect attr ...
+/// # Ok(())
+/// # }
+/// ```
+///
+/// # Errors
+///
+/// This function will return an error if the user lacks the requisite
+/// 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: AsRef<Path>>(path: P) -> io::Result<Metadata> {
+ fs_imp::stat(path.as_ref()).map(Metadata)
+}
+
+/// Rename a file or directory to a new name.
+///
+/// # Errors
+///
+/// This function will return an error if the provided `from` doesn't exist, if
+/// the process lacks permissions to view the contents, if `from` and `to`
+/// reside on separate filesystems, or if some other intermittent I/O error
+/// occurs.
+///
+/// # Examples
+///
+/// ```
+/// use std::fs;
+///
+/// # fn foo() -> std::io::Result<()> {
+/// try!(fs::rename("a.txt", "b.txt"));
+/// # Ok(())
+/// # }
+/// ```
+#[stable(feature = "rust1", since = "1.0.0")]
+pub fn rename<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<()> {
+ fs_imp::rename(from.as_ref(), to.as_ref())
+}
+
+/// Copies the contents of one file to another. This function will also
+/// copy the permission bits of the original file to the destination file.
+///
+/// This function will **overwrite** the contents of `to`.
+///
+/// Note that if `from` and `to` both point to the same file, then the file
+/// will likely get truncated by this operation.
+///
+/// # Errors
+///
+/// This function will return an error in the following situations, but is not
+/// limited to just these cases:
+///
+/// * The `from` path is not a file
+/// * The `from` file does not exist
+/// * The current process does not have the permission rights to access
+/// `from` or write `to`
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::fs;
+///
+/// fs::copy("foo.txt", "bar.txt");
+/// ```
+#[stable(feature = "rust1", since = "1.0.0")]
+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"))
+ }
+
+ let mut reader = try!(File::open(from));
+ let mut writer = try!(File::create(to));
+ let perm = try!(reader.metadata()).permissions();
+
+ let ret = try!(io::copy(&mut reader, &mut writer));
+ try!(set_permissions(to, perm));
+ Ok(ret)
+}
+
+/// Creates a new hard link on the filesystem.
+///
+/// The `dst` path will be a link pointing to the `src` path. Note that systems
+/// often require these two paths to both be located on the same filesystem.
+///
+/// # Examples
+///
+/// ```
+/// use std::fs;
+///
+/// # fn foo() -> std::io::Result<()> {
+/// try!(fs::hard_link("a.txt", "b.txt"));
+/// # Ok(())
+/// # }
+/// ```
+#[stable(feature = "rust1", since = "1.0.0")]
+pub fn hard_link<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()> {
+ fs_imp::link(src.as_ref(), dst.as_ref())
+}
+
+/// Creates a new soft link on the filesystem.
+///
+/// The `dst` path will be a soft link pointing to the `src` path.
+///
+/// # Examples
+///
+/// ```
+/// use std::fs;
+///
+/// # fn foo() -> std::io::Result<()> {
+/// try!(fs::soft_link("a.txt", "b.txt"));
+/// # Ok(())
+/// # }
+/// ```
+#[stable(feature = "rust1", since = "1.0.0")]
+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.
+///
+/// # Errors
+///
+/// This function will return an error on failure. Failure conditions include
+/// reading a file that does not exist or reading a file that is not a soft
+/// link.
+///
+/// # Examples
+///
+/// ```
+/// use std::fs;
+///
+/// # fn foo() -> std::io::Result<()> {
+/// let path = try!(fs::read_link("a.txt"));
+/// # Ok(())
+/// # }
+/// ```
+#[stable(feature = "rust1", since = "1.0.0")]
+pub fn read_link<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> {
+ fs_imp::readlink(path.as_ref())
+}
+
+/// Create a new, empty directory at the provided path
+///
+/// # Errors
+///
+/// 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.
+///
+/// # Examples
+///
+/// ```
+/// use std::fs;
+///
+/// # fn foo() -> std::io::Result<()> {
+/// try!(fs::create_dir("/some/dir"));
+/// # Ok(())
+/// # }
+/// ```
+#[stable(feature = "rust1", since = "1.0.0")]
+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
+/// are missing.
+///
+/// # Errors
+///
+/// This function will fail if any directory in the path specified by `path`
+/// does not already exist and it could not be created otherwise. The specific
+/// error conditions for when a directory is being created (after it is
+/// determined to not exist) are outlined by `fs::create_dir`.
+///
+/// # Examples
+///
+/// ```
+/// use std::fs;
+///
+/// # fn foo() -> std::io::Result<()> {
+/// try!(fs::create_dir_all("/some/dir"));
+/// # Ok(())
+/// # }
+/// ```
+#[stable(feature = "rust1", since = "1.0.0")]
+pub fn create_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()> {
+ let path = path.as_ref();
+ if path == Path::new("") || path.is_dir() { return Ok(()) }
+ if let Some(p) = path.parent() { try!(create_dir_all(p)) }
+ create_dir(path)
+}
+
+/// Remove an existing, empty directory
+///
+/// # Errors
+///
+/// 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.
+///
+/// # Examples
+///
+/// ```
+/// use std::fs;
+///
+/// # fn foo() -> std::io::Result<()> {
+/// try!(fs::remove_dir("/some/dir"));
+/// # Ok(())
+/// # }
+/// ```
+#[stable(feature = "rust1", since = "1.0.0")]
+pub fn remove_dir<P: AsRef<Path>>(path: P) -> io::Result<()> {
+ fs_imp::rmdir(path.as_ref())
+}
+
+/// Removes a directory at this path, after removing all its contents. Use
+/// carefully!
+///
+/// This function does **not** follow soft links and it will simply remove the
+/// soft link itself.
+///
+/// # Errors
+///
+/// See `file::remove_file` and `fs::remove_dir`.
+///
+/// # Examples
+///
+/// ```
+/// use std::fs;
+///
+/// # fn foo() -> std::io::Result<()> {
+/// try!(fs::remove_dir_all("/some/dir"));
+/// # Ok(())
+/// # }
+/// ```
+#[stable(feature = "rust1", since = "1.0.0")]
+pub fn remove_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()> {
+ let path = path.as_ref();
+ for child in try!(read_dir(path)) {
+ let child = try!(child).path();
+ let stat = try!(lstat(&*child));
+ if stat.is_dir() {
+ try!(remove_dir_all(&*child));
+ } else {
+ try!(remove_file(&*child));
+ }
+ }
+ return remove_dir(path);
+
+ #[cfg(unix)]
+ fn lstat(path: &Path) -> io::Result<fs_imp::FileAttr> { fs_imp::lstat(path) }
+ #[cfg(windows)]
+ fn lstat(path: &Path) -> io::Result<fs_imp::FileAttr> { fs_imp::stat(path) }
+}
+
+/// Returns an iterator over the entries within a directory.
+///
+/// The iterator will yield instances of `io::Result<DirEntry>`. New errors may
+/// be encountered after an iterator is initially constructed.
+///
+/// # Examples
+///
+/// ```
+/// # #![feature(path_ext)]
+/// use std::io;
+/// use std::fs::{self, PathExt, DirEntry};
+/// use std::path::Path;
+///
+/// // one possible implementation of fs::walk_dir only visiting files
+/// fn visit_dirs(dir: &Path, cb: &mut FnMut(DirEntry)) -> io::Result<()> {
+/// if dir.is_dir() {
+/// for entry in try!(fs::read_dir(dir)) {
+/// let entry = try!(entry);
+/// if entry.path().is_dir() {
+/// try!(visit_dirs(&entry.path(), cb));
+/// } else {
+/// cb(entry);
+/// }
+/// }
+/// }
+/// Ok(())
+/// }
+/// ```
+///
+/// # Errors
+///
+/// This function will return an error if the provided `path` doesn't exist, if
+/// 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: 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
+/// rooted at `path`.
+///
+/// The path given will not be iterated over, and this will perform iteration in
+/// some top-down order. The contents of unreadable subdirectories are ignored.
+///
+/// The iterator will yield instances of `io::Result<DirEntry>`. New errors may
+/// be encountered after an iterator is initially constructed.
+#[unstable(feature = "fs_walk",
+ 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: AsRef<Path>>(path: P) -> io::Result<WalkDir> {
+ let start = try!(read_dir(path));
+ Ok(WalkDir { cur: Some(start), stack: Vec::new() })
+}
+
+#[unstable(feature = "fs_walk")]
+impl Iterator for WalkDir {
+ type Item = io::Result<DirEntry>;
+
+ fn next(&mut self) -> Option<io::Result<DirEntry>> {
+ loop {
+ if let Some(ref mut cur) = self.cur {
+ match cur.next() {
+ Some(Err(e)) => return Some(Err(e)),
+ Some(Ok(next)) => {
+ let path = next.path();
+ if path.is_dir() {
+ self.stack.push(read_dir(&*path));
+ }
+ return Some(Ok(next))
+ }
+ None => {}
+ }
+ }
+ self.cur = None;
+ match self.stack.pop() {
+ Some(Err(e)) => return Some(Err(e)),
+ Some(Ok(next)) => self.cur = Some(next),
+ None => return None,
+ }
+ }
+ }
+}
+
+/// Utility methods for paths.
+#[unstable(feature = "path_ext",
+ reason = "the precise set of methods exposed on this trait may \
+ change and some methods may be removed")]
+pub trait PathExt {
+ /// Get information on the file, directory, etc at this path.
+ ///
+ /// Consult the `fs::stat` documentation for more info.
+ ///
+ /// This call preserves identical runtime/error semantics with `file::stat`.
+ fn metadata(&self) -> io::Result<Metadata>;
+
+ /// Boolean value indicator whether the underlying file exists on the local
+ /// filesystem. Returns false in exactly the cases where `fs::stat` fails.
+ fn exists(&self) -> bool;
+
+ /// Whether the underlying implementation (be it a file path, or something
+ /// else) points at a "regular file" on the FS. Will return false for paths
+ /// to non-existent locations or directories or other non-regular files
+ /// (named pipes, etc). Follows links when making this determination.
+ fn is_file(&self) -> bool;
+
+ /// Whether the underlying implementation (be it a file path, or something
+ /// else) is pointing at a directory in the underlying FS. Will return
+ /// false for paths to non-existent locations or if the item is not a
+ /// directory (eg files, named pipes, etc). Follows links when making this
+ /// determination.
+ fn is_dir(&self) -> bool;
+}
+
+impl PathExt for Path {
+ fn metadata(&self) -> io::Result<Metadata> { metadata(self) }
+
+ fn exists(&self) -> bool { metadata(self).is_ok() }
+
+ fn is_file(&self) -> bool {
+ metadata(self).map(|s| s.is_file()).unwrap_or(false)
+ }
+ fn is_dir(&self) -> bool {
+ metadata(self).map(|s| s.is_dir()).unwrap_or(false)
+ }
+}
+
+/// Changes the timestamps for a file's last modification and access time.
+///
+/// The file at the path specified will have its last access time set to
+/// `atime` and its modification time set to `mtime`. The times specified should
+/// be in milliseconds.
+#[unstable(feature = "fs_time",
+ 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: AsRef<Path>>(path: P, accessed: u64,
+ modified: u64) -> io::Result<()> {
+ fs_imp::utimes(path.as_ref(), accessed, modified)
+}
+
+/// Changes the permissions found on a file or a directory.
+///
+/// # Examples
+///
+/// ```
+/// # #![feature(fs)]
+/// # fn foo() -> std::io::Result<()> {
+/// use std::fs;
+///
+/// let mut perms = try!(fs::metadata("foo.txt")).permissions();
+/// perms.set_readonly(true);
+/// try!(fs::set_permissions("foo.txt", perms));
+/// # Ok(())
+/// # }
+/// ```
+///
+/// # Errors
+///
+/// This function will return an error if the provided `path` doesn't exist, if
+/// the process lacks permissions to change the attributes of the file, or if
+/// some other I/O error is encountered.
+#[unstable(feature = "fs",
+ 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: AsRef<Path>>(path: P, perm: Permissions) -> io::Result<()> {
+ fs_imp::set_perm(path.as_ref(), perm.0)
+}
+
+#[cfg(test)]
+mod tests {
+ #![allow(deprecated)] //rand
+
+ use prelude::v1::*;
+ use io::prelude::*;
+
+ use env;
+ use fs::{self, File, OpenOptions};
+ use io::{ErrorKind, SeekFrom};
+ use path::PathBuf;
+ use path::Path as Path2;
+ use os;
+ use rand::{self, StdRng, Rng};
+ use str;
+
+ macro_rules! check { ($e:expr) => (
+ match $e {
+ Ok(t) => t,
+ Err(e) => panic!("{} failed with: {}", stringify!($e), e),
+ }
+ ) }
+
+ macro_rules! error { ($e:expr, $s:expr) => (
+ match $e {
+ Ok(_) => panic!("Unexpected success. Should've been: {:?}", $s),
+ Err(ref err) => assert!(err.to_string().contains($s),
+ format!("`{}` did not contain `{}`", err, $s))
+ }
+ ) }
+
+ pub struct TempDir(PathBuf);
+
+ impl TempDir {
+ fn join(&self, path: &str) -> PathBuf {
+ let TempDir(ref p) = *self;
+ p.join(path)
+ }
+
+ fn path<'a>(&'a self) -> &'a Path2 {
+ let TempDir(ref p) = *self;
+ p
+ }
+ }
+
+ impl Drop for TempDir {
+ fn drop(&mut self) {
+ // Gee, seeing how we're testing the fs module I sure hope that we
+ // at least implement this correctly!
+ let TempDir(ref p) = *self;
+ check!(fs::remove_dir_all(p));
+ }
+ }
+
+ pub fn tmpdir() -> TempDir {
+ let p = env::temp_dir();
+ let ret = p.join(&format!("rust-{}", rand::random::<u32>()));
+ check!(fs::create_dir(&ret));
+ TempDir(ret)
+ }
+
+ #[test]
+ fn file_test_io_smoke_test() {
+ let message = "it's alright. have a good time";
+ let tmpdir = tmpdir();
+ let filename = &tmpdir.join("file_rt_io_file_test.txt");
+ {
+ let mut write_stream = check!(File::create(filename));
+ check!(write_stream.write(message.as_bytes()));
+ }
+ {
+ let mut read_stream = check!(File::open(filename));
+ let mut read_buf = [0; 1028];
+ let read_str = match check!(read_stream.read(&mut read_buf)) {
+ 0 => panic!("shouldn't happen"),
+ n => str::from_utf8(&read_buf[..n]).unwrap().to_string()
+ };
+ assert_eq!(read_str, message);
+ }
+ check!(fs::remove_file(filename));
+ }
+
+ #[test]
+ fn invalid_path_raises() {
+ let tmpdir = tmpdir();
+ let filename = &tmpdir.join("file_that_does_not_exist.txt");
+ let result = File::open(filename);
+
+ if cfg!(unix) {
+ error!(result, "o such file or directory");
+ }
+ // error!(result, "couldn't open path as file");
+ // error!(result, format!("path={}; mode=open; access=read", filename.display()));
+ }
+
+ #[test]
+ fn file_test_iounlinking_invalid_path_should_raise_condition() {
+ let tmpdir = tmpdir();
+ let filename = &tmpdir.join("file_another_file_that_does_not_exist.txt");
+
+ let result = fs::remove_file(filename);
+
+ if cfg!(unix) {
+ error!(result, "o such file or directory");
+ }
+ // error!(result, "couldn't unlink path");
+ // error!(result, format!("path={}", filename.display()));
+ }
+
+ #[test]
+ fn file_test_io_non_positional_read() {
+ let message: &str = "ten-four";
+ let mut read_mem = [0; 8];
+ let tmpdir = tmpdir();
+ let filename = &tmpdir.join("file_rt_io_file_test_positional.txt");
+ {
+ let mut rw_stream = check!(File::create(filename));
+ check!(rw_stream.write(message.as_bytes()));
+ }
+ {
+ let mut read_stream = check!(File::open(filename));
+ {
+ let read_buf = &mut read_mem[0..4];
+ check!(read_stream.read(read_buf));
+ }
+ {
+ let read_buf = &mut read_mem[4..8];
+ check!(read_stream.read(read_buf));
+ }
+ }
+ check!(fs::remove_file(filename));
+ let read_str = str::from_utf8(&read_mem).unwrap();
+ assert_eq!(read_str, message);
+ }
+
+ #[test]
+ fn file_test_io_seek_and_tell_smoke_test() {
+ let message = "ten-four";
+ let mut read_mem = [0; 4];
+ let set_cursor = 4 as u64;
+ let mut tell_pos_pre_read;
+ let mut tell_pos_post_read;
+ let tmpdir = tmpdir();
+ let filename = &tmpdir.join("file_rt_io_file_test_seeking.txt");
+ {
+ let mut rw_stream = check!(File::create(filename));
+ check!(rw_stream.write(message.as_bytes()));
+ }
+ {
+ let mut read_stream = check!(File::open(filename));
+ check!(read_stream.seek(SeekFrom::Start(set_cursor)));
+ tell_pos_pre_read = check!(read_stream.seek(SeekFrom::Current(0)));
+ check!(read_stream.read(&mut read_mem));
+ tell_pos_post_read = check!(read_stream.seek(SeekFrom::Current(0)));
+ }
+ check!(fs::remove_file(filename));
+ let read_str = str::from_utf8(&read_mem).unwrap();
+ assert_eq!(read_str, &message[4..8]);
+ assert_eq!(tell_pos_pre_read, set_cursor);
+ assert_eq!(tell_pos_post_read, message.len() as u64);
+ }
+
+ #[test]
+ fn file_test_io_seek_and_write() {
+ let initial_msg = "food-is-yummy";
+ let overwrite_msg = "-the-bar!!";
+ let final_msg = "foo-the-bar!!";
+ let seek_idx = 3;
+ let mut read_mem = [0; 13];
+ let tmpdir = tmpdir();
+ let filename = &tmpdir.join("file_rt_io_file_test_seek_and_write.txt");
+ {
+ let mut rw_stream = check!(File::create(filename));
+ check!(rw_stream.write(initial_msg.as_bytes()));
+ check!(rw_stream.seek(SeekFrom::Start(seek_idx)));
+ check!(rw_stream.write(overwrite_msg.as_bytes()));
+ }
+ {
+ let mut read_stream = check!(File::open(filename));
+ check!(read_stream.read(&mut read_mem));
+ }
+ check!(fs::remove_file(filename));
+ let read_str = str::from_utf8(&read_mem).unwrap();
+ assert!(read_str == final_msg);
+ }
+
+ #[test]
+ fn file_test_io_seek_shakedown() {
+ // 01234567890123
+ let initial_msg = "qwer-asdf-zxcv";
+ let chunk_one: &str = "qwer";
+ let chunk_two: &str = "asdf";
+ let chunk_three: &str = "zxcv";
+ let mut read_mem = [0; 4];
+ let tmpdir = tmpdir();
+ let filename = &tmpdir.join("file_rt_io_file_test_seek_shakedown.txt");
+ {
+ let mut rw_stream = check!(File::create(filename));
+ check!(rw_stream.write(initial_msg.as_bytes()));
+ }
+ {
+ let mut read_stream = check!(File::open(filename));
+
+ check!(read_stream.seek(SeekFrom::End(-4)));
+ check!(read_stream.read(&mut read_mem));
+ assert_eq!(str::from_utf8(&read_mem).unwrap(), chunk_three);
+
+ check!(read_stream.seek(SeekFrom::Current(-9)));
+ check!(read_stream.read(&mut read_mem));
+ assert_eq!(str::from_utf8(&read_mem).unwrap(), chunk_two);
+
+ check!(read_stream.seek(SeekFrom::Start(0)));
+ check!(read_stream.read(&mut read_mem));
+ assert_eq!(str::from_utf8(&read_mem).unwrap(), chunk_one);
+ }
+ check!(fs::remove_file(filename));
+ }
+
+ #[test]
+ fn file_test_stat_is_correct_on_is_file() {
+ let tmpdir = tmpdir();
+ let filename = &tmpdir.join("file_stat_correct_on_is_file.txt");
+ {
+ let mut opts = OpenOptions::new();
+ let mut fs = check!(opts.read(true).write(true)
+ .create(true).open(filename));
+ let msg = "hw";
+ fs.write(msg.as_bytes()).unwrap();
+
+ let fstat_res = check!(fs.metadata());
+ assert!(fstat_res.is_file());
+ }
+ let stat_res_fn = check!(fs::metadata(filename));
+ assert!(stat_res_fn.is_file());
+ let stat_res_meth = check!(filename.metadata());
+ assert!(stat_res_meth.is_file());
+ check!(fs::remove_file(filename));
+ }
+
+ #[test]
+ fn file_test_stat_is_correct_on_is_dir() {
+ let tmpdir = tmpdir();
+ let filename = &tmpdir.join("file_stat_correct_on_is_dir");
+ check!(fs::create_dir(filename));
+ let stat_res_fn = check!(fs::metadata(filename));
+ assert!(stat_res_fn.is_dir());
+ let stat_res_meth = check!(filename.metadata());
+ assert!(stat_res_meth.is_dir());
+ check!(fs::remove_dir(filename));
+ }
+
+ #[test]
+ fn file_test_fileinfo_false_when_checking_is_file_on_a_directory() {
+ let tmpdir = tmpdir();
+ let dir = &tmpdir.join("fileinfo_false_on_dir");
+ check!(fs::create_dir(dir));
+ assert!(dir.is_file() == false);
+ check!(fs::remove_dir(dir));
+ }
+
+ #[test]
+ fn file_test_fileinfo_check_exists_before_and_after_file_creation() {
+ let tmpdir = tmpdir();
+ let file = &tmpdir.join("fileinfo_check_exists_b_and_a.txt");
+ check!(check!(File::create(file)).write(b"foo"));
+ assert!(file.exists());
+ check!(fs::remove_file(file));
+ assert!(!file.exists());
+ }
+
+ #[test]
+ fn file_test_directoryinfo_check_exists_before_and_after_mkdir() {
+ let tmpdir = tmpdir();
+ let dir = &tmpdir.join("before_and_after_dir");
+ assert!(!dir.exists());
+ check!(fs::create_dir(dir));
+ assert!(dir.exists());
+ assert!(dir.is_dir());
+ check!(fs::remove_dir(dir));
+ assert!(!dir.exists());
+ }
+
+ #[test]
+ fn file_test_directoryinfo_readdir() {
+ let tmpdir = tmpdir();
+ let dir = &tmpdir.join("di_readdir");
+ check!(fs::create_dir(dir));
+ let prefix = "foo";
+ for n in 0..3 {
+ let f = dir.join(&format!("{}.txt", n));
+ let mut w = check!(File::create(&f));
+ let msg_str = format!("{}{}", prefix, n.to_string());
+ let msg = msg_str.as_bytes();
+ check!(w.write(msg));
+ }
+ let files = check!(fs::read_dir(dir));
+ let mut mem = [0; 4];
+ for f in files {
+ let f = f.unwrap().path();
+ {
+ let n = f.file_stem().unwrap();
+ check!(check!(File::open(&f)).read(&mut mem));
+ let read_str = str::from_utf8(&mem).unwrap();
+ let expected = format!("{}{}", prefix, n.to_str().unwrap());
+ assert_eq!(expected, read_str);
+ }
+ check!(fs::remove_file(&f));
+ }
+ check!(fs::remove_dir(dir));
+ }
+
+ #[test]
+ fn file_test_walk_dir() {
+ let tmpdir = tmpdir();
+ let dir = &tmpdir.join("walk_dir");
+ check!(fs::create_dir(dir));
+
+ let dir1 = &dir.join("01/02/03");
+ check!(fs::create_dir_all(dir1));
+ check!(File::create(&dir1.join("04")));
+
+ let dir2 = &dir.join("11/12/13");
+ check!(fs::create_dir_all(dir2));
+ check!(File::create(&dir2.join("14")));
+
+ let files = check!(fs::walk_dir(dir));
+ let mut cur = [0; 2];
+ for f in files {
+ let f = f.unwrap().path();
+ let stem = f.file_stem().unwrap().to_str().unwrap();
+ let root = stem.as_bytes()[0] - b'0';
+ let name = stem.as_bytes()[1] - b'0';
+ assert!(cur[root as usize] < name);
+ cur[root as usize] = name;
+ }
+
+ check!(fs::remove_dir_all(dir));
+ }
+
+ #[test]
+ fn mkdir_path_already_exists_error() {
+ let tmpdir = tmpdir();
+ let dir = &tmpdir.join("mkdir_error_twice");
+ check!(fs::create_dir(dir));
+ let e = fs::create_dir(dir).err().unwrap();
+ assert_eq!(e.kind(), ErrorKind::AlreadyExists);
+ }
+
+ #[test]
+ fn recursive_mkdir() {
+ let tmpdir = tmpdir();
+ let dir = tmpdir.join("d1/d2");
+ check!(fs::create_dir_all(&dir));
+ assert!(dir.is_dir())
+ }
+
+ #[test]
+ fn recursive_mkdir_failure() {
+ let tmpdir = tmpdir();
+ let dir = tmpdir.join("d1");
+ let file = dir.join("f1");
+
+ check!(fs::create_dir_all(&dir));
+ check!(File::create(&file));
+
+ let result = fs::create_dir_all(&file);
+
+ assert!(result.is_err());
+ // error!(result, "couldn't recursively mkdir");
+ // error!(result, "couldn't create directory");
+ // error!(result, "mode=0700");
+ // error!(result, format!("path={}", file.display()));
+ }
+
+ #[test]
+ fn recursive_mkdir_slash() {
+ check!(fs::create_dir_all(&Path2::new("/")));
+ }
+
+ // FIXME(#12795) depends on lstat to work on windows
+ #[cfg(not(windows))]
+ #[test]
+ fn recursive_rmdir() {
+ let tmpdir = tmpdir();
+ let d1 = tmpdir.join("d1");
+ let dt = d1.join("t");
+ let dtt = dt.join("t");
+ let d2 = tmpdir.join("d2");
+ let canary = d2.join("do_not_delete");
+ check!(fs::create_dir_all(&dtt));
+ check!(fs::create_dir_all(&d2));
+ check!(check!(File::create(&canary)).write(b"foo"));
+ check!(fs::soft_link(&d2, &dt.join("d2")));
+ check!(fs::remove_dir_all(&d1));
+
+ assert!(!d1.is_dir());
+ assert!(canary.exists());
+ }
+
+ #[test]
+ fn unicode_path_is_dir() {
+ assert!(Path2::new(".").is_dir());
+ assert!(!Path2::new("test/stdtest/fs.rs").is_dir());
+
+ let tmpdir = tmpdir();
+
+ let mut dirpath = tmpdir.path().to_path_buf();
+ dirpath.push(&format!("test-가一ー你好"));
+ check!(fs::create_dir(&dirpath));
+ assert!(dirpath.is_dir());
+
+ let mut filepath = dirpath;
+ filepath.push("unicode-file-\u{ac00}\u{4e00}\u{30fc}\u{4f60}\u{597d}.rs");
+ check!(File::create(&filepath)); // ignore return; touch only
+ assert!(!filepath.is_dir());
+ assert!(filepath.exists());
+ }
+
+ #[test]
+ fn unicode_path_exists() {
+ assert!(Path2::new(".").exists());
+ assert!(!Path2::new("test/nonexistent-bogus-path").exists());
+
+ let tmpdir = tmpdir();
+ let unicode = tmpdir.path();
+ let unicode = unicode.join(&format!("test-각丁ー再见"));
+ check!(fs::create_dir(&unicode));
+ assert!(unicode.exists());
+ assert!(!Path2::new("test/unicode-bogus-path-각丁ー再见").exists());
+ }
+
+ #[test]
+ fn copy_file_does_not_exist() {
+ let from = Path2::new("test/nonexistent-bogus-path");
+ let to = Path2::new("test/other-bogus-path");
+
+ match fs::copy(&from, &to) {
+ Ok(..) => panic!(),
+ Err(..) => {
+ assert!(!from.exists());
+ assert!(!to.exists());
+ }
+ }
+ }
+
+ #[test]
+ fn copy_file_ok() {
+ let tmpdir = tmpdir();
+ let input = tmpdir.join("in.txt");
+ let out = tmpdir.join("out.txt");
+
+ check!(check!(File::create(&input)).write(b"hello"));
+ check!(fs::copy(&input, &out));
+ let mut v = Vec::new();
+ check!(check!(File::open(&out)).read_to_end(&mut v));
+ assert_eq!(v, b"hello");
+
+ assert_eq!(check!(input.metadata()).permissions(),
+ check!(out.metadata()).permissions());
+ }
+
+ #[test]
+ fn copy_file_dst_dir() {
+ let tmpdir = tmpdir();
+ let out = tmpdir.join("out");
+
+ check!(File::create(&out));
+ match fs::copy(&*out, tmpdir.path()) {
+ Ok(..) => panic!(), Err(..) => {}
+ }
+ }
+
+ #[test]
+ fn copy_file_dst_exists() {
+ let tmpdir = tmpdir();
+ let input = tmpdir.join("in");
+ let output = tmpdir.join("out");
+
+ check!(check!(File::create(&input)).write("foo".as_bytes()));
+ check!(check!(File::create(&output)).write("bar".as_bytes()));
+ check!(fs::copy(&input, &output));
+
+ let mut v = Vec::new();
+ check!(check!(File::open(&output)).read_to_end(&mut v));
+ assert_eq!(v, b"foo".to_vec());
+ }
+
+ #[test]
+ fn copy_file_src_dir() {
+ let tmpdir = tmpdir();
+ let out = tmpdir.join("out");
+
+ match fs::copy(tmpdir.path(), &out) {
+ Ok(..) => panic!(), Err(..) => {}
+ }
+ assert!(!out.exists());
+ }
+
+ #[test]
+ fn copy_file_preserves_perm_bits() {
+ let tmpdir = tmpdir();
+ let input = tmpdir.join("in.txt");
+ let out = tmpdir.join("out.txt");
+
+ let attr = check!(check!(File::create(&input)).metadata());
+ let mut p = attr.permissions();
+ p.set_readonly(true);
+ check!(fs::set_permissions(&input, p));
+ check!(fs::copy(&input, &out));
+ assert!(check!(out.metadata()).permissions().readonly());
+ check!(fs::set_permissions(&input, attr.permissions()));
+ check!(fs::set_permissions(&out, attr.permissions()));
+ }
+
+ #[cfg(not(windows))] // FIXME(#10264) operation not permitted?
+ #[test]
+ fn symlinks_work() {
+ let tmpdir = tmpdir();
+ let input = tmpdir.join("in.txt");
+ let out = tmpdir.join("out.txt");
+
+ check!(check!(File::create(&input)).write("foobar".as_bytes()));
+ check!(fs::soft_link(&input, &out));
+ // if cfg!(not(windows)) {
+ // assert_eq!(check!(lstat(&out)).kind, FileType::Symlink);
+ // assert_eq!(check!(out.lstat()).kind, FileType::Symlink);
+ // }
+ assert_eq!(check!(fs::metadata(&out)).len(),
+ check!(fs::metadata(&input)).len());
+ let mut v = Vec::new();
+ check!(check!(File::open(&out)).read_to_end(&mut v));
+ assert_eq!(v, b"foobar".to_vec());
+ }
+
+ #[cfg(not(windows))] // apparently windows doesn't like symlinks
+ #[test]
+ fn symlink_noexist() {
+ let tmpdir = tmpdir();
+ // symlinks can point to things that don't exist
+ check!(fs::soft_link(&tmpdir.join("foo"), &tmpdir.join("bar")));
+ assert_eq!(check!(fs::read_link(&tmpdir.join("bar"))),
+ tmpdir.join("foo"));
+ }
+
+ #[test]
+ fn readlink_not_symlink() {
+ let tmpdir = tmpdir();
+ match fs::read_link(tmpdir.path()) {
+ Ok(..) => panic!("wanted a failure"),
+ Err(..) => {}
+ }
+ }
+
+ #[test]
+ fn links_work() {
+ let tmpdir = tmpdir();
+ let input = tmpdir.join("in.txt");
+ let out = tmpdir.join("out.txt");
+
+ check!(check!(File::create(&input)).write("foobar".as_bytes()));
+ check!(fs::hard_link(&input, &out));
+ assert_eq!(check!(fs::metadata(&out)).len(),
+ check!(fs::metadata(&input)).len());
+ assert_eq!(check!(fs::metadata(&out)).len(),
+ check!(input.metadata()).len());
+ let mut v = Vec::new();
+ check!(check!(File::open(&out)).read_to_end(&mut v));
+ assert_eq!(v, b"foobar".to_vec());
+
+ // can't link to yourself
+ match fs::hard_link(&input, &input) {
+ Ok(..) => panic!("wanted a failure"),
+ Err(..) => {}
+ }
+ // can't link to something that doesn't exist
+ match fs::hard_link(&tmpdir.join("foo"), &tmpdir.join("bar")) {
+ Ok(..) => panic!("wanted a failure"),
+ Err(..) => {}
+ }
+ }
+
+ #[test]
+ fn chmod_works() {
+ let tmpdir = tmpdir();
+ let file = tmpdir.join("in.txt");
+
+ check!(File::create(&file));
+ let attr = check!(fs::metadata(&file));
+ assert!(!attr.permissions().readonly());
+ let mut p = attr.permissions();
+ p.set_readonly(true);
+ check!(fs::set_permissions(&file, p.clone()));
+ let attr = check!(fs::metadata(&file));
+ assert!(attr.permissions().readonly());
+
+ match fs::set_permissions(&tmpdir.join("foo"), p.clone()) {
+ Ok(..) => panic!("wanted an error"),
+ Err(..) => {}
+ }
+
+ p.set_readonly(false);
+ check!(fs::set_permissions(&file, p));
+ }
+
+ #[test]
+ fn sync_doesnt_kill_anything() {
+ let tmpdir = tmpdir();
+ let path = tmpdir.join("in.txt");
+
+ let mut file = check!(File::create(&path));
+ check!(file.sync_all());
+ check!(file.sync_data());
+ check!(file.write(b"foo"));
+ check!(file.sync_all());
+ check!(file.sync_data());
+ }
+
+ #[test]
+ fn truncate_works() {
+ let tmpdir = tmpdir();
+ let path = tmpdir.join("in.txt");
+
+ let mut file = check!(File::create(&path));
+ check!(file.write(b"foo"));
+ check!(file.sync_all());
+
+ // Do some simple things with truncation
+ assert_eq!(check!(file.metadata()).len(), 3);
+ check!(file.set_len(10));
+ assert_eq!(check!(file.metadata()).len(), 10);
+ check!(file.write(b"bar"));
+ check!(file.sync_all());
+ assert_eq!(check!(file.metadata()).len(), 10);
+
+ let mut v = Vec::new();
+ check!(check!(File::open(&path)).read_to_end(&mut v));
+ assert_eq!(v, b"foobar\0\0\0\0".to_vec());
+
+ // Truncate to a smaller length, don't seek, and then write something.
+ // Ensure that the intermediate zeroes are all filled in (we have `seek`ed
+ // past the end of the file).
+ check!(file.set_len(2));
+ assert_eq!(check!(file.metadata()).len(), 2);
+ check!(file.write(b"wut"));
+ check!(file.sync_all());
+ assert_eq!(check!(file.metadata()).len(), 9);
+ let mut v = Vec::new();
+ check!(check!(File::open(&path)).read_to_end(&mut v));
+ assert_eq!(v, b"fo\0\0\0\0wut".to_vec());
+ }
+
+ #[test]
+ fn open_flavors() {
+ use fs::OpenOptions as OO;
+ fn c<T: Clone>(t: &T) -> T { t.clone() }
+
+ let tmpdir = tmpdir();
+
+ let mut r = OO::new(); r.read(true);
+ let mut w = OO::new(); w.write(true);
+ let mut rw = OO::new(); rw.write(true).read(true);
+
+ match r.open(&tmpdir.join("a")) {
+ Ok(..) => panic!(), Err(..) => {}
+ }
+
+ // Perform each one twice to make sure that it succeeds the second time
+ // (where the file exists)
+ check!(c(&w).create(true).open(&tmpdir.join("b")));
+ assert!(tmpdir.join("b").exists());
+ check!(c(&w).create(true).open(&tmpdir.join("b")));
+ check!(w.open(&tmpdir.join("b")));
+
+ check!(c(&rw).create(true).open(&tmpdir.join("c")));
+ assert!(tmpdir.join("c").exists());
+ check!(c(&rw).create(true).open(&tmpdir.join("c")));
+ check!(rw.open(&tmpdir.join("c")));
+
+ check!(c(&w).append(true).create(true).open(&tmpdir.join("d")));
+ assert!(tmpdir.join("d").exists());
+ check!(c(&w).append(true).create(true).open(&tmpdir.join("d")));
+ check!(c(&w).append(true).open(&tmpdir.join("d")));
+
+ check!(c(&rw).append(true).create(true).open(&tmpdir.join("e")));
+ assert!(tmpdir.join("e").exists());
+ check!(c(&rw).append(true).create(true).open(&tmpdir.join("e")));
+ check!(c(&rw).append(true).open(&tmpdir.join("e")));
+
+ check!(c(&w).truncate(true).create(true).open(&tmpdir.join("f")));
+ assert!(tmpdir.join("f").exists());
+ check!(c(&w).truncate(true).create(true).open(&tmpdir.join("f")));
+ check!(c(&w).truncate(true).open(&tmpdir.join("f")));
+
+ check!(c(&rw).truncate(true).create(true).open(&tmpdir.join("g")));
+ assert!(tmpdir.join("g").exists());
+ check!(c(&rw).truncate(true).create(true).open(&tmpdir.join("g")));
+ check!(c(&rw).truncate(true).open(&tmpdir.join("g")));
+
+ check!(check!(File::create(&tmpdir.join("h"))).write("foo".as_bytes()));
+ check!(r.open(&tmpdir.join("h")));
+ {
+ let mut f = check!(r.open(&tmpdir.join("h")));
+ assert!(f.write("wut".as_bytes()).is_err());
+ }
+ assert_eq!(check!(fs::metadata(&tmpdir.join("h"))).len(), 3);
+ {
+ let mut f = check!(c(&w).append(true).open(&tmpdir.join("h")));
+ check!(f.write("bar".as_bytes()));
+ }
+ assert_eq!(check!(fs::metadata(&tmpdir.join("h"))).len(), 6);
+ {
+ let mut f = check!(c(&w).truncate(true).open(&tmpdir.join("h")));
+ check!(f.write("bar".as_bytes()));
+ }
+ assert_eq!(check!(fs::metadata(&tmpdir.join("h"))).len(), 3);
+ }
+
+ #[test]
+ fn utime() {
+ let tmpdir = tmpdir();
+ let path = tmpdir.join("a");
+ check!(File::create(&path));
+ // These numbers have to be bigger than the time in the day to account
+ // for timezones Windows in particular will fail in certain timezones
+ // with small enough values
+ check!(fs::set_file_times(&path, 100000, 200000));
+ assert_eq!(check!(path.metadata()).accessed(), 100000);
+ assert_eq!(check!(path.metadata()).modified(), 200000);
+ }
+
+ #[test]
+ fn utime_noexist() {
+ let tmpdir = tmpdir();
+
+ match fs::set_file_times(&tmpdir.join("a"), 100, 200) {
+ Ok(..) => panic!(),
+ Err(..) => {}
+ }
+ }
+
+ #[test]
+ fn binary_file() {
+ let mut bytes = [0; 1024];
+ StdRng::new().unwrap().fill_bytes(&mut bytes);
+
+ let tmpdir = tmpdir();
+
+ check!(check!(File::create(&tmpdir.join("test"))).write(&bytes));
+ let mut v = Vec::new();
+ check!(check!(File::open(&tmpdir.join("test"))).read_to_end(&mut v));
+ assert!(v == &bytes[..]);
+ }
+
+ #[test]
+ #[cfg(not(windows))]
+ fn unlink_readonly() {
+ let tmpdir = tmpdir();
+ let path = tmpdir.join("file");
+ check!(File::create(&path));
+ let mut perm = check!(fs::metadata(&path)).permissions();
+ perm.set_readonly(true);
+ check!(fs::set_permissions(&path, perm));
+ check!(fs::remove_file(&path));
+ }
+
+ #[test]
+ fn mkdir_trailing_slash() {
+ let tmpdir = tmpdir();
+ let path = tmpdir.join("file");
+ check!(fs::create_dir_all(&path.join("a/")));
+ }
+}
+++ /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.
-
-//! Filesystem manipulation operations
-//!
-//! This module contains basic methods to manipulate the contents of the local
-//! filesystem. All methods in this module represent cross-platform filesystem
-//! operations. Extra platform-specific functionality can be found in the
-//! extension traits of `std::os::$platform`.
-
-#![stable(feature = "rust1", since = "1.0.0")]
-
-use core::prelude::*;
-
-use io::{self, Error, ErrorKind, SeekFrom, Seek, Read, Write};
-use path::{Path, PathBuf};
-use sys::fs2 as fs_imp;
-use sys_common::{AsInnerMut, FromInner, AsInner};
-use vec::Vec;
-
-#[allow(deprecated)]
-pub use self::tempdir::TempDir;
-
-mod tempdir;
-
-/// A reference to an open file on the filesystem.
-///
-/// An instance of a `File` can be read and/or written depending on what options
-/// it was opened with. Files also implement `Seek` to alter the logical cursor
-/// that the file contains internally.
-///
-/// # Examples
-///
-/// ```no_run
-/// use std::io::prelude::*;
-/// use std::fs::File;
-///
-/// # fn foo() -> std::io::Result<()> {
-/// let mut f = try!(File::create("foo.txt"));
-/// try!(f.write_all(b"Hello, world!"));
-///
-/// let mut f = try!(File::open("foo.txt"));
-/// let mut s = String::new();
-/// try!(f.read_to_string(&mut s));
-/// assert_eq!(s, "Hello, world!");
-/// # Ok(())
-/// # }
-/// ```
-#[stable(feature = "rust1", since = "1.0.0")]
-pub struct File {
- inner: fs_imp::File,
- path: PathBuf,
-}
-
-/// Metadata information about a file.
-///
-/// This structure is returned from the `metadata` function or method and
-/// represents known metadata about a file such as its permissions, size,
-/// modification times, etc.
-#[stable(feature = "rust1", since = "1.0.0")]
-pub struct Metadata(fs_imp::FileAttr);
-
-/// Iterator over the entries in a directory.
-///
-/// This iterator is returned from the `read_dir` function of this module and
-/// will yield instances of `io::Result<DirEntry>`. Through a `DirEntry`
-/// information like the entry's path and possibly other metadata can be
-/// learned.
-///
-/// # Failure
-///
-/// This `io::Result` will be an `Err` if there's some sort of intermittent
-/// IO error during iteration.
-#[stable(feature = "rust1", since = "1.0.0")]
-pub struct ReadDir(fs_imp::ReadDir);
-
-/// Entries returned by the `ReadDir` iterator.
-///
-/// An instance of `DirEntry` represents an entry inside of a directory on the
-/// filesystem. Each entry can be inspected via methods to learn about the full
-/// path or possibly other metadata through per-platform extension traits.
-#[stable(feature = "rust1", since = "1.0.0")]
-pub struct DirEntry(fs_imp::DirEntry);
-
-/// An iterator that recursively walks over the contents of a directory.
-#[unstable(feature = "fs_walk",
- 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 struct WalkDir {
- cur: Option<ReadDir>,
- stack: Vec<io::Result<ReadDir>>,
-}
-
-/// Options and flags which can be used to configure how a file is opened.
-///
-/// This builder exposes the ability to configure how a `File` is opened and
-/// what operations are permitted on the open file. The `File::open` and
-/// `File::create` methods are aliases for commonly used options using this
-/// builder.
-#[derive(Clone)]
-#[stable(feature = "rust1", since = "1.0.0")]
-pub struct OpenOptions(fs_imp::OpenOptions);
-
-/// Representation of the various permissions on a file.
-///
-/// This module only currently provides one bit of information, `readonly`,
-/// which is exposed on all currently supported platforms. Unix-specific
-/// functionality, such as mode bits, is available through the
-/// `os::unix::PermissionsExt` trait.
-#[derive(Clone, PartialEq, Eq, Debug)]
-#[stable(feature = "rust1", since = "1.0.0")]
-pub struct Permissions(fs_imp::FilePermissions);
-
-impl File {
- /// Attempts to open a file in read-only mode.
- ///
- /// See the `OpenOptions::open` method for more details.
- ///
- /// # Errors
- ///
- /// This function will return an error if `path` does not already exist.
- /// Other errors may also be returned according to `OpenOptions::open`.
- ///
- /// # Examples
- ///
- /// ```no_run
- /// use std::fs::File;
- ///
- /// # fn foo() -> std::io::Result<()> {
- /// let mut f = try!(File::open("foo.txt"));
- /// # Ok(())
- /// # }
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn open<P: AsRef<Path>>(path: P) -> io::Result<File> {
- OpenOptions::new().read(true).open(path)
- }
-
- /// Open a file in write-only mode.
- ///
- /// This function will create a file if it does not exist,
- /// and will truncate it if it does.
- ///
- /// See the `OpenOptions::open` function for more details.
- ///
- /// # Examples
- ///
- /// ```no_run
- /// use std::fs::File;
- ///
- /// # fn foo() -> std::io::Result<()> {
- /// let mut f = try!(File::create("foo.txt"));
- /// # Ok(())
- /// # }
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn create<P: AsRef<Path>>(path: P) -> io::Result<File> {
- OpenOptions::new().write(true).create(true).truncate(true).open(path)
- }
-
- /// Returns the original path that was used to open this file.
- #[unstable(feature = "file_path",
- reason = "this abstraction is imposed by this library instead \
- of the underlying OS and may be removed")]
- pub fn path(&self) -> Option<&Path> {
- Some(&self.path)
- }
-
- /// Attempt to sync all OS-internal metadata to disk.
- ///
- /// This function will attempt to ensure that all in-core data reaches the
- /// filesystem before returning.
- ///
- /// # Examples
- ///
- /// ```no_run
- /// use std::fs::File;
- /// use std::io::prelude::*;
- ///
- /// # fn foo() -> std::io::Result<()> {
- /// let mut f = try!(File::create("foo.txt"));
- /// try!(f.write_all(b"Hello, world!"));
- ///
- /// try!(f.sync_all());
- /// # Ok(())
- /// # }
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn sync_all(&self) -> io::Result<()> {
- self.inner.fsync()
- }
-
- /// This function is similar to `sync_all`, except that it may not
- /// synchronize file metadata to the filesystem.
- ///
- /// This is intended for use cases that must synchronize content, but don't
- /// need the metadata on disk. The goal of this method is to reduce disk
- /// operations.
- ///
- /// Note that some platforms may simply implement this in terms of
- /// `sync_all`.
- ///
- /// # Examples
- ///
- /// ```no_run
- /// use std::fs::File;
- /// use std::io::prelude::*;
- ///
- /// # fn foo() -> std::io::Result<()> {
- /// let mut f = try!(File::create("foo.txt"));
- /// try!(f.write_all(b"Hello, world!"));
- ///
- /// try!(f.sync_data());
- /// # Ok(())
- /// # }
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn sync_data(&self) -> io::Result<()> {
- self.inner.datasync()
- }
-
- /// Truncates or extends the underlying file, updating the size of
- /// this file to become `size`.
- ///
- /// If the `size` is less than the current file's size, then the file will
- /// be shrunk. If it is greater than the current file's size, then the file
- /// will be extended to `size` and have all of the intermediate data filled
- /// in with 0s.
- ///
- /// # Examples
- ///
- /// ```no_run
- /// use std::fs::File;
- ///
- /// # fn foo() -> std::io::Result<()> {
- /// let mut f = try!(File::open("foo.txt"));
- /// try!(f.set_len(0));
- /// # Ok(())
- /// # }
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn set_len(&self, size: u64) -> io::Result<()> {
- self.inner.truncate(size)
- }
-
- /// Queries metadata about the underlying file.
- ///
- /// # Examples
- ///
- /// ```no_run
- /// use std::fs::File;
- ///
- /// # fn foo() -> std::io::Result<()> {
- /// let mut f = try!(File::open("foo.txt"));
- /// let metadata = try!(f.metadata());
- /// # Ok(())
- /// # }
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn metadata(&self) -> io::Result<Metadata> {
- self.inner.file_attr().map(Metadata)
- }
-}
-
-impl AsInner<fs_imp::File> for File {
- fn as_inner(&self) -> &fs_imp::File { &self.inner }
-}
-#[stable(feature = "rust1", since = "1.0.0")]
-impl Read for File {
- fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
- self.inner.read(buf)
- }
-}
-#[stable(feature = "rust1", since = "1.0.0")]
-impl Write for File {
- fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
- self.inner.write(buf)
- }
- fn flush(&mut self) -> io::Result<()> { self.inner.flush() }
-}
-#[stable(feature = "rust1", since = "1.0.0")]
-impl Seek for File {
- fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
- self.inner.seek(pos)
- }
-}
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a> Read for &'a File {
- fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
- self.inner.read(buf)
- }
-}
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a> Write for &'a File {
- fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
- self.inner.write(buf)
- }
- fn flush(&mut self) -> io::Result<()> { self.inner.flush() }
-}
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a> Seek for &'a File {
- fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
- self.inner.seek(pos)
- }
-}
-
-impl OpenOptions {
- /// Creates a blank net set of options ready for configuration.
- ///
- /// All options are initially set to `false`.
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn new() -> OpenOptions {
- OpenOptions(fs_imp::OpenOptions::new())
- }
-
- /// Set the option for read access.
- ///
- /// This option, when true, will indicate that the file should be
- /// `read`-able if opened.
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn read(&mut self, read: bool) -> &mut OpenOptions {
- self.0.read(read); self
- }
-
- /// Set the option for write access.
- ///
- /// This option, when true, will indicate that the file should be
- /// `write`-able if opened.
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn write(&mut self, write: bool) -> &mut OpenOptions {
- self.0.write(write); self
- }
-
- /// Set the option for the append mode.
- ///
- /// This option, when true, means that writes will append to a file instead
- /// of overwriting previous contents.
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn append(&mut self, append: bool) -> &mut OpenOptions {
- self.0.append(append); self
- }
-
- /// Set the option for truncating a previous file.
- ///
- /// If a file is successfully opened with this option set it will truncate
- /// the file to 0 length if it already exists.
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn truncate(&mut self, truncate: bool) -> &mut OpenOptions {
- self.0.truncate(truncate); self
- }
-
- /// Set the option for creating a new file.
- ///
- /// This option indicates whether a new file will be created if the file
- /// does not yet already exist.
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn create(&mut self, create: bool) -> &mut OpenOptions {
- self.0.create(create); self
- }
-
- /// Open a file at `path` with the options specified by `self`.
- ///
- /// # Errors
- ///
- /// This function will return an error under a number of different
- /// circumstances, to include but not limited to:
- ///
- /// * Opening a file that does not exist with read access.
- /// * Attempting to open a file with access that the user lacks
- /// permissions for
- /// * Filesystem-level errors (full disk, etc)
- #[stable(feature = "rust1", since = "1.0.0")]
- 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 })
- }
-}
-
-impl AsInnerMut<fs_imp::OpenOptions> for OpenOptions {
- fn as_inner_mut(&mut self) -> &mut fs_imp::OpenOptions { &mut self.0 }
-}
-
-impl Metadata {
- /// Returns whether this metadata is for a directory.
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn is_dir(&self) -> bool { self.0.is_dir() }
-
- /// Returns whether this metadata is for a regular file.
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn is_file(&self) -> bool { self.0.is_file() }
-
- /// Returns the size of the file, in bytes, this metadata is for.
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn len(&self) -> u64 { self.0.size() }
-
- /// Returns the permissions of the file this metadata is for.
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn permissions(&self) -> Permissions {
- Permissions(self.0.perm())
- }
-
- /// Returns the most recent access time for a file.
- ///
- /// The return value is in milliseconds since the epoch.
- #[unstable(feature = "fs_time",
- reason = "the return type of u64 is not quite appropriate for \
- this method and may change if the standard library \
- gains a type to represent a moment in time")]
- pub fn accessed(&self) -> u64 { self.0.accessed() }
-
- /// Returns the most recent modification time for a file.
- ///
- /// The return value is in milliseconds since the epoch.
- #[unstable(feature = "fs_time",
- reason = "the return type of u64 is not quite appropriate for \
- this method and may change if the standard library \
- gains a type to represent a moment in time")]
- pub fn modified(&self) -> u64 { self.0.modified() }
-}
-
-impl Permissions {
- /// Returns whether these permissions describe a readonly file.
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn readonly(&self) -> bool { self.0.readonly() }
-
- /// Modify the readonly flag for this set of permissions.
- ///
- /// This operation does **not** modify the filesystem. To modify the
- /// filesystem use the `fs::set_permissions` function.
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn set_readonly(&mut self, readonly: bool) {
- self.0.set_readonly(readonly)
- }
-}
-
-impl FromInner<fs_imp::FilePermissions> for Permissions {
- fn from_inner(f: fs_imp::FilePermissions) -> Permissions {
- Permissions(f)
- }
-}
-
-impl AsInner<fs_imp::FilePermissions> for Permissions {
- fn as_inner(&self) -> &fs_imp::FilePermissions { &self.0 }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl Iterator for ReadDir {
- type Item = io::Result<DirEntry>;
-
- fn next(&mut self) -> Option<io::Result<DirEntry>> {
- self.0.next().map(|entry| entry.map(DirEntry))
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl DirEntry {
- /// Returns the full path to the file that this entry represents.
- ///
- /// The full path is created by joining the original path to `read_dir` or
- /// `walk_dir` with the filename of this entry.
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn path(&self) -> PathBuf { self.0.path() }
-}
-
-/// Remove a file from the underlying filesystem.
-///
-/// # Examples
-///
-/// ```rust,no_run
-/// use std::fs;
-///
-/// fs::remove_file("/some/file/path.txt");
-/// ```
-///
-/// Note that, just because an unlink call was successful, it is not
-/// guaranteed that a file is immediately deleted (e.g. depending on
-/// platform, other open file descriptors may prevent immediate removal).
-///
-/// # Errors
-///
-/// This function will return an error if `path` points to a directory, if the
-/// 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: AsRef<Path>>(path: P) -> io::Result<()> {
- fs_imp::unlink(path.as_ref())
-}
-
-/// Given a path, query the file system to get information about a file,
-/// directory, etc.
-///
-/// This function will traverse soft links to query information about the
-/// destination file.
-///
-/// # Examples
-///
-/// ```rust,no_run
-/// # fn foo() -> std::io::Result<()> {
-/// use std::fs;
-///
-/// let attr = try!(fs::metadata("/some/file/path.txt"));
-/// // inspect attr ...
-/// # Ok(())
-/// # }
-/// ```
-///
-/// # Errors
-///
-/// This function will return an error if the user lacks the requisite
-/// 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: AsRef<Path>>(path: P) -> io::Result<Metadata> {
- fs_imp::stat(path.as_ref()).map(Metadata)
-}
-
-/// Rename a file or directory to a new name.
-///
-/// # Examples
-///
-/// ```rust,no_run
-/// use std::fs;
-///
-/// fs::rename("foo", "bar");
-/// ```
-///
-/// # Errors
-///
-/// This function will return an error if the provided `from` doesn't exist, if
-/// the process lacks permissions to view the contents, if `from` and `to`
-/// reside on separate filesystems, or if some other intermittent I/O error
-/// occurs.
-#[stable(feature = "rust1", since = "1.0.0")]
-pub fn rename<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<()> {
- fs_imp::rename(from.as_ref(), to.as_ref())
-}
-
-/// Copies the contents of one file to another. This function will also
-/// copy the permission bits of the original file to the destination file.
-///
-/// This function will **overwrite** the contents of `to`.
-///
-/// Note that if `from` and `to` both point to the same file, then the file
-/// will likely get truncated by this operation.
-///
-/// # Examples
-///
-/// ```
-/// use std::fs;
-///
-/// fs::copy("foo.txt", "bar.txt");
-/// ```
-///
-/// # Errors
-///
-/// This function will return an error in the following situations, but is not
-/// limited to just these cases:
-///
-/// * The `from` path is not a file
-/// * The `from` file does not exist
-/// * The current process does not have the permission rights to access
-/// `from` or write `to`
-#[stable(feature = "rust1", since = "1.0.0")]
-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",
- None))
- }
-
- let mut reader = try!(File::open(from));
- let mut writer = try!(File::create(to));
- let perm = try!(reader.metadata()).permissions();
-
- let ret = try!(io::copy(&mut reader, &mut writer));
- try!(set_permissions(to, perm));
- Ok(ret)
-}
-
-/// Creates a new hard link on the filesystem.
-///
-/// The `dst` path will be a link pointing to the `src` path. Note that systems
-/// often require these two paths to both be located on the same filesystem.
-#[stable(feature = "rust1", since = "1.0.0")]
-pub fn hard_link<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()> {
- fs_imp::link(src.as_ref(), dst.as_ref())
-}
-
-/// Creates a new 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: 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.
-///
-/// # Errors
-///
-/// This function will return an error on failure. Failure conditions include
-/// 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: AsRef<Path>>(path: P) -> io::Result<PathBuf> {
- fs_imp::readlink(path.as_ref())
-}
-
-/// Create a new, empty directory at the provided path
-///
-/// # Examples
-///
-/// ```
-/// use std::fs;
-///
-/// fs::create_dir("/some/dir");
-/// ```
-///
-/// # Errors
-///
-/// 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: AsRef<Path>>(path: P) -> io::Result<()> {
- fs_imp::mkdir(path.as_ref())
-}
-
-/// Recursively create a directory and all of its parent components if they
-/// are missing.
-///
-/// # Errors
-///
-/// This function will fail if any directory in the path specified by `path`
-/// does not already exist and it could not be created otherwise. The specific
-/// error conditions for when a directory is being created (after it is
-/// determined to not exist) are outlined by `fs::create_dir`.
-#[stable(feature = "rust1", since = "1.0.0")]
-pub fn create_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()> {
- let path = path.as_ref();
- if path == Path::new("") || path.is_dir() { return Ok(()) }
- if let Some(p) = path.parent() { try!(create_dir_all(p)) }
- create_dir(path)
-}
-
-/// Remove an existing, empty directory
-///
-/// # Examples
-///
-/// ```
-/// use std::fs;
-///
-/// fs::remove_dir("/some/dir");
-/// ```
-///
-/// # Errors
-///
-/// 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: AsRef<Path>>(path: P) -> io::Result<()> {
- fs_imp::rmdir(path.as_ref())
-}
-
-/// Removes a directory at this path, after removing all its contents. Use
-/// carefully!
-///
-/// This function does **not** follow soft links and it will simply remove the
-/// soft link itself.
-///
-/// # Errors
-///
-/// See `file::remove_file` and `fs::remove_dir`
-#[stable(feature = "rust1", since = "1.0.0")]
-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));
- if stat.is_dir() {
- try!(remove_dir_all(&*child));
- } else {
- try!(remove_file(&*child));
- }
- }
- return remove_dir(path);
-
- #[cfg(unix)]
- fn lstat(path: &Path) -> io::Result<fs_imp::FileAttr> { fs_imp::lstat(path) }
- #[cfg(windows)]
- fn lstat(path: &Path) -> io::Result<fs_imp::FileAttr> { fs_imp::stat(path) }
-}
-
-/// Returns an iterator over the entries within a directory.
-///
-/// The iterator will yield instances of `io::Result<DirEntry>`. New errors may
-/// be encountered after an iterator is initially constructed.
-///
-/// # Examples
-///
-/// ```
-/// # #![feature(path_ext)]
-/// use std::io;
-/// use std::fs::{self, PathExt, DirEntry};
-/// use std::path::Path;
-///
-/// // one possible implementation of fs::walk_dir only visiting files
-/// fn visit_dirs(dir: &Path, cb: &mut FnMut(DirEntry)) -> io::Result<()> {
-/// if dir.is_dir() {
-/// for entry in try!(fs::read_dir(dir)) {
-/// let entry = try!(entry);
-/// if entry.path().is_dir() {
-/// try!(visit_dirs(&entry.path(), cb));
-/// } else {
-/// cb(entry);
-/// }
-/// }
-/// }
-/// Ok(())
-/// }
-/// ```
-///
-/// # Errors
-///
-/// This function will return an error if the provided `path` doesn't exist, if
-/// 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: 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
-/// rooted at `path`.
-///
-/// The path given will not be iterated over, and this will perform iteration in
-/// some top-down order. The contents of unreadable subdirectories are ignored.
-///
-/// The iterator will yield instances of `io::Result<DirEntry>`. New errors may
-/// be encountered after an iterator is initially constructed.
-#[unstable(feature = "fs_walk",
- 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: AsRef<Path>>(path: P) -> io::Result<WalkDir> {
- let start = try!(read_dir(path));
- Ok(WalkDir { cur: Some(start), stack: Vec::new() })
-}
-
-#[unstable(feature = "fs_walk")]
-impl Iterator for WalkDir {
- type Item = io::Result<DirEntry>;
-
- fn next(&mut self) -> Option<io::Result<DirEntry>> {
- loop {
- if let Some(ref mut cur) = self.cur {
- match cur.next() {
- Some(Err(e)) => return Some(Err(e)),
- Some(Ok(next)) => {
- let path = next.path();
- if path.is_dir() {
- self.stack.push(read_dir(&*path));
- }
- return Some(Ok(next))
- }
- None => {}
- }
- }
- self.cur = None;
- match self.stack.pop() {
- Some(Err(e)) => return Some(Err(e)),
- Some(Ok(next)) => self.cur = Some(next),
- None => return None,
- }
- }
- }
-}
-
-/// Utility methods for paths.
-#[unstable(feature = "path_ext",
- reason = "the precise set of methods exposed on this trait may \
- change and some methods may be removed")]
-pub trait PathExt {
- /// Get information on the file, directory, etc at this path.
- ///
- /// Consult the `fs::stat` documentation for more info.
- ///
- /// This call preserves identical runtime/error semantics with `file::stat`.
- fn metadata(&self) -> io::Result<Metadata>;
-
- /// Boolean value indicator whether the underlying file exists on the local
- /// filesystem. Returns false in exactly the cases where `fs::stat` fails.
- fn exists(&self) -> bool;
-
- /// Whether the underlying implementation (be it a file path, or something
- /// else) points at a "regular file" on the FS. Will return false for paths
- /// to non-existent locations or directories or other non-regular files
- /// (named pipes, etc). Follows links when making this determination.
- fn is_file(&self) -> bool;
-
- /// Whether the underlying implementation (be it a file path, or something
- /// else) is pointing at a directory in the underlying FS. Will return
- /// false for paths to non-existent locations or if the item is not a
- /// directory (eg files, named pipes, etc). Follows links when making this
- /// determination.
- fn is_dir(&self) -> bool;
-}
-
-impl PathExt for Path {
- fn metadata(&self) -> io::Result<Metadata> { metadata(self) }
-
- fn exists(&self) -> bool { metadata(self).is_ok() }
-
- fn is_file(&self) -> bool {
- metadata(self).map(|s| s.is_file()).unwrap_or(false)
- }
- fn is_dir(&self) -> bool {
- metadata(self).map(|s| s.is_dir()).unwrap_or(false)
- }
-}
-
-/// Changes the timestamps for a file's last modification and access time.
-///
-/// The file at the path specified will have its last access time set to
-/// `atime` and its modification time set to `mtime`. The times specified should
-/// be in milliseconds.
-#[unstable(feature = "fs_time",
- 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: AsRef<Path>>(path: P, accessed: u64,
- modified: u64) -> io::Result<()> {
- fs_imp::utimes(path.as_ref(), accessed, modified)
-}
-
-/// Changes the permissions found on a file or a directory.
-///
-/// # Examples
-///
-/// ```
-/// # #![feature(fs)]
-/// # fn foo() -> std::io::Result<()> {
-/// use std::fs;
-///
-/// let mut perms = try!(fs::metadata("foo.txt")).permissions();
-/// perms.set_readonly(true);
-/// try!(fs::set_permissions("foo.txt", perms));
-/// # Ok(())
-/// # }
-/// ```
-///
-/// # Errors
-///
-/// This function will return an error if the provided `path` doesn't exist, if
-/// the process lacks permissions to change the attributes of the file, or if
-/// some other I/O error is encountered.
-#[unstable(feature = "fs",
- 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: AsRef<Path>>(path: P, perm: Permissions) -> io::Result<()> {
- fs_imp::set_perm(path.as_ref(), perm.0)
-}
-
-#[cfg(test)]
-mod tests {
- #![allow(deprecated)] //rand
-
- use prelude::v1::*;
- use io::prelude::*;
-
- use env;
- use fs::{self, File, OpenOptions};
- use io::{ErrorKind, SeekFrom};
- use path::PathBuf;
- use path::Path as Path2;
- use os;
- use rand::{self, StdRng, Rng};
- use str;
-
- macro_rules! check { ($e:expr) => (
- match $e {
- Ok(t) => t,
- Err(e) => panic!("{} failed with: {}", stringify!($e), e),
- }
- ) }
-
- macro_rules! error { ($e:expr, $s:expr) => (
- match $e {
- Ok(_) => panic!("Unexpected success. Should've been: {:?}", $s),
- Err(ref err) => assert!(err.to_string().contains($s),
- format!("`{}` did not contain `{}`", err, $s))
- }
- ) }
-
- pub struct TempDir(PathBuf);
-
- impl TempDir {
- fn join(&self, path: &str) -> PathBuf {
- let TempDir(ref p) = *self;
- p.join(path)
- }
-
- fn path<'a>(&'a self) -> &'a Path2 {
- let TempDir(ref p) = *self;
- p
- }
- }
-
- impl Drop for TempDir {
- fn drop(&mut self) {
- // Gee, seeing how we're testing the fs module I sure hope that we
- // at least implement this correctly!
- let TempDir(ref p) = *self;
- check!(fs::remove_dir_all(p));
- }
- }
-
- pub fn tmpdir() -> TempDir {
- let p = env::temp_dir();
- let ret = p.join(&format!("rust-{}", rand::random::<u32>()));
- check!(fs::create_dir(&ret));
- TempDir(ret)
- }
-
- #[test]
- fn file_test_io_smoke_test() {
- let message = "it's alright. have a good time";
- let tmpdir = tmpdir();
- let filename = &tmpdir.join("file_rt_io_file_test.txt");
- {
- let mut write_stream = check!(File::create(filename));
- check!(write_stream.write(message.as_bytes()));
- }
- {
- let mut read_stream = check!(File::open(filename));
- let mut read_buf = [0; 1028];
- let read_str = match check!(read_stream.read(&mut read_buf)) {
- -1|0 => panic!("shouldn't happen"),
- n => str::from_utf8(&read_buf[..n]).unwrap().to_string()
- };
- assert_eq!(read_str, message);
- }
- check!(fs::remove_file(filename));
- }
-
- #[test]
- fn invalid_path_raises() {
- let tmpdir = tmpdir();
- let filename = &tmpdir.join("file_that_does_not_exist.txt");
- let result = File::open(filename);
-
- if cfg!(unix) {
- error!(result, "o such file or directory");
- }
- // error!(result, "couldn't open path as file");
- // error!(result, format!("path={}; mode=open; access=read", filename.display()));
- }
-
- #[test]
- fn file_test_iounlinking_invalid_path_should_raise_condition() {
- let tmpdir = tmpdir();
- let filename = &tmpdir.join("file_another_file_that_does_not_exist.txt");
-
- let result = fs::remove_file(filename);
-
- if cfg!(unix) {
- error!(result, "o such file or directory");
- }
- // error!(result, "couldn't unlink path");
- // error!(result, format!("path={}", filename.display()));
- }
-
- #[test]
- fn file_test_io_non_positional_read() {
- let message: &str = "ten-four";
- let mut read_mem = [0; 8];
- let tmpdir = tmpdir();
- let filename = &tmpdir.join("file_rt_io_file_test_positional.txt");
- {
- let mut rw_stream = check!(File::create(filename));
- check!(rw_stream.write(message.as_bytes()));
- }
- {
- let mut read_stream = check!(File::open(filename));
- {
- let read_buf = &mut read_mem[0..4];
- check!(read_stream.read(read_buf));
- }
- {
- let read_buf = &mut read_mem[4..8];
- check!(read_stream.read(read_buf));
- }
- }
- check!(fs::remove_file(filename));
- let read_str = str::from_utf8(&read_mem).unwrap();
- assert_eq!(read_str, message);
- }
-
- #[test]
- fn file_test_io_seek_and_tell_smoke_test() {
- let message = "ten-four";
- let mut read_mem = [0; 4];
- let set_cursor = 4 as u64;
- let mut tell_pos_pre_read;
- let mut tell_pos_post_read;
- let tmpdir = tmpdir();
- let filename = &tmpdir.join("file_rt_io_file_test_seeking.txt");
- {
- let mut rw_stream = check!(File::create(filename));
- check!(rw_stream.write(message.as_bytes()));
- }
- {
- let mut read_stream = check!(File::open(filename));
- check!(read_stream.seek(SeekFrom::Start(set_cursor)));
- tell_pos_pre_read = check!(read_stream.seek(SeekFrom::Current(0)));
- check!(read_stream.read(&mut read_mem));
- tell_pos_post_read = check!(read_stream.seek(SeekFrom::Current(0)));
- }
- check!(fs::remove_file(filename));
- let read_str = str::from_utf8(&read_mem).unwrap();
- assert_eq!(read_str, &message[4..8]);
- assert_eq!(tell_pos_pre_read, set_cursor);
- assert_eq!(tell_pos_post_read, message.len() as u64);
- }
-
- #[test]
- fn file_test_io_seek_and_write() {
- let initial_msg = "food-is-yummy";
- let overwrite_msg = "-the-bar!!";
- let final_msg = "foo-the-bar!!";
- let seek_idx = 3;
- let mut read_mem = [0; 13];
- let tmpdir = tmpdir();
- let filename = &tmpdir.join("file_rt_io_file_test_seek_and_write.txt");
- {
- let mut rw_stream = check!(File::create(filename));
- check!(rw_stream.write(initial_msg.as_bytes()));
- check!(rw_stream.seek(SeekFrom::Start(seek_idx)));
- check!(rw_stream.write(overwrite_msg.as_bytes()));
- }
- {
- let mut read_stream = check!(File::open(filename));
- check!(read_stream.read(&mut read_mem));
- }
- check!(fs::remove_file(filename));
- let read_str = str::from_utf8(&read_mem).unwrap();
- assert!(read_str == final_msg);
- }
-
- #[test]
- fn file_test_io_seek_shakedown() {
- // 01234567890123
- let initial_msg = "qwer-asdf-zxcv";
- let chunk_one: &str = "qwer";
- let chunk_two: &str = "asdf";
- let chunk_three: &str = "zxcv";
- let mut read_mem = [0; 4];
- let tmpdir = tmpdir();
- let filename = &tmpdir.join("file_rt_io_file_test_seek_shakedown.txt");
- {
- let mut rw_stream = check!(File::create(filename));
- check!(rw_stream.write(initial_msg.as_bytes()));
- }
- {
- let mut read_stream = check!(File::open(filename));
-
- check!(read_stream.seek(SeekFrom::End(-4)));
- check!(read_stream.read(&mut read_mem));
- assert_eq!(str::from_utf8(&read_mem).unwrap(), chunk_three);
-
- check!(read_stream.seek(SeekFrom::Current(-9)));
- check!(read_stream.read(&mut read_mem));
- assert_eq!(str::from_utf8(&read_mem).unwrap(), chunk_two);
-
- check!(read_stream.seek(SeekFrom::Start(0)));
- check!(read_stream.read(&mut read_mem));
- assert_eq!(str::from_utf8(&read_mem).unwrap(), chunk_one);
- }
- check!(fs::remove_file(filename));
- }
-
- #[test]
- fn file_test_stat_is_correct_on_is_file() {
- let tmpdir = tmpdir();
- let filename = &tmpdir.join("file_stat_correct_on_is_file.txt");
- {
- let mut opts = OpenOptions::new();
- let mut fs = check!(opts.read(true).write(true)
- .create(true).open(filename));
- let msg = "hw";
- fs.write(msg.as_bytes()).unwrap();
-
- let fstat_res = check!(fs.metadata());
- assert!(fstat_res.is_file());
- }
- let stat_res_fn = check!(fs::metadata(filename));
- assert!(stat_res_fn.is_file());
- let stat_res_meth = check!(filename.metadata());
- assert!(stat_res_meth.is_file());
- check!(fs::remove_file(filename));
- }
-
- #[test]
- fn file_test_stat_is_correct_on_is_dir() {
- let tmpdir = tmpdir();
- let filename = &tmpdir.join("file_stat_correct_on_is_dir");
- check!(fs::create_dir(filename));
- let stat_res_fn = check!(fs::metadata(filename));
- assert!(stat_res_fn.is_dir());
- let stat_res_meth = check!(filename.metadata());
- assert!(stat_res_meth.is_dir());
- check!(fs::remove_dir(filename));
- }
-
- #[test]
- fn file_test_fileinfo_false_when_checking_is_file_on_a_directory() {
- let tmpdir = tmpdir();
- let dir = &tmpdir.join("fileinfo_false_on_dir");
- check!(fs::create_dir(dir));
- assert!(dir.is_file() == false);
- check!(fs::remove_dir(dir));
- }
-
- #[test]
- fn file_test_fileinfo_check_exists_before_and_after_file_creation() {
- let tmpdir = tmpdir();
- let file = &tmpdir.join("fileinfo_check_exists_b_and_a.txt");
- check!(check!(File::create(file)).write(b"foo"));
- assert!(file.exists());
- check!(fs::remove_file(file));
- assert!(!file.exists());
- }
-
- #[test]
- fn file_test_directoryinfo_check_exists_before_and_after_mkdir() {
- let tmpdir = tmpdir();
- let dir = &tmpdir.join("before_and_after_dir");
- assert!(!dir.exists());
- check!(fs::create_dir(dir));
- assert!(dir.exists());
- assert!(dir.is_dir());
- check!(fs::remove_dir(dir));
- assert!(!dir.exists());
- }
-
- #[test]
- fn file_test_directoryinfo_readdir() {
- let tmpdir = tmpdir();
- let dir = &tmpdir.join("di_readdir");
- check!(fs::create_dir(dir));
- let prefix = "foo";
- for n in 0..3 {
- let f = dir.join(&format!("{}.txt", n));
- let mut w = check!(File::create(&f));
- let msg_str = format!("{}{}", prefix, n.to_string());
- let msg = msg_str.as_bytes();
- check!(w.write(msg));
- }
- let files = check!(fs::read_dir(dir));
- let mut mem = [0; 4];
- for f in files {
- let f = f.unwrap().path();
- {
- let n = f.file_stem().unwrap();
- check!(check!(File::open(&f)).read(&mut mem));
- let read_str = str::from_utf8(&mem).unwrap();
- let expected = format!("{}{}", prefix, n.to_str().unwrap());
- assert_eq!(expected, read_str);
- }
- check!(fs::remove_file(&f));
- }
- check!(fs::remove_dir(dir));
- }
-
- #[test]
- fn file_test_walk_dir() {
- let tmpdir = tmpdir();
- let dir = &tmpdir.join("walk_dir");
- check!(fs::create_dir(dir));
-
- let dir1 = &dir.join("01/02/03");
- check!(fs::create_dir_all(dir1));
- check!(File::create(&dir1.join("04")));
-
- let dir2 = &dir.join("11/12/13");
- check!(fs::create_dir_all(dir2));
- check!(File::create(&dir2.join("14")));
-
- let files = check!(fs::walk_dir(dir));
- let mut cur = [0; 2];
- for f in files {
- let f = f.unwrap().path();
- let stem = f.file_stem().unwrap().to_str().unwrap();
- let root = stem.as_bytes()[0] - b'0';
- let name = stem.as_bytes()[1] - b'0';
- assert!(cur[root as usize] < name);
- cur[root as usize] = name;
- }
-
- check!(fs::remove_dir_all(dir));
- }
-
- #[test]
- fn mkdir_path_already_exists_error() {
- let tmpdir = tmpdir();
- let dir = &tmpdir.join("mkdir_error_twice");
- check!(fs::create_dir(dir));
- let e = fs::create_dir(dir).err().unwrap();
- assert_eq!(e.kind(), ErrorKind::AlreadyExists);
- }
-
- #[test]
- fn recursive_mkdir() {
- let tmpdir = tmpdir();
- let dir = tmpdir.join("d1/d2");
- check!(fs::create_dir_all(&dir));
- assert!(dir.is_dir())
- }
-
- #[test]
- fn recursive_mkdir_failure() {
- let tmpdir = tmpdir();
- let dir = tmpdir.join("d1");
- let file = dir.join("f1");
-
- check!(fs::create_dir_all(&dir));
- check!(File::create(&file));
-
- let result = fs::create_dir_all(&file);
-
- assert!(result.is_err());
- // error!(result, "couldn't recursively mkdir");
- // error!(result, "couldn't create directory");
- // error!(result, "mode=0700");
- // error!(result, format!("path={}", file.display()));
- }
-
- #[test]
- fn recursive_mkdir_slash() {
- check!(fs::create_dir_all(&Path2::new("/")));
- }
-
- // FIXME(#12795) depends on lstat to work on windows
- #[cfg(not(windows))]
- #[test]
- fn recursive_rmdir() {
- let tmpdir = tmpdir();
- let d1 = tmpdir.join("d1");
- let dt = d1.join("t");
- let dtt = dt.join("t");
- let d2 = tmpdir.join("d2");
- let canary = d2.join("do_not_delete");
- check!(fs::create_dir_all(&dtt));
- check!(fs::create_dir_all(&d2));
- check!(check!(File::create(&canary)).write(b"foo"));
- check!(fs::soft_link(&d2, &dt.join("d2")));
- check!(fs::remove_dir_all(&d1));
-
- assert!(!d1.is_dir());
- assert!(canary.exists());
- }
-
- #[test]
- fn unicode_path_is_dir() {
- assert!(Path2::new(".").is_dir());
- assert!(!Path2::new("test/stdtest/fs.rs").is_dir());
-
- let tmpdir = tmpdir();
-
- let mut dirpath = tmpdir.path().to_path_buf();
- dirpath.push(&format!("test-가一ー你好"));
- check!(fs::create_dir(&dirpath));
- assert!(dirpath.is_dir());
-
- let mut filepath = dirpath;
- filepath.push("unicode-file-\u{ac00}\u{4e00}\u{30fc}\u{4f60}\u{597d}.rs");
- check!(File::create(&filepath)); // ignore return; touch only
- assert!(!filepath.is_dir());
- assert!(filepath.exists());
- }
-
- #[test]
- fn unicode_path_exists() {
- assert!(Path2::new(".").exists());
- assert!(!Path2::new("test/nonexistent-bogus-path").exists());
-
- let tmpdir = tmpdir();
- let unicode = tmpdir.path();
- let unicode = unicode.join(&format!("test-각丁ー再见"));
- check!(fs::create_dir(&unicode));
- assert!(unicode.exists());
- assert!(!Path2::new("test/unicode-bogus-path-각丁ー再见").exists());
- }
-
- #[test]
- fn copy_file_does_not_exist() {
- let from = Path2::new("test/nonexistent-bogus-path");
- let to = Path2::new("test/other-bogus-path");
-
- match fs::copy(&from, &to) {
- Ok(..) => panic!(),
- Err(..) => {
- assert!(!from.exists());
- assert!(!to.exists());
- }
- }
- }
-
- #[test]
- fn copy_file_ok() {
- let tmpdir = tmpdir();
- let input = tmpdir.join("in.txt");
- let out = tmpdir.join("out.txt");
-
- check!(check!(File::create(&input)).write(b"hello"));
- check!(fs::copy(&input, &out));
- let mut v = Vec::new();
- check!(check!(File::open(&out)).read_to_end(&mut v));
- assert_eq!(v.as_slice(), b"hello");
-
- assert_eq!(check!(input.metadata()).permissions(),
- check!(out.metadata()).permissions());
- }
-
- #[test]
- fn copy_file_dst_dir() {
- let tmpdir = tmpdir();
- let out = tmpdir.join("out");
-
- check!(File::create(&out));
- match fs::copy(&*out, tmpdir.path()) {
- Ok(..) => panic!(), Err(..) => {}
- }
- }
-
- #[test]
- fn copy_file_dst_exists() {
- let tmpdir = tmpdir();
- let input = tmpdir.join("in");
- let output = tmpdir.join("out");
-
- check!(check!(File::create(&input)).write("foo".as_bytes()));
- check!(check!(File::create(&output)).write("bar".as_bytes()));
- check!(fs::copy(&input, &output));
-
- let mut v = Vec::new();
- check!(check!(File::open(&output)).read_to_end(&mut v));
- assert_eq!(v, b"foo".to_vec());
- }
-
- #[test]
- fn copy_file_src_dir() {
- let tmpdir = tmpdir();
- let out = tmpdir.join("out");
-
- match fs::copy(tmpdir.path(), &out) {
- Ok(..) => panic!(), Err(..) => {}
- }
- assert!(!out.exists());
- }
-
- #[test]
- fn copy_file_preserves_perm_bits() {
- let tmpdir = tmpdir();
- let input = tmpdir.join("in.txt");
- let out = tmpdir.join("out.txt");
-
- let attr = check!(check!(File::create(&input)).metadata());
- let mut p = attr.permissions();
- p.set_readonly(true);
- check!(fs::set_permissions(&input, p));
- check!(fs::copy(&input, &out));
- assert!(check!(out.metadata()).permissions().readonly());
- check!(fs::set_permissions(&input, attr.permissions()));
- check!(fs::set_permissions(&out, attr.permissions()));
- }
-
- #[cfg(not(windows))] // FIXME(#10264) operation not permitted?
- #[test]
- fn symlinks_work() {
- let tmpdir = tmpdir();
- let input = tmpdir.join("in.txt");
- let out = tmpdir.join("out.txt");
-
- check!(check!(File::create(&input)).write("foobar".as_bytes()));
- check!(fs::soft_link(&input, &out));
- // if cfg!(not(windows)) {
- // assert_eq!(check!(lstat(&out)).kind, FileType::Symlink);
- // assert_eq!(check!(out.lstat()).kind, FileType::Symlink);
- // }
- assert_eq!(check!(fs::metadata(&out)).len(),
- check!(fs::metadata(&input)).len());
- let mut v = Vec::new();
- check!(check!(File::open(&out)).read_to_end(&mut v));
- assert_eq!(v, b"foobar".to_vec());
- }
-
- #[cfg(not(windows))] // apparently windows doesn't like symlinks
- #[test]
- fn symlink_noexist() {
- let tmpdir = tmpdir();
- // symlinks can point to things that don't exist
- check!(fs::soft_link(&tmpdir.join("foo"), &tmpdir.join("bar")));
- assert_eq!(check!(fs::read_link(&tmpdir.join("bar"))),
- tmpdir.join("foo"));
- }
-
- #[test]
- fn readlink_not_symlink() {
- let tmpdir = tmpdir();
- match fs::read_link(tmpdir.path()) {
- Ok(..) => panic!("wanted a failure"),
- Err(..) => {}
- }
- }
-
- #[test]
- fn links_work() {
- let tmpdir = tmpdir();
- let input = tmpdir.join("in.txt");
- let out = tmpdir.join("out.txt");
-
- check!(check!(File::create(&input)).write("foobar".as_bytes()));
- check!(fs::hard_link(&input, &out));
- assert_eq!(check!(fs::metadata(&out)).len(),
- check!(fs::metadata(&input)).len());
- assert_eq!(check!(fs::metadata(&out)).len(),
- check!(input.metadata()).len());
- let mut v = Vec::new();
- check!(check!(File::open(&out)).read_to_end(&mut v));
- assert_eq!(v, b"foobar".to_vec());
-
- // can't link to yourself
- match fs::hard_link(&input, &input) {
- Ok(..) => panic!("wanted a failure"),
- Err(..) => {}
- }
- // can't link to something that doesn't exist
- match fs::hard_link(&tmpdir.join("foo"), &tmpdir.join("bar")) {
- Ok(..) => panic!("wanted a failure"),
- Err(..) => {}
- }
- }
-
- #[test]
- fn chmod_works() {
- let tmpdir = tmpdir();
- let file = tmpdir.join("in.txt");
-
- check!(File::create(&file));
- let attr = check!(fs::metadata(&file));
- assert!(!attr.permissions().readonly());
- let mut p = attr.permissions();
- p.set_readonly(true);
- check!(fs::set_permissions(&file, p.clone()));
- let attr = check!(fs::metadata(&file));
- assert!(attr.permissions().readonly());
-
- match fs::set_permissions(&tmpdir.join("foo"), p.clone()) {
- Ok(..) => panic!("wanted an error"),
- Err(..) => {}
- }
-
- p.set_readonly(false);
- check!(fs::set_permissions(&file, p));
- }
-
- #[test]
- fn sync_doesnt_kill_anything() {
- let tmpdir = tmpdir();
- let path = tmpdir.join("in.txt");
-
- let mut file = check!(File::create(&path));
- check!(file.sync_all());
- check!(file.sync_data());
- check!(file.write(b"foo"));
- check!(file.sync_all());
- check!(file.sync_data());
- }
-
- #[test]
- fn truncate_works() {
- let tmpdir = tmpdir();
- let path = tmpdir.join("in.txt");
-
- let mut file = check!(File::create(&path));
- check!(file.write(b"foo"));
- check!(file.sync_all());
-
- // Do some simple things with truncation
- assert_eq!(check!(file.metadata()).len(), 3);
- check!(file.set_len(10));
- assert_eq!(check!(file.metadata()).len(), 10);
- check!(file.write(b"bar"));
- check!(file.sync_all());
- assert_eq!(check!(file.metadata()).len(), 10);
-
- let mut v = Vec::new();
- check!(check!(File::open(&path)).read_to_end(&mut v));
- assert_eq!(v, b"foobar\0\0\0\0".to_vec());
-
- // Truncate to a smaller length, don't seek, and then write something.
- // Ensure that the intermediate zeroes are all filled in (we have `seek`ed
- // past the end of the file).
- check!(file.set_len(2));
- assert_eq!(check!(file.metadata()).len(), 2);
- check!(file.write(b"wut"));
- check!(file.sync_all());
- assert_eq!(check!(file.metadata()).len(), 9);
- let mut v = Vec::new();
- check!(check!(File::open(&path)).read_to_end(&mut v));
- assert_eq!(v, b"fo\0\0\0\0wut".to_vec());
- }
-
- #[test]
- fn open_flavors() {
- use fs::OpenOptions as OO;
- fn c<T: Clone>(t: &T) -> T { t.clone() }
-
- let tmpdir = tmpdir();
-
- let mut r = OO::new(); r.read(true);
- let mut w = OO::new(); w.write(true);
- let mut rw = OO::new(); rw.write(true).read(true);
-
- match r.open(&tmpdir.join("a")) {
- Ok(..) => panic!(), Err(..) => {}
- }
-
- // Perform each one twice to make sure that it succeeds the second time
- // (where the file exists)
- check!(c(&w).create(true).open(&tmpdir.join("b")));
- assert!(tmpdir.join("b").exists());
- check!(c(&w).create(true).open(&tmpdir.join("b")));
- check!(w.open(&tmpdir.join("b")));
-
- check!(c(&rw).create(true).open(&tmpdir.join("c")));
- assert!(tmpdir.join("c").exists());
- check!(c(&rw).create(true).open(&tmpdir.join("c")));
- check!(rw.open(&tmpdir.join("c")));
-
- check!(c(&w).append(true).create(true).open(&tmpdir.join("d")));
- assert!(tmpdir.join("d").exists());
- check!(c(&w).append(true).create(true).open(&tmpdir.join("d")));
- check!(c(&w).append(true).open(&tmpdir.join("d")));
-
- check!(c(&rw).append(true).create(true).open(&tmpdir.join("e")));
- assert!(tmpdir.join("e").exists());
- check!(c(&rw).append(true).create(true).open(&tmpdir.join("e")));
- check!(c(&rw).append(true).open(&tmpdir.join("e")));
-
- check!(c(&w).truncate(true).create(true).open(&tmpdir.join("f")));
- assert!(tmpdir.join("f").exists());
- check!(c(&w).truncate(true).create(true).open(&tmpdir.join("f")));
- check!(c(&w).truncate(true).open(&tmpdir.join("f")));
-
- check!(c(&rw).truncate(true).create(true).open(&tmpdir.join("g")));
- assert!(tmpdir.join("g").exists());
- check!(c(&rw).truncate(true).create(true).open(&tmpdir.join("g")));
- check!(c(&rw).truncate(true).open(&tmpdir.join("g")));
-
- check!(check!(File::create(&tmpdir.join("h"))).write("foo".as_bytes()));
- check!(r.open(&tmpdir.join("h")));
- {
- let mut f = check!(r.open(&tmpdir.join("h")));
- assert!(f.write("wut".as_bytes()).is_err());
- }
- assert_eq!(check!(fs::metadata(&tmpdir.join("h"))).len(), 3);
- {
- let mut f = check!(c(&w).append(true).open(&tmpdir.join("h")));
- check!(f.write("bar".as_bytes()));
- }
- assert_eq!(check!(fs::metadata(&tmpdir.join("h"))).len(), 6);
- {
- let mut f = check!(c(&w).truncate(true).open(&tmpdir.join("h")));
- check!(f.write("bar".as_bytes()));
- }
- assert_eq!(check!(fs::metadata(&tmpdir.join("h"))).len(), 3);
- }
-
- #[test]
- fn utime() {
- let tmpdir = tmpdir();
- let path = tmpdir.join("a");
- check!(File::create(&path));
- // These numbers have to be bigger than the time in the day to account
- // for timezones Windows in particular will fail in certain timezones
- // with small enough values
- check!(fs::set_file_times(&path, 100000, 200000));
- assert_eq!(check!(path.metadata()).accessed(), 100000);
- assert_eq!(check!(path.metadata()).modified(), 200000);
- }
-
- #[test]
- fn utime_noexist() {
- let tmpdir = tmpdir();
-
- match fs::set_file_times(&tmpdir.join("a"), 100, 200) {
- Ok(..) => panic!(),
- Err(..) => {}
- }
- }
-
- #[test]
- fn binary_file() {
- let mut bytes = [0; 1024];
- StdRng::new().unwrap().fill_bytes(&mut bytes);
-
- let tmpdir = tmpdir();
-
- check!(check!(File::create(&tmpdir.join("test"))).write(&bytes));
- let mut v = Vec::new();
- check!(check!(File::open(&tmpdir.join("test"))).read_to_end(&mut v));
- assert!(v == bytes.as_slice());
- }
-
- #[test]
- #[cfg(not(windows))]
- fn unlink_readonly() {
- let tmpdir = tmpdir();
- let path = tmpdir.join("file");
- check!(File::create(&path));
- let mut perm = check!(fs::metadata(&path)).permissions();
- perm.set_readonly(true);
- check!(fs::set_permissions(&path, perm));
- check!(fs::remove_file(&path));
- }
-
- #[test]
- fn mkdir_trailing_slash() {
- let tmpdir = tmpdir();
- let path = tmpdir.join("file");
- check!(fs::create_dir_all(&path.join("a/")));
- }
-}
+++ /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.
-
-#![unstable(feature = "tempdir", reason = "needs an RFC before stabilization")]
-#![deprecated(since = "1.0.0",
- reason = "use the `tempdir` crate from crates.io instead")]
-#![allow(deprecated)]
-
-use prelude::v1::*;
-
-use env;
-use io::{self, Error, ErrorKind};
-use fs;
-use path::{self, PathBuf};
-use rand::{thread_rng, Rng};
-
-/// A wrapper for a path to temporary directory implementing automatic
-/// scope-based deletion.
-pub struct TempDir {
- path: Option<PathBuf>,
-}
-
-// How many times should we (re)try finding an unused random name? It should be
-// enough that an attacker will run out of luck before we run out of patience.
-const NUM_RETRIES: u32 = 1 << 31;
-// How many characters should we include in a random file name? It needs to
-// be enough to dissuade an attacker from trying to preemptively create names
-// of that length, but not so huge that we unnecessarily drain the random number
-// generator of entropy.
-const NUM_RAND_CHARS: usize = 12;
-
-impl TempDir {
- /// Attempts to make a temporary directory inside of `tmpdir` whose name
- /// will have the prefix `prefix`. The directory will be automatically
- /// deleted once the returned wrapper is destroyed.
- ///
- /// If no directory can be created, `Err` is returned.
- #[allow(deprecated)] // rand usage
- pub fn new_in<P: AsRef<path::Path>>(tmpdir: P, prefix: &str) -> io::Result<TempDir> {
- let storage;
- let mut tmpdir = tmpdir.as_ref();
- if !tmpdir.is_absolute() {
- let cur_dir = try!(env::current_dir());
- storage = cur_dir.join(tmpdir);
- tmpdir = &storage;
- // return TempDir::new_in(&cur_dir.join(tmpdir), prefix);
- }
-
- let mut rng = thread_rng();
- for _ in 0..NUM_RETRIES {
- let suffix: String = rng.gen_ascii_chars().take(NUM_RAND_CHARS).collect();
- let leaf = if prefix.len() > 0 {
- format!("{}.{}", prefix, suffix)
- } else {
- // If we're given an empty string for a prefix, then creating a
- // directory starting with "." would lead to it being
- // semi-invisible on some systems.
- suffix
- };
- let path = tmpdir.join(&leaf);
- match fs::create_dir(&path) {
- Ok(_) => return Ok(TempDir { path: Some(path) }),
- Err(ref e) if e.kind() == ErrorKind::AlreadyExists => {}
- Err(e) => return Err(e)
- }
- }
-
- Err(Error::new(ErrorKind::AlreadyExists,
- "too many temporary directories already exist",
- None))
- }
-
- /// Attempts to make a temporary directory inside of `env::temp_dir()` whose
- /// name will have the prefix `prefix`. The directory will be automatically
- /// deleted once the returned wrapper is destroyed.
- ///
- /// If no directory can be created, `Err` is returned.
- #[allow(deprecated)]
- pub fn new(prefix: &str) -> io::Result<TempDir> {
- TempDir::new_in(&env::temp_dir(), prefix)
- }
-
- /// Unwrap the wrapped `std::path::Path` from the `TempDir` wrapper.
- /// This discards the wrapper so that the automatic deletion of the
- /// temporary directory is prevented.
- pub fn into_path(mut self) -> PathBuf {
- self.path.take().unwrap()
- }
-
- /// Access the wrapped `std::path::Path` to the temporary directory.
- pub fn path(&self) -> &path::Path {
- self.path.as_ref().unwrap()
- }
-
- /// Close and remove the temporary directory
- ///
- /// Although `TempDir` removes the directory on drop, in the destructor
- /// any errors are ignored. To detect errors cleaning up the temporary
- /// directory, call `close` instead.
- pub fn close(mut self) -> io::Result<()> {
- self.cleanup_dir()
- }
-
- fn cleanup_dir(&mut self) -> io::Result<()> {
- match self.path {
- Some(ref p) => fs::remove_dir_all(p),
- None => Ok(())
- }
- }
-}
-
-impl Drop for TempDir {
- fn drop(&mut self) {
- let _ = self.cleanup_dir();
- }
-}
-
-// the tests for this module need to change the path using change_dir,
-// and this doesn't play nicely with other tests so these unit tests are located
-// in src/test/run-pass/tempfile.rs
use io::prelude::*;
use cmp;
-use error::{self, FromError};
+use error;
use fmt;
use io::{self, DEFAULT_BUF_SIZE, Error, ErrorKind};
use ptr;
match self.inner.as_mut().unwrap().write(&self.buf[written..]) {
Ok(0) => {
ret = Err(Error::new(ErrorKind::WriteZero,
- "failed to write the buffered data", None));
+ "failed to write the buffered data"));
break;
}
Ok(n) => written += n,
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<W> FromError<IntoInnerError<W>> for Error {
- fn from_error(iie: IntoInnerError<W>) -> Error { iie.1 }
+impl<W> From<IntoInnerError<W>> for Error {
+ fn from(iie: IntoInnerError<W>) -> Error { iie.1 }
}
#[stable(feature = "rust1", since = "1.0.0")]
let mut buf = [0, 0, 0];
let nread = reader.read(&mut buf);
- assert_eq!(Ok(3), nread);
+ assert_eq!(nread.unwrap(), 3);
let b: &[_] = &[5, 6, 7];
assert_eq!(buf, b);
let mut buf = [0, 0];
let nread = reader.read(&mut buf);
- assert_eq!(Ok(2), nread);
+ assert_eq!(nread.unwrap(), 2);
let b: &[_] = &[0, 1];
assert_eq!(buf, b);
let mut buf = [0];
let nread = reader.read(&mut buf);
- assert_eq!(Ok(1), nread);
+ assert_eq!(nread.unwrap(), 1);
let b: &[_] = &[2];
assert_eq!(buf, b);
let mut buf = [0, 0, 0];
let nread = reader.read(&mut buf);
- assert_eq!(Ok(1), nread);
+ assert_eq!(nread.unwrap(), 1);
let b: &[_] = &[3, 0, 0];
assert_eq!(buf, b);
let nread = reader.read(&mut buf);
- assert_eq!(Ok(1), nread);
+ assert_eq!(nread.unwrap(), 1);
let b: &[_] = &[4, 0, 0];
assert_eq!(buf, b);
- assert_eq!(reader.read(&mut buf), Ok(0));
+ assert_eq!(reader.read(&mut buf).unwrap(), 0);
}
#[test]
}
let mut stream = BufStream::new(S);
- assert_eq!(stream.read(&mut [0; 10]), Ok(0));
+ assert_eq!(stream.read(&mut [0; 10]).unwrap(), 0);
stream.write(&[0; 10]).unwrap();
stream.flush().unwrap();
}
let in_buf: &[u8] = b"a\nb\nc";
let reader = BufReader::with_capacity(2, in_buf);
let mut it = reader.lines();
- assert_eq!(it.next(), Some(Ok("a".to_string())));
- assert_eq!(it.next(), Some(Ok("b".to_string())));
- assert_eq!(it.next(), Some(Ok("c".to_string())));
- assert_eq!(it.next(), None);
+ assert_eq!(it.next().unwrap().unwrap(), "a".to_string());
+ assert_eq!(it.next().unwrap().unwrap(), "b".to_string());
+ assert_eq!(it.next().unwrap().unwrap(), "c".to_string());
+ assert!(it.next().is_none());
}
#[test]
let inner = ShortReader{lengths: vec![0, 1, 2, 0, 1, 0]};
let mut reader = BufReader::new(inner);
let mut buf = [0, 0];
- assert_eq!(reader.read(&mut buf), Ok(0));
- assert_eq!(reader.read(&mut buf), Ok(1));
- assert_eq!(reader.read(&mut buf), Ok(2));
- assert_eq!(reader.read(&mut buf), Ok(0));
- assert_eq!(reader.read(&mut buf), Ok(1));
- assert_eq!(reader.read(&mut buf), Ok(0));
- assert_eq!(reader.read(&mut buf), Ok(0));
+ assert_eq!(reader.read(&mut buf).unwrap(), 0);
+ assert_eq!(reader.read(&mut buf).unwrap(), 1);
+ assert_eq!(reader.read(&mut buf).unwrap(), 2);
+ assert_eq!(reader.read(&mut buf).unwrap(), 0);
+ assert_eq!(reader.read(&mut buf).unwrap(), 1);
+ assert_eq!(reader.read(&mut buf).unwrap(), 0);
+ assert_eq!(reader.read(&mut buf).unwrap(), 0);
}
#[test]
fn read_char_buffered() {
let buf = [195, 159];
let reader = BufReader::with_capacity(1, &buf[..]);
- assert_eq!(reader.chars().next(), Some(Ok('ß')));
+ assert_eq!(reader.chars().next().unwrap().unwrap(), 'ß');
}
#[test]
let buf = [195, 159, b'a'];
let reader = BufReader::with_capacity(1, &buf[..]);
let mut it = reader.chars();
- assert_eq!(it.next(), Some(Ok('ß')));
- assert_eq!(it.next(), Some(Ok('a')));
- assert_eq!(it.next(), None);
+ assert_eq!(it.next().unwrap().unwrap(), 'ß');
+ assert_eq!(it.next().unwrap().unwrap(), 'a');
+ assert!(it.next().is_none());
}
#[test]
if pos < 0 {
Err(Error::new(ErrorKind::InvalidInput,
- "invalid seek to a negative position",
- None))
+ "invalid seek to a negative position"))
} else {
self.pos = pos as u64;
Ok(self.pos)
#[test]
fn test_vec_writer() {
let mut writer = Vec::new();
- assert_eq!(writer.write(&[0]), Ok(1));
- assert_eq!(writer.write(&[1, 2, 3]), Ok(3));
- assert_eq!(writer.write(&[4, 5, 6, 7]), Ok(4));
+ assert_eq!(writer.write(&[0]).unwrap(), 1);
+ assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3);
+ assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4);
let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7];
assert_eq!(writer, b);
}
#[test]
fn test_mem_writer() {
let mut writer = Cursor::new(Vec::new());
- assert_eq!(writer.write(&[0]), Ok(1));
- assert_eq!(writer.write(&[1, 2, 3]), Ok(3));
- assert_eq!(writer.write(&[4, 5, 6, 7]), Ok(4));
+ assert_eq!(writer.write(&[0]).unwrap(), 1);
+ assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3);
+ assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4);
let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7];
assert_eq!(&writer.get_ref()[..], b);
}
{
let mut writer = Cursor::new(&mut buf[..]);
assert_eq!(writer.position(), 0);
- assert_eq!(writer.write(&[0]), Ok(1));
+ assert_eq!(writer.write(&[0]).unwrap(), 1);
assert_eq!(writer.position(), 1);
- assert_eq!(writer.write(&[1, 2, 3]), Ok(3));
- assert_eq!(writer.write(&[4, 5, 6, 7]), Ok(4));
+ assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3);
+ assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4);
assert_eq!(writer.position(), 8);
- assert_eq!(writer.write(&[]), Ok(0));
+ assert_eq!(writer.write(&[]).unwrap(), 0);
assert_eq!(writer.position(), 8);
- assert_eq!(writer.write(&[8, 9]), Ok(1));
- assert_eq!(writer.write(&[10]), Ok(0));
+ assert_eq!(writer.write(&[8, 9]).unwrap(), 1);
+ assert_eq!(writer.write(&[10]).unwrap(), 0);
}
let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8];
assert_eq!(buf, b);
{
let mut writer = Cursor::new(&mut buf[..]);
assert_eq!(writer.position(), 0);
- assert_eq!(writer.write(&[1]), Ok(1));
+ assert_eq!(writer.write(&[1]).unwrap(), 1);
assert_eq!(writer.position(), 1);
- assert_eq!(writer.seek(SeekFrom::Start(2)), Ok(2));
+ assert_eq!(writer.seek(SeekFrom::Start(2)).unwrap(), 2);
assert_eq!(writer.position(), 2);
- assert_eq!(writer.write(&[2]), Ok(1));
+ assert_eq!(writer.write(&[2]).unwrap(), 1);
assert_eq!(writer.position(), 3);
- assert_eq!(writer.seek(SeekFrom::Current(-2)), Ok(1));
+ assert_eq!(writer.seek(SeekFrom::Current(-2)).unwrap(), 1);
assert_eq!(writer.position(), 1);
- assert_eq!(writer.write(&[3]), Ok(1));
+ assert_eq!(writer.write(&[3]).unwrap(), 1);
assert_eq!(writer.position(), 2);
- assert_eq!(writer.seek(SeekFrom::End(-1)), Ok(7));
+ assert_eq!(writer.seek(SeekFrom::End(-1)).unwrap(), 7);
assert_eq!(writer.position(), 7);
- assert_eq!(writer.write(&[4]), Ok(1));
+ assert_eq!(writer.write(&[4]).unwrap(), 1);
assert_eq!(writer.position(), 8);
}
fn test_buf_writer_error() {
let mut buf = [0 as u8; 2];
let mut writer = Cursor::new(&mut buf[..]);
- assert_eq!(writer.write(&[0]), Ok(1));
- assert_eq!(writer.write(&[0, 0]), Ok(1));
- assert_eq!(writer.write(&[0, 0]), Ok(0));
+ assert_eq!(writer.write(&[0]).unwrap(), 1);
+ assert_eq!(writer.write(&[0, 0]).unwrap(), 1);
+ assert_eq!(writer.write(&[0, 0]).unwrap(), 0);
}
#[test]
fn test_mem_reader() {
let mut reader = Cursor::new(vec!(0, 1, 2, 3, 4, 5, 6, 7));
let mut buf = [];
- assert_eq!(reader.read(&mut buf), Ok(0));
+ assert_eq!(reader.read(&mut buf).unwrap(), 0);
assert_eq!(reader.position(), 0);
let mut buf = [0];
- assert_eq!(reader.read(&mut buf), Ok(1));
+ assert_eq!(reader.read(&mut buf).unwrap(), 1);
assert_eq!(reader.position(), 1);
let b: &[_] = &[0];
assert_eq!(buf, b);
let mut buf = [0; 4];
- assert_eq!(reader.read(&mut buf), Ok(4));
+ assert_eq!(reader.read(&mut buf).unwrap(), 4);
assert_eq!(reader.position(), 5);
let b: &[_] = &[1, 2, 3, 4];
assert_eq!(buf, b);
- assert_eq!(reader.read(&mut buf), Ok(3));
+ assert_eq!(reader.read(&mut buf).unwrap(), 3);
let b: &[_] = &[5, 6, 7];
assert_eq!(&buf[..3], b);
- assert_eq!(reader.read(&mut buf), Ok(0));
+ assert_eq!(reader.read(&mut buf).unwrap(), 0);
}
#[test]
#[test]
fn test_slice_reader() {
let in_buf = vec![0, 1, 2, 3, 4, 5, 6, 7];
- let mut reader = &mut in_buf.as_slice();
+ let mut reader = &mut &in_buf[..];
let mut buf = [];
- assert_eq!(reader.read(&mut buf), Ok(0));
+ assert_eq!(reader.read(&mut buf).unwrap(), 0);
let mut buf = [0];
- assert_eq!(reader.read(&mut buf), Ok(1));
+ assert_eq!(reader.read(&mut buf).unwrap(), 1);
assert_eq!(reader.len(), 7);
let b: &[_] = &[0];
- assert_eq!(buf.as_slice(), b);
+ assert_eq!(&buf[..], b);
let mut buf = [0; 4];
- assert_eq!(reader.read(&mut buf), Ok(4));
+ assert_eq!(reader.read(&mut buf).unwrap(), 4);
assert_eq!(reader.len(), 3);
let b: &[_] = &[1, 2, 3, 4];
- assert_eq!(buf.as_slice(), b);
- assert_eq!(reader.read(&mut buf), Ok(3));
+ assert_eq!(&buf[..], b);
+ assert_eq!(reader.read(&mut buf).unwrap(), 3);
let b: &[_] = &[5, 6, 7];
assert_eq!(&buf[..3], b);
- assert_eq!(reader.read(&mut buf), Ok(0));
+ assert_eq!(reader.read(&mut buf).unwrap(), 0);
}
#[test]
fn test_buf_reader() {
let in_buf = vec![0, 1, 2, 3, 4, 5, 6, 7];
- let mut reader = Cursor::new(in_buf.as_slice());
+ let mut reader = Cursor::new(&in_buf[..]);
let mut buf = [];
- assert_eq!(reader.read(&mut buf), Ok(0));
+ assert_eq!(reader.read(&mut buf).unwrap(), 0);
assert_eq!(reader.position(), 0);
let mut buf = [0];
- assert_eq!(reader.read(&mut buf), Ok(1));
+ assert_eq!(reader.read(&mut buf).unwrap(), 1);
assert_eq!(reader.position(), 1);
let b: &[_] = &[0];
assert_eq!(buf, b);
let mut buf = [0; 4];
- assert_eq!(reader.read(&mut buf), Ok(4));
+ assert_eq!(reader.read(&mut buf).unwrap(), 4);
assert_eq!(reader.position(), 5);
let b: &[_] = &[1, 2, 3, 4];
assert_eq!(buf, b);
- assert_eq!(reader.read(&mut buf), Ok(3));
+ assert_eq!(reader.read(&mut buf).unwrap(), 3);
let b: &[_] = &[5, 6, 7];
assert_eq!(&buf[..3], b);
- assert_eq!(reader.read(&mut buf), Ok(0));
+ assert_eq!(reader.read(&mut buf).unwrap(), 0);
}
#[test]
fn test_read_char() {
let b = &b"Vi\xE1\xBB\x87t"[..];
let mut c = Cursor::new(b).chars();
- assert_eq!(c.next(), Some(Ok('V')));
- assert_eq!(c.next(), Some(Ok('i')));
- assert_eq!(c.next(), Some(Ok('ệ')));
- assert_eq!(c.next(), Some(Ok('t')));
- assert_eq!(c.next(), None);
+ assert_eq!(c.next().unwrap().unwrap(), 'V');
+ assert_eq!(c.next().unwrap().unwrap(), 'i');
+ assert_eq!(c.next().unwrap().unwrap(), 'ệ');
+ assert_eq!(c.next().unwrap().unwrap(), 't');
+ assert!(c.next().is_none());
}
#[test]
fn seek_past_end() {
let buf = [0xff];
let mut r = Cursor::new(&buf[..]);
- assert_eq!(r.seek(SeekFrom::Start(10)), Ok(10));
- assert_eq!(r.read(&mut [0]), Ok(0));
+ assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10);
+ assert_eq!(r.read(&mut [0]).unwrap(), 0);
let mut r = Cursor::new(vec!(10));
- assert_eq!(r.seek(SeekFrom::Start(10)), Ok(10));
- assert_eq!(r.read(&mut [0]), Ok(0));
+ assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10);
+ assert_eq!(r.read(&mut [0]).unwrap(), 0);
let mut buf = [0];
let mut r = Cursor::new(&mut buf[..]);
- assert_eq!(r.seek(SeekFrom::Start(10)), Ok(10));
- assert_eq!(r.write(&[3]), Ok(0));
+ assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10);
+ assert_eq!(r.write(&[3]).unwrap(), 0);
}
#[test]
fn test_seekable_mem_writer() {
let mut writer = Cursor::new(Vec::<u8>::new());
assert_eq!(writer.position(), 0);
- assert_eq!(writer.write(&[0]), Ok(1));
+ assert_eq!(writer.write(&[0]).unwrap(), 1);
assert_eq!(writer.position(), 1);
- assert_eq!(writer.write(&[1, 2, 3]), Ok(3));
- assert_eq!(writer.write(&[4, 5, 6, 7]), Ok(4));
+ assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3);
+ assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4);
assert_eq!(writer.position(), 8);
let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7];
assert_eq!(&writer.get_ref()[..], b);
- assert_eq!(writer.seek(SeekFrom::Start(0)), Ok(0));
+ assert_eq!(writer.seek(SeekFrom::Start(0)).unwrap(), 0);
assert_eq!(writer.position(), 0);
- assert_eq!(writer.write(&[3, 4]), Ok(2));
+ assert_eq!(writer.write(&[3, 4]).unwrap(), 2);
let b: &[_] = &[3, 4, 2, 3, 4, 5, 6, 7];
assert_eq!(&writer.get_ref()[..], b);
- assert_eq!(writer.seek(SeekFrom::Current(1)), Ok(3));
- assert_eq!(writer.write(&[0, 1]), Ok(2));
+ assert_eq!(writer.seek(SeekFrom::Current(1)).unwrap(), 3);
+ assert_eq!(writer.write(&[0, 1]).unwrap(), 2);
let b: &[_] = &[3, 4, 2, 0, 1, 5, 6, 7];
assert_eq!(&writer.get_ref()[..], b);
- assert_eq!(writer.seek(SeekFrom::End(-1)), Ok(7));
- assert_eq!(writer.write(&[1, 2]), Ok(2));
+ assert_eq!(writer.seek(SeekFrom::End(-1)).unwrap(), 7);
+ assert_eq!(writer.write(&[1, 2]).unwrap(), 2);
let b: &[_] = &[3, 4, 2, 0, 1, 5, 6, 1, 2];
assert_eq!(&writer.get_ref()[..], b);
- assert_eq!(writer.seek(SeekFrom::End(1)), Ok(10));
- assert_eq!(writer.write(&[1]), Ok(1));
+ assert_eq!(writer.seek(SeekFrom::End(1)).unwrap(), 10);
+ assert_eq!(writer.write(&[1]).unwrap(), 1);
let b: &[_] = &[3, 4, 2, 0, 1, 5, 6, 1, 2, 0, 1];
assert_eq!(&writer.get_ref()[..], b);
}
#[test]
fn vec_seek_past_end() {
let mut r = Cursor::new(Vec::new());
- assert_eq!(r.seek(SeekFrom::Start(10)), Ok(10));
- assert_eq!(r.write(&[3]), Ok(1));
+ assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10);
+ assert_eq!(r.write(&[3]).unwrap(), 1);
}
#[test]
// except according to those terms.
use boxed::Box;
-use clone::Clone;
+use convert::Into;
use error;
use fmt;
+use marker::Send;
use option::Option::{self, Some, None};
use result;
-use string::String;
use sys;
/// A type for results generated by I/O related functions where the `Err` type
/// Errors mostly originate from the underlying OS, but custom instances of
/// `Error` can be created with crafted error messages and a particular value of
/// `ErrorKind`.
-#[derive(PartialEq, Eq, Clone, Debug)]
+#[derive(Debug)]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Error {
repr: Repr,
}
-#[derive(PartialEq, Eq, Clone, Debug)]
+#[derive(Debug)]
enum Repr {
Os(i32),
Custom(Box<Custom>),
}
-#[derive(PartialEq, Eq, Clone, Debug)]
+#[derive(Debug)]
struct Custom {
kind: ErrorKind,
- desc: &'static str,
- detail: Option<String>
+ error: Box<error::Error+Send>,
}
/// A list specifying general categories of I/O error.
}
impl Error {
- /// Creates a new custom error from a specified kind/description/detail.
- #[unstable(feature = "io", reason = "the exact makeup of an Error may
- change to include `Box<Error>` for \
- example")]
- pub fn new(kind: ErrorKind,
- description: &'static str,
- detail: Option<String>) -> Error {
+ /// Creates a new I/O error from a known kind of error as well as an
+ /// arbitrary error payload.
+ ///
+ /// This function is used to generically create I/O errors which do not
+ /// originate from the OS itself. The `error` argument is an arbitrary
+ /// payload which will be contained in this `Error`. Accessors as well as
+ /// downcasting will soon be added to this type as well to access the custom
+ /// information.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::io::{Error, ErrorKind};
+ ///
+ /// // errors can be created from strings
+ /// let custom_error = Error::new(ErrorKind::Other, "oh no!");
+ ///
+ /// // errors can also be created from other errors
+ /// let custom_error2 = Error::new(ErrorKind::Interrupted, custom_error);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn new<E>(kind: ErrorKind, error: E) -> Error
+ where E: Into<Box<error::Error+Send>>
+ {
Error {
repr: Repr::Custom(Box::new(Custom {
kind: kind,
- desc: description,
- detail: detail,
+ error: error.into(),
}))
}
}
///
/// If this `Error` was constructed via `last_os_error` then this function
/// will return `Some`, otherwise it will return `None`.
- #[unstable(feature = "io", reason = "function was just added and the return \
- type may become an abstract OS error")]
+ #[stable(feature = "rust1", since = "1.0.0")]
pub fn raw_os_error(&self) -> Option<i32> {
match self.repr {
Repr::Os(i) => Some(i),
Repr::Custom(ref c) => c.kind,
}
}
-
- /// Returns a short description for this error message
- #[unstable(feature = "io")]
- #[deprecated(since = "1.0.0", reason = "use the Error trait's description \
- method instead")]
- pub fn description(&self) -> &str {
- match self.repr {
- Repr::Os(..) => "os error",
- Repr::Custom(ref c) => c.desc,
- }
- }
-
- /// Returns a detailed error message for this error (if one is available)
- #[unstable(feature = "io")]
- #[deprecated(since = "1.0.0", reason = "use the to_string() method instead")]
- pub fn detail(&self) -> Option<String> {
- match self.repr {
- Repr::Os(code) => Some(sys::os::error_string(code)),
- Repr::Custom(ref s) => s.detail.clone(),
- }
- }
}
#[stable(feature = "rust1", since = "1.0.0")]
let detail = sys::os::error_string(code);
write!(fmt, "{} (os error {})", detail, code)
}
- Repr::Custom(ref c) => {
- match **c {
- Custom {
- kind: ErrorKind::Other,
- desc: "unknown error",
- detail: Some(ref detail)
- } => {
- write!(fmt, "{}", detail)
- }
- Custom { detail: None, desc, .. } =>
- write!(fmt, "{}", desc),
- Custom { detail: Some(ref detail), desc, .. } =>
- write!(fmt, "{} ({})", desc, detail)
- }
- }
+ Repr::Custom(ref c) => c.error.fmt(fmt),
}
}
}
fn description(&self) -> &str {
match self.repr {
Repr::Os(..) => "os error",
- Repr::Custom(ref c) => c.desc,
+ Repr::Custom(ref c) => c.error.description(),
}
}
}
if try!(self.write(data)) == data.len() {
Ok(())
} else {
- Err(Error::new(ErrorKind::WriteZero, "failed to write whole buffer", None))
+ Err(Error::new(ErrorKind::WriteZero, "failed to write whole buffer"))
}
}
if str::from_utf8(&g.s[g.len..]).is_err() {
ret.and_then(|_| {
Err(Error::new(ErrorKind::InvalidInput,
- "stream did not contain valid UTF-8", None))
+ "stream did not contain valid UTF-8"))
})
} else {
g.len = g.s.len();
fn read_to_end<R: Read + ?Sized>(r: &mut R, buf: &mut Vec<u8>) -> Result<usize> {
let start_len = buf.len();
let mut len = start_len;
- let mut cap_bump = 16;
+ let mut new_write_size = 16;
let ret;
loop {
if len == buf.len() {
- if buf.capacity() == buf.len() {
- if cap_bump < DEFAULT_BUF_SIZE {
- cap_bump *= 2;
- }
- buf.reserve(cap_bump);
+ if new_write_size < DEFAULT_BUF_SIZE {
+ new_write_size *= 2;
}
- let new_area = buf.capacity() - buf.len();
- buf.extend(iter::repeat(0).take(new_area));
+ buf.extend(iter::repeat(0).take(new_write_size));
}
match r.read(&mut buf[len..]) {
while buf.len() > 0 {
match self.write(buf) {
Ok(0) => return Err(Error::new(ErrorKind::WriteZero,
- "failed to write whole buffer",
- None)),
+ "failed to write whole buffer")),
Ok(n) => buf = &buf[n..],
Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
Err(e) => return Err(e),
///
/// The stream typically has a fixed size, allowing seeking relative to either
/// end or the current offset.
-#[unstable(feature = "io", reason = "the central `seek` method may be split \
- into multiple methods instead of taking \
- an enum as an argument")]
+#[stable(feature = "rust1", since = "1.0.0")]
pub trait Seek {
/// Seek to an offset, in bytes, in a stream
///
/// # Errors
///
/// Seeking to a negative offset is considered an error
+ #[stable(feature = "rust1", since = "1.0.0")]
fn seek(&mut self, pos: SeekFrom) -> Result<u64>;
}
/// Enumeration of possible methods to seek within an I/O object.
#[derive(Copy, PartialEq, Eq, Clone, Debug)]
-#[unstable(feature = "io", reason = "awaiting the stability of Seek")]
+#[stable(feature = "rust1", since = "1.0.0")]
pub enum SeekFrom {
/// Set the offset to the provided number of bytes.
+ #[stable(feature = "rust1", since = "1.0.0")]
Start(u64),
/// Set the offset to the size of this object plus the specified number of
///
/// It is possible to seek beyond the end of an object, but is an error to
/// seek before byte 0.
+ #[stable(feature = "rust1", since = "1.0.0")]
End(i64),
/// Set the offset to the current position plus the specified number of
///
/// It is possible to seek beyond the end of an object, but is an error to
/// seek before byte 0.
+ #[stable(feature = "rust1", since = "1.0.0")]
Current(i64),
}
/// An enumeration of possible errors that can be generated from the `Chars`
/// adapter.
-#[derive(PartialEq, Clone, Debug)]
+#[derive(Debug)]
#[unstable(feature = "io", reason = "awaiting stability of Read::chars")]
pub enum CharsError {
/// Variant representing that the underlying stream was read successfully
fn read_until() {
let mut buf = Cursor::new(&b"12"[..]);
let mut v = Vec::new();
- assert_eq!(buf.read_until(b'3', &mut v), Ok(2));
+ assert_eq!(buf.read_until(b'3', &mut v).unwrap(), 2);
assert_eq!(v, b"12");
let mut buf = Cursor::new(&b"1233"[..]);
let mut v = Vec::new();
- assert_eq!(buf.read_until(b'3', &mut v), Ok(3));
+ assert_eq!(buf.read_until(b'3', &mut v).unwrap(), 3);
assert_eq!(v, b"123");
v.truncate(0);
- assert_eq!(buf.read_until(b'3', &mut v), Ok(1));
+ assert_eq!(buf.read_until(b'3', &mut v).unwrap(), 1);
assert_eq!(v, b"3");
v.truncate(0);
- assert_eq!(buf.read_until(b'3', &mut v), Ok(0));
+ assert_eq!(buf.read_until(b'3', &mut v).unwrap(), 0);
assert_eq!(v, []);
}
fn split() {
let buf = Cursor::new(&b"12"[..]);
let mut s = buf.split(b'3');
- assert_eq!(s.next(), Some(Ok(vec![b'1', b'2'])));
- assert_eq!(s.next(), None);
+ assert_eq!(s.next().unwrap().unwrap(), vec![b'1', b'2']);
+ assert!(s.next().is_none());
let buf = Cursor::new(&b"1233"[..]);
let mut s = buf.split(b'3');
- assert_eq!(s.next(), Some(Ok(vec![b'1', b'2'])));
- assert_eq!(s.next(), Some(Ok(vec![])));
- assert_eq!(s.next(), None);
+ assert_eq!(s.next().unwrap().unwrap(), vec![b'1', b'2']);
+ assert_eq!(s.next().unwrap().unwrap(), vec![]);
+ assert!(s.next().is_none());
}
#[test]
fn read_line() {
let mut buf = Cursor::new(&b"12"[..]);
let mut v = String::new();
- assert_eq!(buf.read_line(&mut v), Ok(2));
+ assert_eq!(buf.read_line(&mut v).unwrap(), 2);
assert_eq!(v, "12");
let mut buf = Cursor::new(&b"12\n\n"[..]);
let mut v = String::new();
- assert_eq!(buf.read_line(&mut v), Ok(3));
+ assert_eq!(buf.read_line(&mut v).unwrap(), 3);
assert_eq!(v, "12\n");
v.truncate(0);
- assert_eq!(buf.read_line(&mut v), Ok(1));
+ assert_eq!(buf.read_line(&mut v).unwrap(), 1);
assert_eq!(v, "\n");
v.truncate(0);
- assert_eq!(buf.read_line(&mut v), Ok(0));
+ assert_eq!(buf.read_line(&mut v).unwrap(), 0);
assert_eq!(v, "");
}
fn lines() {
let buf = Cursor::new(&b"12"[..]);
let mut s = buf.lines();
- assert_eq!(s.next(), Some(Ok("12".to_string())));
- assert_eq!(s.next(), None);
+ assert_eq!(s.next().unwrap().unwrap(), "12".to_string());
+ assert!(s.next().is_none());
let buf = Cursor::new(&b"12\n\n"[..]);
let mut s = buf.lines();
- assert_eq!(s.next(), Some(Ok("12".to_string())));
- assert_eq!(s.next(), Some(Ok(String::new())));
- assert_eq!(s.next(), None);
+ assert_eq!(s.next().unwrap().unwrap(), "12".to_string());
+ assert_eq!(s.next().unwrap().unwrap(), "".to_string());
+ assert!(s.next().is_none());
}
#[test]
fn read_to_end() {
let mut c = Cursor::new(&b""[..]);
let mut v = Vec::new();
- assert_eq!(c.read_to_end(&mut v), Ok(0));
+ assert_eq!(c.read_to_end(&mut v).unwrap(), 0);
assert_eq!(v, []);
let mut c = Cursor::new(&b"1"[..]);
let mut v = Vec::new();
- assert_eq!(c.read_to_end(&mut v), Ok(1));
+ assert_eq!(c.read_to_end(&mut v).unwrap(), 1);
assert_eq!(v, b"1");
}
fn read_to_string() {
let mut c = Cursor::new(&b""[..]);
let mut v = String::new();
- assert_eq!(c.read_to_string(&mut v), Ok(0));
+ assert_eq!(c.read_to_string(&mut v).unwrap(), 0);
assert_eq!(v, "");
let mut c = Cursor::new(&b"1"[..]);
let mut v = String::new();
- assert_eq!(c.read_to_string(&mut v), Ok(1));
+ assert_eq!(c.read_to_string(&mut v).unwrap(), 1);
assert_eq!(v, "1");
let mut c = Cursor::new(&b"\xff"[..]);
impl Read for R {
fn read(&mut self, _: &mut [u8]) -> io::Result<usize> {
- Err(io::Error::new(io::ErrorKind::Other, "", None))
+ Err(io::Error::new(io::ErrorKind::Other, ""))
}
}
let mut buf = [0; 1];
- assert_eq!(Ok(0), R.take(0).read(&mut buf));
+ assert_eq!(0, R.take(0).read(&mut buf).unwrap());
}
}
#[test]
fn sink_sinks() {
let mut s = sink();
- assert_eq!(s.write(&[]), Ok(0));
- assert_eq!(s.write(&[0]), Ok(1));
- assert_eq!(s.write(&[0; 1024]), Ok(1024));
- assert_eq!(s.by_ref().write(&[0; 1024]), Ok(1024));
+ assert_eq!(s.write(&[]).unwrap(), 0);
+ assert_eq!(s.write(&[0]).unwrap(), 1);
+ assert_eq!(s.write(&[0; 1024]).unwrap(), 1024);
+ assert_eq!(s.by_ref().write(&[0; 1024]).unwrap(), 1024);
}
#[test]
fn empty_reads() {
let mut e = empty();
- assert_eq!(e.read(&mut []), Ok(0));
- assert_eq!(e.read(&mut [0]), Ok(0));
- assert_eq!(e.read(&mut [0; 1024]), Ok(0));
- assert_eq!(e.by_ref().read(&mut [0; 1024]), Ok(0));
+ assert_eq!(e.read(&mut []).unwrap(), 0);
+ assert_eq!(e.read(&mut [0]).unwrap(), 0);
+ assert_eq!(e.read(&mut [0; 1024]).unwrap(), 0);
+ assert_eq!(e.by_ref().read(&mut [0; 1024]).unwrap(), 0);
}
#[test]
fn repeat_repeats() {
let mut r = repeat(4);
let mut b = [0; 1024];
- assert_eq!(r.read(&mut b), Ok(1024));
+ assert_eq!(r.read(&mut b).unwrap(), 1024);
assert!(b.iter().all(|b| *b == 4));
}
#[test]
fn take_some_bytes() {
assert_eq!(repeat(4).take(100).bytes().count(), 100);
- assert_eq!(repeat(4).take(100).bytes().next(), Some(Ok(4)));
+ assert_eq!(repeat(4).take(100).bytes().next().unwrap().unwrap(), 4);
assert_eq!(repeat(1).take(10).chain(repeat(2).take(10)).bytes().count(), 20);
}
let mut buf = [0; 10];
{
let mut ptr: &mut [u8] = &mut buf;
- assert_eq!(repeat(4).tee(&mut ptr).take(5).read(&mut [0; 10]), Ok(5));
+ assert_eq!(repeat(4).tee(&mut ptr).take(5).read(&mut [0; 10]).unwrap(), 5);
}
assert_eq!(buf, [4, 4, 4, 4, 4, 0, 0, 0, 0, 0]);
}
let mut ptr2: &mut [u8] = &mut buf2;
assert_eq!((&mut ptr1).broadcast(&mut ptr2)
- .write(&[1, 2, 3]), Ok(3));
+ .write(&[1, 2, 3]).unwrap(), 3);
}
assert_eq!(buf1, buf2);
assert_eq!(buf1, [1, 2, 3, 0, 0, 0, 0, 0, 0, 0]);
//! lives in the [`vec`](vec/index.html) module. Contiguous, unsized regions
//! of memory, `[T]`, commonly called "slices", and their borrowed versions,
//! `&[T]`, commonly called "borrowed slices", are built-in types for which the
-//! for which the [`slice`](slice/index.html) module defines many methods.
+//! [`slice`](slice/index.html) module defines many methods.
//!
//! `&str`, a UTF-8 string, is a built-in type, and the standard library
//! defines methods for it on a variety of traits in the
#![feature(unsafe_no_drop_flag, filling_drop)]
#![feature(macro_reexport)]
#![feature(unique)]
-#![feature(convert)]
#![feature(allow_internal_unstable)]
#![feature(str_char)]
#![feature(into_cow)]
-#![feature(slice_patterns)]
#![feature(std_misc)]
+#![feature(slice_patterns)]
#![feature(debug_builders)]
#![cfg_attr(test, feature(test, rustc_private, std_misc))]
#[cfg(not(test))] pub use core::cmp;
pub use core::convert;
pub use core::default;
-#[allow(deprecated)]
-pub use core::finally;
pub use core::hash;
pub use core::intrinsics;
pub use core::iter;
pub use core::simd;
pub use core::result;
pub use core::option;
-pub use core::error;
+pub mod error;
#[cfg(not(test))] pub use alloc::boxed;
pub use alloc::rc;
#[path = "num/f64.rs"] pub mod f64;
pub mod ascii;
+
pub mod thunk;
/* Common traits */
($expr:expr) => (match $expr {
$crate::result::Result::Ok(val) => val,
$crate::result::Result::Err(err) => {
- return $crate::result::Result::Err($crate::error::FromError::from_error(err))
+ return $crate::result::Result::Err($crate::convert::From::from(err))
}
})
}
match $e {
Some(r) => r,
None => return Err(io::Error::new(io::ErrorKind::InvalidInput,
- $msg, None)),
+ $msg)),
}
)
}
// split the string by ':' and convert the second part to u16
- let mut parts_iter = self.rsplitn(1, ':');
+ let mut parts_iter = self.rsplitn(2, ':');
let port_str = try_opt!(parts_iter.next(), "invalid socket address");
let host = try_opt!(parts_iter.next(), "invalid socket address");
let port: u16 = try_opt!(port_str.parse().ok(), "invalid port value");
false, false, false, true, false, false, false, Some(Global));
}
- fn tsa<A: ToSocketAddrs>(a: A) -> io::Result<Vec<SocketAddr>> {
- Ok(try!(a.to_socket_addrs()).collect())
+ fn tsa<A: ToSocketAddrs>(a: A) -> Result<Vec<SocketAddr>, String> {
+ match a.to_socket_addrs() {
+ Ok(a) => Ok(a.collect()),
+ Err(e) => Err(e.to_string()),
+ }
}
#[test]
}
Err(last_err.unwrap_or_else(|| {
Error::new(ErrorKind::InvalidInput,
- "could not resolve to any addresses", None)
+ "could not resolve to any addresses")
}))
}
use io;
use net::{ToSocketAddrs, SocketAddr, Shutdown};
use sys_common::net2 as net_imp;
-use sys_common::AsInner;
+use sys_common::{AsInner, FromInner};
/// A structure which represents a TCP stream between a local socket and a
/// remote socket.
self.0.peer_addr()
}
- /// Returns the socket address of the local half of this TCP connection.
- #[unstable(feature = "net")]
- #[deprecated(since = "1.0.0", reason = "renamed to local_addr")]
- pub fn socket_addr(&self) -> io::Result<SocketAddr> {
- self.0.socket_addr()
- }
-
/// Returns the socket address of the local half of this TCP connection.
#[stable(feature = "rust1", since = "1.0.0")]
pub fn local_addr(&self) -> io::Result<SocketAddr> {
fn as_inner(&self) -> &net_imp::TcpStream { &self.0 }
}
+impl FromInner<net_imp::TcpStream> for TcpStream {
+ fn from_inner(inner: net_imp::TcpStream) -> TcpStream { TcpStream(inner) }
+}
+
impl TcpListener {
/// Creates a new `TcpListener` which will be bound to the specified
/// address.
self.0.socket_addr()
}
- /// Deprecated, renamed to local_addr
- #[unstable(feature = "net")]
- #[deprecated(since = "1.0.0", reason = "renamed to local_addr")]
- pub fn socket_addr(&self) -> io::Result<SocketAddr> {
- self.0.socket_addr()
- }
-
/// Create a new independently owned handle to the underlying socket.
///
/// The returned `TcpListener` is a reference to the same socket that this
fn as_inner(&self) -> &net_imp::TcpListener { &self.0 }
}
+impl FromInner<net_imp::TcpListener> for TcpListener {
+ fn from_inner(inner: net_imp::TcpListener) -> TcpListener {
+ TcpListener(inner)
+ }
+}
+
#[cfg(test)]
mod tests {
use prelude::v1::*;
let _t = thread::spawn(move|| {
let mut stream = t!(TcpStream::connect(&addr));
t!(stream.write(&[99]));
- tx.send(t!(stream.socket_addr())).unwrap();
+ tx.send(t!(stream.local_addr())).unwrap();
});
let (mut stream, addr) = t!(acceptor.accept());
fn socket_and_peer_name_ip4() {
each_ip(&mut |addr| {
let listener = t!(TcpListener::bind(&addr));
- let so_name = t!(listener.socket_addr());
+ let so_name = t!(listener.local_addr());
assert_eq!(addr, so_name);
let _t = thread::spawn(move|| {
t!(listener.accept());
let mut c = t!(TcpStream::connect(&addr));
let mut b = [0; 10];
- assert_eq!(c.read(&mut b), Ok(1));
+ assert_eq!(c.read(&mut b).unwrap(), 1);
t!(c.write(&[1]));
rx.recv().unwrap();
})
let _t = thread::spawn(move|| {
let mut s = t!(TcpStream::connect(&addr));
let mut buf = [0, 0];
- assert_eq!(s.read(&mut buf), Ok(1));
+ assert_eq!(s.read(&mut buf).unwrap(), 1);
assert_eq!(buf[0], 1);
t!(s.write(&[2]));
});
});
tx1.send(()).unwrap();
let mut buf = [0, 0];
- assert_eq!(s1.read(&mut buf), Ok(1));
+ assert_eq!(s1.read(&mut buf).unwrap(), 1);
rx2.recv().unwrap();
})
}
let _t = thread::spawn(move|| {
let mut c = t!(a.accept()).0;
let mut b = [0];
- assert_eq!(c.read(&mut b), Ok(0));
+ assert_eq!(c.read(&mut b).unwrap(), 0);
t!(c.write(&[1]));
});
t!(s.shutdown(Shutdown::Write));
assert!(s.write(&[0]).is_err());
t!(s.shutdown(Shutdown::Read));
- assert_eq!(s.read(&mut b), Ok(0));
+ assert_eq!(s.read(&mut b).unwrap(), 0);
// closing should affect previous handles
assert!(s2.write(&[0]).is_err());
- assert_eq!(s2.read(&mut b), Ok(0));
+ assert_eq!(s2.read(&mut b).unwrap(), 0);
// closing should affect new handles
let mut s3 = t!(s.try_clone());
assert!(s3.write(&[0]).is_err());
- assert_eq!(s3.read(&mut b), Ok(0));
+ assert_eq!(s3.read(&mut b).unwrap(), 0);
// make sure these don't die
let _ = s2.shutdown(Shutdown::Read);
use io::{self, Error, ErrorKind};
use net::{ToSocketAddrs, SocketAddr, IpAddr};
use sys_common::net2 as net_imp;
-use sys_common::AsInner;
+use sys_common::{AsInner, FromInner};
/// A User Datagram Protocol socket.
///
match try!(addr.to_socket_addrs()).next() {
Some(addr) => self.0.send_to(buf, &addr),
None => Err(Error::new(ErrorKind::InvalidInput,
- "no addresses to send data to", None)),
+ "no addresses to send data to")),
}
}
- /// Returns the socket address that this socket was created from.
- #[unstable(feature = "net")]
- #[deprecated(since = "1.0.0", reason = "renamed to local_addr")]
- pub fn socket_addr(&self) -> io::Result<SocketAddr> {
- self.0.socket_addr()
- }
-
/// Returns the socket address that this socket was created from.
#[stable(feature = "rust1", since = "1.0.0")]
pub fn local_addr(&self) -> io::Result<SocketAddr> {
fn as_inner(&self) -> &net_imp::UdpSocket { &self.0 }
}
+impl FromInner<net_imp::UdpSocket> for UdpSocket {
+ fn from_inner(inner: net_imp::UdpSocket) -> UdpSocket { UdpSocket(inner) }
+}
+
#[cfg(test)]
mod tests {
use prelude::v1::*;
fn socket_name_ip4() {
each_ip(&mut |addr, _| {
let server = t!(UdpSocket::bind(&addr));
- assert_eq!(addr, t!(server.socket_addr()));
+ assert_eq!(addr, t!(server.local_addr()));
})
}
let _t = thread::spawn(move|| {
let mut buf = [0, 0];
- assert_eq!(sock2.recv_from(&mut buf), Ok((1, addr1)));
+ assert_eq!(sock2.recv_from(&mut buf).unwrap(), (1, addr1));
assert_eq!(buf[0], 1);
t!(sock2.send_to(&[2], &addr1));
});
});
tx1.send(()).unwrap();
let mut buf = [0, 0];
- assert_eq!(sock1.recv_from(&mut buf), Ok((1, addr2)));
+ assert_eq!(sock1.recv_from(&mut buf).unwrap(), (1, addr2));
rx2.recv().unwrap();
})
}
use vec::Vec;
/// A flag that specifies whether to use exponential (scientific) notation.
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub enum ExponentFormat {
/// Do not use exponential notation.
ExpNone,
/// The number of digits used for emitting the fractional part of a number, if
/// any.
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub enum SignificantDigits {
/// All calculable digits will be printed.
///
}
/// How to emit the sign of a number.
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub enum SignFormat {
/// No sign will be printed. The exponent sign will also be emitted.
SignNone,
let mut w = BufferedWriter::with_capacity(3, Vec::new());
w.write_all(&[0, 1]).unwrap();
let a: &[_] = &[];
- assert_eq!(a, &w.get_ref()[..]);
+ assert_eq!(&w.get_ref()[..], a);
let w = w.into_inner();
let a: &[_] = &[0, 1];
assert_eq!(a, &w[..]);
({
use super::u64_from_be_bytes;
- let data = (0..$stride*100+$start_index).collect::<Vec<_>>();
+ let len = ($stride as u8).wrapping_mul(100).wrapping_add($start_index);
+ let data = (0..len).collect::<Vec<_>>();
let mut sum = 0;
$b.iter(|| {
let mut i = $start_index;
pub fn tmpdir() -> TempDir {
use os;
use rand;
- let ret = os::tmpdir().join(format!("rust-{}", rand::random::<u32>()));
+ let temp = Path::new(::env::temp_dir().to_str().unwrap());
+ let ret = temp.join(format!("rust-{}", rand::random::<u32>()));
check!(old_io::fs::mkdir(&ret, old_io::USER_RWX));
TempDir(ret)
}
let mut read_stream = File::open_mode(filename, Open, Read);
let mut read_buf = [0; 1028];
let read_str = match check!(read_stream.read(&mut read_buf)) {
- -1|0 => panic!("shouldn't happen"),
+ 0 => panic!("shouldn't happen"),
n => str::from_utf8(&read_buf[..n]).unwrap().to_string()
};
assert_eq!(read_str, message);
check!(File::create(&tmpdir.join("test")).write(&bytes));
let actual = check!(File::open(&tmpdir.join("test")).read_to_end());
- assert!(actual == bytes.as_slice());
+ assert!(actual == &bytes[..]);
}
#[test]
mod test {
extern crate test as test_crate;
use old_io::{SeekSet, SeekCur, SeekEnd, Reader, Writer, Seek, Buffer};
- use prelude::v1::{Ok, Err, Vec, AsSlice};
+ use prelude::v1::{Ok, Err, Vec};
use prelude::v1::Iterator;
use old_io;
use iter::repeat;
wr.write(&[5; 10]).unwrap();
}
}
- assert_eq!(buf.as_slice(), [5; 100].as_slice());
+ assert_eq!(&buf[..], &[5; 100][..]);
});
}
use ops::FnOnce;
use option::Option;
use option::Option::{Some, None};
-use os;
+use sys::os;
use boxed::Box;
use result::Result;
use result::Result::{Ok, Err};
}
/// A list specifying general categories of I/O error.
-#[derive(Copy, PartialEq, Eq, Clone, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum IoErrorKind {
/// Any I/O error not part of this list.
OtherIoError,
///
/// The number of bytes returned is system-dependent.
fn read_le_uint(&mut self) -> IoResult<usize> {
- self.read_le_uint_n(usize::BYTES as usize).map(|i| i as usize)
+ self.read_le_uint_n(usize::BYTES).map(|i| i as usize)
}
/// Reads a little-endian integer.
///
/// The number of bytes returned is system-dependent.
fn read_le_int(&mut self) -> IoResult<isize> {
- self.read_le_int_n(isize::BYTES as usize).map(|i| i as isize)
+ self.read_le_int_n(isize::BYTES).map(|i| i as isize)
}
/// Reads a big-endian unsigned integer.
///
/// The number of bytes returned is system-dependent.
fn read_be_uint(&mut self) -> IoResult<usize> {
- self.read_be_uint_n(usize::BYTES as usize).map(|i| i as usize)
+ self.read_be_uint_n(usize::BYTES).map(|i| i as usize)
}
/// Reads a big-endian integer.
///
/// The number of bytes returned is system-dependent.
fn read_be_int(&mut self) -> IoResult<isize> {
- self.read_be_int_n(isize::BYTES as usize).map(|i| i as isize)
+ self.read_be_int_n(isize::BYTES).map(|i| i as isize)
}
/// Reads a big-endian `u64`.
/// Write a little-endian usize (number of bytes depends on system).
#[inline]
fn write_le_uint(&mut self, n: usize) -> IoResult<()> {
- extensions::u64_to_le_bytes(n as u64, usize::BYTES as usize, |v| self.write_all(v))
+ extensions::u64_to_le_bytes(n as u64, usize::BYTES, |v| self.write_all(v))
}
/// Write a little-endian isize (number of bytes depends on system).
#[inline]
fn write_le_int(&mut self, n: isize) -> IoResult<()> {
- extensions::u64_to_le_bytes(n as u64, isize::BYTES as usize, |v| self.write_all(v))
+ extensions::u64_to_le_bytes(n as u64, isize::BYTES, |v| self.write_all(v))
}
/// Write a big-endian usize (number of bytes depends on system).
#[inline]
fn write_be_uint(&mut self, n: usize) -> IoResult<()> {
- extensions::u64_to_be_bytes(n as u64, usize::BYTES as usize, |v| self.write_all(v))
+ extensions::u64_to_be_bytes(n as u64, usize::BYTES, |v| self.write_all(v))
}
/// Write a big-endian isize (number of bytes depends on system).
#[inline]
fn write_be_int(&mut self, n: isize) -> IoResult<()> {
- extensions::u64_to_be_bytes(n as u64, isize::BYTES as usize, |v| self.write_all(v))
+ extensions::u64_to_be_bytes(n as u64, isize::BYTES, |v| self.write_all(v))
}
/// Write a big-endian u64 (8 bytes).
/// When seeking, the resulting cursor is offset from a base by the offset given
/// to the `seek` function. The base used is specified by this enumeration.
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub enum SeekStyle {
/// Seek from the beginning of the stream
SeekSet,
///
/// println!("byte size: {}", info.size);
/// ```
-#[derive(Copy, Hash)]
+#[derive(Copy, Clone, Hash)]
pub struct FileStat {
/// The size of the file, in bytes
pub size: u64,
/// structure. This information is not necessarily platform independent, and may
/// have different meanings or no meaning at all on some platforms.
#[unstable(feature = "io")]
-#[derive(Copy, Hash)]
+#[derive(Copy, Clone, Hash)]
pub struct UnstableFileStat {
/// The ID of the device containing the file.
pub device: u64,
use vec::Vec;
/// Hints to the types of sockets that are desired when looking up hosts
-#[derive(Copy, Debug)]
+#[derive(Copy, Clone, Debug)]
pub enum SocketType {
Stream, Datagram, Raw
}
/// to manipulate how a query is performed.
///
/// The meaning of each of these flags can be found with `man -s 3 getaddrinfo`
-#[derive(Copy, Debug)]
+#[derive(Copy, Clone, Debug)]
pub enum Flag {
AddrConfig,
All,
/// A transport protocol associated with either a hint or a return value of
/// `lookup`
-#[derive(Copy, Debug)]
+#[derive(Copy, Clone, Debug)]
pub enum Protocol {
TCP, UDP
}
///
/// For details on these fields, see their corresponding definitions via
/// `man -s 3 getaddrinfo`
-#[derive(Copy, Debug)]
+#[derive(Copy, Clone, Debug)]
pub struct Hint {
pub family: usize,
pub socktype: Option<SocketType>,
pub flags: usize,
}
-#[derive(Copy, Debug)]
+#[derive(Copy, Clone, Debug)]
pub struct Info {
pub address: SocketAddr,
pub family: usize,
assert!(found_local);
}
- #[ignore]
#[test]
fn issue_10663() {
// Something should happen here, but this certainly shouldn't cause
// everything to die. The actual outcome we don't care too much about.
- get_host_addresses("example.com").unwrap();
+ let _ = get_host_addresses("example.com");
}
}
/// Some examples:
///
/// ```rust,no_run
-/// # #![feature(old_io, core)]
+/// # #![feature(old_io, core, convert)]
/// # #![allow(unused_must_use)]
///
/// use std::old_io::{TcpStream, TcpListener};
/// let tcp_l = TcpListener::bind("localhost:12345");
///
/// let mut udp_s = UdpSocket::bind(("127.0.0.1", 23451)).unwrap();
-/// udp_s.send_to([7, 7, 7].as_slice(), (Ipv4Addr(127, 0, 0, 1), 23451));
+/// udp_s.send_to([7, 7, 7].as_ref(), (Ipv4Addr(127, 0, 0, 1), 23451));
/// }
/// ```
pub trait ToSocketAddr {
use os;
use old_io::pipe::PipeStream;
- let os::Pipe { reader, writer } = unsafe { os::pipe().unwrap() };
- let out = PipeStream::open(writer);
- let mut input = PipeStream::open(reader);
+ let (reader, writer) = unsafe { ::sys::os::pipe().unwrap() };
+ let out = PipeStream::open(writer.unwrap());
+ let mut input = PipeStream::open(reader.unwrap());
let (tx, rx) = channel();
let _t = thread::spawn(move|| {
let mut out = out;
None => {
// if the env is currently just inheriting from the parent's,
// materialize the parent's env into a hashtable.
- self.env = Some(os::env_as_bytes().into_iter().map(|(k, v)| {
+ self.env = Some(::env::vars().map(|(k, v)| {
(EnvKey(CString::new(k).unwrap()),
CString::new(v).unwrap())
}).collect());
/// # Examples
///
/// ```
- /// # #![feature(old_io, core)]
+ /// # #![feature(old_io, core, convert)]
/// use std::old_io::Command;
///
/// let output = match Command::new("cat").arg("foot.txt").output() {
/// };
///
/// println!("status: {}", output.status);
- /// println!("stdout: {}", String::from_utf8_lossy(output.output.as_slice()));
- /// println!("stderr: {}", String::from_utf8_lossy(output.error.as_slice()));
+ /// println!("stdout: {}", String::from_utf8_lossy(output.output.as_ref()));
+ /// println!("stderr: {}", String::from_utf8_lossy(output.error.as_ref()));
/// ```
pub fn output(&self) -> IoResult<ProcessOutput> {
self.spawn().and_then(|p| p.wait_with_output())
#[cfg(test)]
mod tests {
+ use prelude::v1::*;
use old_io::{Truncate, Write, TimedOut, timer, process, FileNotFound};
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::*;
let prog = pwd_cmd().spawn().unwrap();
let output = String::from_utf8(prog.wait_with_output().unwrap().output).unwrap();
- let parent_dir = os::getcwd().unwrap();
+ let parent_dir = Path::new(::env::current_dir().unwrap().to_str().unwrap());
let child_dir = Path::new(output.trim());
let parent_stat = parent_dir.stat().unwrap();
use os;
// test changing to the parent of os::getcwd() because we know
// the path exists (and os::getcwd() is not expected to be root)
- let parent_dir = os::getcwd().unwrap().dir_path();
+ let parent_dir = Path::new(::env::current_dir().unwrap().to_str().unwrap());
let prog = pwd_cmd().cwd(&parent_dir).spawn().unwrap();
let output = String::from_utf8(prog.wait_with_output().unwrap().output).unwrap();
let prog = env_cmd().spawn().unwrap();
let output = String::from_utf8(prog.wait_with_output().unwrap().output).unwrap();
- let r = os::env();
- for &(ref k, ref v) in &r {
+ let r = ::env::vars();
+ for (k, v) in r {
// don't check windows magical empty-named variables
assert!(k.is_empty() ||
- output.contains(&format!("{}={}", *k, *v)),
+ output.contains(&format!("{}={}", k, v)),
"output doesn't contain `{}={}`\n{}",
k, v, output);
}
let mut prog = env_cmd().spawn().unwrap();
let output = String::from_utf8(prog.wait_with_output().unwrap().output).unwrap();
- let r = os::env();
- for &(ref k, ref v) in &r {
+ let r = ::env::vars();
+ for (k, v) in r {
// don't check android RANDOM variables
- if *k != "RANDOM".to_string() {
- assert!(output.contains(&format!("{}={}",
- *k,
- *v)) ||
- output.contains(&format!("{}=\'{}\'",
- *k,
- *v)));
+ if k != "RANDOM".to_string() {
+ assert!(output.contains(&format!("{}={}", k, v)) ||
+ output.contains(&format!("{}=\'{}\'", k, v)));
}
}
}
// PATH to our sub-process.
let path_val: String;
let mut new_env = vec![("RUN_TEST_NEW_ENV", "123")];
- match os::getenv("PATH") {
- None => {}
- Some(val) => {
+ match ::env::var("PATH") {
+ Err(..) => {}
+ Ok(val) => {
path_val = val;
new_env.push(("PATH", &path_val))
}
#[allow(deprecated)]
pub fn new_in(tmpdir: &Path, prefix: &str) -> IoResult<TempDir> {
if !tmpdir.is_absolute() {
- let cur_dir = try!(::os::getcwd());
+ let cur_dir = ::env::current_dir().unwrap();
+ let cur_dir = Path::new(cur_dir.to_str().unwrap());
return TempDir::new_in(&cur_dir.join(tmpdir), prefix);
}
/// If no directory can be created, `Err` is returned.
#[allow(deprecated)]
pub fn new(prefix: &str) -> IoResult<TempDir> {
- TempDir::new_in(&::os::tmpdir(), prefix)
+ let tmp = Path::new(::env::temp_dir().to_str().unwrap());
+ TempDir::new_in(&tmp, prefix)
}
/// Unwrap the wrapped `std::path::Path` from the `TempDir` wrapper.
pub fn next_test_unix() -> Path {
let string = next_test_unix_socket();
if cfg!(unix) {
- ::os::tmpdir().join(string)
+ Path::new(::env::temp_dir().to_str().unwrap()).join(string)
} else {
Path::new(format!("{}{}", r"\\.\pipe\", string))
}
// sysctl value, and bump the soft resource limit for maxfiles up to the sysctl value.
use ptr::null_mut;
use mem::size_of_val;
- use os::last_os_error;
+ use io;
// Fetch the kern.maxfilesperproc value
let mut mib: [libc::c_int; 2] = [CTL_KERN, KERN_MAXFILESPERPROC];
let mut size: libc::size_t = size_of_val(&maxfiles) as libc::size_t;
if sysctl(&mut mib[0], 2, &mut maxfiles as *mut libc::c_int as *mut libc::c_void, &mut size,
null_mut(), 0) != 0 {
- let err = last_os_error();
+ let err = io::Error::last_os_error();
panic!("raise_fd_limit: error calling sysctl: {}", err);
}
// Fetch the current resource limits
let mut rlim = rlimit{rlim_cur: 0, rlim_max: 0};
if getrlimit(RLIMIT_NOFILE, &mut rlim) != 0 {
- let err = last_os_error();
+ let err = io::Error::last_os_error();
panic!("raise_fd_limit: error calling getrlimit: {}", err);
}
// Set our newly-increased resource limit
if setrlimit(RLIMIT_NOFILE, &rlim) != 0 {
- let err = last_os_error();
+ let err = io::Error::last_os_error();
panic!("raise_fd_limit: error calling setrlimit: {}", err);
}
}
}
/// A `Writer` which ignores bytes written to it, like /dev/null.
-#[derive(Copy, Debug)]
+#[derive(Copy, Clone, Debug)]
#[deprecated(since = "1.0.0", reason = "use std::io::sink() instead")]
#[unstable(feature = "old_io")]
pub struct NullWriter;
}
/// A `Reader` which returns an infinite stream of 0 bytes, like /dev/zero.
-#[derive(Copy, Debug)]
+#[derive(Copy, Clone, Debug)]
#[deprecated(since = "1.0.0", reason = "use std::io::repeat(0) instead")]
#[unstable(feature = "old_io")]
pub struct ZeroReader;
}
/// A `Reader` which is always at EOF, like /dev/null.
-#[derive(Copy, Debug)]
+#[derive(Copy, Clone, Debug)]
#[deprecated(since = "1.0.0", reason = "use std::io::empty() instead")]
#[unstable(feature = "old_io")]
pub struct NullReader;
let mut r = MemReader::new(vec!(0, 1, 2));
{
let mut r = LimitReader::new(r.by_ref(), 4);
- assert_eq!([0, 1, 2], r.read_to_end().unwrap());
+ assert_eq!(r.read_to_end().unwrap(), [0, 1, 2]);
}
}
let mut r = MemReader::new(vec!(0, 1, 2));
{
let mut r = LimitReader::new(r.by_ref(), 2);
- assert_eq!([0, 1], r.read_to_end().unwrap());
+ assert_eq!(r.read_to_end().unwrap(), [0, 1]);
}
- assert_eq!([2], r.read_to_end().unwrap());
+ assert_eq!(r.read_to_end().unwrap(), [2]);
}
#[test]
assert_eq!(3, r.limit());
assert_eq!(0, r.read_byte().unwrap());
assert_eq!(2, r.limit());
- assert_eq!([1, 2], r.read_to_end().unwrap());
+ assert_eq!(r.read_to_end().unwrap(), [1, 2]);
assert_eq!(0, r.limit());
}
let mut r = MemReader::new(vec![0, 1, 2, 3, 4, 5]);
let mut r = LimitReader::new(r.by_ref(), 1);
r.consume(2);
- assert_eq!([], r.read_to_end().unwrap());
+ assert_eq!(r.read_to_end().unwrap(), []);
}
#[test]
let mut s = ZeroReader;
let mut buf = vec![1, 2, 3];
assert_eq!(s.read(&mut buf), Ok(3));
- assert_eq!([0, 0, 0], buf);
+ assert_eq!(buf, [0, 0, 0]);
}
#[test]
let rs = vec!(MemReader::new(vec!(0, 1)), MemReader::new(vec!()),
MemReader::new(vec!(2, 3)));
let mut r = ChainedReader::new(rs.into_iter());
- assert_eq!([0, 1, 2, 3], r.read_to_end().unwrap());
+ assert_eq!(r.read_to_end().unwrap(), [0, 1, 2, 3]);
}
#[test]
fn test_tee_reader() {
let mut r = TeeReader::new(MemReader::new(vec!(0, 1, 2)),
Vec::new());
- assert_eq!([0, 1, 2], r.read_to_end().unwrap());
+ assert_eq!(r.read_to_end().unwrap(), [0, 1, 2]);
let (_, w) = r.into_inner();
- assert_eq!([0, 1, 2], w);
+ assert_eq!(w, [0, 1, 2]);
}
#[test]
let mut r = MemReader::new(vec!(0, 1, 2, 3, 4));
let mut w = Vec::new();
copy(&mut r, &mut w).unwrap();
- assert_eq!([0, 1, 2, 3, 4], w);
+ assert_eq!(w, [0, 1, 2, 3, 4]);
}
#[test]
use core::marker::Sized;
use ffi::CString;
use clone::Clone;
+use borrow::Cow;
use fmt;
use iter::Iterator;
use option::Option;
use option::Option::{None, Some};
use str;
-use string::{String, CowString};
+use string::String;
use vec::Vec;
/// Typedef for POSIX file paths.
/// If the path is not UTF-8, invalid sequences will be replaced with the
/// Unicode replacement char. This involves allocation.
#[inline]
- pub fn as_cow(&self) -> CowString<'a> {
+ pub fn as_cow(&self) -> Cow<'a, str> {
String::from_utf8_lossy(if self.filename {
match self.path.filename() {
None => {
use marker::Sized;
use option::Option::{self, Some, None};
use result::Result::{self, Ok, Err};
-use slice::{AsSlice, Split, SliceConcatExt};
+use slice::{Split, SliceConcatExt};
use str::{self, FromStr};
use vec::Vec;
unsafe fn set_filename_unchecked<T: BytesContainer>(&mut self, filename: T) {
let filename = filename.container_as_bytes();
match self.sepidx {
- None if b".." == self.repr => {
+ None if self.repr == b".." => {
let mut v = Vec::with_capacity(3 + filename.len());
v.push_all(dot_dot_static);
v.push(SEP_BYTE);
fn dirname<'a>(&'a self) -> &'a [u8] {
match self.sepidx {
- None if b".." == self.repr => &self.repr,
+ None if self.repr == b".." => &self.repr,
None => dot_static,
Some(0) => &self.repr[..1],
Some(idx) if &self.repr[idx+1..] == b".." => &self.repr,
fn filename<'a>(&'a self) -> Option<&'a [u8]> {
match self.sepidx {
- None if b"." == self.repr ||
- b".." == self.repr => None,
+ None if self.repr == b"." || self.repr == b".." => None,
None => Some(&self.repr),
Some(idx) if &self.repr[idx+1..] == b".." => None,
Some(0) if self.repr[1..].is_empty() => None,
fn pop(&mut self) -> bool {
match self.sepidx {
- None if b"." == self.repr => false,
+ None if self.repr == b"." => false,
None => {
self.repr = vec![b'.'];
self.sepidx = None;
true
}
- Some(0) if b"/" == self.repr => false,
+ Some(0) if self.repr == b"/" => false,
Some(idx) => {
if idx == 0 {
self.repr.truncate(idx+1);
} else {
let mut ita = self.components();
let mut itb = other.components();
- if b"." == self.repr {
+ if self.repr == b"." {
return match itb.next() {
None => true,
Some(b) => b != b".."
/// Returns a normalized byte vector representation of a path, by removing all empty
/// components, and unnecessary . and .. components.
- fn normalize<V: ?Sized + AsSlice<u8>>(v: &V) -> Vec<u8> {
+ fn normalize(v: &[u8]) -> Vec<u8> {
// borrowck is being very picky
let val = {
- let is_abs = !v.as_slice().is_empty() && v.as_slice()[0] == SEP_BYTE;
- let v_ = if is_abs { &v.as_slice()[1..] } else { v.as_slice() };
+ let is_abs = !v.is_empty() && v[0] == SEP_BYTE;
+ let v_ = if is_abs { &v[1..] } else { v };
let comps = normalize_helper(v_, is_abs);
match comps {
None => None,
}
};
match val {
- None => v.as_slice().to_vec(),
+ None => v.to_vec(),
Some(val) => val
}
}
use clone::Clone;
use option::Option::{self, Some, None};
use old_path::GenericPath;
- use slice::AsSlice;
- use str::{self, Str};
+ use str;
use string::ToString;
use vec::Vec;
use iter::Iterator;
use iter::Iterator;
use option::Option::{self, Some, None};
use old_path::GenericPath;
- use slice::AsSlice;
- use str::Str;
use string::ToString;
use vec::Vec;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-//! Higher-level interfaces to libc::* functions and operating system services.
-//!
-//! In general these take and return rust types, use rust idioms (enums,
-//! closures, vectors) rather than C idioms, and do more extensive safety
-//! checks.
-//!
-//! This module is not meant to only contain 1:1 mappings to libc entries; any
-//! os-interface code that is reasonably useful and broadly applicable can go
-//! here. Including utility routines that merely build on other os code.
-//!
-//! We assume the general case is that users do not care, and do not want to be
-//! made to care, which operating system they are on. While they may want to
-//! special case various special cases -- and so we will not _hide_ the facts of
-//! which OS the user is on -- they should be given the opportunity to write
-//! OS-ignorant code by default.
+//! OS-specific functionality
-#![unstable(feature = "os")]
-#![deprecated(since = "1.0.0", reason = "replaced with std::env APIs")]
-
-#![allow(missing_docs)]
-#![allow(non_snake_case)]
-#![allow(unused_imports)]
-#![allow(deprecated)]
-
-use self::MemoryMapKind::*;
-use self::MapOption::*;
-use self::MapError::*;
-
-use boxed::Box;
-use clone::Clone;
-use convert::From;
-use env;
-use error::{FromError, Error};
-use ffi::{OsString, OsStr};
-use fmt;
-use iter::Iterator;
-use libc::{c_void, c_int, c_char};
-use libc;
-use marker::{Copy, Send};
-use old_io::{IoResult, IoError};
-use ops::{Drop, FnOnce};
-use option::Option::{Some, None};
-use option::Option;
-use old_path::{Path, GenericPath, BytesContainer};
-use path::{self, PathBuf};
-use ptr;
-use result::Result::{Err, Ok};
-use result::Result;
-use slice::AsSlice;
-use str::Str;
-use str;
-use string::{String, ToString};
-use sync::atomic::{AtomicIsize, ATOMIC_ISIZE_INIT, Ordering};
-use sys::os as os_imp;
-use sys;
-use vec::Vec;
-
-#[cfg(unix)] use ffi::{self, CString};
+#![stable(feature = "os", since = "1.0.0")]
#[cfg(unix)] pub use sys::ext as unix;
#[cfg(windows)] pub use sys::ext as windows;
-
-fn err2old(new: ::io::Error) -> IoError {
- IoError {
- kind: ::old_io::OtherIoError,
- desc: "os error",
- detail: Some(new.to_string()),
- }
-}
-
-#[cfg(windows)]
-fn path2new(path: &Path) -> PathBuf {
- PathBuf::from(path.as_str().unwrap())
-}
-#[cfg(unix)]
-fn path2new(path: &Path) -> PathBuf {
- use os::unix::prelude::*;
- PathBuf::from(<OsStr as OsStrExt>::from_bytes(path.as_vec()))
-}
-
-#[cfg(unix)]
-fn path2old(path: &path::Path) -> Path {
- use os::unix::prelude::*;
- use ffi::AsOsStr;
- Path::new(path.as_os_str().as_bytes())
-}
-#[cfg(windows)]
-fn path2old(path: &path::Path) -> Path {
- Path::new(path.to_str().unwrap())
-}
-
-/// Get the number of cores available
-pub fn num_cpus() -> usize {
- unsafe {
- return rust_get_num_cpus() as usize;
- }
-
- extern {
- fn rust_get_num_cpus() -> libc::uintptr_t;
- }
-}
-
-pub const TMPBUF_SZ : usize = 1000;
-
-/// Returns the current working directory as a `Path`.
-///
-/// # Errors
-///
-/// Returns an `Err` if the current working directory value is invalid.
-/// Possible cases:
-///
-/// * Current directory does not exist.
-/// * There are insufficient permissions to access the current directory.
-/// * The internal buffer is not large enough to hold the path.
-///
-/// # Examples
-///
-/// ```
-/// # #![feature(os, old_path)]
-/// 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();
-/// println!("The current directory is {:?}", current_working_directory.display());
-/// ```
-#[unstable(feature = "os")]
-pub fn getcwd() -> IoResult<Path> {
- env::current_dir().map_err(err2old).map(|s| path2old(&s))
-}
-
-/// Returns a vector of (variable, value) pairs, for all the environment
-/// variables of the current process.
-///
-/// Invalid UTF-8 bytes are replaced with \uFFFD. See `String::from_utf8_lossy()`
-/// for details.
-///
-/// # Examples
-///
-/// ```
-/// # #![feature(os)]
-/// use std::os;
-///
-/// // We will iterate through the references to the element returned by os::env();
-/// for &(ref key, ref value) in os::env().iter() {
-/// println!("'{}': '{}'", key, value );
-/// }
-/// ```
-#[deprecated(since = "1.0.0", reason = "use env::vars instead")]
-#[unstable(feature = "os")]
-pub fn env() -> Vec<(String,String)> {
- env::vars_os().map(|(k, v)| {
- (k.to_string_lossy().into_owned(), v.to_string_lossy().into_owned())
- }).collect()
-}
-
-/// Returns a vector of (variable, value) byte-vector pairs for all the
-/// environment variables of the current process.
-#[deprecated(since = "1.0.0", reason = "use env::vars_os instead")]
-#[unstable(feature = "os")]
-pub fn env_as_bytes() -> Vec<(Vec<u8>, Vec<u8>)> {
- env::vars_os().map(|(k, v)| (byteify(k), byteify(v))).collect()
-}
-
-/// Fetches the environment variable `n` from the current process, returning
-/// None if the variable isn't set.
-///
-/// Any invalid UTF-8 bytes in the value are replaced by \uFFFD. See
-/// `String::from_utf8_lossy()` for details.
-///
-/// # Panics
-///
-/// Panics if `n` has any interior NULs.
-///
-/// # Examples
-///
-/// ```
-/// # #![feature(os)]
-/// use std::os;
-///
-/// let key = "HOME";
-/// match os::getenv(key) {
-/// Some(val) => println!("{}: {}", key, val),
-/// None => println!("{} is not defined in the environment.", key)
-/// }
-/// ```
-#[deprecated(since = "1.0.0", reason = "use env::var instead")]
-#[unstable(feature = "os")]
-pub fn getenv(n: &str) -> Option<String> {
- env::var(n).ok()
-}
-
-/// Fetches the environment variable `n` byte vector from the current process,
-/// returning None if the variable isn't set.
-///
-/// # Panics
-///
-/// Panics if `n` has any interior NULs.
-#[deprecated(since = "1.0.0", reason = "use env::var_os instead")]
-#[unstable(feature = "os")]
-pub fn getenv_as_bytes(n: &str) -> Option<Vec<u8>> {
- env::var_os(n).map(byteify)
-}
-
-#[cfg(unix)]
-fn byteify(s: OsString) -> Vec<u8> {
- use os::unix::prelude::*;
- s.into_vec()
-}
-#[cfg(windows)]
-fn byteify(s: OsString) -> Vec<u8> {
- s.to_string_lossy().as_bytes().to_vec()
-}
-
-/// Sets the environment variable `n` to the value `v` for the currently running
-/// process.
-///
-/// # Examples
-///
-/// ```
-/// # #![feature(os)]
-/// use std::os;
-///
-/// let key = "KEY";
-/// os::setenv(key, "VALUE");
-/// match os::getenv(key) {
-/// Some(ref val) => println!("{}: {}", key, val),
-/// None => println!("{} is not defined in the environment.", key)
-/// }
-/// ```
-#[deprecated(since = "1.0.0", reason = "renamed to env::set_var")]
-#[unstable(feature = "os")]
-pub fn setenv<T: BytesContainer>(n: &str, v: T) {
- #[cfg(unix)]
- fn _setenv(n: &str, v: &[u8]) {
- use os::unix::prelude::*;
- let v: OsString = OsStringExt::from_vec(v.to_vec());
- env::set_var(n, &v)
- }
-
- #[cfg(windows)]
- fn _setenv(n: &str, v: &[u8]) {
- let v = str::from_utf8(v).unwrap();
- env::set_var(n, v)
- }
-
- _setenv(n, v.container_as_bytes())
-}
-
-/// Remove a variable from the environment entirely.
-#[deprecated(since = "1.0.0", reason = "renamed to env::remove_var")]
-#[unstable(feature = "os")]
-pub fn unsetenv(n: &str) {
- env::remove_var(n)
-}
-
-/// Parses input according to platform conventions for the `PATH`
-/// environment variable.
-///
-/// # Examples
-///
-/// ```
-/// # #![feature(old_path, os)]
-/// use std::os;
-/// use std::old_path::{Path, GenericPath};
-///
-/// let key = "PATH";
-/// match os::getenv_as_bytes(key) {
-/// Some(paths) => {
-/// for path in os::split_paths(paths).iter() {
-/// println!("'{}'", path.display());
-/// }
-/// }
-/// None => println!("{} is not defined in the environment.", key)
-/// }
-/// ```
-#[unstable(feature = "os")]
-pub fn split_paths<T: BytesContainer>(unparsed: T) -> Vec<Path> {
- let b = unparsed.container_as_bytes();
- let s = str::from_utf8(b).unwrap();
- env::split_paths(s).map(|s| path2old(&s)).collect()
-}
-
-/// Joins a collection of `Path`s appropriately for the `PATH`
-/// environment variable.
-///
-/// Returns a `Vec<u8>` on success, since `Path`s are not utf-8
-/// encoded on all platforms.
-///
-/// Returns an `Err` (containing an error message) if one of the input
-/// `Path`s contains an invalid character for constructing the `PATH`
-/// variable (a double quote on Windows or a colon on Unix).
-///
-/// # Examples
-///
-/// ```
-/// # #![feature(os, old_path, core)]
-/// use std::os;
-/// use std::old_path::Path;
-///
-/// let key = "PATH";
-/// let mut paths = os::getenv_as_bytes(key).map_or(Vec::new(), os::split_paths);
-/// paths.push(Path::new("/home/xyz/bin"));
-/// os::setenv(key, os::join_paths(paths.as_slice()).unwrap());
-/// ```
-#[unstable(feature = "os")]
-pub fn join_paths<T: BytesContainer>(paths: &[T]) -> Result<Vec<u8>, &'static str> {
- env::join_paths(paths.iter().map(|s| {
- str::from_utf8(s.container_as_bytes()).unwrap()
- })).map(|s| {
- s.to_string_lossy().into_owned().into_bytes()
- }).map_err(|_| "failed to join paths")
-}
-
-/// A low-level OS in-memory pipe.
-#[derive(Copy)]
-pub struct Pipe {
- /// A file descriptor representing the reading end of the pipe. Data written
- /// on the `out` file descriptor can be read from this file descriptor.
- pub reader: c_int,
- /// A file descriptor representing the write end of the pipe. Data written
- /// to this file descriptor can be read from the `input` file descriptor.
- pub writer: c_int,
-}
-
-/// Creates a new low-level OS in-memory pipe.
-///
-/// This function can fail to succeed if there are no more resources available
-/// to allocate a pipe.
-///
-/// This function is also unsafe as there is no destructor associated with the
-/// `Pipe` structure will return. If it is not arranged for the returned file
-/// descriptors to be closed, the file descriptors will leak. For safe handling
-/// of this scenario, use `std::old_io::PipeStream` instead.
-pub unsafe fn pipe() -> IoResult<Pipe> {
- let (reader, writer) = try!(sys::os::pipe());
- Ok(Pipe {
- reader: reader.unwrap(),
- writer: writer.unwrap(),
- })
-}
-
-/// Returns the proper dll filename for the given basename of a file
-/// as a String.
-#[cfg(not(target_os="ios"))]
-#[deprecated(since = "1.0.0", reason = "this function will be removed, use the constants directly")]
-#[unstable(feature = "os")]
-#[allow(deprecated)]
-pub fn dll_filename(base: &str) -> String {
- format!("{}{}{}", consts::DLL_PREFIX, base, consts::DLL_SUFFIX)
-}
-
-/// Optionally returns the filesystem path to the current executable which is
-/// running but with the executable name.
-///
-/// # Examples
-///
-/// ```
-/// # #![feature(os, old_path)]
-/// 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()),
-/// None => println!("Unable to get the path of this executable!")
-/// };
-/// ```
-#[unstable(feature = "os")]
-pub fn self_exe_name() -> Option<Path> {
- env::current_exe().ok().map(|p| path2old(&p))
-}
-
-/// Optionally returns the filesystem path to the current executable which is
-/// running.
-///
-/// Like self_exe_name() but without the binary's name.
-///
-/// # Examples
-///
-/// ```
-/// # #![feature(os, old_path)]
-/// 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()),
-/// None => println!("Impossible to fetch the path of this executable.")
-/// };
-/// ```
-#[unstable(feature = "os")]
-pub fn self_exe_path() -> Option<Path> {
- env::current_exe().ok().map(|p| { let mut p = path2old(&p); p.pop(); p })
-}
-
-/// Optionally returns the path to the current user's home directory if known.
-///
-/// # Unix
-///
-/// Returns the value of the 'HOME' environment variable if it is set
-/// and not equal to the empty string.
-///
-/// # Windows
-///
-/// Returns the value of the 'HOME' environment variable if it is
-/// set and not equal to the empty string. Otherwise, returns the value of the
-/// 'USERPROFILE' environment variable if it is set and not equal to the empty
-/// string.
-///
-/// # Examples
-///
-/// ```
-/// # #![feature(os, old_path)]
-/// use std::os;
-/// use std::old_path::{Path, GenericPath};
-///
-/// match os::homedir() {
-/// Some(ref p) => println!("{}", p.display()),
-/// None => println!("Impossible to get your home dir!")
-/// }
-/// ```
-#[unstable(feature = "os")]
-#[allow(deprecated)]
-pub fn homedir() -> Option<Path> {
- #[inline]
- #[cfg(unix)]
- fn _homedir() -> Option<Path> {
- aux_homedir("HOME")
- }
-
- #[inline]
- #[cfg(windows)]
- fn _homedir() -> Option<Path> {
- aux_homedir("HOME").or(aux_homedir("USERPROFILE"))
- }
-
- #[inline]
- fn aux_homedir(home_name: &str) -> Option<Path> {
- match getenv_as_bytes(home_name) {
- Some(p) => {
- if p.is_empty() { None } else { Path::new_opt(p) }
- },
- _ => None
- }
- }
- _homedir()
-}
-
-/// Returns the path to a temporary directory.
-///
-/// On Unix, returns the value of the 'TMPDIR' environment variable if it is
-/// set, otherwise for non-Android it returns '/tmp'. If Android, since there
-/// is no global temporary folder (it is usually allocated per-app), we return
-/// '/data/local/tmp'.
-///
-/// On Windows, returns the value of, in order, the 'TMP', 'TEMP',
-/// 'USERPROFILE' environment variable if any are set and not the empty
-/// string. Otherwise, tmpdir returns the path to the Windows directory.
-#[unstable(feature = "os")]
-#[allow(deprecated)]
-pub fn tmpdir() -> Path {
- return lookup();
-
- fn getenv_nonempty(v: &str) -> Option<Path> {
- match getenv(v) {
- Some(x) =>
- if x.is_empty() {
- None
- } else {
- Path::new_opt(x)
- },
- _ => None
- }
- }
-
- #[cfg(unix)]
- fn lookup() -> Path {
- let default = if cfg!(target_os = "android") {
- Path::new("/data/local/tmp")
- } else {
- Path::new("/tmp")
- };
-
- getenv_nonempty("TMPDIR").unwrap_or(default)
- }
-
- #[cfg(windows)]
- fn lookup() -> Path {
- getenv_nonempty("TMP").or(
- getenv_nonempty("TEMP").or(
- getenv_nonempty("USERPROFILE").or(
- getenv_nonempty("WINDIR")))).unwrap_or(Path::new("C:\\Windows"))
- }
-}
-
-/// Convert a relative path to an absolute path
-///
-/// If the given path is relative, return it prepended with the current working
-/// directory. If the given path is already an absolute path, return it
-/// as is.
-///
-/// # Examples
-///
-/// ```
-/// # #![feature(os, old_path)]
-/// use std::os;
-/// use std::old_path::{Path, GenericPath};
-///
-/// // Assume we're in a path like /home/someuser
-/// let rel_path = Path::new("..");
-/// let abs_path = os::make_absolute(&rel_path).unwrap();
-/// println!("The absolute path is {}", abs_path.display());
-/// // Prints "The absolute path is /home"
-/// ```
-// NB: this is here rather than in path because it is a form of environment
-// querying; what it does depends on the process working directory, not just
-// the input paths.
-#[deprecated(since = "1.0.0", reason = "use env::current_dir + .join directly")]
-#[unstable(feature = "os")]
-pub fn make_absolute(p: &Path) -> IoResult<Path> {
- if p.is_absolute() {
- Ok(p.clone())
- } else {
- env::current_dir().map_err(err2old).map(|cwd| {
- let mut cwd = path2old(&cwd);
- cwd.push(p);
- cwd
- })
- }
-}
-
-/// Changes the current working directory to the specified path, returning
-/// whether the change was completed successfully or not.
-///
-/// # Examples
-///
-/// ```
-/// # #![feature(os, old_path)]
-/// use std::os;
-/// use std::old_path::{Path, GenericPath};
-///
-/// let root = Path::new("/");
-/// assert!(os::change_dir(&root).is_ok());
-/// println!("Successfully changed working directory to {}!", root.display());
-/// ```
-#[unstable(feature = "os")]
-pub fn change_dir(p: &Path) -> IoResult<()> {
- sys::os::chdir(&path2new(p)).map_err(err2old)
-}
-
-/// Returns the platform-specific value of errno
-pub fn errno() -> i32 {
- sys::os::errno() as i32
-}
-
-/// Return the string corresponding to an `errno()` value of `errnum`.
-///
-/// # Examples
-///
-/// ```
-/// # #![feature(os)]
-/// use std::os;
-///
-/// // Same as println!("{}", last_os_error());
-/// println!("{}", os::error_string(os::errno() as i32));
-/// ```
-pub fn error_string(errnum: i32) -> String {
- return sys::os::error_string(errnum);
-}
-
-/// Get a string representing the platform-dependent last error
-pub fn last_os_error() -> String {
- error_string(errno())
-}
-
-/// Sets the process exit code
-///
-/// Sets the exit code returned by the process if all supervised tasks
-/// terminate successfully (without panicking). If the current root task panics
-/// and is supervised by the scheduler then any user-specified exit status is
-/// ignored and the process exits with the default panic status.
-///
-/// Note that this is not synchronized against modifications of other threads.
-#[deprecated(since = "1.0.0", reason = "renamed to env::set_exit_status")]
-#[unstable(feature = "os")]
-pub fn set_exit_status(code: isize) {
- env::set_exit_status(code as i32)
-}
-
-/// Fetches the process's current exit code. This defaults to 0 and can change
-/// by calling `set_exit_status`.
-#[deprecated(since = "1.0.0", reason = "renamed to env::get_exit_status")]
-#[unstable(feature = "os")]
-pub fn get_exit_status() -> isize {
- env::get_exit_status() as isize
-}
-
-#[cfg(target_os = "macos")]
-unsafe fn load_argc_and_argv(argc: isize,
- argv: *const *const c_char) -> Vec<Vec<u8>> {
- use ffi::CStr;
-
- (0..argc).map(|i| {
- CStr::from_ptr(*argv.offset(i)).to_bytes().to_vec()
- }).collect()
-}
-
-/// Returns the command line arguments
-///
-/// Returns a list of the command line arguments.
-#[cfg(target_os = "macos")]
-fn real_args_as_bytes() -> Vec<Vec<u8>> {
- unsafe {
- let (argc, argv) = (*_NSGetArgc() as isize,
- *_NSGetArgv() as *const *const c_char);
- load_argc_and_argv(argc, argv)
- }
-}
-
-// As _NSGetArgc and _NSGetArgv aren't mentioned in iOS docs
-// and use underscores in their names - they're most probably
-// are considered private and therefore should be avoided
-// Here is another way to get arguments using Objective C
-// runtime
-//
-// In general it looks like:
-// res = Vec::new()
-// let args = [[NSProcessInfo processInfo] arguments]
-// for i in 0..[args count]
-// res.push([args objectAtIndex:i])
-// res
-#[cfg(target_os = "ios")]
-fn real_args_as_bytes() -> Vec<Vec<u8>> {
- use ffi::CStr;
- use iter::range;
- use mem;
-
- #[link(name = "objc")]
- extern {
- fn sel_registerName(name: *const libc::c_uchar) -> Sel;
- fn objc_msgSend(obj: NsId, sel: Sel, ...) -> NsId;
- fn objc_getClass(class_name: *const libc::c_uchar) -> NsId;
- }
-
- #[link(name = "Foundation", kind = "framework")]
- extern {}
-
- type Sel = *const libc::c_void;
- type NsId = *const libc::c_void;
-
- let mut res = Vec::new();
-
- unsafe {
- let processInfoSel = sel_registerName("processInfo\0".as_ptr());
- let argumentsSel = sel_registerName("arguments\0".as_ptr());
- let utf8Sel = sel_registerName("UTF8String\0".as_ptr());
- let countSel = sel_registerName("count\0".as_ptr());
- let objectAtSel = sel_registerName("objectAtIndex:\0".as_ptr());
-
- let klass = objc_getClass("NSProcessInfo\0".as_ptr());
- let info = objc_msgSend(klass, processInfoSel);
- let args = objc_msgSend(info, argumentsSel);
-
- let cnt: isize = mem::transmute(objc_msgSend(args, countSel));
- for i in 0..cnt {
- let tmp = objc_msgSend(args, objectAtSel, i);
- let utf_c_str: *const libc::c_char =
- mem::transmute(objc_msgSend(tmp, utf8Sel));
- res.push(CStr::from_ptr(utf_c_str).to_bytes().to_vec());
- }
- }
-
- res
-}
-
-#[cfg(any(target_os = "linux",
- target_os = "android",
- target_os = "freebsd",
- target_os = "dragonfly",
- target_os = "bitrig",
- target_os = "openbsd"))]
-fn real_args_as_bytes() -> Vec<Vec<u8>> {
- use rt;
- rt::args::clone().unwrap_or_else(|| vec![])
-}
-
-#[cfg(not(windows))]
-fn real_args() -> Vec<String> {
- real_args_as_bytes().into_iter()
- .map(|v| {
- String::from_utf8_lossy(&v).into_owned()
- }).collect()
-}
-
-#[cfg(windows)]
-fn real_args() -> Vec<String> {
- use slice;
- use iter::range;
-
- let mut nArgs: c_int = 0;
- let lpArgCount: *mut c_int = &mut nArgs;
- let lpCmdLine = unsafe { GetCommandLineW() };
- let szArgList = unsafe { CommandLineToArgvW(lpCmdLine, lpArgCount) };
-
- let args: Vec<_> = (0..nArgs as usize).map(|i| unsafe {
- // Determine the length of this argument.
- let ptr = *szArgList.offset(i as isize);
- let mut len = 0;
- while *ptr.offset(len as isize) != 0 { len += 1; }
-
- // Push it onto the list.
- let ptr = ptr as *const u16;
- let buf = slice::from_raw_parts(ptr, len);
- let opt_s = String::from_utf16(sys::truncate_utf16_at_nul(buf));
- opt_s.ok().expect("CommandLineToArgvW returned invalid UTF-16")
- }).collect();
-
- unsafe {
- LocalFree(szArgList as *mut c_void);
- }
-
- return args
-}
-
-#[cfg(windows)]
-fn real_args_as_bytes() -> Vec<Vec<u8>> {
- real_args().into_iter().map(|s| s.into_bytes()).collect()
-}
-
-type LPCWSTR = *const u16;
-
-#[cfg(windows)]
-#[link_name="kernel32"]
-extern "system" {
- fn GetCommandLineW() -> LPCWSTR;
- fn LocalFree(ptr: *mut c_void);
-}
-
-#[cfg(windows)]
-#[link_name="shell32"]
-extern "system" {
- fn CommandLineToArgvW(lpCmdLine: LPCWSTR,
- pNumArgs: *mut c_int) -> *mut *mut u16;
-}
-
-/// Returns the arguments which this program was started with (normally passed
-/// via the command line).
-///
-/// The first element is traditionally the path to the executable, but it can be
-/// set to arbitrary text, and it may not even exist, so this property should not
-/// be relied upon for security purposes.
-///
-/// The arguments are interpreted as utf-8, with invalid bytes replaced with \uFFFD.
-/// See `String::from_utf8_lossy` for details.
-/// # Examples
-///
-/// ```
-/// # #![feature(os)]
-/// use std::os;
-///
-/// // Prints each argument on a separate line
-/// for argument in os::args().iter() {
-/// println!("{}", argument);
-/// }
-/// ```
-#[deprecated(since = "1.0.0", reason = "use std::env::args() instead")]
-#[unstable(feature = "os")]
-pub fn args() -> Vec<String> {
- real_args()
-}
-
-/// Returns the arguments which this program was started with (normally passed
-/// via the command line) as byte vectors.
-#[deprecated(since = "1.0.0", reason = "use env::args_os instead")]
-#[unstable(feature = "os")]
-pub fn args_as_bytes() -> Vec<Vec<u8>> {
- real_args_as_bytes()
-}
-
-#[cfg(target_os = "macos")]
-extern {
- // These functions are in crt_externs.h.
- fn _NSGetArgc() -> *mut c_int;
- fn _NSGetArgv() -> *mut *mut *mut c_char;
-}
-
-/// Returns the page size of the current architecture in bytes.
-#[deprecated(since = "1.0.0", reason = "renamed to env::page_size")]
-#[unstable(feature = "os")]
-pub fn page_size() -> usize {
- sys::os::page_size()
-}
-
-/// A memory mapped file or chunk of memory. This is a very system-specific
-/// interface to the OS's memory mapping facilities (`mmap` on POSIX,
-/// `VirtualAlloc`/`CreateFileMapping` on Windows). It makes no attempt at
-/// abstracting platform differences, besides in error values returned. Consider
-/// yourself warned.
-///
-/// The memory map is released (unmapped) when the destructor is run, so don't
-/// let it leave scope by accident if you want it to stick around.
-pub struct MemoryMap {
- data: *mut u8,
- len: usize,
- kind: MemoryMapKind,
-}
-
-/// Type of memory map
-#[allow(raw_pointer_derive)]
-#[derive(Copy)]
-pub enum MemoryMapKind {
- /// Virtual memory map. Usually used to change the permissions of a given
- /// chunk of memory. Corresponds to `VirtualAlloc` on Windows.
- MapFile(*const u8),
- /// Virtual memory map. Usually used to change the permissions of a given
- /// chunk of memory, or for allocation. Corresponds to `VirtualAlloc` on
- /// Windows.
- MapVirtual
-}
-
-/// Options the memory map is created with
-#[allow(raw_pointer_derive)]
-#[derive(Copy)]
-pub enum MapOption {
- /// The memory should be readable
- MapReadable,
- /// The memory should be writable
- MapWritable,
- /// The memory should be executable
- MapExecutable,
- /// Create a map for a specific address range. Corresponds to `MAP_FIXED` on
- /// POSIX.
- MapAddr(*const u8),
- /// Create a memory mapping for a file with a given HANDLE.
- #[cfg(windows)]
- MapFd(libc::HANDLE),
- /// Create a memory mapping for a file with a given fd.
- #[cfg(not(windows))]
- MapFd(c_int),
- /// When using `MapFd`, the start of the map is `usize` bytes from the start
- /// of the file.
- MapOffset(usize),
- /// On POSIX, this can be used to specify the default flags passed to
- /// `mmap`. By default it uses `MAP_PRIVATE` and, if not using `MapFd`,
- /// `MAP_ANON`. This will override both of those. This is platform-specific
- /// (the exact values used) and ignored on Windows.
- MapNonStandardFlags(c_int),
-}
-
-/// Possible errors when creating a map.
-#[derive(Copy, Debug)]
-pub enum MapError {
- /// # The following are POSIX-specific
- ///
- /// fd was not open for reading or, if using `MapWritable`, was not open for
- /// writing.
- ErrFdNotAvail,
- /// fd was not valid
- ErrInvalidFd,
- /// Either the address given by `MapAddr` or offset given by `MapOffset` was
- /// not a multiple of `MemoryMap::granularity` (unaligned to page size).
- ErrUnaligned,
- /// With `MapFd`, the fd does not support mapping.
- ErrNoMapSupport,
- /// If using `MapAddr`, the address + `min_len` was outside of the process's
- /// address space. If using `MapFd`, the target of the fd didn't have enough
- /// resources to fulfill the request.
- ErrNoMem,
- /// A zero-length map was requested. This is invalid according to
- /// [POSIX](http://pubs.opengroup.org/onlinepubs/9699919799/functions/mmap.html).
- /// Not all platforms obey this, but this wrapper does.
- ErrZeroLength,
- /// Unrecognized error. The inner value is the unrecognized errno.
- ErrUnknown(isize),
- /// # The following are Windows-specific
- ///
- /// Unsupported combination of protection flags
- /// (`MapReadable`/`MapWritable`/`MapExecutable`).
- ErrUnsupProt,
- /// When using `MapFd`, `MapOffset` was given (Windows does not support this
- /// at all)
- ErrUnsupOffset,
- /// When using `MapFd`, there was already a mapping to the file.
- ErrAlreadyExists,
- /// Unrecognized error from `VirtualAlloc`. The inner value is the return
- /// value of GetLastError.
- ErrVirtualAlloc(i32),
- /// Unrecognized error from `CreateFileMapping`. The inner value is the
- /// return value of `GetLastError`.
- ErrCreateFileMappingW(i32),
- /// Unrecognized error from `MapViewOfFile`. The inner value is the return
- /// value of `GetLastError`.
- ErrMapViewOfFile(i32)
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl fmt::Display for MapError {
- fn fmt(&self, out: &mut fmt::Formatter) -> fmt::Result {
- let str = match *self {
- ErrFdNotAvail => "fd not available for reading or writing",
- ErrInvalidFd => "Invalid fd",
- ErrUnaligned => {
- "Unaligned address, invalid flags, negative length or \
- unaligned offset"
- }
- ErrNoMapSupport=> "File doesn't support mapping",
- ErrNoMem => "Invalid address, or not enough available memory",
- ErrUnsupProt => "Protection mode unsupported",
- ErrUnsupOffset => "Offset in virtual memory mode is unsupported",
- ErrAlreadyExists => "File mapping for specified file already exists",
- ErrZeroLength => "Zero-length mapping not allowed",
- ErrUnknown(code) => {
- return write!(out, "Unknown error = {}", code)
- },
- ErrVirtualAlloc(code) => {
- return write!(out, "VirtualAlloc failure = {}", code)
- },
- ErrCreateFileMappingW(code) => {
- return write!(out, "CreateFileMappingW failure = {}", code)
- },
- ErrMapViewOfFile(code) => {
- return write!(out, "MapViewOfFile failure = {}", code)
- }
- };
- write!(out, "{}", str)
- }
-}
-
-impl Error for MapError {
- fn description(&self) -> &str { "memory map error" }
-}
-
-// Round up `from` to be divisible by `to`
-fn round_up(from: usize, to: usize) -> usize {
- let r = if from % to == 0 {
- from
- } else {
- from + to - (from % to)
- };
- if r == 0 {
- to
- } else {
- r
- }
-}
-
-#[cfg(unix)]
-impl MemoryMap {
- /// Create a new mapping with the given `options`, at least `min_len` bytes
- /// long. `min_len` must be greater than zero; see the note on
- /// `ErrZeroLength`.
- pub fn new(min_len: usize, options: &[MapOption]) -> Result<MemoryMap, MapError> {
- use libc::off_t;
-
- if min_len == 0 {
- return Err(ErrZeroLength)
- }
- let mut addr: *const u8 = ptr::null();
- let mut prot = 0;
- let mut flags = libc::MAP_PRIVATE;
- let mut fd = -1;
- let mut offset = 0;
- let mut custom_flags = false;
- let len = round_up(min_len, env::page_size());
-
- for &o in options {
- match o {
- MapReadable => { prot |= libc::PROT_READ; },
- MapWritable => { prot |= libc::PROT_WRITE; },
- MapExecutable => { prot |= libc::PROT_EXEC; },
- MapAddr(addr_) => {
- flags |= libc::MAP_FIXED;
- addr = addr_;
- },
- MapFd(fd_) => {
- flags |= libc::MAP_FILE;
- fd = fd_;
- },
- MapOffset(offset_) => { offset = offset_ as off_t; },
- MapNonStandardFlags(f) => { custom_flags = true; flags = f },
- }
- }
- if fd == -1 && !custom_flags { flags |= libc::MAP_ANON; }
-
- let r = unsafe {
- libc::mmap(addr as *mut c_void, len as libc::size_t, prot, flags,
- fd, offset)
- };
- if r == libc::MAP_FAILED {
- Err(match errno() as c_int {
- libc::EACCES => ErrFdNotAvail,
- libc::EBADF => ErrInvalidFd,
- libc::EINVAL => ErrUnaligned,
- libc::ENODEV => ErrNoMapSupport,
- libc::ENOMEM => ErrNoMem,
- code => ErrUnknown(code as isize)
- })
- } else {
- Ok(MemoryMap {
- data: r as *mut u8,
- len: len,
- kind: if fd == -1 {
- MapVirtual
- } else {
- MapFile(ptr::null())
- }
- })
- }
- }
-
- /// Granularity that the offset or address must be for `MapOffset` and
- /// `MapAddr` respectively.
- pub fn granularity() -> usize {
- env::page_size()
- }
-}
-
-#[cfg(unix)]
-impl Drop for MemoryMap {
- /// Unmap the mapping. Panics the task if `munmap` panics.
- fn drop(&mut self) {
- if self.len == 0 { /* workaround for dummy_stack */ return; }
-
- unsafe {
- // `munmap` only panics due to logic errors
- libc::munmap(self.data as *mut c_void, self.len as libc::size_t);
- }
- }
-}
-
-#[cfg(windows)]
-impl MemoryMap {
- /// Create a new mapping with the given `options`, at least `min_len` bytes long.
- pub fn new(min_len: usize, options: &[MapOption]) -> Result<MemoryMap, MapError> {
- use libc::types::os::arch::extra::{LPVOID, DWORD, SIZE_T, HANDLE};
-
- let mut lpAddress: LPVOID = ptr::null_mut();
- let mut readable = false;
- let mut writable = false;
- let mut executable = false;
- let mut handle: HANDLE = libc::INVALID_HANDLE_VALUE;
- let mut offset: usize = 0;
- let len = round_up(min_len, env::page_size());
-
- for &o in options {
- match o {
- MapReadable => { readable = true; },
- MapWritable => { writable = true; },
- MapExecutable => { executable = true; }
- MapAddr(addr_) => { lpAddress = addr_ as LPVOID; },
- MapFd(handle_) => { handle = handle_; },
- MapOffset(offset_) => { offset = offset_; },
- MapNonStandardFlags(..) => {}
- }
- }
-
- let flProtect = match (executable, readable, writable) {
- (false, false, false) if handle == libc::INVALID_HANDLE_VALUE => libc::PAGE_NOACCESS,
- (false, true, false) => libc::PAGE_READONLY,
- (false, true, true) => libc::PAGE_READWRITE,
- (true, false, false) if handle == libc::INVALID_HANDLE_VALUE => libc::PAGE_EXECUTE,
- (true, true, false) => libc::PAGE_EXECUTE_READ,
- (true, true, true) => libc::PAGE_EXECUTE_READWRITE,
- _ => return Err(ErrUnsupProt)
- };
-
- if handle == libc::INVALID_HANDLE_VALUE {
- if offset != 0 {
- return Err(ErrUnsupOffset);
- }
- let r = unsafe {
- libc::VirtualAlloc(lpAddress,
- len as SIZE_T,
- libc::MEM_COMMIT | libc::MEM_RESERVE,
- flProtect)
- };
- match r as usize {
- 0 => Err(ErrVirtualAlloc(errno())),
- _ => Ok(MemoryMap {
- data: r as *mut u8,
- len: len,
- kind: MapVirtual
- })
- }
- } else {
- let dwDesiredAccess = match (executable, readable, writable) {
- (false, true, false) => libc::FILE_MAP_READ,
- (false, true, true) => libc::FILE_MAP_WRITE,
- (true, true, false) => libc::FILE_MAP_READ | libc::FILE_MAP_EXECUTE,
- (true, true, true) => libc::FILE_MAP_WRITE | libc::FILE_MAP_EXECUTE,
- _ => return Err(ErrUnsupProt) // Actually, because of the check above,
- // we should never get here.
- };
- unsafe {
- let hFile = handle;
- let mapping = libc::CreateFileMappingW(hFile,
- ptr::null_mut(),
- flProtect,
- 0,
- 0,
- ptr::null());
- if mapping == ptr::null_mut() {
- return Err(ErrCreateFileMappingW(errno()));
- }
- if errno() as c_int == libc::ERROR_ALREADY_EXISTS {
- return Err(ErrAlreadyExists);
- }
- let r = libc::MapViewOfFile(mapping,
- dwDesiredAccess,
- ((len as u64) >> 32) as DWORD,
- (offset & 0xffff_ffff) as DWORD,
- 0);
- match r as usize {
- 0 => Err(ErrMapViewOfFile(errno())),
- _ => Ok(MemoryMap {
- data: r as *mut u8,
- len: len,
- kind: MapFile(mapping as *const u8)
- })
- }
- }
- }
- }
-
- /// Granularity of MapAddr() and MapOffset() parameter values.
- /// This may be greater than the value returned by page_size().
- pub fn granularity() -> usize {
- use mem;
- unsafe {
- let mut info = mem::zeroed();
- libc::GetSystemInfo(&mut info);
-
- return info.dwAllocationGranularity as usize;
- }
- }
-}
-
-#[cfg(windows)]
-impl Drop for MemoryMap {
- /// Unmap the mapping. Panics the task if any of `VirtualFree`,
- /// `UnmapViewOfFile`, or `CloseHandle` fail.
- fn drop(&mut self) {
- use libc::types::os::arch::extra::{LPCVOID, HANDLE};
- use libc::consts::os::extra::FALSE;
- if self.len == 0 { return }
-
- unsafe {
- match self.kind {
- MapVirtual => {
- if libc::VirtualFree(self.data as *mut c_void, 0,
- libc::MEM_RELEASE) == 0 {
- println!("VirtualFree failed: {}", errno());
- }
- },
- MapFile(mapping) => {
- if libc::UnmapViewOfFile(self.data as LPCVOID) == FALSE {
- println!("UnmapViewOfFile failed: {}", errno());
- }
- if libc::CloseHandle(mapping as HANDLE) == FALSE {
- println!("CloseHandle failed: {}", errno());
- }
- }
- }
- }
- }
-}
-
-impl MemoryMap {
- /// Returns the pointer to the memory created or modified by this map.
- pub fn data(&self) -> *mut u8 { self.data }
- /// Returns the number of bytes this map applies to.
- pub fn len(&self) -> usize { self.len }
- /// Returns the type of mapping this represents.
- pub fn kind(&self) -> MemoryMapKind { self.kind }
-}
-
-#[cfg(target_os = "linux")]
-#[deprecated(since = "1.0.0", reason = "renamed to env::consts")]
-#[unstable(feature = "os")]
-pub mod consts {
- pub use os::arch_consts::ARCH;
-
- pub const FAMILY: &'static str = "unix";
-
- /// A string describing the specific operating system in use: in this
- /// case, `linux`.
- pub const SYSNAME: &'static str = "linux";
-
- /// Specifies the filename prefix used for shared libraries on this
- /// platform: in this case, `lib`.
- pub const DLL_PREFIX: &'static str = "lib";
-
- /// Specifies the filename suffix used for shared libraries on this
- /// platform: in this case, `.so`.
- pub const DLL_SUFFIX: &'static str = ".so";
-
- /// Specifies the file extension used for shared libraries on this
- /// platform that goes after the dot: in this case, `so`.
- pub const DLL_EXTENSION: &'static str = "so";
-
- /// Specifies the filename suffix used for executable binaries on this
- /// platform: in this case, the empty string.
- pub const EXE_SUFFIX: &'static str = "";
-
- /// Specifies the file extension, if any, used for executable binaries
- /// on this platform: in this case, the empty string.
- pub const EXE_EXTENSION: &'static str = "";
-}
-
-#[cfg(target_os = "macos")]
-#[deprecated(since = "1.0.0", reason = "renamed to env::consts")]
-#[unstable(feature = "os")]
-pub mod consts {
- pub use os::arch_consts::ARCH;
-
- pub const FAMILY: &'static str = "unix";
-
- /// A string describing the specific operating system in use: in this
- /// case, `macos`.
- pub const SYSNAME: &'static str = "macos";
-
- /// Specifies the filename prefix used for shared libraries on this
- /// platform: in this case, `lib`.
- pub const DLL_PREFIX: &'static str = "lib";
-
- /// Specifies the filename suffix used for shared libraries on this
- /// platform: in this case, `.dylib`.
- pub const DLL_SUFFIX: &'static str = ".dylib";
-
- /// Specifies the file extension used for shared libraries on this
- /// platform that goes after the dot: in this case, `dylib`.
- pub const DLL_EXTENSION: &'static str = "dylib";
-
- /// Specifies the filename suffix used for executable binaries on this
- /// platform: in this case, the empty string.
- pub const EXE_SUFFIX: &'static str = "";
-
- /// Specifies the file extension, if any, used for executable binaries
- /// on this platform: in this case, the empty string.
- pub const EXE_EXTENSION: &'static str = "";
-}
-
-#[cfg(target_os = "ios")]
-#[deprecated(since = "1.0.0", reason = "renamed to env::consts")]
-#[unstable(feature = "os")]
-pub mod consts {
- pub use os::arch_consts::ARCH;
-
- pub const FAMILY: &'static str = "unix";
-
- /// A string describing the specific operating system in use: in this
- /// case, `ios`.
- pub const SYSNAME: &'static str = "ios";
-
- /// Specifies the filename suffix used for executable binaries on this
- /// platform: in this case, the empty string.
- pub const EXE_SUFFIX: &'static str = "";
-
- /// Specifies the file extension, if any, used for executable binaries
- /// on this platform: in this case, the empty string.
- pub const EXE_EXTENSION: &'static str = "";
-}
-
-#[cfg(target_os = "freebsd")]
-#[deprecated(since = "1.0.0", reason = "renamed to env::consts")]
-#[unstable(feature = "os")]
-pub mod consts {
- pub use os::arch_consts::ARCH;
-
- pub const FAMILY: &'static str = "unix";
-
- /// A string describing the specific operating system in use: in this
- /// case, `freebsd`.
- pub const SYSNAME: &'static str = "freebsd";
-
- /// Specifies the filename prefix used for shared libraries on this
- /// platform: in this case, `lib`.
- pub const DLL_PREFIX: &'static str = "lib";
-
- /// Specifies the filename suffix used for shared libraries on this
- /// platform: in this case, `.so`.
- pub const DLL_SUFFIX: &'static str = ".so";
-
- /// Specifies the file extension used for shared libraries on this
- /// platform that goes after the dot: in this case, `so`.
- pub const DLL_EXTENSION: &'static str = "so";
-
- /// Specifies the filename suffix used for executable binaries on this
- /// platform: in this case, the empty string.
- pub const EXE_SUFFIX: &'static str = "";
-
- /// Specifies the file extension, if any, used for executable binaries
- /// on this platform: in this case, the empty string.
- pub const EXE_EXTENSION: &'static str = "";
-}
-
-#[cfg(target_os = "dragonfly")]
-#[deprecated(since = "1.0.0", reason = "renamed to env::consts")]
-#[unstable(feature = "os")]
-pub mod consts {
- pub use os::arch_consts::ARCH;
-
- pub const FAMILY: &'static str = "unix";
-
- /// A string describing the specific operating system in use: in this
- /// case, `dragonfly`.
- pub const SYSNAME: &'static str = "dragonfly";
-
- /// Specifies the filename prefix used for shared libraries on this
- /// platform: in this case, `lib`.
- pub const DLL_PREFIX: &'static str = "lib";
-
- /// Specifies the filename suffix used for shared libraries on this
- /// platform: in this case, `.so`.
- pub const DLL_SUFFIX: &'static str = ".so";
-
- /// Specifies the file extension used for shared libraries on this
- /// platform that goes after the dot: in this case, `so`.
- pub const DLL_EXTENSION: &'static str = "so";
-
- /// Specifies the filename suffix used for executable binaries on this
- /// platform: in this case, the empty string.
- pub const EXE_SUFFIX: &'static str = "";
-
- /// Specifies the file extension, if any, used for executable binaries
- /// on this platform: in this case, the empty string.
- pub const EXE_EXTENSION: &'static str = "";
-}
-
-#[cfg(target_os = "bitrig")]
-#[deprecated(since = "1.0.0", reason = "renamed to env::consts")]
-#[unstable(feature = "os")]
-pub mod consts {
- pub use os::arch_consts::ARCH;
-
- pub const FAMILY: &'static str = "unix";
-
- /// A string describing the specific operating system in use: in this
- /// case, `bitrig`.
- pub const SYSNAME: &'static str = "bitrig";
-
- /// Specifies the filename prefix used for shared libraries on this
- /// platform: in this case, `lib`.
- pub const DLL_PREFIX: &'static str = "lib";
-
- /// Specifies the filename suffix used for shared libraries on this
- /// platform: in this case, `.so`.
- pub const DLL_SUFFIX: &'static str = ".so";
-
- /// Specifies the file extension used for shared libraries on this
- /// platform that goes after the dot: in this case, `so`.
- pub const DLL_EXTENSION: &'static str = "so";
-
- /// Specifies the filename suffix used for executable binaries on this
- /// platform: in this case, the empty string.
- pub const EXE_SUFFIX: &'static str = "";
-
- /// Specifies the file extension, if any, used for executable binaries
- /// on this platform: in this case, the empty string.
- pub const EXE_EXTENSION: &'static str = "";
-}
-
-#[cfg(target_os = "openbsd")]
-#[deprecated(since = "1.0.0", reason = "renamed to env::consts")]
-#[unstable(feature = "os")]
-pub mod consts {
- pub use os::arch_consts::ARCH;
-
- pub const FAMILY: &'static str = "unix";
-
- /// A string describing the specific operating system in use: in this
- /// case, `openbsd`.
- pub const SYSNAME: &'static str = "openbsd";
-
- /// Specifies the filename prefix used for shared libraries on this
- /// platform: in this case, `lib`.
- pub const DLL_PREFIX: &'static str = "lib";
-
- /// Specifies the filename suffix used for shared libraries on this
- /// platform: in this case, `.so`.
- pub const DLL_SUFFIX: &'static str = ".so";
-
- /// Specifies the file extension used for shared libraries on this
- /// platform that goes after the dot: in this case, `so`.
- pub const DLL_EXTENSION: &'static str = "so";
-
- /// Specifies the filename suffix used for executable binaries on this
- /// platform: in this case, the empty string.
- pub const EXE_SUFFIX: &'static str = "";
-
- /// Specifies the file extension, if any, used for executable binaries
- /// on this platform: in this case, the empty string.
- pub const EXE_EXTENSION: &'static str = "";
-}
-
-#[cfg(target_os = "android")]
-#[deprecated(since = "1.0.0", reason = "renamed to env::consts")]
-#[unstable(feature = "os")]
-pub mod consts {
- pub use os::arch_consts::ARCH;
-
- pub const FAMILY: &'static str = "unix";
-
- /// A string describing the specific operating system in use: in this
- /// case, `android`.
- pub const SYSNAME: &'static str = "android";
-
- /// Specifies the filename prefix used for shared libraries on this
- /// platform: in this case, `lib`.
- pub const DLL_PREFIX: &'static str = "lib";
-
- /// Specifies the filename suffix used for shared libraries on this
- /// platform: in this case, `.so`.
- pub const DLL_SUFFIX: &'static str = ".so";
-
- /// Specifies the file extension used for shared libraries on this
- /// platform that goes after the dot: in this case, `so`.
- pub const DLL_EXTENSION: &'static str = "so";
-
- /// Specifies the filename suffix used for executable binaries on this
- /// platform: in this case, the empty string.
- pub const EXE_SUFFIX: &'static str = "";
-
- /// Specifies the file extension, if any, used for executable binaries
- /// on this platform: in this case, the empty string.
- pub const EXE_EXTENSION: &'static str = "";
-}
-
-#[cfg(target_os = "windows")]
-#[deprecated(since = "1.0.0", reason = "renamed to env::consts")]
-#[unstable(feature = "os")]
-pub mod consts {
- pub use os::arch_consts::ARCH;
-
- pub const FAMILY: &'static str = "windows";
-
- /// A string describing the specific operating system in use: in this
- /// case, `windows`.
- pub const SYSNAME: &'static str = "windows";
-
- /// Specifies the filename prefix used for shared libraries on this
- /// platform: in this case, the empty string.
- pub const DLL_PREFIX: &'static str = "";
-
- /// Specifies the filename suffix used for shared libraries on this
- /// platform: in this case, `.dll`.
- pub const DLL_SUFFIX: &'static str = ".dll";
-
- /// Specifies the file extension used for shared libraries on this
- /// platform that goes after the dot: in this case, `dll`.
- pub const DLL_EXTENSION: &'static str = "dll";
-
- /// Specifies the filename suffix used for executable binaries on this
- /// platform: in this case, `.exe`.
- pub const EXE_SUFFIX: &'static str = ".exe";
-
- /// Specifies the file extension, if any, used for executable binaries
- /// on this platform: in this case, `exe`.
- pub const EXE_EXTENSION: &'static str = "exe";
-}
-
-#[cfg(target_arch = "x86")]
-mod arch_consts {
- pub const ARCH: &'static str = "x86";
-}
-
-#[cfg(target_arch = "x86_64")]
-mod arch_consts {
- pub const ARCH: &'static str = "x86_64";
-}
-
-#[cfg(target_arch = "arm")]
-mod arch_consts {
- pub const ARCH: &'static str = "arm";
-}
-
-#[cfg(target_arch = "aarch64")]
-mod arch_consts {
- pub const ARCH: &'static str = "aarch64";
-}
-
-#[cfg(target_arch = "mips")]
-mod arch_consts {
- pub const ARCH: &'static str = "mips";
-}
-
-#[cfg(target_arch = "mipsel")]
-mod arch_consts {
- pub const ARCH: &'static str = "mipsel";
-}
-
-#[cfg(target_arch = "powerpc")]
-mod arch_consts {
- pub const ARCH: &'static str = "powerpc";
-}
-
-#[cfg(test)]
-mod tests {
- #![allow(deprecated)] // rand
-
- use prelude::v1::*;
-
- use iter::repeat;
- use os::{env, getcwd, getenv, make_absolute};
- use os::{split_paths, join_paths, setenv, unsetenv};
- use os;
- use rand::Rng;
- use rand;
- use old_path::{Path, GenericPath};
- use old_io::{Reader, Writer, Seek};
-
- #[test]
- pub fn last_os_error() {
- debug!("{}", os::last_os_error());
- }
-
- fn make_rand_name() -> String {
- let mut rng = rand::thread_rng();
- let n = format!("TEST{}", rng.gen_ascii_chars().take(10)
- .collect::<String>());
- assert!(getenv(&n).is_none());
- n
- }
-
- #[test]
- fn test_num_cpus() {
- assert!(os::num_cpus() > 0);
- }
-
- #[test]
- fn test_setenv() {
- let n = make_rand_name();
- setenv(&n, "VALUE");
- assert_eq!(getenv(&n), Some("VALUE".to_string()));
- }
-
- #[test]
- fn test_unsetenv() {
- let n = make_rand_name();
- setenv(&n, "VALUE");
- unsetenv(&n);
- assert_eq!(getenv(&n), None);
- }
-
- #[test]
- #[ignore]
- fn test_setenv_overwrite() {
- let n = make_rand_name();
- setenv(&n, "1");
- setenv(&n, "2");
- assert_eq!(getenv(&n), Some("2".to_string()));
- setenv(&n, "");
- assert_eq!(getenv(&n), Some("".to_string()));
- }
-
- // Windows GetEnvironmentVariable requires some extra work to make sure
- // the buffer the variable is copied into is the right size
- #[test]
- #[ignore]
- fn test_getenv_big() {
- let mut s = "".to_string();
- let mut i = 0;
- while i < 100 {
- s.push_str("aaaaaaaaaa");
- i += 1;
- }
- let n = make_rand_name();
- setenv(&n, &s);
- debug!("{}", s.clone());
- assert_eq!(getenv(&n), Some(s));
- }
-
- #[test]
- fn test_self_exe_name() {
- let path = os::self_exe_name();
- assert!(path.is_some());
- let path = path.unwrap();
- debug!("{}", path.display());
-
- // Hard to test this function
- assert!(path.is_absolute());
- }
-
- #[test]
- fn test_self_exe_path() {
- let path = os::self_exe_path();
- assert!(path.is_some());
- let path = path.unwrap();
- debug!("{}", path.display());
-
- // Hard to test this function
- assert!(path.is_absolute());
- }
-
- #[test]
- #[ignore]
- fn test_env_getenv() {
- let e = env();
- assert!(e.len() > 0);
- for p in &e {
- let (n, v) = (*p).clone();
- debug!("{}", n);
- let v2 = getenv(&n);
- // MingW seems to set some funky environment variables like
- // "=C:=C:\MinGW\msys\1.0\bin" and "!::=::\" that are returned
- // from env() but not visible from getenv().
- assert!(v2.is_none() || v2 == Some(v));
- }
- }
-
- #[test]
- fn test_env_set_get_huge() {
- let n = make_rand_name();
- let s = repeat("x").take(10000).collect::<String>();
- setenv(&n, &s);
- assert_eq!(getenv(&n), Some(s));
- unsetenv(&n);
- assert_eq!(getenv(&n), None);
- }
-
- #[test]
- fn test_env_setenv() {
- let n = make_rand_name();
-
- let mut e = env();
- setenv(&n, "VALUE");
- assert!(!e.contains(&(n.clone(), "VALUE".to_string())));
-
- e = env();
- assert!(e.contains(&(n, "VALUE".to_string())));
- }
-
- #[test]
- fn test() {
- assert!((!Path::new("test-path").is_absolute()));
-
- let cwd = getcwd().unwrap();
- debug!("Current working directory: {}", cwd.display());
-
- debug!("{}", make_absolute(&Path::new("test-path")).unwrap().display());
- debug!("{}", make_absolute(&Path::new("/usr/bin")).unwrap().display());
- }
-
- #[test]
- #[cfg(unix)]
- fn homedir() {
- let oldhome = getenv("HOME");
-
- setenv("HOME", "/home/MountainView");
- assert!(os::homedir() == Some(Path::new("/home/MountainView")));
-
- setenv("HOME", "");
- assert!(os::homedir().is_none());
-
- if let Some(s) = oldhome {
- setenv("HOME", s);
- }
- }
-
- #[test]
- #[cfg(windows)]
- fn homedir() {
-
- let oldhome = getenv("HOME");
- let olduserprofile = getenv("USERPROFILE");
-
- setenv("HOME", "");
- setenv("USERPROFILE", "");
-
- assert!(os::homedir().is_none());
-
- setenv("HOME", "/home/MountainView");
- assert!(os::homedir() == Some(Path::new("/home/MountainView")));
-
- setenv("HOME", "");
-
- setenv("USERPROFILE", "/home/MountainView");
- assert!(os::homedir() == Some(Path::new("/home/MountainView")));
-
- setenv("HOME", "/home/MountainView");
- setenv("USERPROFILE", "/home/PaloAlto");
- assert!(os::homedir() == Some(Path::new("/home/MountainView")));
-
- if let Some(s) = oldhome {
- setenv("HOME", &s);
- }
- if let Some(s) = olduserprofile {
- setenv("USERPROFILE", &s);
- }
- }
-
- #[test]
- fn memory_map_rw() {
- use result::Result::{Ok, Err};
-
- let chunk = match os::MemoryMap::new(16, &[
- os::MapOption::MapReadable,
- os::MapOption::MapWritable
- ]) {
- Ok(chunk) => chunk,
- Err(msg) => panic!("{:?}", msg)
- };
- assert!(chunk.len >= 16);
-
- unsafe {
- *chunk.data = 0xBE;
- assert!(*chunk.data == 0xBE);
- }
- }
-
- #[test]
- fn memory_map_file() {
- use libc;
- use os::*;
- use old_io::fs::{File, unlink};
- use old_io::SeekStyle::SeekSet;
- use old_io::FileMode::Open;
- use old_io::FileAccess::ReadWrite;
-
- #[cfg(not(windows))]
- fn get_fd(file: &File) -> libc::c_int {
- use os::unix::prelude::*;
- file.as_raw_fd()
- }
-
- #[cfg(windows)]
- fn get_fd(file: &File) -> libc::HANDLE {
- use os::windows::prelude::*;
- file.as_raw_handle()
- }
-
- let mut path = tmpdir();
- path.push("mmap_file.tmp");
- let size = MemoryMap::granularity() * 2;
- let mut file = File::open_mode(&path, Open, ReadWrite).unwrap();
- file.seek(size as i64, SeekSet).unwrap();
- file.write_u8(0).unwrap();
-
- let chunk = MemoryMap::new(size / 2, &[
- MapOption::MapReadable,
- MapOption::MapWritable,
- MapOption::MapFd(get_fd(&file)),
- MapOption::MapOffset(size / 2)
- ]).unwrap();
- assert!(chunk.len > 0);
-
- unsafe {
- *chunk.data = 0xbe;
- assert!(*chunk.data == 0xbe);
- }
- drop(chunk);
-
- unlink(&path).unwrap();
- }
-
- #[test]
- #[cfg(windows)]
- fn split_paths_windows() {
- fn check_parse(unparsed: &str, parsed: &[&str]) -> bool {
- split_paths(unparsed) ==
- parsed.iter().map(|s| Path::new(*s)).collect::<Vec<_>>()
- }
-
- assert!(check_parse("", &mut [""]));
- assert!(check_parse(r#""""#, &mut [""]));
- assert!(check_parse(";;", &mut ["", "", ""]));
- assert!(check_parse(r"c:\", &mut [r"c:\"]));
- assert!(check_parse(r"c:\;", &mut [r"c:\", ""]));
- assert!(check_parse(r"c:\;c:\Program Files\",
- &mut [r"c:\", r"c:\Program Files\"]));
- assert!(check_parse(r#"c:\;c:\"foo"\"#, &mut [r"c:\", r"c:\foo\"]));
- assert!(check_parse(r#"c:\;c:\"foo;bar"\;c:\baz"#,
- &mut [r"c:\", r"c:\foo;bar\", r"c:\baz"]));
- }
-
- #[test]
- #[cfg(unix)]
- fn split_paths_unix() {
- fn check_parse(unparsed: &str, parsed: &[&str]) -> bool {
- split_paths(unparsed) ==
- parsed.iter().map(|s| Path::new(*s)).collect::<Vec<_>>()
- }
-
- assert!(check_parse("", &mut [""]));
- assert!(check_parse("::", &mut ["", "", ""]));
- assert!(check_parse("/", &mut ["/"]));
- assert!(check_parse("/:", &mut ["/", ""]));
- assert!(check_parse("/:/usr/local", &mut ["/", "/usr/local"]));
- }
-
- #[test]
- #[cfg(unix)]
- fn join_paths_unix() {
- fn test_eq(input: &[&str], output: &str) -> bool {
- join_paths(input).unwrap() == output.as_bytes()
- }
-
- assert!(test_eq(&[], ""));
- assert!(test_eq(&["/bin", "/usr/bin", "/usr/local/bin"],
- "/bin:/usr/bin:/usr/local/bin"));
- assert!(test_eq(&["", "/bin", "", "", "/usr/bin", ""],
- ":/bin:::/usr/bin:"));
- assert!(join_paths(&["/te:st"]).is_err());
- }
-
- #[test]
- #[cfg(windows)]
- fn join_paths_windows() {
- fn test_eq(input: &[&str], output: &str) -> bool {
- join_paths(input).unwrap() == output.as_bytes()
- }
-
- assert!(test_eq(&[], ""));
- assert!(test_eq(&[r"c:\windows", r"c:\"],
- r"c:\windows;c:\"));
- assert!(test_eq(&["", r"c:\windows", "", "", r"c:\", ""],
- r";c:\windows;;;c:\;"));
- assert!(test_eq(&[r"c:\te;st", r"c:\"],
- r#""c:\te;st";c:\"#));
- assert!(join_paths(&[r#"c:\te"st"#]).is_err());
- }
-
- // More recursive_mkdir tests are in extra::tempfile
-}
//! To build or modify paths, use `PathBuf`:
//!
//! ```rust
-//! # #![feature(convert)]
//! use std::path::PathBuf;
//!
//! let mut path = PathBuf::from("c:\\");
/// Determine whether the character is one of the permitted path
/// separators for the current platform.
+///
+/// # Examples
+///
+/// ```
+/// use std::path;
+///
+/// assert!(path::is_separator('/'));
+/// assert!(!path::is_separator('❤'));
+/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn is_separator(c: char) -> bool {
use ascii::*;
// contents of the encoding and (2) new &OsStr values are produced
// only from ASCII-bounded slices of existing &OsStr values.
- let mut iter = os_str_as_u8_slice(file).rsplitn(1, |b| *b == b'.');
+ let mut iter = os_str_as_u8_slice(file).rsplitn(2, |b| *b == b'.');
let after = iter.next();
let before = iter.next();
if before == Some(b"") {
pub fn as_os_str(self) -> &'a OsStr {
match self {
Component::Prefix(p) => p.as_os_str(),
- Component::RootDir => OsStr::from_str(MAIN_SEP_STR),
- Component::CurDir => OsStr::from_str("."),
- Component::ParentDir => OsStr::from_str(".."),
+ Component::RootDir => OsStr::new(MAIN_SEP_STR),
+ Component::CurDir => OsStr::new("."),
+ Component::ParentDir => OsStr::new(".."),
Component::Normal(path) => path,
}
}
///
/// See the module documentation for an in-depth explanation of components and
/// their role in the API.
+///
+/// # Examples
+///
+/// ```
+/// use std::path::Path;
+///
+/// let path = Path::new("/tmp/foo/bar.txt");
+///
+/// for component in path.components() {
+/// println!("{:?}", component);
+/// }
+/// ```
#[derive(Clone)]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Components<'a> {
}
/// Extract a slice corresponding to the portion of the path remaining for iteration.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::path::Path;
+ ///
+ /// let path = Path::new("/tmp/foo/bar.txt");
+ ///
+ /// println!("{:?}", path.components().as_path());
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn as_path(&self) -> &'a Path {
let mut comps = self.clone();
/// # Examples
///
/// ```
-/// # #![feature(convert)]
/// use std::path::PathBuf;
///
/// let mut path = PathBuf::from("c:\\");
PathBuf { inner: OsString::new() }
}
+ /// Coerce to a `Path` slice.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn as_path(&self) -> &Path {
+ self
+ }
+
/// Extend `self` with `path`.
///
/// If `path` is absolute, it replaces the current path.
/// # Examples
///
/// ```
- /// # #![feature(convert)]
/// use std::path::PathBuf;
///
/// let mut buf = PathBuf::from("/");
/// Directly wrap a string slice as a `Path` slice.
///
/// This is a cost-free conversion.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::path::Path;
+ ///
+ /// Path::new("foo.txt");
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn new<S: AsRef<OsStr> + ?Sized>(s: &S) -> &Path {
unsafe { mem::transmute(s.as_ref()) }
}
/// Yield the underlying `OsStr` slice.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::path::Path;
+ ///
+ /// let os_str = Path::new("foo.txt").as_os_str();
+ /// ```
#[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.
///
/// This conversion may entail doing a check for UTF-8 validity.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::path::Path;
+ ///
+ /// let path_str = Path::new("foo.txt").to_str();
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn to_str(&self) -> Option<&str> {
self.inner.to_str()
/// Convert a `Path` to a `Cow<str>`.
///
/// Any non-Unicode sequences are replaced with U+FFFD REPLACEMENT CHARACTER.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::path::Path;
+ ///
+ /// let path_str = Path::new("foo.txt").to_string_lossy();
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn to_string_lossy(&self) -> Cow<str> {
self.inner.to_string_lossy()
}
/// Convert a `Path` to an owned `PathBuf`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::path::Path;
+ ///
+ /// let path_str = Path::new("foo.txt").to_path_buf();
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn to_path_buf(&self) -> PathBuf {
PathBuf::from(self.inner.to_os_string())
/// * On Windows, a path is absolute if it has a prefix and starts with the
/// root: `c:\windows` is absolute, while `c:temp` and `\temp` are not. In
/// other words, `path.is_absolute() == path.prefix().is_some() && path.has_root()`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::path::Path;
+ ///
+ /// assert_eq!(false, Path::new("foo.txt").is_absolute());
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn is_absolute(&self) -> bool {
self.has_root() &&
}
/// A path is *relative* if it is not absolute.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::path::Path;
+ ///
+ /// assert!(Path::new("foo.txt").is_relative());
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn is_relative(&self) -> bool {
!self.is_absolute()
/// * has no prefix and begins with a separator, e.g. `\\windows`
/// * has a prefix followed by a separator, e.g. `c:\windows` but not `c:windows`
/// * has any non-disk prefix, e.g. `\\server\share`
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::path::Path;
+ ///
+ /// assert!(Path::new("/etc/passwd").has_root());
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn has_root(&self) -> bool {
self.components().has_root()
///
/// let path = Path::new("/foo/bar");
/// let foo = path.parent().unwrap();
+ ///
/// assert!(foo == Path::new("/foo"));
+ ///
/// let root = foo.parent().unwrap();
+ ///
/// assert!(root == Path::new("/"));
/// assert!(root.parent() == None);
/// ```
///
/// If the path terminates in `.`, `..`, or consists solely or a root of
/// prefix, `file_name` will return `None`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::path::Path;
+ ///
+ /// let path = Path::new("hello_world.rs");
+ /// let filename = "hello_world.rs";
+ ///
+ /// assert_eq!(filename, path.file_name().unwrap());
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn file_name(&self) -> Option<&OsStr> {
self.components().next_back().and_then(|p| match p {
- Component::Normal(p) => Some(p.as_os_str()),
+ Component::Normal(p) => Some(p.as_ref()),
_ => None
})
}
}
/// Determines whether `base` is a prefix of `self`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::path::Path;
+ ///
+ /// let path = Path::new("/etc/passwd");
+ ///
+ /// assert!(path.starts_with("/etc"));
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
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`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::path::Path;
+ ///
+ /// let path = Path::new("/etc/passwd");
+ ///
+ /// assert!(path.ends_with("passwd"));
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn ends_with<P: AsRef<Path>>(&self, child: P) -> bool {
iter_after(self.components().rev(), child.as_ref().components().rev()).is_some()
/// * The entire file name if there is no embedded `.`;
/// * The entire file name if the file name begins with `.` and has no other `.`s within;
/// * Otherwise, the portion of the file name before the final `.`
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::path::Path;
+ ///
+ /// let path = Path::new("foo.rs");
+ ///
+ /// assert_eq!("foo", path.file_stem().unwrap());
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn file_stem(&self) -> Option<&OsStr> {
self.file_name().map(split_file_at_dot).and_then(|(before, after)| before.or(after))
/// * None, if there is no embedded `.`;
/// * None, if the file name begins with `.` and has no other `.`s within;
/// * Otherwise, the portion of the file name after the final `.`
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::path::Path;
+ ///
+ /// let path = Path::new("foo.rs");
+ ///
+ /// assert_eq!("rs", path.extension().unwrap());
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn extension(&self) -> Option<&OsStr> {
self.file_name().map(split_file_at_dot).and_then(|(before, after)| before.and(after))
/// Creates an owned `PathBuf` with `path` adjoined to `self`.
///
/// See `PathBuf::push` for more details on what it means to adjoin a path.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::path::Path;
+ ///
+ /// let path = Path::new("/tmp");
+ ///
+ /// let new_path = path.join("foo");
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn join<P: AsRef<Path>>(&self, path: P) -> PathBuf {
let mut buf = self.to_path_buf();
/// Creates an owned `PathBuf` like `self` but with the given file name.
///
/// See `PathBuf::set_file_name` for more details.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::path::Path;
+ ///
+ /// let path = Path::new("/tmp/foo.rs");
+ ///
+ /// let new_path = path.with_file_name("bar.rs");
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn with_file_name<S: AsRef<OsStr>>(&self, file_name: S) -> PathBuf {
let mut buf = self.to_path_buf();
/// Creates an owned `PathBuf` like `self` but with the given extension.
///
/// See `PathBuf::set_extension` for more details.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::path::Path;
+ ///
+ /// let path = Path::new("/tmp/foo.rs");
+ ///
+ /// let new_path = path.with_extension("foo.txt");
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn with_extension<S: AsRef<OsStr>>(&self, extension: S) -> PathBuf {
let mut buf = self.to_path_buf();
}
/// Produce an iterator over the components of the path.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::path::Path;
+ ///
+ /// let path = Path::new("/tmp/foo.rs");
+ ///
+ /// for component in path.components() {
+ /// println!("{:?}", component);
+ /// }
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn components(&self) -> Components {
let prefix = parse_prefix(self.as_os_str());
}
/// Produce an iterator over the path's components viewed as `OsStr` slices.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::path::Path;
+ ///
+ /// let path = Path::new("/tmp/foo.rs");
+ ///
+ /// for component in path.iter() {
+ /// println!("{:?}", component);
+ /// }
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn iter(&self) -> Iter {
Iter { inner: self.components() }
/// Returns an object that implements `Display` for safely printing paths
/// that may contain non-Unicode data.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::path::Path;
+ ///
+ /// let path = Path::new("/tmp/foo.rs");
+ ///
+ /// println!("{}", path.display());
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn display(&self) -> Display {
Display { path: self }
#[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;
+#[doc(no_inline)] pub use slice::SliceConcatExt;
#[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;
+
+#[allow(deprecated)] pub use slice::AsSlice;
+#[allow(deprecated)] pub use str::Str;
use prelude::v1::*;
use io::prelude::*;
-use ffi::AsOsStr;
+use ffi::OsStr;
use fmt;
use io::{self, Error, ErrorKind};
use libc;
use path;
use sync::mpsc::{channel, Receiver};
use sys::pipe2::{self, AnonPipe};
-use sys::process2::Process as ProcessImp;
use sys::process2::Command as CommandImp;
+use sys::process2::Process as ProcessImp;
use sys::process2::ExitStatus as ExitStatusImp;
use sys_common::{AsInner, AsInnerMut};
use thread;
/// Builder methods are provided to change these defaults and
/// otherwise configure the process.
#[stable(feature = "process", since = "1.0.0")]
- pub fn new<S: AsOsStr>(program: S) -> Command {
+ pub fn new<S: AsRef<OsStr>>(program: S) -> Command {
Command {
- inner: CommandImp::new(program.as_os_str()),
+ inner: CommandImp::new(program.as_ref()),
stdin: None,
stdout: None,
stderr: None,
/// Add an argument to pass to the program.
#[stable(feature = "process", since = "1.0.0")]
- pub fn arg<S: AsOsStr>(&mut self, arg: S) -> &mut Command {
- self.inner.arg(arg.as_os_str());
+ pub fn arg<S: AsRef<OsStr>>(&mut self, arg: S) -> &mut Command {
+ self.inner.arg(arg.as_ref());
self
}
/// Add multiple arguments to pass to the program.
#[stable(feature = "process", since = "1.0.0")]
- pub fn args<S: AsOsStr>(&mut self, args: &[S]) -> &mut Command {
- self.inner.args(args.iter().map(AsOsStr::as_os_str));
+ pub fn args<S: AsRef<OsStr>>(&mut self, args: &[S]) -> &mut Command {
+ self.inner.args(args.iter().map(AsRef::as_ref));
self
}
/// and case-sensitive on all other platforms.
#[stable(feature = "process", since = "1.0.0")]
pub fn env<K, V>(&mut self, key: K, val: V) -> &mut Command
- where K: AsOsStr, V: AsOsStr
+ where K: AsRef<OsStr>, V: AsRef<OsStr>
{
- self.inner.env(key.as_os_str(), val.as_os_str());
+ self.inner.env(key.as_ref(), val.as_ref());
self
}
/// Removes an environment variable mapping.
#[stable(feature = "process", since = "1.0.0")]
- pub fn env_remove<K: AsOsStr>(&mut self, key: K) -> &mut Command {
- self.inner.env_remove(key.as_os_str());
+ pub fn env_remove<K: AsRef<OsStr>>(&mut self, key: K) -> &mut Command {
+ self.inner.env_remove(key.as_ref());
self
}
/// Set the working directory for the child process.
#[stable(feature = "process", since = "1.0.0")]
pub fn current_dir<P: AsRef<path::Path>>(&mut self, dir: P) -> &mut Command {
- self.inner.cwd(dir.as_ref().as_os_str());
+ self.inner.cwd(dir.as_ref().as_ref());
self
}
}
impl Stdio {
- /// A new pipe should be arranged to connect the parent and child processes.
- #[unstable(feature = "process_capture")]
- #[deprecated(since = "1.0.0", reason = "renamed to `Stdio::piped`")]
- pub fn capture() -> Stdio { Stdio::piped() }
-
/// A new pipe should be arranged to connect the parent and child processes.
#[stable(feature = "process", since = "1.0.0")]
pub fn piped() -> Stdio { Stdio(StdioImp::Piped) }
return Err(Error::new(
ErrorKind::InvalidInput,
"invalid argument: can't kill an exited process",
- None
))
}
}
}
+/// Terminates the current process with the specified exit code.
+///
+/// This function will never return and will immediately terminate the current
+/// process. The exit code is passed through to the underlying OS and will be
+/// available for consumption by another process.
+///
+/// Note that because this function never returns, and that it terminates the
+/// process, no destructors on the current stack or any other thread's stack
+/// will be run. If a clean shutdown is needed it is recommended to only call
+/// this function at a known point where there are no more destructors left
+/// to run.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub fn exit(code: i32) -> ! {
+ ::sys::os::exit(code)
+}
+
#[cfg(test)]
mod tests {
- use io::ErrorKind;
+ use prelude::v1::*;
use io::prelude::*;
- use prelude::v1::{Ok, Err, drop, Some, Vec};
- use prelude::v1::{String, Clone};
- use prelude::v1::{Str, AsSlice, ToString};
+
+ use io::ErrorKind;
use old_path::{self, GenericPath};
use old_io::fs::PathExtensions;
use rt::running_on_valgrind;
assert!(p.is_ok());
let mut p = p.unwrap();
assert!(p.wait().unwrap().code() == Some(1));
- drop(p.wait().clone());
+ drop(p.wait());
}
#[cfg(all(unix, not(target_os="android")))]
fn test_process_output_output() {
let Output {status, stdout, stderr}
= Command::new("echo").arg("hello").output().unwrap();
- let output_str = str::from_utf8(stdout.as_slice()).unwrap();
+ let output_str = str::from_utf8(&stdout).unwrap();
assert!(status.success());
assert_eq!(output_str.trim().to_string(), "hello");
let prog = Command::new("echo").arg("hello").stdout(Stdio::piped())
.spawn().unwrap();
let Output {status, stdout, stderr} = prog.wait_with_output().unwrap();
- let output_str = str::from_utf8(stdout.as_slice()).unwrap();
+ let output_str = str::from_utf8(&stdout).unwrap();
assert!(status.success());
assert_eq!(output_str.trim().to_string(), "hello");
let prog = pwd_cmd().spawn().unwrap();
let output = String::from_utf8(prog.wait_with_output().unwrap().stdout).unwrap();
- let parent_dir = os::getcwd().unwrap();
+ let parent_dir = ::env::current_dir().unwrap().to_str().unwrap().to_string();
+ let parent_dir = old_path::Path::new(parent_dir);
let child_dir = old_path::Path::new(output.trim());
let parent_stat = parent_dir.stat().unwrap();
use os;
// test changing to the parent of os::getcwd() because we know
// the path exists (and os::getcwd() is not expected to be root)
- let parent_dir = os::getcwd().unwrap().dir_path();
+ let parent_dir = ::env::current_dir().unwrap().to_str().unwrap().to_string();
+ let parent_dir = old_path::Path::new(parent_dir).dir_path();
let result = pwd_cmd().current_dir(parent_dir.as_str().unwrap()).output().unwrap();
let output = String::from_utf8(result.stdout).unwrap();
#[cfg(target_os="android")]
#[test]
fn test_inherit_env() {
- use os;
+ use std::env;
if running_on_valgrind() { return; }
let mut result = env_cmd().output().unwrap();
let output = String::from_utf8(result.stdout).unwrap();
- let r = os::env();
- for &(ref k, ref v) in &r {
+ for (ref k, ref v) in env::vars() {
// don't check android RANDOM variables
if *k != "RANDOM".to_string() {
assert!(output.contains(&format!("{}={}",
cmd.env("PATH", &p);
}
let result = cmd.output().unwrap();
- let output = String::from_utf8_lossy(result.stdout.as_slice()).to_string();
+ let output = String::from_utf8_lossy(&result.stdout).to_string();
assert!(output.contains("RUN_TEST_NEW_ENV=123"),
"didn't find RUN_TEST_NEW_ENV inside of:\n\n{}", output);
#[test]
fn test_add_to_env() {
let result = env_cmd().env("RUN_TEST_NEW_ENV", "123").output().unwrap();
- let output = String::from_utf8_lossy(result.stdout.as_slice()).to_string();
+ let output = String::from_utf8_lossy(&result.stdout).to_string();
assert!(output.contains("RUN_TEST_NEW_ENV=123"),
"didn't find RUN_TEST_NEW_ENV inside of:\n\n{}", output);
#[cfg(all(unix, not(target_os = "ios")))]
mod imp {
- extern crate libc;
-
+ use prelude::v1::*;
use self::OsRngInner::*;
+ use libc;
+ use mem;
use old_io::{IoResult, File};
use old_path::Path;
use rand::Rng;
use rand::reader::ReaderRng;
- use result::Result::Ok;
- use mem;
- use os::errno;
+ use sys::os::errno;
#[cfg(all(target_os = "linux",
any(target_arch = "x86_64",
#[cfg(target_os = "ios")]
mod imp {
- extern crate libc;
+ use prelude::v1::*;
- use old_io::{IoResult};
+ use io;
+ use old_io::IoResult;
use mem;
- use os;
use rand::Rng;
- use result::Result::{Ok};
- use self::libc::{c_int, size_t};
+ use libc::{c_int, size_t};
/// A random number generator that retrieves randomness straight from
/// the operating system. Platform sources:
SecRandomCopyBytes(kSecRandomDefault, v.len() as size_t, v.as_mut_ptr())
};
if ret == -1 {
- panic!("couldn't generate random bytes: {}", os::last_os_error());
+ panic!("couldn't generate random bytes: {}", io::Error::last_os_error());
}
}
}
#[cfg(windows)]
mod imp {
- extern crate libc;
+ use prelude::v1::*;
- use old_io::{IoResult, IoError};
+ use io;
use mem;
- use ops::Drop;
- use os;
+ use old_io::{IoResult, IoError};
use rand::Rng;
- use result::Result::{Ok, Err};
- use self::libc::{DWORD, BYTE, LPCSTR, BOOL};
- use self::libc::types::os::arch::extra::{LONG_PTR};
+ use libc::types::os::arch::extra::{LONG_PTR};
+ use libc::{DWORD, BYTE, LPCSTR, BOOL};
type HCRYPTPROV = LONG_PTR;
v.as_mut_ptr())
};
if ret == 0 {
- panic!("couldn't generate random bytes: {}", os::last_os_error());
+ panic!("couldn't generate random bytes: {}",
+ io::Error::last_os_error());
}
}
}
CryptReleaseContext(self.hcryptprov, 0)
};
if ret == 0 {
- panic!("couldn't release context: {}", os::last_os_error());
+ panic!("couldn't release context: {}",
+ io::Error::last_os_error());
}
}
}
#[cfg(test)]
mod tests {
use prelude::v1::*;
- use finally::Finally;
use super::*;
assert!(take() == Some(expected.clone()));
assert!(take() == None);
- (|| {
- }).finally(|| {
- // Restore the actual global state.
- match saved_value {
- Some(ref args) => put(args.clone()),
- None => ()
- }
- })
+ // Restore the actual global state.
+ match saved_value {
+ Some(ref args) => put(args.clone()),
+ None => ()
+ }
}
}
}
if queue as usize != 0 {
let queue: Box<Queue> = Box::from_raw(queue);
for to_run in *queue {
- to_run.invoke(());
+ to_run();
}
}
}
#[cfg(any(not(target_arch = "arm"), target_os = "ios"))]
#[repr(C)]
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub enum _Unwind_Action {
_UA_SEARCH_PHASE = 1,
_UA_CLEANUP_PHASE = 2,
use prelude::v1::*;
use sys;
-use thunk::Thunk;
use usize;
// Reexport some of our utilities which are expected by other crates.
use libc;
use libc::funcs::posix01::signal::signal;
unsafe {
- assert!(signal(libc::SIGPIPE, libc::SIG_IGN) != -1);
+ assert!(signal(libc::SIGPIPE, libc::SIG_IGN) != !0);
}
}
ignore_sigpipe();
/// that the closure could not be registered, meaning that it is not scheduled
/// to be rune.
pub fn at_exit<F: FnOnce() + Send + 'static>(f: F) -> Result<(), ()> {
- if at_exit_imp::push(Thunk::new(f)) {Ok(())} else {Err(())}
+ if at_exit_imp::push(Box::new(f)) {Ok(())} else {Err(())}
}
/// One-time runtime cleanup.
pub struct DISPATCHER_CONTEXT;
#[repr(C)]
- #[derive(Copy)]
+ #[derive(Copy, Clone)]
pub enum EXCEPTION_DISPOSITION {
ExceptionContinueExecution,
ExceptionContinueSearch,
/// Wait on this condition variable for a notification, timing out after a
/// specified duration.
///
- /// The semantics of this function are equivalent to `wait()` except that
- /// the thread will be blocked for roughly no longer than `dur`. This method
- /// should not be used for precise timing due to anomalies such as
- /// preemption or platform differences that may not cause the maximum amount
- /// of time waited to be precisely `dur`.
+ /// The semantics of this function are equivalent to `wait()`
+ /// except that the thread will be blocked for roughly no longer
+ /// than `ms` milliseconds. This method should not be used for
+ /// precise timing due to anomalies such as preemption or platform
+ /// differences that may not cause the maximum amount of time
+ /// waited to be precisely `ms`.
///
- /// If the wait timed out, then `false` will be returned. Otherwise if a
- /// notification was received then `true` will be returned.
+ /// The returned boolean is `false` only if the timeout is known
+ /// to have elapsed.
///
/// Like `wait`, the lock specified will be re-acquired when this function
/// returns, regardless of whether the timeout elapsed or not.
- #[unstable(feature = "std_misc")]
- pub fn wait_timeout<'a, T>(&self, guard: MutexGuard<'a, T>, dur: Duration)
- -> LockResult<(MutexGuard<'a, T>, bool)> {
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn wait_timeout_ms<'a, T>(&self, guard: MutexGuard<'a, T>, ms: u32)
+ -> LockResult<(MutexGuard<'a, T>, bool)> {
unsafe {
let me: &'static Condvar = &*(self as *const _);
- me.inner.wait_timeout(guard, dur)
+ me.inner.wait_timeout_ms(guard, ms)
}
}
+ /// Deprecated: use `wait_timeout_ms` instead.
+ #[unstable(feature = "std_misc")]
+ #[deprecated(since = "1.0.0", reason = "use wait_timeout_ms instead")]
+ pub fn wait_timeout<'a, T>(&self, guard: MutexGuard<'a, T>, dur: Duration)
+ -> LockResult<(MutexGuard<'a, T>, bool)> {
+ self.wait_timeout_ms(guard, dur.num_milliseconds() as u32)
+ }
+
/// Wait on this condition variable for a notification, timing out after a
/// specified duration.
///
/// The semantics of this function are equivalent to `wait_timeout` except
/// that the implementation will repeatedly wait while the duration has not
/// passed and the provided function returns `false`.
- #[unstable(feature = "std_misc")]
+ #[unstable(feature = "wait_timeout_with",
+ reason = "unsure if this API is broadly needed or what form it should take")]
pub fn wait_timeout_with<'a, T, F>(&self,
guard: MutexGuard<'a, T>,
dur: Duration,
/// See `Condvar::wait_timeout`.
#[unstable(feature = "std_misc",
reason = "may be merged with Condvar in the future")]
- pub fn wait_timeout<'a, T>(&'static self, guard: MutexGuard<'a, T>, dur: Duration)
- -> LockResult<(MutexGuard<'a, T>, bool)> {
+ pub fn wait_timeout_ms<'a, T>(&'static self, guard: MutexGuard<'a, T>, ms: u32)
+ -> LockResult<(MutexGuard<'a, T>, bool)> {
let (poisoned, success) = unsafe {
let lock = mutex::guard_lock(&guard);
self.verify(lock);
- let success = self.inner.wait_timeout(lock, dur);
+ let success = self.inner.wait_timeout(lock, Duration::milliseconds(ms as i64));
(mutex::guard_poison(&guard).get(), success)
};
if poisoned {
let now = SteadyTime::now();
let consumed = &now - &start;
let guard = guard_result.unwrap_or_else(|e| e.into_inner());
- let (new_guard_result, no_timeout) = match self.wait_timeout(guard, dur - consumed) {
+ let res = self.wait_timeout_ms(guard, (dur - consumed).num_milliseconds() as u32);
+ let (new_guard_result, no_timeout) = match res {
Ok((new_guard, no_timeout)) => (Ok(new_guard), no_timeout),
Err(err) => {
let (new_guard, no_timeout) = err.into_inner();
use sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
use thread;
use time::Duration;
+ use u32;
#[test]
fn smoke() {
}
#[test]
- fn wait_timeout() {
+ fn wait_timeout_ms() {
static C: StaticCondvar = CONDVAR_INIT;
static M: StaticMutex = MUTEX_INIT;
let g = M.lock().unwrap();
- let (g, _no_timeout) = C.wait_timeout(g, Duration::nanoseconds(1000)).unwrap();
+ let (g, _no_timeout) = C.wait_timeout_ms(g, 1).unwrap();
// spurious wakeups mean this isn't necessarily true
// assert!(!no_timeout);
let _t = thread::spawn(move || {
let _g = M.lock().unwrap();
C.notify_one();
});
- let (g, no_timeout) = C.wait_timeout(g, Duration::days(1)).unwrap();
+ let (g, no_timeout) = C.wait_timeout_ms(g, u32::MAX).unwrap();
assert!(no_timeout);
drop(g);
unsafe { C.destroy(); M.destroy(); }
use core::prelude::*;
use core::mem::replace;
+use boxed::Box;
use self::FutureState::*;
use sync::mpsc::{Receiver, channel};
use thunk::Thunk;
match replace(&mut self.state, Evaluating) {
Forced(_) | Evaluating => panic!("Logic error."),
Pending(f) => {
- self.state = Forced(f.invoke(()));
+ self.state = Forced(f());
self.get_ref()
}
}
* function. It is not spawned into another task.
*/
- Future {state: Pending(Thunk::new(f))}
+ Future {state: Pending(Box::new(f))}
}
}
pub use self::poison::{PoisonError, TryLockError, TryLockResult, LockResult};
pub use self::future::Future;
-#[allow(deprecated)]
-pub use self::task_pool::TaskPool;
pub mod mpsc;
mod poison;
mod rwlock;
mod semaphore;
-mod task_pool;
//! ```
//!
//! Reading from a channel with a timeout requires to use a Timer together
-//! with the channel. You can use the select! macro to select either and
+//! with the channel. You can use the `select!` macro to select either and
//! handle the timeout case. This first example will break out of the loop
//! after 10 seconds no matter what:
//!
/// The receiving-half of Rust's channel type. This half can only be owned by
/// one task
#[stable(feature = "rust1", since = "1.0.0")]
-pub struct Receiver<T:Send> {
+pub struct Receiver<T> {
inner: UnsafeCell<Flavor<T>>,
}
/// whenever `next` is called, waiting for a new message, and `None` will be
/// returned when the corresponding channel has hung up.
#[stable(feature = "rust1", since = "1.0.0")]
-pub struct Iter<'a, T:Send+'a> {
+pub struct Iter<'a, T: 'a> {
rx: &'a Receiver<T>
}
/// The sending-half of Rust's asynchronous channel type. This half can only be
/// owned by one task, but it can be cloned to send to other tasks.
#[stable(feature = "rust1", since = "1.0.0")]
-pub struct Sender<T:Send> {
+pub struct Sender<T> {
inner: UnsafeCell<Flavor<T>>,
}
/// The sending-half of Rust's synchronous channel type. This half can only be
/// owned by one task, but it can be cloned to send to other tasks.
#[stable(feature = "rust1", since = "1.0.0")]
-pub struct SyncSender<T: Send> {
+pub struct SyncSender<T> {
inner: Arc<UnsafeCell<sync::Packet<T>>>,
}
Disconnected(T),
}
-enum Flavor<T:Send> {
+enum Flavor<T> {
Oneshot(Arc<UnsafeCell<oneshot::Packet<T>>>),
Stream(Arc<UnsafeCell<stream::Packet<T>>>),
Shared(Arc<UnsafeCell<shared::Packet<T>>>),
}
#[doc(hidden)]
-trait UnsafeFlavor<T:Send> {
+trait UnsafeFlavor<T> {
fn inner_unsafe<'a>(&'a self) -> &'a UnsafeCell<Flavor<T>>;
unsafe fn inner_mut<'a>(&'a self) -> &'a mut Flavor<T> {
&mut *self.inner_unsafe().get()
&*self.inner_unsafe().get()
}
}
-impl<T:Send> UnsafeFlavor<T> for Sender<T> {
+impl<T> UnsafeFlavor<T> for Sender<T> {
fn inner_unsafe<'a>(&'a self) -> &'a UnsafeCell<Flavor<T>> {
&self.inner
}
}
-impl<T:Send> UnsafeFlavor<T> for Receiver<T> {
+impl<T> UnsafeFlavor<T> for Receiver<T> {
fn inner_unsafe<'a>(&'a self) -> &'a UnsafeCell<Flavor<T>> {
&self.inner
}
/// println!("{:?}", rx.recv().unwrap());
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
-pub fn channel<T: Send>() -> (Sender<T>, Receiver<T>) {
+pub fn channel<T>() -> (Sender<T>, Receiver<T>) {
let a = Arc::new(UnsafeCell::new(oneshot::Packet::new()));
(Sender::new(Flavor::Oneshot(a.clone())), Receiver::new(Flavor::Oneshot(a)))
}
/// assert_eq!(rx.recv().unwrap(), 2);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
-pub fn sync_channel<T: Send>(bound: usize) -> (SyncSender<T>, Receiver<T>) {
+pub fn sync_channel<T>(bound: usize) -> (SyncSender<T>, Receiver<T>) {
let a = Arc::new(UnsafeCell::new(sync::Packet::new(bound)));
(SyncSender::new(a.clone()), Receiver::new(Flavor::Sync(a)))
}
// Sender
////////////////////////////////////////////////////////////////////////////////
-impl<T: Send> Sender<T> {
+impl<T> Sender<T> {
fn new(inner: Flavor<T>) -> Sender<T> {
Sender {
inner: UnsafeCell::new(inner),
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: Send> Clone for Sender<T> {
+impl<T> Clone for Sender<T> {
fn clone(&self) -> Sender<T> {
let (packet, sleeper, guard) = match *unsafe { self.inner() } {
Flavor::Oneshot(ref p) => {
#[unsafe_destructor]
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: Send> Drop for Sender<T> {
+impl<T> Drop for Sender<T> {
fn drop(&mut self) {
match *unsafe { self.inner_mut() } {
Flavor::Oneshot(ref mut p) => unsafe { (*p.get()).drop_chan(); },
// SyncSender
////////////////////////////////////////////////////////////////////////////////
-impl<T: Send> SyncSender<T> {
+impl<T> SyncSender<T> {
fn new(inner: Arc<UnsafeCell<sync::Packet<T>>>) -> SyncSender<T> {
SyncSender { inner: inner }
}
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: Send> Clone for SyncSender<T> {
+impl<T> Clone for SyncSender<T> {
fn clone(&self) -> SyncSender<T> {
unsafe { (*self.inner.get()).clone_chan(); }
return SyncSender::new(self.inner.clone());
#[unsafe_destructor]
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: Send> Drop for SyncSender<T> {
+impl<T> Drop for SyncSender<T> {
fn drop(&mut self) {
unsafe { (*self.inner.get()).drop_chan(); }
}
// Receiver
////////////////////////////////////////////////////////////////////////////////
-impl<T: Send> Receiver<T> {
+impl<T> Receiver<T> {
fn new(inner: Flavor<T>) -> Receiver<T> {
Receiver { inner: UnsafeCell::new(inner) }
}
}
}
-impl<T: Send> select::Packet for Receiver<T> {
+impl<T> select::Packet for Receiver<T> {
fn can_recv(&self) -> bool {
loop {
let new_port = match *unsafe { self.inner() } {
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, T: Send> Iterator for Iter<'a, T> {
+impl<'a, T> Iterator for Iter<'a, T> {
type Item = T;
fn next(&mut self) -> Option<T> { self.rx.recv().ok() }
#[unsafe_destructor]
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: Send> Drop for Receiver<T> {
+impl<T> Drop for Receiver<T> {
fn drop(&mut self) {
match *unsafe { self.inner_mut() } {
Flavor::Oneshot(ref mut p) => unsafe { (*p.get()).drop_port(); },
/// The multi-producer single-consumer structure. This is not cloneable, but it
/// may be safely shared so long as it is guaranteed that there is only one
/// popper at a time (many pushers are allowed).
-pub struct Queue<T: Send> {
+pub struct Queue<T> {
head: AtomicPtr<Node<T>>,
tail: UnsafeCell<*mut Node<T>>,
}
-unsafe impl<T:Send> Send for Queue<T> { }
+unsafe impl<T: Send> Send for Queue<T> { }
unsafe impl<T: Send> Sync for Queue<T> { }
impl<T> Node<T> {
}
}
-impl<T: Send> Queue<T> {
+impl<T> Queue<T> {
/// Creates a new queue that is safe to share among multiple producers and
/// one consumer.
pub fn new() -> Queue<T> {
#[unsafe_destructor]
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: Send> Drop for Queue<T> {
+impl<T> Drop for Queue<T> {
fn drop(&mut self) {
unsafe {
let mut cur = *self.tail.get();
// moves *from* a pointer, ownership of the token is transferred to
// whoever changed the state.
-pub struct Packet<T:Send> {
+pub struct Packet<T> {
// Internal state of the chan/port pair (stores the blocked task as well)
state: AtomicUsize,
// One-shot data slot location
upgrade: MyUpgrade<T>,
}
-pub enum Failure<T:Send> {
+pub enum Failure<T> {
Empty,
Disconnected,
Upgraded(Receiver<T>),
UpWoke(SignalToken),
}
-pub enum SelectionResult<T:Send> {
+pub enum SelectionResult<T> {
SelCanceled,
SelUpgraded(SignalToken, Receiver<T>),
SelSuccess,
}
-enum MyUpgrade<T:Send> {
+enum MyUpgrade<T> {
NothingSent,
SendUsed,
GoUp(Receiver<T>),
}
-impl<T: Send> Packet<T> {
+impl<T> Packet<T> {
pub fn new() -> Packet<T> {
Packet {
data: None,
}
#[unsafe_destructor]
-impl<T: Send> Drop for Packet<T> {
+impl<T> Drop for Packet<T> {
fn drop(&mut self) {
assert_eq!(self.state.load(Ordering::SeqCst), DISCONNECTED);
}
#[cfg(not(test))]
const MAX_STEALS: isize = 1 << 20;
-pub struct Packet<T: Send> {
+pub struct Packet<T> {
queue: mpsc::Queue<T>,
cnt: AtomicIsize, // How many items are on this channel
steals: isize, // How many times has a port received without blocking?
Disconnected,
}
-impl<T: Send> Packet<T> {
+impl<T> Packet<T> {
// Creation of a packet *must* be followed by a call to postinit_lock
// and later by inherit_blocker
pub fn new() -> Packet<T> {
}
#[unsafe_destructor]
-impl<T: Send> Drop for Packet<T> {
+impl<T> Drop for Packet<T> {
fn drop(&mut self) {
// Note that this load is not only an assert for correctness about
// disconnection, but also a proper fence before the read of
/// but it can be safely shared in an Arc if it is guaranteed that there
/// is only one popper and one pusher touching the queue at any one point in
/// time.
-pub struct Queue<T: Send> {
+pub struct Queue<T> {
// consumer fields
tail: UnsafeCell<*mut Node<T>>, // where to pop from
tail_prev: AtomicPtr<Node<T>>, // where to pop from
unsafe impl<T: Send> Sync for Queue<T> { }
-impl<T: Send> Node<T> {
+impl<T> Node<T> {
fn new() -> *mut Node<T> {
unsafe {
boxed::into_raw(box Node {
}
}
-impl<T: Send> Queue<T> {
+impl<T> Queue<T> {
/// Creates a new queue.
///
/// This is unsafe as the type system doesn't enforce a single
}
#[unsafe_destructor]
-impl<T: Send> Drop for Queue<T> {
+impl<T> Drop for Queue<T> {
fn drop(&mut self) {
unsafe {
let mut cur = *self.first.get();
#[cfg(not(test))]
const MAX_STEALS: isize = 1 << 20;
-pub struct Packet<T:Send> {
+pub struct Packet<T> {
queue: spsc::Queue<Message<T>>, // internal queue for all message
cnt: AtomicIsize, // How many items are on this channel
port_dropped: AtomicBool, // flag if the channel has been destroyed.
}
-pub enum Failure<T:Send> {
+pub enum Failure<T> {
Empty,
Disconnected,
Upgraded(Receiver<T>),
UpWoke(SignalToken),
}
-pub enum SelectionResult<T:Send> {
+pub enum SelectionResult<T> {
SelSuccess,
SelCanceled,
SelUpgraded(SignalToken, Receiver<T>),
// Any message could contain an "upgrade request" to a new shared port, so the
// internal queue it's a queue of T, but rather Message<T>
-enum Message<T:Send> {
+enum Message<T> {
Data(T),
GoUp(Receiver<T>),
}
-impl<T: Send> Packet<T> {
+impl<T> Packet<T> {
pub fn new() -> Packet<T> {
Packet {
queue: unsafe { spsc::Queue::new(128) },
}
#[unsafe_destructor]
-impl<T: Send> Drop for Packet<T> {
+impl<T> Drop for Packet<T> {
fn drop(&mut self) {
// Note that this load is not only an assert for correctness about
// disconnection, but also a proper fence before the read of
use sync::mpsc::select::StartResult::{self, Installed, Abort};
use sync::{Mutex, MutexGuard};
-pub struct Packet<T: Send> {
+pub struct Packet<T> {
/// Only field outside of the mutex. Just done for kicks, but mainly because
/// the other shared channel already had the code implemented
channels: AtomicUsize,
/// Atomically blocks the current thread, placing it into `slot`, unlocking `lock`
/// in the meantime. This re-locks the mutex upon returning.
-fn wait<'a, 'b, T: Send>(lock: &'a Mutex<State<T>>,
- mut guard: MutexGuard<'b, State<T>>,
- f: fn(SignalToken) -> Blocker)
- -> MutexGuard<'a, State<T>>
+fn wait<'a, 'b, T>(lock: &'a Mutex<State<T>>,
+ mut guard: MutexGuard<'b, State<T>>,
+ f: fn(SignalToken) -> Blocker)
+ -> MutexGuard<'a, State<T>>
{
let (wait_token, signal_token) = blocking::tokens();
match mem::replace(&mut guard.blocker, f(signal_token)) {
token.signal();
}
-impl<T: Send> Packet<T> {
+impl<T> Packet<T> {
pub fn new(cap: usize) -> Packet<T> {
Packet {
channels: AtomicUsize::new(1),
}
#[unsafe_destructor]
-impl<T: Send> Drop for Packet<T> {
+impl<T> Drop for Packet<T> {
fn drop(&mut self) {
assert_eq!(self.channels.load(Ordering::SeqCst), 0);
let mut guard = self.lock.lock().unwrap();
/// *guard += 1;
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
-pub struct Mutex<T: Send> {
+pub struct Mutex<T> {
// Note that this static mutex is in a *box*, not inlined into the struct
// itself. Once a native mutex has been used once, its address can never
// change (it can't be moved). This mutex type can be safely moved at any
data: UnsafeCell<T>,
}
+// these are the only places where `T: Send` matters; all other
+// functionality works fine on a single thread.
unsafe impl<T: Send> Send for Mutex<T> { }
unsafe impl<T: Send> Sync for Mutex<T> { }
poison: poison::FLAG_INIT,
};
-impl<T: Send> Mutex<T> {
+impl<T> Mutex<T> {
/// Creates a new mutex in an unlocked state ready for use.
#[stable(feature = "rust1", since = "1.0.0")]
pub fn new(t: T) -> Mutex<T> {
#[unsafe_destructor]
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: Send> Drop for Mutex<T> {
+impl<T> Drop for Mutex<T> {
fn drop(&mut self) {
// This is actually safe b/c we know that there is no further usage of
// this mutex (it's up to the user to arrange for a mutex to get
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: fmt::Debug + Send + 'static> fmt::Debug for Mutex<T> {
+impl<T: fmt::Debug + 'static> fmt::Debug for Mutex<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.try_lock() {
Ok(guard) => write!(f, "Mutex {{ data: {:?} }}", *guard),
use prelude::v1::*;
use cell::UnsafeCell;
-use error::{Error, FromError};
+use error::{Error};
use fmt;
use thread;
PoisonError { guard: guard }
}
- /// Consumes this error indicating that a lock is poisoned, returning the
- /// underlying guard to allow access regardless.
- #[unstable(feature = "std_misc")]
- #[deprecated(since = "1.0.0", reason = "renamed to into_inner")]
- pub fn into_guard(self) -> T { self.guard }
-
/// Consumes this error indicating that a lock is poisoned, returning the
/// underlying guard to allow access regardless.
#[unstable(feature = "std_misc")]
pub fn get_mut(&mut self) -> &mut T { &mut self.guard }
}
-impl<T> FromError<PoisonError<T>> for TryLockError<T> {
- fn from_error(err: PoisonError<T>) -> TryLockError<T> {
+impl<T> From<PoisonError<T>> for TryLockError<T> {
+ fn from(err: PoisonError<T>) -> TryLockError<T> {
TryLockError::Poisoned(err)
}
}
impl<'a, T> !marker::Send for RwLockWriteGuard<'a, T> {}
-impl<T: Send + Sync> RwLock<T> {
+impl<T> RwLock<T> {
/// Creates a new instance of an `RwLock<T>` which is unlocked.
///
/// # Examples
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: fmt::Debug + Send + Sync> fmt::Debug for RwLock<T> {
+impl<T: fmt::Debug> fmt::Debug for RwLock<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.try_read() {
Ok(guard) => write!(f, "RwLock {{ data: {:?} }}", *guard),
+++ /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.
-
-//! Abstraction of a thread pool for basic parallelism.
-
-#![deprecated(since = "1.0.0",
- reason = "This kind of API needs some time to bake in \
- crates.io. This functionality is available through \
- https://crates.io/crates/threadpool")]
-#![unstable(feature = "std_misc")]
-
-#![allow(deprecated)]
-
-use core::prelude::*;
-
-use sync::{Arc, Mutex};
-use sync::mpsc::{channel, Sender, Receiver};
-use thread;
-use thunk::Thunk;
-
-struct Sentinel<'a> {
- jobs: &'a Arc<Mutex<Receiver<Thunk<'static>>>>,
- active: bool
-}
-
-impl<'a> Sentinel<'a> {
- fn new(jobs: &'a Arc<Mutex<Receiver<Thunk<'static>>>>) -> Sentinel<'a> {
- Sentinel {
- jobs: jobs,
- active: true
- }
- }
-
- // Cancel and destroy this sentinel.
- fn cancel(mut self) {
- self.active = false;
- }
-}
-
-#[unsafe_destructor]
-impl<'a> Drop for Sentinel<'a> {
- fn drop(&mut self) {
- if self.active {
- spawn_in_pool(self.jobs.clone())
- }
- }
-}
-
-/// A thread pool used to execute functions in parallel.
-///
-/// Spawns `n` worker threads and replenishes the pool if any worker threads
-/// panic.
-///
-/// # Examples
-///
-/// ```
-/// # #![feature(std_misc, core)]
-/// use std::sync::TaskPool;
-/// use std::iter::AdditiveIterator;
-/// use std::sync::mpsc::channel;
-///
-/// let pool = TaskPool::new(4);
-///
-/// let (tx, rx) = channel();
-/// for _ in 0..8 {
-/// let tx = tx.clone();
-/// pool.execute(move|| {
-/// tx.send(1_u32).unwrap();
-/// });
-/// }
-///
-/// assert_eq!(rx.iter().take(8).sum(), 8);
-/// ```
-pub struct TaskPool {
- // How the threadpool communicates with subthreads.
- //
- // This is the only such Sender, so when it is dropped all subthreads will
- // quit.
- jobs: Sender<Thunk<'static>>
-}
-
-impl TaskPool {
- /// Spawns a new thread pool with `threads` threads.
- ///
- /// # Panics
- ///
- /// This function will panic if `threads` is 0.
- pub fn new(threads: usize) -> TaskPool {
- assert!(threads >= 1);
-
- let (tx, rx) = channel::<Thunk>();
- let rx = Arc::new(Mutex::new(rx));
-
- // Threadpool threads
- for _ in 0..threads {
- spawn_in_pool(rx.clone());
- }
-
- TaskPool { jobs: tx }
- }
-
- /// Executes the function `job` on a thread in the pool.
- pub fn execute<F>(&self, job: F)
- where F : FnOnce(), F : Send + 'static
- {
- self.jobs.send(Thunk::new(job)).unwrap();
- }
-}
-
-fn spawn_in_pool(jobs: Arc<Mutex<Receiver<Thunk<'static>>>>) {
- thread::spawn(move || {
- // Will spawn a new thread on panic unless it is cancelled.
- let sentinel = Sentinel::new(&jobs);
-
- loop {
- let message = {
- // Only lock jobs for the time it takes
- // to get a job, not run it.
- let lock = jobs.lock().unwrap();
- lock.recv()
- };
-
- match message {
- Ok(job) => job.invoke(()),
-
- // The Taskpool was dropped.
- Err(..) => break
- }
- }
-
- sentinel.cancel();
- });
-}
-
-#[cfg(test)]
-mod test {
- use prelude::v1::*;
- use super::*;
- use sync::mpsc::channel;
-
- const TEST_TASKS: usize = 4;
-
- #[test]
- fn test_works() {
- use iter::AdditiveIterator;
-
- let pool = TaskPool::new(TEST_TASKS);
-
- let (tx, rx) = channel();
- for _ in 0..TEST_TASKS {
- let tx = tx.clone();
- pool.execute(move|| {
- tx.send(1).unwrap();
- });
- }
-
- assert_eq!(rx.iter().take(TEST_TASKS).sum(), TEST_TASKS);
- }
-
- #[test]
- #[should_panic]
- fn test_zero_tasks_panic() {
- TaskPool::new(0);
- }
-
- #[test]
- fn test_recovery_from_subtask_panic() {
- use iter::AdditiveIterator;
-
- let pool = TaskPool::new(TEST_TASKS);
-
- // Panic all the existing threads.
- for _ in 0..TEST_TASKS {
- pool.execute(move|| -> () { panic!() });
- }
-
- // Ensure new threads were spawned to compensate.
- let (tx, rx) = channel();
- for _ in 0..TEST_TASKS {
- let tx = tx.clone();
- pool.execute(move|| {
- tx.send(1).unwrap();
- });
- }
-
- assert_eq!(rx.iter().take(TEST_TASKS).sum(), TEST_TASKS);
- }
-
- #[test]
- fn test_should_not_panic_on_drop_if_subtasks_panic_after_drop() {
- use sync::{Arc, Barrier};
-
- let pool = TaskPool::new(TEST_TASKS);
- let waiter = Arc::new(Barrier::new(TEST_TASKS + 1));
-
- // Panic all the existing threads in a bit.
- for _ in 0..TEST_TASKS {
- let waiter = waiter.clone();
- pool.execute(move|| {
- waiter.wait();
- panic!();
- });
- }
-
- drop(pool);
-
- // Kick off the failure.
- waiter.wait();
- }
-}
Ipv4Addr(..) => libc::AF_INET,
Ipv6Addr(..) => libc::AF_INET6,
};
- match libc::socket(fam, ty, 0) {
+ match libc::socket(fam, ty, 0) as i32 {
-1 => Err(last_net_error()),
- fd => Ok(fd),
+ fd => Ok(fd as sock_t),
}
}
}
})))
}
_ => {
- Err(Error::new(ErrorKind::InvalidInput, "invalid argument", None))
+ Err(Error::new(ErrorKind::InvalidInput, "invalid argument"))
}
}
}
match from_utf8(data.to_bytes()) {
Ok(name) => Ok(name.to_string()),
Err(_) => Err(io::Error::new(io::ErrorKind::Other,
- "failed to lookup address information",
- Some("invalid host name".to_string())))
+ "failed to lookup address information"))
}
}
}
}
+impl FromInner<Socket> for TcpStream {
+ fn from_inner(socket: Socket) -> TcpStream {
+ TcpStream { inner: socket }
+ }
+}
+
////////////////////////////////////////////////////////////////////////////////
// TCP listeners
////////////////////////////////////////////////////////////////////////////////
}
}
+impl FromInner<Socket> for TcpListener {
+ fn from_inner(socket: Socket) -> TcpListener {
+ TcpListener { inner: socket }
+ }
+}
+
////////////////////////////////////////////////////////////////////////////////
// UDP
////////////////////////////////////////////////////////////////////////////////
self.inner.duplicate().map(|s| UdpSocket { inner: s })
}
}
+
+impl FromInner<Socket> for UdpSocket {
+ fn from_inner(socket: Socket) -> UdpSocket {
+ UdpSocket { inner: socket }
+ }
+}
unsafe {
stack::record_os_managed_stack_bounds(0, usize::MAX);
let _handler = stack_overflow::Handler::new();
- Box::from_raw(main as *mut Thunk).invoke(());
+ let main: Box<Thunk> = Box::from_raw(main as *mut Thunk);
+ main();
}
}
fn print(w: &mut Write, idx: isize, addr: *mut libc::c_void,
symaddr: *mut libc::c_void) -> io::Result<()> {
use env;
- use ffi::AsOsStr;
use os::unix::prelude::*;
use ptr;
#[repr(C)]
pub struct fd_set {
// FIXME: shouldn't this be a c_ulong?
- fds_bits: [libc::uintptr_t; (FD_SETSIZE / usize::BITS as usize)]
+ fds_bits: [libc::uintptr_t; (FD_SETSIZE / usize::BITS)]
}
pub fn fd_set(set: &mut fd_set, fd: i32) {
let fd = fd as usize;
- set.fds_bits[fd / usize::BITS as usize] |= 1 << (fd % usize::BITS as usize);
+ set.fds_bits[fd / usize::BITS] |= 1 << (fd % usize::BITS);
}
}
#![stable(feature = "rust1", since = "1.0.0")]
/// Unix-specific extensions to general I/O primitives
-#[unstable(feature = "io_ext",
- reason = "may want a slightly different organization or a more \
- general file descriptor primitive")]
+#[stable(feature = "rust1", since = "1.0.0")]
pub mod io {
#[allow(deprecated)] use old_io;
use fs;
use libc;
use net;
- use sys_common::AsInner;
+ use sys_common::{net2, AsInner, FromInner};
+ use sys;
/// Raw file descriptors.
- pub type Fd = libc::c_int;
-
- /// Extract raw file descriptor
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub type RawFd = libc::c_int;
+
+ /// A trait to extract the raw unix file descriptor from an underlying
+ /// object.
+ ///
+ /// This is only available on unix platforms and must be imported in order
+ /// to call the method. Windows platforms have a corresponding `AsRawHandle`
+ /// and `AsRawSocket` set of traits.
+ #[stable(feature = "rust1", since = "1.0.0")]
pub trait AsRawFd {
- /// Extract the raw file descriptor, without taking any ownership.
- fn as_raw_fd(&self) -> Fd;
+ /// Extract the raw file descriptor.
+ ///
+ /// This method does **not** pass ownership of the raw file descriptor
+ /// to the caller. The descriptor is only guarantee to be valid while
+ /// the original object has not yet been destroyed.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ fn as_raw_fd(&self) -> RawFd;
+ }
+
+ /// A trait to express the ability to construct an object from a raw file
+ /// descriptor.
+ #[unstable(feature = "from_raw_os",
+ reason = "recent addition to std::os::unix::io")]
+ pub trait FromRawFd {
+ /// Constructs a new instances of `Self` from the given raw file
+ /// descriptor.
+ ///
+ /// This function **consumes ownership** of the specified file
+ /// descriptor. The returned object will take responsibility for closing
+ /// it when the object goes out of scope.
+ ///
+ /// Callers should normally only pass in a valid file descriptor to this
+ /// method or otherwise methods will return errors.
+ fn from_raw_fd(fd: RawFd) -> Self;
}
#[allow(deprecated)]
+ #[stable(feature = "rust1", since = "1.0.0")]
impl AsRawFd for old_io::fs::File {
- fn as_raw_fd(&self) -> Fd {
+ fn as_raw_fd(&self) -> RawFd {
self.as_inner().fd()
}
}
+ #[stable(feature = "rust1", since = "1.0.0")]
impl AsRawFd for fs::File {
- fn as_raw_fd(&self) -> Fd {
+ fn as_raw_fd(&self) -> RawFd {
self.as_inner().fd().raw()
}
}
+ #[unstable(feature = "from_raw_os", reason = "trait is unstable")]
+ impl FromRawFd for fs::File {
+ fn from_raw_fd(fd: RawFd) -> fs::File {
+ fs::File::from_inner(sys::fs2::File::from_inner(fd))
+ }
+ }
#[allow(deprecated)]
+ #[stable(feature = "rust1", since = "1.0.0")]
impl AsRawFd for old_io::pipe::PipeStream {
- fn as_raw_fd(&self) -> Fd {
+ fn as_raw_fd(&self) -> RawFd {
self.as_inner().fd()
}
}
#[allow(deprecated)]
+ #[stable(feature = "rust1", since = "1.0.0")]
impl AsRawFd for old_io::net::pipe::UnixStream {
- fn as_raw_fd(&self) -> Fd {
+ fn as_raw_fd(&self) -> RawFd {
self.as_inner().fd()
}
}
#[allow(deprecated)]
+ #[stable(feature = "rust1", since = "1.0.0")]
impl AsRawFd for old_io::net::pipe::UnixListener {
- fn as_raw_fd(&self) -> Fd {
+ fn as_raw_fd(&self) -> RawFd {
self.as_inner().fd()
}
}
#[allow(deprecated)]
+ #[stable(feature = "rust1", since = "1.0.0")]
impl AsRawFd for old_io::net::pipe::UnixAcceptor {
- fn as_raw_fd(&self) -> Fd {
+ fn as_raw_fd(&self) -> RawFd {
self.as_inner().fd()
}
}
+ #[stable(feature = "rust1", since = "1.0.0")]
#[allow(deprecated)]
impl AsRawFd for old_io::net::tcp::TcpStream {
- fn as_raw_fd(&self) -> Fd {
+ fn as_raw_fd(&self) -> RawFd {
self.as_inner().fd()
}
}
+ #[stable(feature = "rust1", since = "1.0.0")]
#[allow(deprecated)]
impl AsRawFd for old_io::net::tcp::TcpListener {
- fn as_raw_fd(&self) -> Fd {
+ fn as_raw_fd(&self) -> RawFd {
self.as_inner().fd()
}
}
+ #[stable(feature = "rust1", since = "1.0.0")]
#[allow(deprecated)]
impl AsRawFd for old_io::net::tcp::TcpAcceptor {
- fn as_raw_fd(&self) -> Fd {
+ fn as_raw_fd(&self) -> RawFd {
self.as_inner().fd()
}
}
#[allow(deprecated)]
+ #[stable(feature = "rust1", since = "1.0.0")]
impl AsRawFd for old_io::net::udp::UdpSocket {
- fn as_raw_fd(&self) -> Fd {
+ fn as_raw_fd(&self) -> RawFd {
self.as_inner().fd()
}
}
+ #[stable(feature = "rust1", since = "1.0.0")]
impl AsRawFd for net::TcpStream {
- fn as_raw_fd(&self) -> Fd { *self.as_inner().socket().as_inner() }
+ fn as_raw_fd(&self) -> RawFd { *self.as_inner().socket().as_inner() }
}
+ #[stable(feature = "rust1", since = "1.0.0")]
impl AsRawFd for net::TcpListener {
- fn as_raw_fd(&self) -> Fd { *self.as_inner().socket().as_inner() }
+ fn as_raw_fd(&self) -> RawFd { *self.as_inner().socket().as_inner() }
}
+ #[stable(feature = "rust1", since = "1.0.0")]
impl AsRawFd for net::UdpSocket {
- fn as_raw_fd(&self) -> Fd { *self.as_inner().socket().as_inner() }
+ fn as_raw_fd(&self) -> RawFd { *self.as_inner().socket().as_inner() }
+ }
+
+ #[unstable(feature = "from_raw_os", reason = "trait is unstable")]
+ impl FromRawFd for net::TcpStream {
+ fn from_raw_fd(fd: RawFd) -> net::TcpStream {
+ let socket = sys::net::Socket::from_inner(fd);
+ net::TcpStream::from_inner(net2::TcpStream::from_inner(socket))
+ }
+ }
+ #[unstable(feature = "from_raw_os", reason = "trait is unstable")]
+ impl FromRawFd for net::TcpListener {
+ fn from_raw_fd(fd: RawFd) -> net::TcpListener {
+ let socket = sys::net::Socket::from_inner(fd);
+ net::TcpListener::from_inner(net2::TcpListener::from_inner(socket))
+ }
+ }
+ #[unstable(feature = "from_raw_os", reason = "trait is unstable")]
+ impl FromRawFd for net::UdpSocket {
+ fn from_raw_fd(fd: RawFd) -> net::UdpSocket {
+ let socket = sys::net::Socket::from_inner(fd);
+ net::UdpSocket::from_inner(net2::UdpSocket::from_inner(socket))
+ }
}
}
/// Unix-specific extension to the primitives in the `std::ffi` module
#[stable(feature = "rust1", since = "1.0.0")]
pub mod ffi {
- use ffi::{CString, NulError, OsStr, OsString};
+ use ffi::{OsStr, OsString};
use mem;
use prelude::v1::*;
use sys::os_str::Buf;
/// Get the underlying byte view of the `OsStr` slice.
#[stable(feature = "rust1", since = "1.0.0")]
fn as_bytes(&self) -> &[u8];
-
- /// Convert the `OsStr` slice into a `CString`.
- #[stable(feature = "rust1", since = "1.0.0")]
- fn to_cstring(&self) -> Result<CString, NulError>;
}
#[stable(feature = "rust1", since = "1.0.0")]
fn as_bytes(&self) -> &[u8] {
&self.as_inner().inner
}
- fn to_cstring(&self) -> Result<CString, NulError> {
- CString::new(self.as_bytes())
- }
}
}
#[stable(feature = "rust1", since = "1.0.0")]
pub mod prelude {
#[doc(no_inline)]
- pub use super::io::{Fd, AsRawFd};
+ pub use super::io::{RawFd, AsRawFd};
#[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
pub use super::ffi::{OsStrExt, OsStringExt};
#[doc(no_inline)]
fn test_file_desc() {
// Run this test with some pipes so we don't have to mess around with
// opening or closing files.
- let os::Pipe { reader, writer } = unsafe { os::pipe().unwrap() };
- let mut reader = FileDesc::new(reader, true);
- let mut writer = FileDesc::new(writer, true);
+ let (mut reader, mut writer) = unsafe { ::sys::os::pipe().unwrap() };
writer.write(b"test").unwrap();
let mut buf = [0; 4];
use io::prelude::*;
use os::unix::prelude::*;
-use ffi::{CString, CStr, OsString, AsOsStr, OsStr};
+use ffi::{CString, CStr, OsString, OsStr};
use io::{self, Error, SeekFrom};
use libc::{self, c_int, size_t, off_t, c_char, mode_t};
use mem;
}
fn cstr(path: &Path) -> io::Result<CString> {
- let cstring = try!(path.as_os_str().to_cstring());
- Ok(cstring)
+ path.as_os_str().to_cstring().ok_or(
+ io::Error::new(io::ErrorKind::InvalidInput, "path contained a null"))
+}
+
+impl FromInner<c_int> for File {
+ fn from_inner(fd: c_int) -> File {
+ File(FileDesc::new(fd))
+ }
}
pub fn mkdir(p: &Path) -> io::Result<()> {
#![allow(deprecated)]
use libc;
-use os;
+use sys::os;
use sys::fs::FileDesc;
pub type signal = libc::c_int;
pub fn new() -> (signal, signal) {
- let os::Pipe { reader, writer } = unsafe { os::pipe().unwrap() };
- (reader, writer)
+ let (a, b) = unsafe { os::pipe().unwrap() };
+ (a.unwrap(), b.unwrap())
}
pub fn signal(fd: libc::c_int) {
use sys::c;
use net::SocketAddr;
use sys::fd::FileDesc;
-use sys_common::AsInner;
+use sys_common::{AsInner, FromInner};
pub use sys::{cvt, cvt_r};
.to_string()
};
Err(io::Error::new(io::ErrorKind::Other,
- "failed to lookup address information", Some(detail)))
+ &format!("failed to lookup address information: {}",
+ detail)[..]))
}
impl Socket {
impl AsInner<c_int> for Socket {
fn as_inner(&self) -> &c_int { self.0.as_inner() }
}
+
+impl FromInner<c_int> for Socket {
+ fn from_inner(fd: c_int) -> Socket { Socket(FileDesc::new(fd)) }
+}
use os::unix::prelude::*;
use error::Error as StdError;
-use ffi::{CString, CStr, OsString, OsStr, AsOsStr};
+use ffi::{CString, CStr, OsString, OsStr};
use fmt;
use io;
use iter;
}
pub fn chdir(p: &path::Path) -> io::Result<()> {
- let p = try!(CString::new(p.as_os_str().as_bytes()));
+ let p: &OsStr = p.as_ref();
+ let p = try!(CString::new(p.as_bytes()));
unsafe {
match libc::chdir(p.as_ptr()) == (0 as c_int) {
true => Ok(()),
pub struct JoinPathsError;
pub fn join_paths<I, T>(paths: I) -> Result<OsString, JoinPathsError>
- where I: Iterator<Item=T>, T: AsOsStr
+ where I: Iterator<Item=T>, T: AsRef<OsStr>
{
let mut joined = Vec::new();
let sep = b':';
for (i, path) in paths.enumerate() {
- let path = path.as_os_str().as_bytes();
+ let path = path.as_ref().as_bytes();
if i > 0 { joined.push(sep) }
if path.contains(&sep) {
return Err(JoinPathsError)
};
fn parse(input: &[u8]) -> (OsString, OsString) {
- let mut it = input.splitn(1, |b| *b == b'=');
+ let mut it = input.splitn(2, |b| *b == b'=');
let key = it.next().unwrap().to_vec();
let default: &[u8] = &[];
let val = it.next().unwrap_or(default).to_vec();
}
pub fn temp_dir() -> PathBuf {
- getenv("TMPDIR".as_os_str()).map(os2path).unwrap_or_else(|| {
+ getenv("TMPDIR".as_ref()).map(os2path).unwrap_or_else(|| {
if cfg!(target_os = "android") {
PathBuf::from("/data/local/tmp")
} else {
}
pub fn home_dir() -> Option<PathBuf> {
- return getenv("HOME".as_os_str()).or_else(|| unsafe {
+ return getenv("HOME".as_ref()).or_else(|| unsafe {
fallback()
}).map(os2path);
}
}
}
+
+pub fn exit(code: i32) -> ! {
+ unsafe { libc::exit(code as c_int) }
+}
use old_io::process::{ProcessExit, ExitStatus, ExitSignal};
use old_io::{IoResult, EndOfFile};
use libc::{self, pid_t, c_void, c_int};
+use io;
use mem;
-use os;
+use sys::os;
use old_path::BytesContainer;
use ptr;
use sync::mpsc::{channel, Sender, Receiver};
n if n > 0 => { ret = true; }
0 => return true,
-1 if wouldblock() => return ret,
- n => panic!("bad read {:?} ({:?})", os::last_os_error(), n),
+ n => panic!("bad read {} ({})",
+ io::Error::last_os_error(), n),
}
}
}
self.args.push(arg.to_cstring().unwrap())
}
pub fn args<'a, I: Iterator<Item = &'a OsStr>>(&mut self, args: I) {
- self.args.extend(args.map(|s| OsStrExt::to_cstring(s).unwrap()))
+ self.args.extend(args.map(|s| s.to_cstring().unwrap()))
}
fn init_env_map(&mut self) {
if self.env.is_none() {
use old_io::IoResult;
use libc;
use mem;
-use os;
+use sys::os;
+use io;
use ptr;
use sync::atomic::{self, Ordering};
use sync::mpsc::{channel, Sender, Receiver, TryRecvError};
-1 if os::errno() == libc::EINTR as i32 => {}
n => panic!("helper thread failed in select() with error: {} ({})",
- n, os::last_os_error())
+ n, io::Error::last_os_error())
}
}
}
pub const TOKEN_READ: libc::DWORD = 0x20008;
// Note that these are not actually HANDLEs, just values to pass to GetStdHandle
-pub const STD_INPUT_HANDLE: libc::DWORD = -10;
-pub const STD_OUTPUT_HANDLE: libc::DWORD = -11;
-pub const STD_ERROR_HANDLE: libc::DWORD = -12;
+pub const STD_INPUT_HANDLE: libc::DWORD = -10i32 as libc::DWORD;
+pub const STD_OUTPUT_HANDLE: libc::DWORD = -11i32 as libc::DWORD;
+pub const STD_ERROR_HANDLE: libc::DWORD = -12i32 as libc::DWORD;
#[repr(C)]
#[cfg(target_arch = "x86")]
pub type WSAEVENT = libc::HANDLE;
#[repr(C)]
-#[derive(Copy)]
pub struct WSAPROTOCOL_INFO {
pub dwServiceFlags1: libc::DWORD,
pub dwServiceFlags2: libc::DWORD,
TokenHandle: *mut libc::HANDLE) -> libc::BOOL;
pub fn GetCurrentProcess() -> libc::HANDLE;
pub fn GetStdHandle(which: libc::DWORD) -> libc::HANDLE;
+ pub fn ExitProcess(uExitCode: libc::c_uint) -> !;
}
#[link(name = "userenv")]
#![stable(feature = "rust1", since = "1.0.0")]
-#[unstable(feature = "io_ext",
- reason = "organization may change slightly and the primitives \
- provided may be tweaked")]
+#[stable(feature = "rust1", since = "1.0.0")]
pub mod io {
use fs;
use libc;
use net;
- use sys_common::AsInner;
+ use sys_common::{net2, AsInner, FromInner};
+ use sys;
#[allow(deprecated)]
use old_io;
/// Raw HANDLEs.
- pub type Handle = libc::HANDLE;
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub type RawHandle = libc::HANDLE;
/// Raw SOCKETs.
- pub type Socket = libc::SOCKET;
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub type RawSocket = libc::SOCKET;
/// Extract raw handles.
+ #[stable(feature = "rust1", since = "1.0.0")]
pub trait AsRawHandle {
/// Extract the raw handle, without taking any ownership.
- fn as_raw_handle(&self) -> Handle;
+ #[stable(feature = "rust1", since = "1.0.0")]
+ fn as_raw_handle(&self) -> RawHandle;
+ }
+
+ /// Construct I/O objects from raw handles.
+ #[unstable(feature = "from_raw_os",
+ reason = "recent addition to the std::os::windows::io module")]
+ pub trait FromRawHandle {
+ /// Construct a new I/O object from the specified raw handle.
+ ///
+ /// This function will **consume ownership** of the handle given,
+ /// passing responsibility for closing the handle to the returned
+ /// object.
+ fn from_raw_handle(handle: RawHandle) -> Self;
}
#[allow(deprecated)]
+ #[stable(feature = "rust1", since = "1.0.0")]
impl AsRawHandle for old_io::fs::File {
- fn as_raw_handle(&self) -> Handle {
+ fn as_raw_handle(&self) -> RawHandle {
self.as_inner().handle()
}
}
+ #[stable(feature = "rust1", since = "1.0.0")]
impl AsRawHandle for fs::File {
- fn as_raw_handle(&self) -> Handle {
+ fn as_raw_handle(&self) -> RawHandle {
self.as_inner().handle().raw()
}
}
+ #[unstable(feature = "from_raw_os", reason = "trait is unstable")]
+ impl FromRawHandle for fs::File {
+ fn from_raw_handle(handle: RawHandle) -> fs::File {
+ fs::File::from_inner(sys::fs2::File::from_inner(handle))
+ }
+ }
+
#[allow(deprecated)]
+ #[stable(feature = "rust1", since = "1.0.0")]
impl AsRawHandle for old_io::pipe::PipeStream {
- fn as_raw_handle(&self) -> Handle {
+ fn as_raw_handle(&self) -> RawHandle {
self.as_inner().handle()
}
}
#[allow(deprecated)]
+ #[stable(feature = "rust1", since = "1.0.0")]
impl AsRawHandle for old_io::net::pipe::UnixStream {
- fn as_raw_handle(&self) -> Handle {
+ fn as_raw_handle(&self) -> RawHandle {
self.as_inner().handle()
}
}
#[allow(deprecated)]
+ #[stable(feature = "rust1", since = "1.0.0")]
impl AsRawHandle for old_io::net::pipe::UnixListener {
- fn as_raw_handle(&self) -> Handle {
+ fn as_raw_handle(&self) -> RawHandle {
self.as_inner().handle()
}
}
#[allow(deprecated)]
+ #[stable(feature = "rust1", since = "1.0.0")]
impl AsRawHandle for old_io::net::pipe::UnixAcceptor {
- fn as_raw_handle(&self) -> Handle {
+ fn as_raw_handle(&self) -> RawHandle {
self.as_inner().handle()
}
}
/// Extract raw sockets.
+ #[stable(feature = "rust1", since = "1.0.0")]
pub trait AsRawSocket {
- fn as_raw_socket(&self) -> Socket;
+ /// Extract the underlying raw socket from this object.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ fn as_raw_socket(&self) -> RawSocket;
+ }
+
+ /// Create I/O objects from raw sockets.
+ #[unstable(feature = "from_raw_os", reason = "recent addition to module")]
+ pub trait FromRawSocket {
+ /// Creates a new I/O object from the given raw socket.
+ ///
+ /// This function will **consume ownership** of the socket provided and
+ /// it will be closed when the returned object goes out of scope.
+ fn from_raw_socket(sock: RawSocket) -> Self;
}
#[allow(deprecated)]
+ #[stable(feature = "rust1", since = "1.0.0")]
impl AsRawSocket for old_io::net::tcp::TcpStream {
- fn as_raw_socket(&self) -> Socket {
+ fn as_raw_socket(&self) -> RawSocket {
self.as_inner().fd()
}
}
#[allow(deprecated)]
+ #[stable(feature = "rust1", since = "1.0.0")]
impl AsRawSocket for old_io::net::tcp::TcpListener {
- fn as_raw_socket(&self) -> Socket {
+ fn as_raw_socket(&self) -> RawSocket {
self.as_inner().socket()
}
}
#[allow(deprecated)]
+ #[stable(feature = "rust1", since = "1.0.0")]
impl AsRawSocket for old_io::net::tcp::TcpAcceptor {
- fn as_raw_socket(&self) -> Socket {
+ fn as_raw_socket(&self) -> RawSocket {
self.as_inner().socket()
}
}
#[allow(deprecated)]
+ #[stable(feature = "rust1", since = "1.0.0")]
impl AsRawSocket for old_io::net::udp::UdpSocket {
- fn as_raw_socket(&self) -> Socket {
+ fn as_raw_socket(&self) -> RawSocket {
self.as_inner().fd()
}
}
+ #[stable(feature = "rust1", since = "1.0.0")]
impl AsRawSocket for net::TcpStream {
- fn as_raw_socket(&self) -> Socket { *self.as_inner().socket().as_inner() }
+ fn as_raw_socket(&self) -> RawSocket {
+ *self.as_inner().socket().as_inner()
+ }
}
+ #[stable(feature = "rust1", since = "1.0.0")]
impl AsRawSocket for net::TcpListener {
- fn as_raw_socket(&self) -> Socket { *self.as_inner().socket().as_inner() }
+ fn as_raw_socket(&self) -> RawSocket {
+ *self.as_inner().socket().as_inner()
+ }
}
+ #[stable(feature = "rust1", since = "1.0.0")]
impl AsRawSocket for net::UdpSocket {
- fn as_raw_socket(&self) -> Socket { *self.as_inner().socket().as_inner() }
+ fn as_raw_socket(&self) -> RawSocket {
+ *self.as_inner().socket().as_inner()
+ }
+ }
+
+ #[unstable(feature = "from_raw_os", reason = "trait is unstable")]
+ impl FromRawSocket for net::TcpStream {
+ fn from_raw_socket(sock: RawSocket) -> net::TcpStream {
+ let sock = sys::net::Socket::from_inner(sock);
+ net::TcpStream::from_inner(net2::TcpStream::from_inner(sock))
+ }
+ }
+ #[unstable(feature = "from_raw_os", reason = "trait is unstable")]
+ impl FromRawSocket for net::TcpListener {
+ fn from_raw_socket(sock: RawSocket) -> net::TcpListener {
+ let sock = sys::net::Socket::from_inner(sock);
+ net::TcpListener::from_inner(net2::TcpListener::from_inner(sock))
+ }
+ }
+ #[unstable(feature = "from_raw_os", reason = "trait is unstable")]
+ impl FromRawSocket for net::UdpSocket {
+ fn from_raw_socket(sock: RawSocket) -> net::UdpSocket {
+ let sock = sys::net::Socket::from_inner(sock);
+ net::UdpSocket::from_inner(net2::UdpSocket::from_inner(sock))
+ }
}
}
#[stable(feature = "rust1", since = "1.0.0")]
pub mod prelude {
#[doc(no_inline)]
- pub use super::io::{Socket, Handle, AsRawSocket, AsRawHandle};
+ pub use super::io::{RawSocket, RawHandle, AsRawSocket, AsRawHandle};
#[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
pub use super::ffi::{OsStrExt, OsStringExt};
#[doc(no_inline)]
}
}
- /// Extract the actual filedescriptor without closing it.
+ #[allow(dead_code)]
pub fn unwrap(self) -> fd_t {
let fd = self.fd;
unsafe { mem::forget(self) };
use path::{Path, PathBuf};
use ptr;
use sync::Arc;
-use sys::handle::Handle as RawHandle;
+use sys::handle::Handle;
use sys::{c, cvt};
+use sys_common::FromInner;
use vec::Vec;
-pub struct File { handle: RawHandle }
+pub struct File { handle: Handle }
pub struct FileAttr { data: c::WIN32_FILE_ATTRIBUTE_DATA }
pub struct ReadDir {
if handle == libc::INVALID_HANDLE_VALUE {
Err(Error::last_os_error())
} else {
- Ok(File { handle: RawHandle::new(handle) })
+ Ok(File { handle: Handle::new(handle) })
}
}
Ok(newpos as u64)
}
- pub fn handle(&self) -> &RawHandle { &self.handle }
+ pub fn handle(&self) -> &Handle { &self.handle }
+}
+
+impl FromInner<libc::HANDLE> for File {
+ fn from_inner(handle: libc::HANDLE) -> File {
+ File { handle: Handle::new(handle) }
+ }
}
pub fn to_utf16(s: &Path) -> Vec<u16> {
use rt;
use sync::{Once, ONCE_INIT};
use sys::c;
-use sys_common::AsInner;
+use sys_common::{AsInner, FromInner};
pub type wrlen_t = i32;
impl Drop for Socket {
fn drop(&mut self) {
- unsafe { cvt(libc::closesocket(self.0)).unwrap(); }
+ let _ = unsafe { libc::closesocket(self.0) };
}
}
impl AsInner<libc::SOCKET> for Socket {
fn as_inner(&self) -> &libc::SOCKET { &self.0 }
}
+
+impl FromInner<libc::SOCKET> for Socket {
+ fn from_inner(sock: libc::SOCKET) -> Socket { Socket(sock) }
+}
use os::windows::prelude::*;
use error::Error as StdError;
-use ffi::{OsString, OsStr, AsOsStr};
+use ffi::{OsString, OsStr};
use fmt;
use io;
use libc::types::os::arch::extra::LPWCH;
use slice;
use sys::c;
use sys::fs::FileDesc;
-use sys::handle::Handle as RawHandle;
+use sys::handle::Handle;
use libc::funcs::extra::kernel32::{
GetEnvironmentStringsW,
pub struct JoinPathsError;
pub fn join_paths<I, T>(paths: I) -> Result<OsString, JoinPathsError>
- where I: Iterator<Item=T>, T: AsOsStr
+ where I: Iterator<Item=T>, T: AsRef<OsStr>
{
let mut joined = Vec::new();
let sep = b';' as u16;
for (i, path) in paths.enumerate() {
- let path = path.as_os_str();
+ let path = path.as_ref();
if i > 0 { joined.push(sep) }
let v = path.encode_wide().collect::<Vec<u16>>();
if v.contains(&(b'"' as u16)) {
}
pub fn chdir(p: &path::Path) -> io::Result<()> {
- let mut p = p.as_os_str().encode_wide().collect::<Vec<_>>();
+ let p: &OsStr = p.as_ref();
+ let mut p = p.encode_wide().collect::<Vec<_>>();
p.push(0);
unsafe {
}
pub fn home_dir() -> Option<PathBuf> {
- getenv("HOME".as_os_str()).or_else(|| {
- getenv("USERPROFILE".as_os_str())
+ getenv("HOME".as_ref()).or_else(|| {
+ getenv("USERPROFILE".as_ref())
}).map(PathBuf::from).or_else(|| unsafe {
let me = c::GetCurrentProcess();
let mut token = ptr::null_mut();
if c::OpenProcessToken(me, c::TOKEN_READ, &mut token) == 0 {
return None
}
- let _handle = RawHandle::new(token);
+ let _handle = Handle::new(token);
super::fill_utf16_buf_new(|buf, mut sz| {
match c::GetUserProfileDirectoryW(token, buf, &mut sz) {
0 if libc::GetLastError() != 0 => 0,
}, super::os2path).ok()
})
}
+
+pub fn exit(code: i32) -> ! {
+ unsafe { c::ExitProcess(code as libc::c_uint) }
+}
use old_io::process::{ProcessExit, ExitStatus};
use old_io::{IoResult, IoError};
use old_io;
-use os;
+use fs::PathExt;
use old_path::{BytesContainer, GenericPath};
use ptr;
use str;
let program = cfg.env().and_then(|env| {
for (key, v) in env {
if b"PATH" != key.container_as_bytes() { continue }
+ let v = match ::str::from_utf8(v.container_as_bytes()) {
+ Ok(s) => s,
+ Err(..) => continue,
+ };
// Split the value and test each path to see if the
// program exists.
- for path in os::split_paths(v.container_as_bytes()) {
- let path = path.join(cfg.program().as_bytes())
+ for path in ::env::split_paths(v) {
+ let program = str::from_utf8(cfg.program().as_bytes()).unwrap();
+ let path = path.join(program)
.with_extension(env::consts::EXE_EXTENSION);
if path.exists() {
- return Some(CString::from_slice(path.as_vec()))
+ return Some(CString::new(path.to_str().unwrap()).unwrap())
}
}
break
#[test]
fn test_make_command_line() {
fn test_wrapper(prog: &str, args: &[&str]) -> String {
- make_command_line(&CString::from_slice(prog.as_bytes()),
+ make_command_line(&CString::new(prog).unwrap(),
&args.iter()
- .map(|a| CString::from_slice(a.as_bytes()))
+ .map(|a| CString::new(*a).unwrap())
.collect::<Vec<CString>>())
}
fn test_wrapper(prog: &str, args: &[&str]) -> String {
String::from_utf16(
&make_command_line(OsStr::from_str(prog),
- args.iter()
- .map(|a| OsString::from_str(a))
- .collect::<Vec<OsString>>()
- .as_slice())).unwrap()
+ &args.iter()
+ .map(|a| OsString::from(a))
+ .collect::<Vec<OsString>>())).unwrap()
}
assert_eq!(
Err(io::Error::last_os_error())
} else if handle.is_null() {
Err(io::Error::new(io::ErrorKind::Other,
- "no stdio handle available for this process", None))
+ "no stdio handle available for this process"))
} else {
let ret = NoClose::new(handle);
let mut out = 0;
}
fn invalid_encoding() -> io::Error {
- io::Error::new(io::ErrorKind::InvalidInput, "text was not valid unicode",
- None)
+ io::Error::new(io::ErrorKind::InvalidInput, "text was not valid unicode")
}
use old_io::net::ip;
use old_io::IoResult;
use libc;
+use libc::consts::os::extra::INVALID_SOCKET;
use mem;
use ptr;
use super::{last_error, last_net_error, sock_t};
match unsafe {
libc::accept(self.socket(), ptr::null_mut(), ptr::null_mut())
} {
- -1 if wouldblock() => {}
- -1 => return Err(last_net_error()),
+ INVALID_SOCKET if wouldblock() => {}
+ INVALID_SOCKET => return Err(last_net_error()),
// Accepted sockets inherit the same properties as the caller,
// so we need to deregister our event and switch the socket back
/// Indicator of the state of a thread local storage key.
#[unstable(feature = "std_misc",
reason = "state querying was recently added")]
-#[derive(Eq, PartialEq, Copy)]
+#[derive(Eq, PartialEq, Copy, Clone)]
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
}
}
}
-
- /// 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")))]
use thunk::Thunk;
use time::Duration;
-#[allow(deprecated)] use old_io::Writer;
-
////////////////////////////////////////////////////////////////////////////////
// Thread-local storage
////////////////////////////////////////////////////////////////////////////////
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
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))
+ self.spawn_inner(Box::new(f)).map(|i| JoinHandle(i))
}
/// Spawn a new child thread that must be joined within a given
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| {
+ self.spawn_inner(Box::new(f)).map(|inner| {
JoinGuard { inner: inner, _marker: PhantomData }
})
}
thread_info::set(imp::guard::current(), their_thread);
}
- let mut output = None;
+ let mut output: Option<T> = None;
let try_result = {
let ptr = &mut output;
// 'unwinding' flag in the thread itself. For these reasons,
// this unsafety should be ok.
unsafe {
- unwind::try(move || *ptr = Some(f.invoke(())))
+ unwind::try(move || {
+ let f: Thunk<(), T> = f;
+ let v: T = f();
+ *ptr = Some(v)
+ })
}
};
unsafe {
};
Ok(JoinInner {
- native: try!(unsafe { imp::create(stack_size, Thunk::new(main)) }),
+ native: try!(unsafe { imp::create(stack_size, Box::new(main)) }),
thread: my_thread,
packet: my_packet,
joined: false,
/// 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.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub fn sleep_ms(ms: u32) {
+ imp::sleep(Duration::milliseconds(ms as i64))
+}
+
+/// Deprecated: use `sleep_ms` instead.
#[unstable(feature = "thread_sleep",
reason = "recently added, needs an RFC, and `Duration` itself is \
unstable")]
+#[deprecated(since = "1.0.0", reason = "use sleep_ms instead")]
pub fn sleep(dur: Duration) {
imp::sleep(dur)
}
/// 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) {
+#[stable(feature = "rust1", since = "1.0.0")]
+pub fn park_timeout_ms(ms: u32) {
let thread = current();
let mut guard = thread.inner.lock.lock().unwrap();
if !*guard {
- let (g, _) = thread.inner.cvar.wait_timeout(guard, duration).unwrap();
+ let (g, _) = thread.inner.cvar.wait_timeout_ms(guard, ms).unwrap();
guard = g;
}
*guard = false;
}
+/// Deprecated: use `park_timeout_ms`
+#[unstable(feature = "std_misc", reason = "recently introduced, depends on Duration")]
+#[deprecated(since = "1.0.0", reason = "use park_timeout_ms instead")]
+pub fn park_timeout(duration: Duration) {
+ park_timeout_ms(duration.num_milliseconds() as u32)
+}
+
////////////////////////////////////////////////////////////////////////////////
// Thread
////////////////////////////////////////////////////////////////////////////////
}
}
- /// 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.
&self.inner.thread
}
- /// Wait for the associated thread to finish, returning the result of the thread's
- /// calculation.
+ /// Wait for the associated thread to finish, returning the result of the
+ /// thread's calculation.
///
/// # Panics
///
}
}
-#[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> {
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;
+ use u32;
// !!! These tests are dangerous. If something is buggy, they will hang, !!!
// !!! instead of exiting cleanly. This might wedge the buildbots. !!!
let x: Box<_> = box 1;
let x_in_parent = (&*x) as *const i32 as usize;
- spawnfn(Thunk::new(move|| {
+ spawnfn(Box::new(move|| {
let x_in_child = (&*x) as *const i32 as usize;
tx.send(x_in_child).unwrap();
}));
#[test]
fn test_avoid_copying_the_body_spawn() {
avoid_copying_the_body(|v| {
- thread::spawn(move || v.invoke(()));
+ thread::spawn(move || v());
});
}
fn test_avoid_copying_the_body_thread_spawn() {
avoid_copying_the_body(|f| {
thread::spawn(move|| {
- f.invoke(());
+ f();
});
})
}
fn test_avoid_copying_the_body_join() {
avoid_copying_the_body(|f| {
let _ = thread::spawn(move|| {
- f.invoke(())
+ f()
}).join();
})
}
// valgrind-friendly. try this at home, instead..!)
const GENERATIONS: u32 = 16;
fn child_no(x: u32) -> Thunk<'static> {
- return Thunk::new(move|| {
+ return Box::new(move|| {
if x < GENERATIONS {
- thread::spawn(move|| child_no(x+1).invoke(()));
+ thread::spawn(move|| child_no(x+1)());
}
});
}
- thread::spawn(|| child_no(0).invoke(()));
+ thread::spawn(|| child_no(0)());
}
#[test]
fn test_park_timeout_unpark_before() {
for _ in 0..10 {
thread::current().unpark();
- thread::park_timeout(Duration::seconds(10_000_000));
+ thread::park_timeout_ms(u32::MAX);
}
}
#[test]
fn test_park_timeout_unpark_not_called() {
for _ in 0..10 {
- thread::park_timeout(Duration::milliseconds(10));
+ thread::park_timeout_ms(10);
}
}
th.unpark();
});
- thread::park_timeout(Duration::seconds(10_000_000));
+ thread::park_timeout_ms(u32::MAX);
}
}
#[test]
- fn sleep_smoke() {
- thread::sleep(Duration::milliseconds(2));
- thread::sleep(Duration::milliseconds(-2));
+ fn sleep_ms_smoke() {
+ thread::sleep_ms(2);
}
// NOTE: the corresponding test for stderr is in run-pass/task-stderr, due
#![allow(missing_docs)]
#![unstable(feature = "std_misc")]
-use alloc::boxed::Box;
+use alloc::boxed::{Box, FnBox};
use core::marker::Send;
-use core::ops::FnOnce;
-pub struct Thunk<'a, A=(),R=()> {
- invoke: Box<Invoke<A,R>+Send + 'a>,
-}
+pub type Thunk<'a, A=(), R=()> =
+ Box<FnBox<A,Output=R> + Send + 'a>;
-impl<'a, R> Thunk<'a,(),R> {
- pub fn new<F>(func: F) -> Thunk<'a,(),R>
- where F : FnOnce() -> R, F : Send + 'a
- {
- Thunk::with_arg(move|()| func())
- }
-}
-
-impl<'a,A,R> Thunk<'a,A,R> {
- pub fn with_arg<F>(func: F) -> Thunk<'a,A,R>
- where F : FnOnce(A) -> R, F : Send + 'a
- {
- Thunk {
- invoke: Box::<F>::new(func)
- }
- }
-
- pub fn invoke(self, arg: A) -> R {
- self.invoke.invoke(arg)
- }
-}
-
-pub trait Invoke<A=(),R=()> {
- fn invoke(self: Box<Self>, arg: A) -> R;
-}
-
-impl<A,R,F> Invoke<A,R> for F
- where F : FnOnce(A) -> R
-{
- fn invoke(self: Box<F>, arg: A) -> R {
- let f = *self;
- f(arg)
- }
-}
use std::fmt;
-#[derive(Copy, PartialEq, Eq, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum Os {
OsWindows,
OsMacos,
}
#[allow(non_camel_case_types)]
-#[derive(Copy, PartialEq, Debug)]
+#[derive(Copy, Clone, PartialEq, Debug)]
pub enum Architecture {
X86,
X86_64,
Mipsel
}
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub struct AbiData {
abi: Abi,
name: &'static str,
}
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub enum AbiArchitecture {
/// Not a real ABI (e.g., intrinsic)
RustArch,
/// When parsing and doing expansions, we initially give all AST nodes this AST
/// node value. Then later, in the renumber pass, we renumber them to have
/// small, positive ids.
-pub const DUMMY_NODE_ID: NodeId = -1;
+pub const DUMMY_NODE_ID: NodeId = !0;
/// The AST represents all type param bounds as types.
/// typeck::collect::compute_bounds matches these against
/// - The default implementation for a trait method.
///
/// To construct one, use the `Code::from_node` function.
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub struct FnLikeNode<'a> { node: ast_map::Node<'a> }
/// MaybeFnLike wraps a method that indicates if an object
/// Carries either an FnLikeNode or a Block, as these are the two
/// constructs that correspond to "code" (as in, something from which
/// we can construct a control-flow graph).
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub enum Code<'a> {
FnLikeCode(FnLikeNode<'a>),
BlockCode(&'a Block),
}
#[derive(Clone)]
-struct LinkedPathNode<'a> {
+pub struct LinkedPathNode<'a> {
node: PathElem,
next: LinkedPath<'a>,
}
-type LinkedPath<'a> = Option<&'a LinkedPathNode<'a>>;
+#[derive(Copy, Clone)]
+pub struct LinkedPath<'a>(Option<&'a LinkedPathNode<'a>>);
+
+impl<'a> LinkedPath<'a> {
+ pub fn empty() -> LinkedPath<'a> {
+ LinkedPath(None)
+ }
+
+ pub fn from(node: &'a LinkedPathNode) -> LinkedPath<'a> {
+ LinkedPath(Some(node))
+ }
+}
impl<'a> Iterator for LinkedPath<'a> {
type Item = PathElem;
fn next(&mut self) -> Option<PathElem> {
- match *self {
+ match self.0 {
Some(node) => {
*self = node.next;
Some(node.node)
})
}
-#[derive(Copy, Debug)]
+#[derive(Copy, Clone, Debug)]
pub enum Node<'ast> {
NodeItem(&'ast Item),
NodeForeignItem(&'ast ForeignItem),
pub fn with_path<T, F>(&self, id: NodeId, f: F) -> T where
F: FnOnce(PathElems) -> T,
{
- self.with_path_next(id, None, f)
+ self.with_path_next(id, LinkedPath::empty(), f)
}
pub fn path_to_string(&self, id: NodeId) -> String {
_ => f([].iter().cloned().chain(next))
}
} else {
- self.with_path_next(parent, Some(&LinkedPathNode {
+ self.with_path_next(parent, LinkedPath::from(&LinkedPathNode {
node: self.get_path_elem(id),
next: next
}), f)
// ______________________________________________________________________
// Enumerating the IDs which appear in an AST
-#[derive(RustcEncodable, RustcDecodable, Debug, Copy)]
+#[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug)]
pub struct IdRange {
pub min: NodeId,
pub max: NodeId,
first_attr_value_str_by_name(attrs, "crate_name")
}
-#[derive(Copy, PartialEq)]
+#[derive(Copy, Clone, PartialEq)]
pub enum InlineAttr {
None,
Hint,
}
}
-#[derive(PartialEq, Debug, RustcEncodable, RustcDecodable, Copy)]
+#[derive(PartialEq, Debug, RustcEncodable, RustcDecodable, Copy, Clone)]
pub enum ReprAttr {
ReprAny,
ReprInt(Span, IntType),
}
}
-#[derive(Eq, Hash, PartialEq, Debug, RustcEncodable, RustcDecodable, Copy)]
+#[derive(Eq, Hash, PartialEq, Debug, RustcEncodable, RustcDecodable, Copy, Clone)]
pub enum IntType {
SignedInt(ast::IntTy),
UnsignedInt(ast::UintTy)
/// A character offset. Because of multibyte utf8 characters, a byte offset
/// is not equivalent to a character offset. The CodeMap will convert BytePos
/// values to CharPos values as necessary.
-#[derive(Copy, PartialEq, Hash, PartialOrd, Debug)]
+#[derive(Copy, Clone, PartialEq, Hash, PartialOrd, Debug)]
pub struct CharPos(pub usize);
// FIXME: Lots of boilerplate in these impls, but so far my attempts to fix
#[derive(PartialEq, Eq, Clone, Debug, Hash, RustcEncodable, RustcDecodable, Copy)]
pub struct ExpnId(u32);
-pub const NO_EXPANSION: ExpnId = ExpnId(-1);
+pub const NO_EXPANSION: ExpnId = ExpnId(!0);
// For code appearing from the command line
-pub const COMMAND_LINE_EXPN: ExpnId = ExpnId(-2);
+pub const COMMAND_LINE_EXPN: ExpnId = ExpnId(!1);
impl ExpnId {
pub fn from_llvm_cookie(cookie: c_uint) -> ExpnId {
}
/// Identifies an offset of a multi-byte character in a FileMap
-#[derive(Copy, RustcEncodable, RustcDecodable, Eq, PartialEq)]
+#[derive(Copy, Clone, RustcEncodable, RustcDecodable, Eq, PartialEq)]
pub struct MultiByteChar {
/// The absolute offset of the character in the CodeMap
pub pos: BytePos,
/// This structure is used to signify that a task has panicked with a fatal error
/// from the diagnostics. You can use this with the `Any` trait to figure out
/// how a rustc task died (if so desired).
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub struct FatalError;
/// Signifies that the compiler died with an explicit call to `.bug`
/// or `.span_bug` rather than a failed assertion, etc.
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub struct ExplicitBug;
/// A span-handler is like a handler but also
}
#[cfg(windows)]
fn stderr_isatty() -> bool {
- const STD_ERROR_HANDLE: libc::DWORD = -12;
+ const STD_ERROR_HANDLE: libc::DWORD = -12i32 as libc::DWORD;
extern "system" {
fn GetStdHandle(which: libc::DWORD) -> libc::HANDLE;
fn GetConsoleMode(hConsoleHandle: libc::HANDLE,
/// Fill-in macro expansion result, to allow compilation to continue
/// after hitting errors.
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub struct DummyResult {
expr_only: bool,
span: Span
trait_def.expand(cx, mitem, item, push)
}
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub enum OrderingOp {
PartialCmpOp, LtOp, LeOp, GtOp, GeOp,
}
// suggests that this can only occur in the presence of local-expand, which
// we have no plans to support. ... unless it's needed for item hygiene....
#[ignore]
- #[test] fn issue_8062(){
+ #[test]
+ fn issue_8062(){
run_renaming_test(
&("fn main() {let hrcoo = 19; macro_rules! getx(()=>(hrcoo)); getx!();}",
vec!(vec!(0)), true), 0)
// (just g) along the other, so the result of the whole thing should
// be "let z_123 = 3; z_123"
#[ignore]
- #[test] fn issue_6994(){
+ #[test]
+ fn issue_6994(){
run_renaming_test(
&("macro_rules! g (($x:ident) =>
({macro_rules! f(($y:ident)=>({let $y=3;$x}));f!($x)}));
// match variable hygiene. Should expand into
// fn z() {match 8 {x_1 => {match 9 {x_2 | x_2 if x_2 == x_1 => x_2 + x_1}}}}
- #[test] fn issue_9384(){
+ #[test]
+ fn issue_9384(){
run_renaming_test(
&("macro_rules! bad_macro (($ex:expr) => ({match 9 {x | x if x == $ex => x + $ex}}));
fn z() {match 8 {x => bad_macro!(x)}}",
// interpolated nodes weren't getting labeled.
// should expand into
// fn main(){let g1_1 = 13; g1_1}}
- #[test] fn pat_expand_issue_15221(){
+ #[test]
+ fn pat_expand_issue_15221(){
run_renaming_test(
&("macro_rules! inner ( ($e:pat ) => ($e));
macro_rules! outer ( ($e:pat ) => (inner!($e)));
// method arg hygiene
// method expands to fn get_x(&self_0, x_1: i32) {self_0 + self_2 + x_3 + x_1}
- #[test] fn method_arg_hygiene(){
+ #[test]
+ fn method_arg_hygiene(){
run_renaming_test(
&("macro_rules! inject_x (()=>(x));
macro_rules! inject_self (()=>(self));
// ooh, got another bite?
// expands to struct A; impl A {fn thingy(&self_1) {self_1;}}
- #[test] fn method_arg_hygiene_2(){
+ #[test]
+ fn method_arg_hygiene_2(){
run_renaming_test(
&("struct A;
macro_rules! add_method (($T:ty) =>
// item fn hygiene
// expands to fn q(x_1: i32){fn g(x_2: i32){x_2 + x_1};}
- #[test] fn issue_9383(){
+ #[test]
+ fn issue_9383(){
run_renaming_test(
&("macro_rules! bad_macro (($ex:expr) => (fn g(x: i32){ x + $ex }));
fn q(x: i32) { bad_macro!(x); }",
// closure arg hygiene (ExprClosure)
// expands to fn f(){(|x_1 : i32| {(x_2 + x_1)})(3);}
- #[test] fn closure_arg_hygiene(){
+ #[test]
+ fn closure_arg_hygiene(){
run_renaming_test(
&("macro_rules! inject_x (()=>(x));
fn f(){(|x : i32| {(inject_x!() + x)})(3);}",
}
// macro_rules in method position. Sadly, unimplemented.
- #[test] fn macro_in_method_posn(){
+ #[test]
+ fn macro_in_method_posn(){
expand_crate_str(
"macro_rules! my_method (() => (fn thirteen(&self) -> i32 {13}));
struct A;
// another nested macro
// expands to impl Entries {fn size_hint(&self_1) {self_1;}
- #[test] fn item_macro_workaround(){
+ #[test]
+ fn item_macro_workaround(){
run_renaming_test(
&("macro_rules! item { ($i:item) => {$i}}
struct Entries;
}
}
- #[test] fn fmt_in_macro_used_inside_module_macro() {
+ #[test]
+ fn fmt_in_macro_used_inside_module_macro() {
let crate_str = "macro_rules! fmt_wrap(($b:expr)=>($b.to_string()));
macro_rules! foo_module (() => (mod generated { fn a() { let xx = 147; fmt_wrap!(xx);}}));
foo_module!();
rename_memo: RefCell<HashMap<(SyntaxContext,Ident,Name),SyntaxContext>>,
}
-#[derive(PartialEq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
+#[derive(PartialEq, RustcEncodable, RustcDecodable, Hash, Debug, Copy, Clone)]
pub enum SyntaxContext_ {
EmptyCtxt,
Mark (Mrk,SyntaxContext),
use self::Status::*;
use self::AttributeType::*;
-use abi::RustIntrinsic;
+use abi::Abi;
use ast::NodeId;
use ast;
use attr;
("start", "1.0.0", Active),
("main", "1.0.0", Active),
+ ("fundamental", "1.0.0", Active),
+
// Deprecate after snapshot
- // SNAP a923278
+ // SNAP 5520801
("unsafe_destructor", "1.0.0", Active),
// A temporary feature gate used to enable parser extensions needed
// A way to temporarily opt out of opt in copy. This will *never* be accepted.
("opt_out_copy", "1.0.0", Removed),
- // A way to temporarily opt out of the new orphan rules. This will *never* be accepted.
- ("old_orphan_check", "1.0.0", Deprecated),
-
// OIBIT specific features
("optin_builtin_traits", "1.0.0", Active),
// #23121. Array patterns have some hazards yet.
("slice_patterns", "1.0.0", Active),
+
+ // Allows use of unary negate on unsigned integers, e.g. -e for e: u8
+ ("negate_unsigned", "1.0.0", Active),
];
// (changing above list without updating src/doc/reference.md makes @cmr sad)
/// currently being considered for addition/removal.
Active,
- /// Represents a feature gate that is temporarily enabling deprecated behavior.
- /// This gate will never be accepted.
- Deprecated,
-
/// Represents a feature which has since been removed (it was once Active)
Removed,
("allow_internal_unstable", Gated("allow_internal_unstable",
EXPLAIN_ALLOW_INTERNAL_UNSTABLE)),
+ ("fundamental", Gated("fundamental",
+ "the `#[fundamental]` attribute \
+ is an experimental feature")),
+
// FIXME: #14408 whitelist docs since rustdoc looks at them
("doc", Whitelisted),
("stable", Whitelisted),
("unstable", Whitelisted),
- // FIXME: #19470 this shouldn't be needed forever
- ("old_orphan_check", Whitelisted),
-
("rustc_paren_sugar", Gated("unboxed_closures",
"unboxed_closures are still evolving")),
("rustc_reflect_like", Gated("reflect",
("recursion_limit", CrateLevel),
];
-#[derive(PartialEq, Copy, Debug)]
+#[derive(PartialEq, Copy, Clone, Debug)]
pub enum AttributeType {
/// Normal, builtin attribute that is consumed
/// by the compiler before the unused_attribute check
pub allow_trace_macros: bool,
pub allow_internal_unstable: bool,
pub allow_custom_derive: bool,
- pub old_orphan_check: bool,
pub simd_ffi: bool,
pub unmarked_api: bool,
+ pub negate_unsigned: bool,
/// spans of #![feature] attrs for stable language features. for error reporting
pub declared_stable_lang_features: Vec<Span>,
/// #![feature] attrs for non-language (library) features
allow_trace_macros: false,
allow_internal_unstable: false,
allow_custom_derive: false,
- old_orphan_check: false,
simd_ffi: false,
unmarked_api: false,
+ negate_unsigned: false,
declared_stable_lang_features: Vec::new(),
declared_lib_features: Vec::new()
}
pub fn emit_feature_err(diag: &SpanHandler, feature: &str, span: Span, explain: &str) {
diag.span_err(span, explain);
+
+ // #23973: do not suggest `#![feature(...)]` if we are in beta/stable
+ if option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_some() { return; }
diag.fileline_help(span, &format!("add #![feature({})] to the \
crate attributes to enable",
feature));
pub fn emit_feature_warn(diag: &SpanHandler, feature: &str, span: Span, explain: &str) {
diag.span_warn(span, explain);
+
+ // #23973: do not suggest `#![feature(...)]` if we are in beta/stable
+ if option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_some() { return; }
if diag.handler.can_emit_warnings {
diag.fileline_help(span, &format!("add #![feature({})] to the \
crate attributes to silence this warning",
across platforms, it is recommended to \
use `#[link(name = \"foo\")]` instead")
}
- if foreign_module.abi == RustIntrinsic {
+ if foreign_module.abi == Abi::RustIntrinsic {
self.gate_feature("intrinsics",
i.span,
"intrinsics are subject to change")
},
_ => {}
}
-
- if attr::contains_name(&i.attrs[..],
- "old_orphan_check") {
- self.gate_feature(
- "old_orphan_check",
- i.span,
- "the new orphan check rules will eventually be strictly enforced");
- }
}
_ => {}
span: Span,
_node_id: NodeId) {
match fn_kind {
- visit::FkItemFn(_, _, _, abi) if abi == RustIntrinsic => {
+ visit::FkItemFn(_, _, _, abi) if abi == Abi::RustIntrinsic => {
self.gate_feature("intrinsics",
span,
"intrinsics are subject to change")
}
+ visit::FkItemFn(_, _, _, abi) |
+ visit::FkMethod(_, &ast::MethodSig { abi, .. }) if abi == Abi::RustCall => {
+ self.gate_feature("unboxed_closures",
+ span,
+ "rust-call ABI is subject to change")
+ }
_ => {}
}
visit::walk_fn(self, fn_kind, fn_decl, block, span);
Some(&(name, _, Active)) => {
cx.features.push(name);
}
- Some(&(name, _, Deprecated)) => {
- cx.features.push(name);
- span_handler.span_warn(
- mi.span,
- "feature is deprecated and will only be available \
- for a limited time, please rewrite code that relies on it");
- }
Some(&(_, _, Removed)) => {
span_handler.span_err(mi.span, "feature has been removed");
}
allow_trace_macros: cx.has_feature("trace_macros"),
allow_internal_unstable: cx.has_feature("allow_internal_unstable"),
allow_custom_derive: cx.has_feature("custom_derive"),
- old_orphan_check: cx.has_feature("old_orphan_check"),
simd_ffi: cx.has_feature("simd_ffi"),
unmarked_api: cx.has_feature("unmarked_api"),
+ negate_unsigned: cx.has_feature("negate_unsigned"),
declared_stable_lang_features: accepted_features,
declared_lib_features: unknown_features
}
#![feature(unicode)]
#![feature(path_ext)]
#![feature(str_char)]
-#![feature(convert)]
#![feature(into_cow)]
#![feature(slice_patterns)]
let base = 10;
// find the integer representing the name
- self.scan_digits(base);
- let encoded_name: u32 = self.with_str_from(start_bpos, |s| {
+ self.scan_digits(base, base);
+ let encoded_name : u32 = self.with_str_from(start_bpos, |s| {
u32::from_str_radix(s, 10).unwrap_or_else(|_| {
panic!("expected digits representing a name, got {:?}, {}, range [{:?},{:?}]",
s, whence, start_bpos, self.last_pos);
// find the integer representing the ctxt
let start_bpos = self.last_pos;
- self.scan_digits(base);
+ self.scan_digits(base, base);
let encoded_ctxt : ast::SyntaxContext = self.with_str_from(start_bpos, |s| {
u32::from_str_radix(s, 10).unwrap_or_else(|_| {
panic!("expected digits representing a ctxt, got {:?}, {}", s, whence);
ctxt: encoded_ctxt, }
}
- /// Scan through any digits (base `radix`) or underscores, and return how
- /// many digits there were.
- fn scan_digits(&mut self, radix: u32) -> usize {
+ /// Scan through any digits (base `scan_radix`) or underscores,
+ /// and return how many digits there were.
+ ///
+ /// `real_radix` represents the true radix of the number we're
+ /// interested in, and errors will be emitted for any digits
+ /// between `real_radix` and `scan_radix`.
+ fn scan_digits(&mut self, real_radix: u32, scan_radix: u32) -> usize {
+ assert!(real_radix <= scan_radix);
let mut len = 0;
loop {
let c = self.curr;
if c == Some('_') { debug!("skipping a _"); self.bump(); continue; }
- match c.and_then(|cc| cc.to_digit(radix)) {
+ match c.and_then(|cc| cc.to_digit(scan_radix)) {
Some(_) => {
debug!("{:?} in scan_digits", c);
+ // check that the hypothetical digit is actually
+ // in range for the true radix
+ if c.unwrap().to_digit(real_radix).is_none() {
+ self.err_span_(self.last_pos, self.pos,
+ &format!("invalid digit for a base {} literal",
+ real_radix));
+ }
len += 1;
self.bump();
}
if c == '0' {
match self.curr.unwrap_or('\0') {
- 'b' => { self.bump(); base = 2; num_digits = self.scan_digits(2); }
- 'o' => { self.bump(); base = 8; num_digits = self.scan_digits(8); }
- 'x' => { self.bump(); base = 16; num_digits = self.scan_digits(16); }
+ 'b' => { self.bump(); base = 2; num_digits = self.scan_digits(2, 10); }
+ 'o' => { self.bump(); base = 8; num_digits = self.scan_digits(8, 10); }
+ 'x' => { self.bump(); base = 16; num_digits = self.scan_digits(16, 16); }
'0'...'9' | '_' | '.' => {
- num_digits = self.scan_digits(10) + 1;
+ num_digits = self.scan_digits(10, 10) + 1;
}
_ => {
// just a 0
}
}
} else if c.is_digit(10) {
- num_digits = self.scan_digits(10) + 1;
+ num_digits = self.scan_digits(10, 10) + 1;
} else {
num_digits = 0;
}
// with a number
self.bump();
if self.curr.unwrap_or('\0').is_digit(10) {
- self.scan_digits(10);
+ self.scan_digits(10, 10);
self.scan_float_exponent();
}
let last_pos = self.last_pos;
if self.curr_is('-') || self.curr_is('+') {
self.bump();
}
- if self.scan_digits(10) == 0 {
+ if self.scan_digits(10, 10) == 0 {
self.err_span_(self.last_pos, self.pos, "expected at least one digit in exponent")
}
}
let res = match u64::from_str_radix(s, base).ok() {
Some(r) => r,
- None => { sd.span_err(sp, "int literal is too large"); 0 }
+ None => {
+ // small bases are lexed as if they were base 10, e.g, the string
+ // might be `0b10201`. This will cause the conversion above to fail,
+ // but these cases have errors in the lexer: we don't want to emit
+ // two errors, and we especially don't want to emit this error since
+ // it isn't necessarily true.
+ let already_errored = base < 10 &&
+ s.chars().any(|c| c.to_digit(10).map_or(false, |d| d >= base));
+
+ if !already_errored {
+ sd.span_err(sp, "int literal is too large");
+ }
+ 0
+ }
};
// adjust the sign
use ptr::P;
/// The specific types of unsupported syntax
-#[derive(Copy, PartialEq, Eq, Hash)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub enum ObsoleteSyntax {
ClosureKind,
ExternCrateString,
/// How to parse a path. There are four different kinds of paths, all of which
/// are parsed somewhat differently.
-#[derive(Copy, PartialEq)]
+#[derive(Copy, Clone, PartialEq)]
pub enum PathParsingMode {
/// A path with no type parameters; e.g. `foo::bar::Baz`
NoTypesAllowed,
}
/// How to parse a bound, whether to allow bound modifiers such as `?`.
-#[derive(Copy, PartialEq)]
+#[derive(Copy, Clone, PartialEq)]
pub enum BoundParsingMode {
Bare,
Modified,
s
}
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub enum PrintStackBreak {
Fits,
Broken(Breaks),
}
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub struct PrintStackElem {
offset: isize,
pbreak: PrintStackBreak
NodeName(&'a ast::Name),
NodeBlock(&'a ast::Block),
NodeItem(&'a ast::Item),
+ NodeSubItem(ast::NodeId),
NodeExpr(&'a ast::Expr),
NodePat(&'a ast::Pat),
}
fn post(&self, _state: &mut State, _node: AnnNode) -> io::Result<()> { Ok(()) }
}
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub struct NoAnn;
impl PpAnn for NoAnn {}
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub struct CurrentCommentAndLiteral {
cur_cmnt: usize,
cur_lit: usize,
pub fn print_trait_item(&mut self, ti: &ast::TraitItem)
-> io::Result<()> {
+ try!(self.ann.pre(self, NodeSubItem(ti.id)));
try!(self.hardbreak_if_not_bol());
try!(self.maybe_print_comment(ti.span.lo));
try!(self.print_outer_attributes(&ti.attrs));
try!(self.print_method_sig(ti.ident, sig, ast::Inherited));
if let Some(ref body) = *body {
try!(self.nbsp());
- self.print_block_with_attrs(body, &ti.attrs)
+ try!(self.print_block_with_attrs(body, &ti.attrs));
} else {
- word(&mut self.s, ";")
+ try!(word(&mut self.s, ";"));
}
}
ast::TypeTraitItem(ref bounds, ref default) => {
- self.print_associated_type(ti.ident, Some(bounds),
- default.as_ref().map(|ty| &**ty))
+ try!(self.print_associated_type(ti.ident, Some(bounds),
+ default.as_ref().map(|ty| &**ty)));
}
}
+ self.ann.post(self, NodeSubItem(ti.id))
}
pub fn print_impl_item(&mut self, ii: &ast::ImplItem) -> io::Result<()> {
+ try!(self.ann.pre(self, NodeSubItem(ii.id)));
try!(self.hardbreak_if_not_bol());
try!(self.maybe_print_comment(ii.span.lo));
try!(self.print_outer_attributes(&ii.attrs));
try!(self.head(""));
try!(self.print_method_sig(ii.ident, sig, ii.vis));
try!(self.nbsp());
- self.print_block_with_attrs(body, &ii.attrs)
+ try!(self.print_block_with_attrs(body, &ii.attrs));
}
ast::TypeImplItem(ref ty) => {
- self.print_associated_type(ii.ident, None, Some(ty))
+ try!(self.print_associated_type(ii.ident, None, Some(ty)));
}
ast::MacImplItem(codemap::Spanned { node: ast::MacInvocTT(ref pth, ref tts, _),
..}) => {
try!(self.print_tts(&tts[..]));
try!(self.pclose());
try!(word(&mut self.s, ";"));
- self.end()
+ try!(self.end())
}
}
+ self.ann.post(self, NodeSubItem(ii.id))
}
pub fn print_outer_attributes(&mut self,
#[test]
fn test_signed_int_to_string() {
let pos_int = ast::LitInt(42, ast::SignedIntLit(ast::TyI32, ast::Plus));
- let neg_int = ast::LitInt((-42) as u64, ast::SignedIntLit(ast::TyI32, ast::Minus));
+ let neg_int = ast::LitInt((!42 + 1) as u64, ast::SignedIntLit(ast::TyI32, ast::Minus));
assert_eq!(format!("-{}", lit_to_string(&codemap::dummy_spanned(pos_int))),
lit_to_string(&codemap::dummy_spanned(neg_int)));
}
fn test_move_iter() {
let v = SmallVector::zero();
let v: Vec<isize> = v.into_iter().collect();
- assert_eq!(Vec::new(), v);
+ assert_eq!(v, Vec::new());
let v = SmallVector::one(1);
- assert_eq!([1], v.into_iter().collect::<Vec<_>>());
+ assert_eq!(v.into_iter().collect::<Vec<_>>(), [1]);
let v = SmallVector::many(vec![1, 2, 3]);
- assert_eq!([1, 2, 3], v.into_iter().collect::<Vec<_>>());
+ assert_eq!(v.into_iter().collect::<Vec<_>>(), [1, 2, 3]);
}
#[test]
use ptr::P;
use owned_slice::OwnedSlice;
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub enum FnKind<'a> {
/// fn foo() or extern "Abi" fn foo()
FkItemFn(Ident, &'a Generics, Unsafety, Abi),
#![feature(std_misc)]
#![feature(str_char)]
#![feature(path_ext)]
-#![feature(convert)]
#![cfg_attr(windows, feature(libc))]
#[macro_use] extern crate log;
/// Most attributes can only be turned on and must be turned off with term.reset().
/// The ones that can be turned off explicitly take a boolean value.
/// Color is also represented as an attribute for convenience.
- #[derive(Copy)]
+ #[derive(Copy, Clone)]
pub enum Attr {
/// Bold (or possibly bright) mode
Bold,
use std::mem::replace;
use std::iter::repeat;
-#[derive(Copy, PartialEq)]
+#[derive(Copy, Clone, PartialEq)]
enum States {
Nothing,
Percent,
SeekIfEndPercent(isize)
}
-#[derive(Copy, PartialEq)]
+#[derive(Copy, Clone, PartialEq)]
enum FormatState {
FormatStateFlags,
FormatStateWidth,
Ok(output)
}
-#[derive(Copy, PartialEq)]
+#[derive(Copy, Clone, PartialEq)]
struct Flags {
width: usize,
precision: usize,
}
}
-#[derive(Copy)]
+#[derive(Copy, Clone)]
enum FormatOp {
FormatDigit,
FormatOctal,
// terminal! Admittedly, this is fragile, since stderr could be
// redirected to a different console. This is good enough for
// rustc though. See #13400.
- let out = GetStdHandle(-11);
+ let out = GetStdHandle(-11i32 as libc::DWORD);
SetConsoleTextAttribute(out, accum);
}
}
let bg;
unsafe {
let mut buffer_info = ::std::mem::uninitialized();
- if GetConsoleScreenBufferInfo(GetStdHandle(-11), &mut buffer_info) != 0 {
+ if GetConsoleScreenBufferInfo(GetStdHandle(-11i32 as libc::DWORD),
+ &mut buffer_info) != 0 {
fg = bits_to_color(buffer_info.wAttributes);
bg = bits_to_color(buffer_info.wAttributes >> 4);
} else {
#![feature(std_misc)]
#![feature(libc)]
#![feature(set_stdio)]
-#![feature(os)]
-#![feature(convert)]
#![cfg_attr(test, feature(old_io))]
extern crate getopts;
use stats::Stats;
use getopts::{OptGroup, optflag, optopt};
use serialize::Encodable;
+use std::boxed::FnBox;
use term::Terminal;
use term::color::{Color, RED, YELLOW, GREEN, CYAN};
use std::sync::mpsc::{channel, Sender};
use std::sync::{Arc, Mutex};
use std::thread;
-use std::thunk::{Thunk, Invoke};
+use std::thunk::Thunk;
use std::time::Duration;
// to be used by rustc to compile tests in libtest
StaticBenchFn(fn(&mut Bencher)),
StaticMetricFn(fn(&mut MetricMap)),
DynTestFn(Thunk<'static>),
- DynMetricFn(Box<for<'a> Invoke<&'a mut MetricMap>+'static>),
+ DynMetricFn(Box<FnBox(&mut MetricMap)+Send>),
DynBenchFn(Box<TDynBenchFn+'static>)
}
/// This is fed into functions marked with `#[bench]` to allow for
/// set-up & tear-down before running a piece of code repeatedly via a
/// call to `iter`.
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub struct Bencher {
iterations: u64,
dur: Duration,
test_main(&args, owned_tests)
}
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub enum ColorConfig {
AutoColor,
AlwaysColor,
}
#[cfg(windows)]
fn stdout_isatty() -> bool {
- const STD_OUTPUT_HANDLE: libc::DWORD = -11;
+ const STD_OUTPUT_HANDLE: libc::DWORD = -11i32 as libc::DWORD;
extern "system" {
fn GetStdHandle(which: libc::DWORD) -> libc::HANDLE;
fn GetConsoleMode(hConsoleHandle: libc::HANDLE,
if std::rt::util::limit_thread_creation_due_to_osx_and_valgrind() {
1
} else {
- std::os::num_cpus()
+ extern { fn rust_get_num_cpus() -> libc::uintptr_t; }
+ unsafe { rust_get_num_cpus() as usize }
}
}
}
io::set_print(box Sink(data2.clone()));
io::set_panic(box Sink(data2));
}
- testfn.invoke(())
+ testfn()
}).unwrap();
let test_result = calc_result(&desc, result_guard.join());
let stdout = data.lock().unwrap().to_vec();
}
DynMetricFn(f) => {
let mut mm = MetricMap::new();
- f.invoke(&mut mm);
+ f.call_box((&mut mm,));
monitor_ch.send((desc, TrMetrics(mm), Vec::new())).unwrap();
return;
}
}
DynTestFn(f) => run_test_inner(desc, monitor_ch, opts.nocapture, f),
StaticTestFn(f) => run_test_inner(desc, monitor_ch, opts.nocapture,
- Thunk::new(move|| f()))
+ Box::new(move|| f()))
}
}
ignore: true,
should_panic: ShouldPanic::No,
},
- testfn: DynTestFn(Thunk::new(move|| f())),
+ testfn: DynTestFn(Box::new(move|| f())),
};
let (tx, rx) = channel();
run_test(&TestOpts::new(), false, desc, tx);
ignore: true,
should_panic: ShouldPanic::No,
},
- testfn: DynTestFn(Thunk::new(move|| f())),
+ testfn: DynTestFn(Box::new(move|| f())),
};
let (tx, rx) = channel();
run_test(&TestOpts::new(), false, desc, tx);
ignore: false,
should_panic: ShouldPanic::Yes(None)
},
- testfn: DynTestFn(Thunk::new(move|| f())),
+ testfn: DynTestFn(Box::new(move|| f())),
};
let (tx, rx) = channel();
run_test(&TestOpts::new(), false, desc, tx);
ignore: false,
should_panic: ShouldPanic::Yes(Some("error message"))
},
- testfn: DynTestFn(Thunk::new(move|| f())),
+ testfn: DynTestFn(Box::new(move|| f())),
};
let (tx, rx) = channel();
run_test(&TestOpts::new(), false, desc, tx);
ignore: false,
should_panic: ShouldPanic::Yes(Some("foobar"))
},
- testfn: DynTestFn(Thunk::new(move|| f())),
+ testfn: DynTestFn(Box::new(move|| f())),
};
let (tx, rx) = channel();
run_test(&TestOpts::new(), false, desc, tx);
ignore: false,
should_panic: ShouldPanic::Yes(None)
},
- testfn: DynTestFn(Thunk::new(move|| f())),
+ testfn: DynTestFn(Box::new(move|| f())),
};
let (tx, rx) = channel();
run_test(&TestOpts::new(), false, desc, tx);
ignore: true,
should_panic: ShouldPanic::No,
},
- testfn: DynTestFn(Thunk::new(move|| {})),
+ testfn: DynTestFn(Box::new(move|| {})),
},
TestDescAndFn {
desc: TestDesc {
ignore: false,
should_panic: ShouldPanic::No,
},
- testfn: DynTestFn(Thunk::new(move|| {})),
+ testfn: DynTestFn(Box::new(move|| {})),
});
let filtered = filter_tests(&opts, tests);
ignore: false,
should_panic: ShouldPanic::No,
},
- testfn: DynTestFn(Thunk::new(testfn)),
+ testfn: DynTestFn(Box::new(testfn)),
};
tests.push(test);
}
#![feature(rustdoc)]
#![feature(rustc_private)]
#![feature(path_relative_from)]
-#![feature(convert)]
extern crate rustdoc;
extern crate rustc_back;
+S 2015-03-27 5520801
+ bitrig-x86_64 55a69b0ae5481ccda54c2fcfc54025a0945c4f57
+ freebsd-x86_64 0910bbad35e213f679d0433884fd51398eb3bc8d
+ linux-i386 1ef82402ed16f5a6d2f87a9a62eaa83170e249ec
+ linux-x86_64 ef2154372e97a3cb687897d027fd51c8f2c5f349
+ macos-i386 0310b1a970f2da7e61770fd14dbbbdca3b518234
+ macos-x86_64 5f35d9c920b8083a7420ef8cf5b00d5ef3085dfa
+ winnt-i386 808b7961f85872f04ec15ad0d3e9e23ae9bc0c3b
+ winnt-x86_64 903a99a58f57a9bd9848cc68a2445dda881f1ee8
+
S 2015-03-25 a923278
- bitrig-x86_64 41de2c7a69a1ac648d3fa3b65e96a29bdc122163
+ bitrig-x86_64 e56c400a04bca7b52ab54e0780484bb68fa449c2
freebsd-x86_64 cd02c86a9218da73b2a45aff293787010d33bf3e
linux-i386 da50141558eed6dabab97b79b2c6a7de4f2d2c5e
linux-x86_64 bca03458d28d07506bad4b80e5770b2117286244
--- /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.
+
+#![crate_type = "rlib"]
+#![feature(fundamental)]
+
+use std::marker::MarkerTrait;
+
+pub trait MyCopy : MarkerTrait { }
+impl MyCopy for i32 { }
+
+pub struct MyStruct<T>(T);
+
+#[fundamental]
+pub struct MyFundamentalStruct<T>(T);
pub mod hidden_core {
use super::aliases::B;
- #[derive(Copy)]
+ #[derive(Copy, Clone)]
pub struct A;
pub fn make() -> B { A }
pub use private::P;
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub struct S {
p: P,
}
mod private {
- #[derive(Copy)]
+ #[derive(Copy, Clone)]
pub struct P {
p: i32,
}
pub fn get_count() -> u64 { unsafe { COUNT } }
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub struct Foo;
impl Foo {
pub fn get_count() -> u64 { unsafe { COUNT } }
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub struct Foo;
impl Foo {
#![crate_name="struct_variant_xc_aux"]
#![crate_type = "lib"]
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub enum Enum {
Variant(u8),
StructVariant { arg: u8 }
// used by the rpass test
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub struct Struct;
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub enum Unit {
UnitVariant,
Argument(Struct)
}
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub struct TupleStruct(pub usize, pub &'static str);
// used by the cfail test
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub struct StructWithFields {
foo: isize,
}
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub enum EnumWithVariants {
EnumVariant,
EnumVariantArg(isize)
use std::num::Float;
use std::rand::{Rng, StdRng};
-#[derive(Copy)]
+#[derive(Copy, Clone)]
struct Vec2 {
x: f32,
y: f32,
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
// OF THE POSSIBILITY OF SUCH DAMAGE.
-#![feature(rustc_private, core)]
+#![feature(rustc_private, core, step_by)]
extern crate arena;
-use std::iter::range_step;
use std::thread;
use arena::TypedArena;
let long_lived_arena = TypedArena::new();
let long_lived_tree = bottom_up_tree(&long_lived_arena, 0, max_depth);
- let messages = range_step(min_depth, max_depth + 1, 2).map(|depth| {
+ let messages = (min_depth..max_depth + 1).step_by(2).map(|depth| {
use std::num::Int;
let iterations = 2.pow((max_depth - depth + min_depth) as u32);
thread::scoped(move || inner(depth, iterations))
}
}
-#[derive(Copy)]
+#[derive(Copy, Clone)]
enum Color {
Red,
Yellow,
}
}
-#[derive(Copy)]
+#[derive(Copy, Clone)]
struct CreatureInfo {
name: usize,
color: Color
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
// OF THE POSSIBILITY OF SUCH DAMAGE.
-#![feature(core)]
+#![feature(step_by)]
-use std::{cmp, iter, mem};
+use std::{cmp, mem};
use std::thread;
fn rotate(x: &mut [i32]) {
}
}
-#[derive(Copy)]
+#[derive(Copy, Clone)]
struct P {
p: [i32; 16],
}
-#[derive(Copy)]
+#[derive(Copy, Clone)]
struct Perm {
cnt: [i32; 16],
fact: [u32; 16],
let mut futures = vec![];
let k = perm.max() / N;
- for (_, j) in (0..N).zip(iter::count(0, k)) {
+ for (_, j) in (0..N).zip((0..).step_by(k)) {
let max = cmp::min(j+k, perm.max());
futures.push(thread::scoped(move|| {
result
}
-#[derive(Copy)]
+#[derive(Copy, Clone)]
struct AminoAcid {
c: u8,
p: f32,
// start processing if this is the one
('>', false) => {
- match line[1..].find_str("THREE") {
+ match line[1..].find("THREE") {
Some(_) => { proc_mode = true; }
None => { }
}
// Code implementation
-#[derive(Copy, PartialEq, PartialOrd, Ord, Eq)]
+#[derive(Copy, Clone, PartialEq, PartialOrd, Ord, Eq)]
struct Code(u64);
impl Code {
},
];
-#[derive(Copy)]
+#[derive(Copy, Clone)]
struct Planet {
x: f64, y: f64, z: f64,
vx: f64, vy: f64, vz: f64,
fn parallel<'a,T, F>(v: &mut [T], ref f: F)
where T: Send + Sync + 'a,
F: Fn(usize, &mut [T]) + Sync + 'a {
- let size = v.len() / os::num_cpus() + 1;
+ // FIXME: pick a more appropriate parallel factor
+ let parallelism = 4;
+ let size = v.len() / parallelism + 1;
v.chunks_mut(size).enumerate().map(|(i, chunk)| {
thread::scoped(move|| {
f(i * size, chunk)
#[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
// except according to those terms.
-#[derive(Copy)]
+#[derive(Copy, Clone)]
struct Foo {
bar1: Bar,
bar2: Bar
}
-#[derive(Copy)]
+#[derive(Copy, Clone)]
struct Bar {
int1: isize,
int2: isize,
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#[derive(Copy)]
+#[derive(Copy, Clone)]
struct Foo {
bar1: Bar,
bar2: Bar
}
-#[derive(Copy)]
+#[derive(Copy, Clone)]
struct Bar {
int1: isize,
int2: isize,
use std::ops::Add;
-#[derive(Copy)]
+#[derive(Copy, Clone)]
struct Point {
x: isize,
y: isize,
#![feature(box_syntax)]
-#[derive(Copy)]
+#[derive(Copy, Clone)]
struct A { a: isize, b: isize }
struct B { a: isize, b: Box<isize> }
--- /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.
+
+// aux-build:coherence_lib.rs
+
+// pretty-expanded FIXME #23616
+
+// Test that the `Pair` type reports an error if it contains type
+// parameters, even when they are covered by local types. This test
+// was originally intended to test the opposite, but the rules changed
+// with RFC 1023 and this became illegal.
+
+extern crate coherence_lib as lib;
+use lib::{Remote,Pair};
+
+pub struct Cover<T>(T);
+
+impl<T> Remote for Pair<T,Cover<T>> { }
+//~^ ERROR E0210
+
+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.
+
+// aux-build:coherence_lib.rs
+
+// Test that the `Pair` type reports an error if it contains type
+// parameters, even when they are covered by local types. This test
+// was originally intended to test the opposite, but the rules changed
+// with RFC 1023 and this became illegal.
+
+// pretty-expanded FIXME #23616
+
+extern crate coherence_lib as lib;
+use lib::{Remote,Pair};
+
+pub struct Cover<T>(T);
+
+impl<T> Remote for Pair<Cover<T>,T> { } //~ ERROR E0210
+
+fn main() { }
// aux-build:coherence_lib.rs
-// Test that it's not ok for U to appear uncovered
+// Test that it's not ok for T to appear uncovered
extern crate coherence_lib as lib;
use lib::{Remote,Pair};
pub struct Cover<T>(T);
impl<T,U> Remote for Pair<Cover<T>,U> { }
-//~^ ERROR type parameter `U` must be used as the type parameter for some local type
+//~^ ERROR type parameter `T` must be used as the type parameter for some local type
fn main() { }
impl !Sync for NotSync {}
impl Copy for TestE {}
+impl Clone for TestE { fn clone(&self) -> Self { *self } }
+
impl Copy for MyType {}
+
+impl Copy for &'static mut MyType {}
+//~^ ERROR E0206
+//~| ERROR E0277
+//~| ERROR E0277
+impl Clone for MyType { fn clone(&self) -> Self { *self } }
+
impl Copy for (MyType, MyType) {}
//~^ ERROR E0206
+//~| ERROR E0117
impl Copy for &'static NotSync {}
//~^ ERROR E0206
impl Copy for [MyType] {}
//~^ ERROR E0206
+//~| ERROR E0117
+//~| ERROR E0277
+//~| ERROR E0277
impl Copy for &'static [NotSync] {}
//~^ ERROR E0206
+//~| ERROR E0117
fn main() {
}
unsafe impl Send for TestE {}
unsafe impl Send for MyType {}
unsafe impl Send for (MyType, MyType) {}
-//~^ ERROR E0321
+//~^ ERROR E0117
unsafe impl Send for &'static NotSync {}
//~^ ERROR E0321
unsafe impl Send for [MyType] {}
-//~^ ERROR E0321
+//~^ ERROR E0117
unsafe impl Send for &'static [NotSync] {}
-//~^ ERROR E0321
-//~| ERROR conflicting implementations
+//~^ ERROR E0117
+//~| ERROR E0119
fn main() {
}
impl !Sync for NotSync {}
impl Sized for TestE {} //~ ERROR E0322
+
impl Sized for MyType {} //~ ERROR E0322
-impl Sized for (MyType, MyType) {} //~ ERROR E0322
+
+impl Sized for (MyType, MyType) {} //~ ERROR E0117
+
impl Sized for &'static NotSync {} //~ ERROR E0322
-impl Sized for [MyType] {} //~ ERROR E0322
+
+impl Sized for [MyType] {} //~ ERROR E0117
//~^ ERROR E0277
-impl Sized for &'static [NotSync] {} //~ ERROR E0322
+
+impl Sized for &'static [NotSync] {} //~ ERROR E0117
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.
+
+// Tests that we consider `Box<U>: !Sugar` to be ambiguous, even
+// though we see no impl of `Sugar` for `Box`. Therefore, an overlap
+// error is reported for the following pair of impls (#23516).
+
+pub trait Sugar { fn dummy(&self) { } }
+pub trait Sweet { fn dummy(&self) { } }
+impl<T:Sugar> Sweet for T { } //~ ERROR E0119
+impl<U:Sugar> Sweet for Box<U> { }
+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.
+
+// Test that a local, generic type appearing within a
+// *non-fundamental* remote type like `Vec` is not considered local.
+
+// aux-build:coherence_lib.rs
+
+// pretty-expanded FIXME #23616
+
+extern crate coherence_lib as lib;
+use lib::Remote;
+
+struct Local<T>(T);
+
+impl<T> Remote for Vec<Local<T>> { } //~ ERROR E0210
+
+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.
+
+// Test that a local type (with no type parameters) appearing within a
+// *non-fundamental* remote type like `Vec` is not considered local.
+
+// aux-build:coherence_lib.rs
+
+// pretty-expanded FIXME #23616
+
+extern crate coherence_lib as lib;
+use lib::Remote;
+
+struct Local;
+
+impl Remote for Vec<Local> { } //~ ERROR E0117
+
+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.
+
+// Test that we are able to introduce a negative constraint that
+// `MyType: !MyTrait` along with other "fundamental" wrappers.
+
+// aux-build:coherence_copy_like_lib.rs
+
+#![feature(rustc_attrs)]
+#![allow(dead_code)]
+
+extern crate coherence_copy_like_lib as lib;
+
+use std::marker::MarkerTrait;
+
+struct MyType { x: i32 }
+
+trait MyTrait : MarkerTrait { }
+impl<T: lib::MyCopy> MyTrait for T { }
+
+// `MyFundamentalStruct` is declared fundamental, so we can test that
+//
+// MyFundamentalStruct<MyTrait>: !MyTrait
+//
+// Huzzah.
+impl MyTrait for lib::MyFundamentalStruct<MyType> { }
+
+#[rustc_error]
+fn main() { } //~ ERROR compilation successful
--- /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 we are able to introduce a negative constraint that
+// `MyType: !MyTrait` along with other "fundamental" wrappers.
+
+// aux-build:coherence_copy_like_lib.rs
+
+#![feature(rustc_attrs)]
+#![allow(dead_code)]
+
+extern crate coherence_copy_like_lib as lib;
+
+use std::marker::MarkerTrait;
+
+struct MyType { x: i32 }
+
+trait MyTrait : MarkerTrait { }
+impl<T: lib::MyCopy> MyTrait for T { }
+
+// `MyFundamentalStruct` is declared fundamental, so we can test that
+//
+// MyFundamentalStruct<&MyTrait>: !MyTrait
+//
+// Huzzah.
+impl<'a> MyTrait for lib::MyFundamentalStruct<&'a MyType> { }
+
+#[rustc_error]
+fn main() { } //~ ERROR compilation successful
--- /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 we are able to introduce a negative constraint that
+// `MyType: !MyTrait` along with other "fundamental" wrappers.
+
+// aux-build:coherence_copy_like_lib.rs
+
+#![feature(rustc_attrs)]
+
+extern crate coherence_copy_like_lib as lib;
+
+use std::marker::MarkerTrait;
+
+struct MyType { x: i32 }
+
+trait MyTrait : MarkerTrait { }
+
+impl<T: lib::MyCopy> MyTrait for T { } //~ ERROR E0119
+
+// Tuples are not fundamental.
+impl MyTrait for lib::MyFundamentalStruct<(MyType,)> { }
+
+#[rustc_error]
+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.
+
+// aux-build:coherence_copy_like_lib.rs
+
+// Test that we are able to introduce a negative constraint that
+// `MyType: !MyTrait` along with other "fundamental" wrappers.
+
+extern crate coherence_copy_like_lib as lib;
+
+use std::marker::MarkerTrait;
+
+struct MyType { x: i32 }
+
+trait MyTrait : MarkerTrait { }
+impl<T: lib::MyCopy> MyTrait for T { } //~ ERROR E0119
+
+// `MyStruct` is not declared fundamental, therefore this would
+// require that
+//
+// MyStruct<MyType>: !MyTrait
+//
+// which we cannot approve.
+impl MyTrait for lib::MyStruct<MyType> { }
+
+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.
+
+// Test that we are able to introduce a negative constraint that
+// `MyType: !MyTrait` along with other "fundamental" wrappers.
+
+// aux-build:coherence_copy_like_lib.rs
+
+extern crate coherence_copy_like_lib as lib;
+
+use std::marker::MarkerTrait;
+
+struct MyType { x: i32 }
+
+trait MyTrait : MarkerTrait { }
+impl<T: lib::MyCopy> MyTrait for T { } //~ ERROR E0119
+
+// Tuples are not fundamental, therefore this would require that
+//
+// (MyType,): !MyTrait
+//
+// which we cannot approve.
+impl MyTrait for (MyType,) { }
+
+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.
+
+// Test that we are able to introduce a negative constraint that
+// `MyType: !MyTrait` along with other "fundamental" wrappers.
+
+// aux-build:coherence_copy_like_lib.rs
+
+#![feature(rustc_attrs)]
+#![allow(dead_code)]
+
+extern crate coherence_copy_like_lib as lib;
+
+struct MyType { x: i32 }
+
+// These are all legal because they are all fundamental types:
+
+impl lib::MyCopy for MyType { }
+impl<'a> lib::MyCopy for &'a MyType { }
+impl<'a> lib::MyCopy for &'a Box<MyType> { }
+impl lib::MyCopy for Box<MyType> { }
+impl lib::MyCopy for lib::MyFundamentalStruct<MyType> { }
+impl lib::MyCopy for lib::MyFundamentalStruct<Box<MyType>> { }
+
+#[rustc_error]
+fn main() { } //~ ERROR compilation successful
--- /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 we are able to introduce a negative constraint that
+// `MyType: !MyTrait` along with other "fundamental" wrappers.
+
+// aux-build:coherence_copy_like_lib.rs
+
+#![feature(rustc_attrs)]
+#![allow(dead_code)]
+
+extern crate coherence_copy_like_lib as lib;
+
+struct MyType { x: i32 }
+
+// These are all legal because they are all fundamental types:
+
+// MyStruct is not fundamental.
+impl lib::MyCopy for lib::MyStruct<MyType> { } //~ ERROR E0117
+
+#[rustc_error]
+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.
+
+// Test that we are able to introduce a negative constraint that
+// `MyType: !MyTrait` along with other "fundamental" wrappers.
+
+// aux-build:coherence_copy_like_lib.rs
+
+#![feature(rustc_attrs)]
+#![allow(dead_code)]
+
+extern crate coherence_copy_like_lib as lib;
+
+struct MyType { x: i32 }
+
+// These are all legal because they are all fundamental types:
+
+// Tuples are not fundamental, so this is not a local impl.
+impl lib::MyCopy for (MyType,) { } //~ ERROR E0117
+
+#[rustc_error]
+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.
+
+// Test that we are able to introduce a negative constraint that
+// `MyType: !MyTrait` along with other "fundamental" wrappers.
+
+// aux-build:coherence_copy_like_lib.rs
+
+#![feature(rustc_attrs)]
+#![allow(dead_code)]
+
+extern crate coherence_copy_like_lib as lib;
+
+struct MyType { x: i32 }
+
+// naturally, legal
+impl lib::MyCopy for MyType { }
+
+#[rustc_error]
+fn main() { } //~ ERROR compilation successful
--- /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.
+
+// Evaluation of constants in refutable patterns goes through
+// different compiler control-flow paths.
+
+#![allow(unused_imports)]
+
+use std::fmt;
+use std::{i8, i16, i32, i64, isize};
+use std::{u8, u16, u32, u64, usize};
+
+const NEG_128: i8 = -128;
+const NEG_NEG_128: i8 = -NEG_128;
+//~^ ERROR constant evaluation error: attempted to negate with overflow
+//~| ERROR attempted to negate with overflow
+
+fn main() {
+ match -128i8 {
+ NEG_NEG_128 => println!("A"),
+ _ => println!("B"),
+ }
+}
--- /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.
+
+// Evaluation of constants in array-elem count goes through different
+// compiler control-flow paths.
+//
+// This test is checking the count in an array expression.
+
+// FIXME (#23926): the error output is not consistent between a
+// self-hosted and a cross-compiled setup; therefore resorting to
+// error-pattern for now.
+
+// error-pattern: expected constant integer for repeat count, but attempted to add with overflow
+
+#![allow(unused_imports)]
+
+use std::fmt;
+use std::{i8, i16, i32, i64, isize};
+use std::{u8, u16, u32, u64, usize};
+
+const A_I8_I
+ : [u32; (i8::MAX as usize) + 1]
+ = [0; (i8::MAX + 1) as usize];
+
+fn main() {
+ foo(&A_I8_I[..]);
+}
+
+fn foo<T:fmt::Debug>(x: T) {
+ println!("{:?}", 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.
+
+// Evaluation of constants in array-elem count goes through different
+// compiler control-flow paths.
+//
+// This test is checking the count in an array expression.
+//
+// This is a variation of another such test, but in this case the
+// types for the left- and right-hand sides of the addition do not
+// match (as well as overflow).
+
+// FIXME (#23926): the error output is not consistent between a
+// self-hosted and a cross-compiled setup; therefore resorting to
+// error-pattern for now.
+
+// error-pattern: mismatched types
+
+#![allow(unused_imports)]
+
+use std::fmt;
+use std::{i8, i16, i32, i64, isize};
+use std::{u8, u16, u32, u64, usize};
+
+const A_I8_I
+ : [u32; (i8::MAX as usize) + 1]
+ = [0; (i8::MAX + 1u8) as usize];
+
+fn main() {
+ foo(&A_I8_I[..]);
+}
+
+fn foo<T:fmt::Debug>(x: T) {
+ println!("{:?}", 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.
+
+// ignore-test this should fail to compile (#23833)
+
+// Evaluation of constants in array-elem count goes through different
+// compiler control-flow paths.
+//
+// This test is checking the count in an array type.
+
+#![allow(unused_imports)]
+
+use std::fmt;
+use std::{i8, i16, i32, i64, isize};
+use std::{u8, u16, u32, u64, usize};
+
+const A_I8_T
+ : [u32; (i8::MAX as i8 + 1i8) as usize]
+ //~^ ERROR error evaluating count: attempted to add with overflow
+ = [0; (i8::MAX as usize) + 1];
+
+fn main() {
+ foo(&A_I8_T[..]);
+}
+
+fn foo<T:fmt::Debug>(x: T) {
+ println!("{:?}", 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.
+
+// Evaluation of constants in array-elem count goes through different
+// compiler control-flow paths.
+//
+// This test is checking the count in an array type.
+
+#![allow(unused_imports)]
+
+use std::fmt;
+use std::{i8, i16, i32, i64, isize};
+use std::{u8, u16, u32, u64, usize};
+
+const A_I8_T
+ : [u32; (i8::MAX as i8 + 1u8) as usize]
+ //~^ ERROR mismatched types
+ //~| the trait `core::ops::Add<u8>` is not implemented for the type `i8`
+ //~| the trait `core::ops::Add<u8>` is not implemented for the type `i8`
+ = [0; (i8::MAX as usize) + 1];
+
+fn main() {
+ foo(&A_I8_T[..]);
+}
+
+fn foo<T:fmt::Debug>(x: T) {
+ println!("{:?}", 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.
+
+#![feature(negate_unsigned)]
+
+#![allow(unused_imports)]
+#![feature(negate_unsigned)]
+
+// Note: the relevant lint pass here runs before some of the constant
+// evaluation below (e.g. that performed by trans and llvm), so if you
+// change this warn to a deny, then the compiler will exit before
+// those errors are detected.
+#![warn(unsigned_negation)]
+
+use std::fmt;
+use std::{i8, i16, i32, i64, isize};
+use std::{u8, u16, u32, u64, usize};
+
+const VALS_I8: (i8, i8, i8, i8) =
+ (-i8::MIN,
+ //~^ ERROR attempted to negate with overflow
+ i8::MIN - 1,
+ //~^ ERROR attempted to sub with overflow
+ i8::MAX + 1,
+ //~^ ERROR attempted to add with overflow
+ i8::MIN * 2,
+ //~^ ERROR attempted to mul with overflow
+ );
+
+const VALS_I16: (i16, i16, i16, i16) =
+ (-i16::MIN,
+ //~^ ERROR attempted to negate with overflow
+ i16::MIN - 1,
+ //~^ ERROR attempted to sub with overflow
+ i16::MAX + 1,
+ //~^ ERROR attempted to add with overflow
+ i16::MIN * 2,
+ //~^ ERROR attempted to mul with overflow
+ );
+
+const VALS_I32: (i32, i32, i32, i32) =
+ (-i32::MIN,
+ //~^ ERROR attempted to negate with overflow
+ i32::MIN - 1,
+ //~^ ERROR attempted to sub with overflow
+ i32::MAX + 1,
+ //~^ ERROR attempted to add with overflow
+ i32::MIN * 2,
+ //~^ ERROR attempted to mul with overflow
+ );
+
+const VALS_I64: (i64, i64, i64, i64) =
+ (-i64::MIN,
+ //~^ ERROR attempted to negate with overflow
+ i64::MIN - 1,
+ //~^ ERROR attempted to sub with overflow
+ i64::MAX + 1,
+ //~^ ERROR attempted to add with overflow
+ i64::MAX * 2,
+ //~^ ERROR attempted to mul with overflow
+ );
+
+const VALS_U8: (u8, u8, u8, u8) =
+ (-u8::MIN,
+ //~^ WARNING negation of unsigned int variable may be unintentional
+ // (The above is separately linted; unsigned negation is defined to be !x+1.)
+ u8::MIN - 1,
+ //~^ ERROR attempted to sub with overflow
+ u8::MAX + 1,
+ //~^ ERROR attempted to add with overflow
+ u8::MAX * 2,
+ //~^ ERROR attempted to mul with overflow
+ );
+
+const VALS_U16: (u16, u16, u16, u16) =
+ (-u16::MIN,
+ //~^ WARNING negation of unsigned int variable may be unintentional
+ // (The above is separately linted; unsigned negation is defined to be !x+1.)
+ u16::MIN - 1,
+ //~^ ERROR attempted to sub with overflow
+ u16::MAX + 1,
+ //~^ ERROR attempted to add with overflow
+ u16::MAX * 2,
+ //~^ ERROR attempted to mul with overflow
+ );
+
+const VALS_U32: (u32, u32, u32, u32) =
+ (-u32::MIN,
+ //~^ WARNING negation of unsigned int variable may be unintentional
+ // (The above is separately linted; unsigned negation is defined to be !x+1.)
+ u32::MIN - 1,
+ //~^ ERROR attempted to sub with overflow
+ u32::MAX + 1,
+ //~^ ERROR attempted to add with overflow
+ u32::MAX * 2,
+ //~^ ERROR attempted to mul with overflow
+ );
+
+const VALS_U64: (u64, u64, u64, u64) =
+ (-u64::MIN,
+ //~^ WARNING negation of unsigned int variable may be unintentional
+ // (The above is separately linted; unsigned negation is defined to be !x+1.)
+ u64::MIN - 1,
+ //~^ ERROR attempted to sub with overflow
+ u64::MAX + 1,
+ //~^ ERROR attempted to add with overflow
+ u64::MAX * 2,
+ //~^ ERROR attempted to mul with overflow
+ );
+
+fn main() {
+ foo(VALS_I8);
+ foo(VALS_I16);
+ foo(VALS_I32);
+ foo(VALS_I64);
+
+ foo(VALS_U8);
+ foo(VALS_U16);
+ foo(VALS_U32);
+ foo(VALS_U64);
+}
+
+fn foo<T:fmt::Debug>(x: T) {
+ println!("{:?}", 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.
+
+// When explicit discriminant value has
+// a type that does not match the representation
+// type, rustc should fail gracefully.
+
+// See also run-pass/discrim-explicit-23030.rs where the input types
+// are correct.
+
+#![allow(dead_code, unused_variables, unused_imports)]
+
+use std::{i8,u8,i16,u16,i32,u32,i64, u64};
+
+fn f_i8() {
+ #[repr(i8)]
+ enum A {
+ Ok = i8::MAX - 1,
+ Ok2,
+ OhNo = 0_u8,
+ //~^ ERROR mismatched types
+ }
+
+ let x = A::Ok;
+}
+
+fn f_u8() {
+ #[repr(u8)]
+ enum A {
+ Ok = u8::MAX - 1,
+ Ok2,
+ OhNo = 0_i8,
+ //~^ ERROR mismatched types
+ }
+
+ let x = A::Ok;
+}
+
+fn f_i16() {
+ #[repr(i16)]
+ enum A {
+ Ok = i16::MAX - 1,
+ Ok2,
+ OhNo = 0_u16,
+ //~^ ERROR mismatched types
+ }
+
+ let x = A::Ok;
+}
+
+fn f_u16() {
+ #[repr(u16)]
+ enum A {
+ Ok = u16::MAX - 1,
+ Ok2,
+ OhNo = 0_i16,
+ //~^ ERROR mismatched types
+ }
+
+ let x = A::Ok;
+}
+
+fn f_i32() {
+ #[repr(i32)]
+ enum A {
+ Ok = i32::MAX - 1,
+ Ok2,
+ OhNo = 0_u32,
+ //~^ ERROR mismatched types
+ }
+
+ let x = A::Ok;
+}
+
+fn f_u32() {
+ #[repr(u32)]
+ enum A {
+ Ok = u32::MAX - 1,
+ Ok2,
+ OhNo = 0_i32,
+ //~^ ERROR mismatched types
+ }
+
+ let x = A::Ok;
+}
+
+fn f_i64() {
+ #[repr(i64)]
+ enum A {
+ Ok = i64::MAX - 1,
+ Ok2,
+ OhNo = 0_u64,
+ //~^ ERROR mismatched types
+ }
+
+ let x = A::Ok;
+}
+
+fn f_u64() {
+ #[repr(u64)]
+ enum A {
+ Ok = u64::MAX - 1,
+ Ok2,
+ OhNo = 0_i64,
+ //~^ ERROR mismatched types
+ }
+
+ let x = A::Ok;
+}
+
+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.
+
+// ignore-tidy-linelength
+
+// Issue 23030: Detect overflowing discriminant
+//
+// Check that we detect the overflow even if enum is not used.
+
+// See also run-pass/discrim-explicit-23030.rs where the suggested
+// workaround is tested.
+
+use std::{i8,u8,i16,u16,i32,u32,i64, u64};
+
+fn f_i8() {
+ #[repr(i8)]
+ enum A {
+ Ok = i8::MAX - 1,
+ Ok2,
+ OhNo, //~ ERROR enum discriminant overflowed on value after 127: i8; set explicitly via OhNo = -128 if that is desired outcome
+ }
+}
+
+fn f_u8() {
+ #[repr(u8)]
+ enum A {
+ Ok = u8::MAX - 1,
+ Ok2,
+ OhNo, //~ ERROR enum discriminant overflowed on value after 255: u8; set explicitly via OhNo = 0 if that is desired outcome
+ }
+}
+
+fn f_i16() {
+ #[repr(i16)]
+ enum A {
+ Ok = i16::MAX - 1,
+ Ok2,
+ OhNo, //~ ERROR enum discriminant overflowed
+ }
+}
+
+fn f_u16() {
+ #[repr(u16)]
+ enum A {
+ Ok = u16::MAX - 1,
+ Ok2,
+ OhNo, //~ ERROR enum discriminant overflowed
+ }
+}
+
+fn f_i32() {
+ #[repr(i32)]
+ enum A {
+ Ok = i32::MAX - 1,
+ Ok2,
+ OhNo, //~ ERROR enum discriminant overflowed
+ }
+}
+
+fn f_u32() {
+ #[repr(u32)]
+ enum A {
+ Ok = u32::MAX - 1,
+ Ok2,
+ OhNo, //~ ERROR enum discriminant overflowed
+ }
+}
+
+fn f_i64() {
+ #[repr(i64)]
+ enum A {
+ Ok = i64::MAX - 1,
+ Ok2,
+ OhNo, //~ ERROR enum discriminant overflowed
+ }
+}
+
+fn f_u64() {
+ #[repr(u64)]
+ enum A {
+ Ok = u64::MAX - 1,
+ Ok2,
+ OhNo, //~ ERROR enum discriminant overflowed
+ }
+}
+
+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.
+
+// ignore-tidy-linelength
+
+// Issue 23030: Detect overflowing discriminant
+
+// See also run-pass/discrim-explicit-23030.rs where the suggested
+// workaround is tested.
+
+use std::{i8,u8,i16,u16,i32,u32,i64, u64};
+
+fn f_i8() {
+ #[repr(i8)]
+ enum A {
+ Ok = i8::MAX - 1,
+ Ok2,
+ OhNo, //~ ERROR enum discriminant overflowed on value after 127: i8; set explicitly via OhNo = -128 if that is desired outcome
+ }
+
+ let x = A::Ok;
+}
+
+fn f_u8() {
+ #[repr(u8)]
+ enum A {
+ Ok = u8::MAX - 1,
+ Ok2,
+ OhNo, //~ ERROR enum discriminant overflowed on value after 255: u8; set explicitly via OhNo = 0 if that is desired outcome
+ }
+
+ let x = A::Ok;
+}
+
+fn f_i16() {
+ #[repr(i16)]
+ enum A {
+ Ok = i16::MAX - 1,
+ Ok2,
+ OhNo, //~ ERROR enum discriminant overflowed
+ }
+
+ let x = A::Ok;
+}
+
+fn f_u16() {
+ #[repr(u16)]
+ enum A {
+ Ok = u16::MAX - 1,
+ Ok2,
+ OhNo, //~ ERROR enum discriminant overflowed
+ }
+
+ let x = A::Ok;
+}
+
+fn f_i32() {
+ #[repr(i32)]
+ enum A {
+ Ok = i32::MAX - 1,
+ Ok2,
+ OhNo, //~ ERROR enum discriminant overflowed
+ }
+
+ let x = A::Ok;
+}
+
+fn f_u32() {
+ #[repr(u32)]
+ enum A {
+ Ok = u32::MAX - 1,
+ Ok2,
+ OhNo, //~ ERROR enum discriminant overflowed
+ }
+
+ let x = A::Ok;
+}
+
+fn f_i64() {
+ #[repr(i64)]
+ enum A {
+ Ok = i64::MAX - 1,
+ Ok2,
+ OhNo, //~ ERROR enum discriminant overflowed
+ }
+
+ let x = A::Ok;
+}
+
+fn f_u64() {
+ #[repr(u64)]
+ enum A {
+ Ok = u64::MAX - 1,
+ Ok2,
+ OhNo, //~ ERROR enum discriminant overflowed
+ }
+
+ let x = A::Ok;
+}
+
+fn main() { }
mod s {
#![allow(unstable)]
- use std::sync::atomic::{AtomicUint, ATOMIC_UINT_INIT, Ordering};
+ use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
- static S_COUNT: AtomicUint = ATOMIC_UINT_INIT;
+ static S_COUNT: AtomicUsize = ATOMIC_USIZE_INIT;
pub fn next_count() -> usize {
S_COUNT.fetch_add(1, Ordering::SeqCst) + 1
mod s {
#![allow(unstable)]
- use std::sync::atomic::{AtomicUint, ATOMIC_UINT_INIT, Ordering};
+ use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
- static S_COUNT: AtomicUint = ATOMIC_UINT_INIT;
+ static S_COUNT: AtomicUsize = ATOMIC_USIZE_INIT;
pub fn next_count() -> usize {
S_COUNT.fetch_add(1, Ordering::SeqCst) + 1
mod s {
#![allow(unstable)]
- use std::sync::atomic::{AtomicUint, ATOMIC_UINT_INIT, Ordering};
+ use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
- static S_COUNT: AtomicUint = ATOMIC_UINT_INIT;
+ static S_COUNT: AtomicUsize = ATOMIC_USIZE_INIT;
pub fn next_count() -> usize {
S_COUNT.fetch_add(1, Ordering::SeqCst) + 1
let f2: &Fat<[isize; 3]> = &f1;
let f3: &Fat<[usize]> = f2;
//~^ ERROR mismatched types
- //~| expected `&Fat<[usize]>`
- //~| found `&Fat<[isize; 3]>`
- //~| expected usize
- //~| found isize
// With a trait.
let f1 = Fat { ptr: Foo };
use std::ops::Index;
use std::fmt::Debug;
-#[derive(Copy)]
+#[derive(Copy, Clone)]
struct S;
impl Index<usize> for S {
}
}
-#[derive(Copy)]
+#[derive(Copy, Clone)]
struct T;
impl Index<usize> for T {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![feature(negate_unsigned)]
+
#[repr(u8)] //~ NOTE discriminant type specified here
enum Eu8 {
Au8 = 23,
fn has_slice(x: &str) {
wants_uniq(x); //~ ERROR mismatched types
- wants_slice(x.as_slice());
+ wants_slice(x);
}
fn main() {
// issue #20126
-#[derive(Copy)] //~ ERROR the trait `Copy` may not be implemented
+#[derive(Copy, Clone)] //~ ERROR the trait `Copy` may not be implemented
struct Foo;
impl Drop for Foo {
fn drop(&mut self) {}
}
-#[derive(Copy)] //~ ERROR the trait `Copy` may not be implemented
+#[derive(Copy, Clone)] //~ ERROR the trait `Copy` may not be implemented
struct Bar<T>(::std::marker::PhantomData<T>);
#[unsafe_destructor]
--- /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.
+
+extern "rust-call" fn foo() { } //~ ERROR rust-call ABI is subject to change
+
+trait Foo {
+ extern "rust-call" fn foo();
+}
+
+impl Foo for i32 {
+ extern "rust-call" fn foo() { } //~ ERROR rust-call ABI is subject to change
+}
+
+fn main() { }
use std::simd::f32x4;
-#[simd] #[derive(Copy)] #[repr(C)] struct LocalSimd(u8, u8);
+#[simd] #[derive(Copy, Clone)] #[repr(C)] struct LocalSimd(u8, u8);
extern {
fn foo() -> f32x4; //~ ERROR use of SIMD type
struct Foo;
impl Fn<()> for Foo {
- //~^ ERROR angle-bracket notation is not stable when used with the `Fn` family of traits
extern "rust-call" fn call(self, args: ()) -> () {}
+ //~^ ERROR rust-call ABI is subject to change
}
struct Foo1;
impl FnOnce() for Foo1 {
- //~^ ERROR associated type bindings are not allowed here
extern "rust-call" fn call_once(self, args: ()) -> () {}
+ //~^ ERROR rust-call ABI is subject to change
}
struct Bar;
impl FnMut<()> for Bar {
- //~^ ERROR angle-bracket notation is not stable when used with the `Fn` family of traits
extern "rust-call" fn call_mut(&self, args: ()) -> () {}
+ //~^ ERROR rust-call ABI is subject to change
}
struct Baz;
impl FnOnce<()> for Baz {
- //~^ ERROR angle-bracket notation is not stable when used with the `Fn` family of traits
extern "rust-call" fn call_once(&self, args: ()) -> () {}
+ //~^ ERROR rust-call ABI is subject to change
}
fn main() {}
match x {
box 1 => (),
//~^ box pattern syntax is experimental
- //~| add #![feature(box_patterns)] to the crate attributes to enable
_ => ()
};
}
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
}
#[link_args = "aFdEfSeVEEE"]
extern {}
//~^ ERROR the `link_args` attribute is not portable across platforms
-//~| HELP add #![feature(link_args)] to the crate attributes to enable
fn main() { }
#[link_name = "llvm.sqrt.f32"]
fn sqrt(x: f32) -> f32;
//~^ ERROR linking to LLVM intrinsics is experimental
- //~| HELP add #![feature(link_llvm_intrinsics)] to the crate attributes
}
fn main(){
#[plugin_registrar]
pub fn registrar() {}
//~^ ERROR compiler plugins are experimental
-//~| HELP add #![feature(plugin_registrar)] to the crate attributes to enable
fn main() {}
#![feature(simd)]
#[repr(C)]
-#[derive(Copy)]
+#[derive(Copy, Clone)]
#[simd]
pub struct f32x4(f32, f32, f32, f32);
#[unsafe_destructor]
//~^ ERROR `#[unsafe_destructor]` does nothing anymore
-//~| HELP: add #![feature(unsafe_destructor)] to the crate attributes to enable
-// (but of couse there is no point in doing so)
impl<'a> Drop for D<'a> {
fn drop(&mut self) { }
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// error-pattern: too big for the current
+// FIXME (#23926): the error output is not consistent between a
+// self-hosted and a cross-compiled setup. Skipping for now.
+
+// ignore-test FIXME(#23926)
+
#![allow(exceeding_bitshifts)]
fn main() {
- let fat : [u8; (1<<61)+(1<<31)] = [0; (1u64<<61) as usize +(1u64<<31) as usize];
+ let _fat : [u8; (1<<61)+(1<<31)] =
+ [0; (1u64<<61) as usize +(1u64<<31) as usize];
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::iter::{Range,range};
+use std::ops::Range;
trait Itble<'r, T, I: Iterator<Item=T>> { fn iter(&'r self) -> I; }
impl<'r> Itble<'r, usize, Range<usize>> for (usize, usize) {
fn iter(&'r self) -> Range<usize> {
let &(min, max) = self;
- range(min, max)
+ min..max
}
}
fn main() {
// FIXME (#22405): Replace `Box::new` with `box` here when/if possible.
- (|| Box::new(*[0].as_slice()))();
+ (|| Box::new(*(&[0][..])))();
//~^ ERROR the trait `core::marker::Sized` is not implemented for the type `[_]`
}
trait Dummy : MarkerTrait { }
-#[derive(Copy)]
+#[derive(Copy, Clone)]
struct MyStruct {
x: isize,
y: isize,
fn a() {
let x: Box<_> = box 3;
- take_param(&x); //~ ERROR `core::marker::Copy` is not implemented
+ take_param(&x); //~ ERROR E0277
}
fn b() {
let x: Box<_> = box 3;
let y = &x;
- let z = &x as &Foo; //~ ERROR `core::marker::Copy` is not implemented
+ let z = &x as &Foo; //~ ERROR E0038
}
fn main() { }
// ignore-tidy-linelength
-use std::iter::{Range,range};
+use std::ops::Range;
trait Itble<'r, T, I: Iterator<Item=T>> { fn iter(&'r self) -> I; }
impl<'r> Itble<'r, usize, Range<usize>> for (usize, usize) {
fn iter(&'r self) -> Range<usize> {
let &(min, max) = self;
- range(min, max)
+ min..max
}
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![feature(negate_unsigned)]
#![deny(exceeding_bitshifts)]
#![allow(unused_variables)]
#![allow(dead_code)]
-#![feature(core)]
+#![feature(core, negate_unsigned)]
fn main() {
let n = 1u8 << 7;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![feature(negate_unsigned)]
#![allow(dead_code)]
+#![feature(negate_unsigned)]
// compile-flags: -D unused-comparisons
fn main() { }
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// Note: This test is checking that we forbid a coding pattern that
+// Issue #5873 explicitly wants to allow.
+
enum State { ST_NULL, ST_WHITESPACE }
fn main() {
[State::ST_NULL; (State::ST_WHITESPACE as usize)];
- //~^ ERROR expected constant integer for repeat count, found non-constant expression
+ //~^ ERROR expected constant integer for repeat count, but non-constant path
}
fn main() {
fn bar(n: usize) {
- let _x = [0; n]; //~ ERROR expected constant integer for repeat count, found variable
+ let _x = [0; n];
+ //~^ ERROR expected constant integer for repeat count, found variable
}
}
// which fails to type check.
ss
- //~^ ERROR cannot infer
- //~| ERROR mismatched types
+ //~^ ERROR lifetime of the source pointer does not outlive lifetime bound
+ //~| ERROR cannot infer
}
fn main() {
// `Box<SomeTrait>` defaults to a `'static` bound, so this return
// is illegal.
- ss.r //~ ERROR mismatched types
+ ss.r //~ ERROR lifetime of the source pointer does not outlive lifetime bound
}
fn store(ss: &mut SomeStruct, b: Box<SomeTrait>) {
fn store1<'b>(ss: &mut SomeStruct, b: Box<SomeTrait+'b>) {
// Here we override the lifetimes explicitly, and so naturally we get an error.
- ss.r = b; //~ ERROR mismatched types
+ ss.r = b; //~ ERROR lifetime of the source pointer does not outlive lifetime bound
}
fn main() {
impl Copy for IWantToCopyThis {}
//~^ ERROR the trait `Copy` may not be implemented for this type
+//~| ERROR E0277
enum CantCopyThisEither {
A,
impl Copy for IWantToCopyThisToo {}
//~^ ERROR the trait `Copy` may not be implemented for this type
+//~| ERROR E0277
fn main() {}
)
}
- #[derive(Copy)]
+ #[derive(Copy, Clone)]
pub struct S;
impl S {
fn make_object_bad<'a,'b,'c,A:SomeTrait+'a+'b>(v: A) -> Box<SomeTrait+'c> {
// A outlives 'a AND 'b...but not 'c.
- box v as Box<SomeTrait+'a> //~ ERROR mismatched types
+ box v as Box<SomeTrait+'a> //~ ERROR lifetime of the source pointer does not outlive
}
fn main() {
fn foo3<'a,'b>(x: &'a mut Dummy) -> &'b mut Dummy {
// Without knowing 'a:'b, we can't coerce
- x //~ ERROR mismatched types
+ x //~ ERROR lifetime of the source pointer does not outlive
//~^ ERROR cannot infer
}
use lib::DefaultedTrait;
struct A;
-impl DefaultedTrait for (A,) { } //~ ERROR E0321
+impl DefaultedTrait for (A,) { } //~ ERROR E0117
struct B;
-impl !DefaultedTrait for (B,) { } //~ ERROR E0321
+impl !DefaultedTrait for (B,) { } //~ ERROR E0117
struct C;
struct D<T>(T);
impl DefaultedTrait for Box<C> { } //~ ERROR E0321
-impl DefaultedTrait for lib::Something<C> { } //~ ERROR E0321
+impl DefaultedTrait for lib::Something<C> { } //~ ERROR E0117
impl DefaultedTrait for D<C> { } // OK
fn main() { }
+++ /dev/null
-// Copyright 2012 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::sync::mpsc::channel;
-
-// Test that a class with an unsendable field can't be
-// sent
-
-use std::rc::Rc;
-
-struct foo {
- i: isize,
- j: Rc<String>,
-}
-
-fn foo(i:isize, j: Rc<String>) -> foo {
- foo {
- i: i,
- j: j
- }
-}
-
-fn main() {
- let cat = "kitty".to_string();
- let (tx, _) = channel();
- //~^ ERROR `core::marker::Send` is not implemented
- tx.send(foo(42, Rc::new(cat)));
-}
+++ /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 deprecated markers still have their old effect.
-
-#![feature(rustc_attrs)]
-
-use std::marker;
-
-#[rustc_variance]
-struct A<T>(marker::CovariantType<T>); //~ ERROR types=[[+];[];[]]
-
-#[rustc_variance]
-struct B<T>(marker::ContravariantType<T>); //~ ERROR types=[[-];[];[]]
-
-#[rustc_variance]
-struct C<T>(marker::InvariantType<T>); //~ ERROR types=[[o];[];[]]
-
-#[rustc_variance]
-struct D<'a>(marker::CovariantLifetime<'a>); //~ ERROR regions=[[+];[];[]]
-
-#[rustc_variance]
-struct E<'a>(marker::ContravariantLifetime<'a>); //~ ERROR regions=[[-];[];[]]
-
-#[rustc_variance]
-struct F<'a>(marker::InvariantLifetime<'a>); //~ ERROR regions=[[o];[];[]]
-
-fn main() { }
mod s {
#![allow(unstable)]
- use std::sync::atomic::{AtomicUint, ATOMIC_UINT_INIT, Ordering};
+ use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
- static S_COUNT: AtomicUint = ATOMIC_UINT_INIT;
+ static S_COUNT: AtomicUsize = ATOMIC_USIZE_INIT;
/// generates globally unique count (global across the current
/// process, that is)
v.push(&x); //~ ERROR `x` does not live long enough
v.push(&y); //~ ERROR `y` does not live long enough
- assert_eq!(v.as_slice(), [&3, &4]);
+ assert_eq!(v, [&3, &4]);
}
use self::ManualDiscriminant::{OneHundred, OneThousand, OneMillion};
use self::SingleVariant::TheOnlyVariant;
-#[derive(Copy)]
+#[derive(Copy, Clone)]
enum AutoDiscriminant {
One,
Two,
Three
}
-#[derive(Copy)]
+#[derive(Copy, Clone)]
enum ManualDiscriminant {
OneHundred = 100,
OneThousand = 1000,
OneMillion = 1000000
}
-#[derive(Copy)]
+#[derive(Copy, Clone)]
enum SingleVariant {
TheOnlyVariant
}
#![feature(box_syntax)]
#![omit_gdb_pretty_printer_section]
-#[derive(Copy)]
+#[derive(Copy, Clone)]
struct Struct<T> {
x: T
}
#![feature(box_syntax)]
#![omit_gdb_pretty_printer_section]
-#[derive(Copy)]
+#[derive(Copy, Clone)]
enum Enum {
Variant1 { x: u16, y: u16 },
Variant2 (u32)
#![feature(box_syntax)]
#![omit_gdb_pretty_printer_section]
-#[derive(Copy)]
+#[derive(Copy, Clone)]
struct Struct<T> {
x: T
}
#![feature(box_syntax)]
#![omit_gdb_pretty_printer_section]
-#[derive(Copy)]
+#[derive(Copy, Clone)]
struct Struct {
x: isize
}
#![feature(box_syntax)]
#![omit_gdb_pretty_printer_section]
-#[derive(Copy)]
+#[derive(Copy, Clone)]
struct Struct {
x: isize
}
#![feature(box_syntax)]
#![omit_gdb_pretty_printer_section]
-#[derive(Copy)]
+#[derive(Copy, Clone)]
struct TupleStruct(isize, f64);
impl TupleStruct {
#![feature(box_syntax)]
#![omit_gdb_pretty_printer_section]
-#[derive(Copy)]
+#[derive(Copy, Clone)]
struct Struct {
x: isize
}
#![feature(box_syntax)]
#![omit_gdb_pretty_printer_section]
-#[derive(Copy)]
+#[derive(Copy, Clone)]
struct Struct {
x: isize
}
(a, ref b) => {}
}
for a in &[111i32] {}
+ let test = if some_predicate() { 1 } else { 2 };
+ while some_predicate() {
+ let abc = !some_predicate();
+ }
+ loop {
+ let abc = !some_predicate();
+ break;
+ }
+ // nested block
+ {
+ let abc = !some_predicate();
+
+ {
+ let def = !some_predicate();
+ }
+ }
}
fn after_panic() {
(a, ref b) => {}
}
for a in &[111i32] {}
+ let test = if some_predicate() { 1 } else { 2 };
+ while some_predicate() {
+ let abc = !some_predicate();
+ }
+ loop {
+ let abc = !some_predicate();
+ break;
+ }
+ // nested block
+ {
+ let abc = !some_predicate();
+
+ {
+ let def = !some_predicate();
+ }
+ }
}
fn after_diverging_function() {
(a, ref b) => {}
}
for a in &[111i32] {}
+ let test = if some_predicate() { 1 } else { 2 };
+ while some_predicate() {
+ let abc = !some_predicate();
+ }
+ loop {
+ let abc = !some_predicate();
+ break;
+ }
+ // nested block
+ {
+ let abc = !some_predicate();
+
+ {
+ let def = !some_predicate();
+ }
+ }
}
fn after_break() {
(a, ref b) => {}
}
for a in &[111i32] {}
+ let test = if some_predicate() { 1 } else { 2 };
+ while some_predicate() {
+ let abc = !some_predicate();
+ }
+ loop {
+ let abc = !some_predicate();
+ break;
+ }
+ // nested block
+ {
+ let abc = !some_predicate();
+
+ {
+ let def = !some_predicate();
+ }
+ }
}
}
fn after_continue() {
for _ in 0..10i32 {
- break;
+ continue;
let x = "0";
let (ref y,z) = (1i32, 2u32);
match (20i32, 'c') {
(a, ref b) => {}
}
for a in &[111i32] {}
+ let test = if some_predicate() { 1 } else { 2 };
+ while some_predicate() {
+ let abc = !some_predicate();
+ }
+ loop {
+ let abc = !some_predicate();
+ break;
+ }
+ // nested block
+ {
+ let abc = !some_predicate();
+
+ {
+ let def = !some_predicate();
+ }
+ }
}
}
fn diverge() -> ! {
panic!();
}
+
+fn some_predicate() -> bool { true || false }
+
// error-pattern:no valid digits found for number
fn main() {
- log(error, 0b42);
+ log(error, 0b);
}
--- /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.
+
+fn main() {
+ 0b121; //~ ERROR invalid digit for a base 2 literal
+ 0b10_10301; //~ ERROR invalid digit for a base 2 literal
+ 0b30; //~ ERROR invalid digit for a base 2 literal
+ 0b41; //~ ERROR invalid digit for a base 2 literal
+ 0b5; //~ ERROR invalid digit for a base 2 literal
+ 0b6; //~ ERROR invalid digit for a base 2 literal
+ 0b7; //~ ERROR invalid digit for a base 2 literal
+ 0b8; //~ ERROR invalid digit for a base 2 literal
+ 0b9; //~ ERROR invalid digit for a base 2 literal
+}
--- /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.
+
+fn main() {
+ 0o18; //~ ERROR invalid digit for a base 8 literal
+ 0o1234_9_5670; //~ ERROR invalid digit for a base 8 literal
+}
fn test2() -> isize { let val = &0; { } *val }
-#[derive(Copy)]
+#[derive(Copy, Clone)]
struct S { eax: isize }
fn test3() {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// error-pattern:assertion failed: `(left == right) && (right == left)` (left: `14`, right: `15`)
+// error-pattern:assertion failed: `(left == right)` (left: `14`, right: `15`)
fn main() {
assert_eq!(14,15);
// error-pattern:whatever
-#![feature(os, rustc_private)]
+#![feature(exit_status, rustc_private)]
#[macro_use] extern crate log;
-use std::os;
+use std::env;
fn main() {
error!("whatever");
// Setting the exit status only works when the scheduler terminates
// normally. In this case we're going to panic, so instead of
// returning 50 the process will return the typical rt failure code.
- os::set_exit_status(50);
+ env::set_exit_status(50);
panic!();
}
// error-pattern:whatever
-#![feature(os, rustc_private)]
+#![feature(exit_status, rustc_private)]
#[macro_use] extern crate log;
-use std::os;
+use std::env;
use std::thread;
struct r {
// runtime's exit code
impl Drop for r {
fn drop(&mut self) {
- os::set_exit_status(50);
+ env::set_exit_status(50);
}
}
// error-pattern:whatever
-#![feature(rustc_private, os)]
+#![feature(rustc_private, exit_status)]
#[macro_use] extern crate log;
-use std::os;
+use std::env;
fn main() {
error!("whatever");
// 101 is the code the runtime uses on task panic and the value
// compiletest expects run-fail tests to return.
- os::set_exit_status(101);
+ env::set_exit_status(101);
}
// except according to those terms.
#[derive()]
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub struct Foo;
pub fn main() { }
// except according to those terms.
#[repr(packed)]
-#[derive(Copy, PartialEq, Debug)]
+#[derive(Copy, Clone, PartialEq, Debug)]
struct Foo {
a: i8,
b: i16,
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(libc, os)]
+#![feature(libc, exit_status)]
extern crate libc;
};
if result != 1 {
- std::os::set_exit_status(255);
+ std::env::set_exit_status(255);
}
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![feature(unboxed_closures)]
+
extern crate foo;
// @has bar/trait.Foo.html //pre "pub trait Foo"
// except according to those terms.
#![crate_type="lib"]
+#![feature(unboxed_closures)]
pub trait Foo {
extern "rust-call" fn foo(&self, _: ()) -> i32;
MyTypes(MyType, MyType)
}
-#[derive(Copy)]
+#[derive(Copy, Clone)]
enum SomeOtherEnum {
SomeConst1,
SomeConst2,
let expected_span = format!("\n{}^{}\n",
repeat(" ").take(offset + 7).collect::<String>(),
repeat("~").take(8).collect::<String>());
- assert!(err.contains(expected_span.as_slice()));
+ assert!(err.contains(&expected_span));
// Second snake is 8 ~s long, with 36 preceding spaces
let expected_span = format!("\n{}^{}\n",
repeat(" ").take(offset + 36).collect::<String>(),
repeat("~").take(8).collect::<String>());
- assert!(err.contains(expected_span.as_slice()));
+ assert!(err.contains(&expected_span));
}
let mut tc = TestCalls { count: 1 };
// we should never get use this filename, but lets make sure they are valid args.
let args = vec!["compiler-calls".to_string(), "foo.rs".to_string()];
- rustc_driver::run_compiler(args.as_slice(), &mut tc);
+ rustc_driver::run_compiler(&args, &mut tc);
assert!(tc.count == 30);
}
--- /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.
+
+// ignore-android
+
+#![feature(rustc_private)]
+
+extern crate rustc_back;
+
+use std::env;
+use std::fs;
+use rustc_back::tempdir::TempDir;
+
+fn main() {
+ let td = TempDir::new("create-dir-all-bare").unwrap();
+ env::set_current_dir(td.path()).unwrap();
+ fs::create_dir_all("create-dir-all-bare").unwrap();
+}
--- /dev/null
+// Copyright 2013-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.
+
+// This test can't be a unit test in std,
+// because it needs TempDir, which is in extra
+
+// ignore-android
+// pretty-expanded FIXME #23616
+
+#![feature(rustc_private, path_ext)]
+
+extern crate rustc_back;
+
+use std::ffi::CString;
+use std::fs::{self, File, PathExt};
+use rustc_back::tempdir::TempDir;
+
+fn rename_directory() {
+ 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() }
fn dummy(&self) { }
}
-#[derive(Copy)] pub struct X;
+#[derive(Copy, Clone)] pub struct X;
impl Offset for X { type State = Y; }
-#[derive(Copy)] pub struct Y;
+#[derive(Copy, Clone)] pub struct Y;
impl OffsetState for Y {}
pub fn now() -> DateTime<X> { from_utc(Y) }
let s = str::from_utf8(&out.error).unwrap();
let mut i = 0;
for _ in 0..2 {
- i += s[i + 10..].find_str("stack backtrace").unwrap() + 10;
+ i += s[i + 10..].find("stack backtrace").unwrap() + 10;
}
- assert!(s[i + 10..].find_str("stack backtrace").is_none(),
+ assert!(s[i + 10..].find("stack backtrace").is_none(),
"bad output4: {}", s);
}
// pretty-expanded FIXME #23616
+#![feature(core)]
+
+// Catch mistakes in the overflowing literals lint.
+#![deny(overflowing_literals)]
+
pub fn main() {
- assert_eq!(0xffffffff, (-1 as u32));
- assert_eq!(4294967295, (-1 as u32));
- assert_eq!(0xffffffffffffffff, (-1 as u64));
- assert_eq!(18446744073709551615, (-1 as u64));
+ assert_eq!(0xffffffff, (!0 as u32));
+ assert_eq!(4294967295, (!0 as u32));
+ assert_eq!(0xffffffffffffffff, (!0 as u64));
+ assert_eq!(18446744073709551615, (!0 as u64));
- assert_eq!(-2147483648 - 1, 2147483647);
+ assert_eq!((-2147483648i32).wrapping_sub(1), 2147483647);
}
use std::ops::Mul;
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub struct Foo {
x: f64,
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![feature(negate_unsigned)]
#[cfg(any(target_arch = "x86", target_arch = "arm"))]
fn target() {
use std::cell::Cell;
-#[derive(Copy)]
+#[derive(Copy, Clone)]
enum newtype {
newvar(isize)
}
use trait_superkinds_in_metadata::RequiresCopy;
use std::marker;
-#[derive(Copy)]
+#[derive(Copy, Clone)]
struct X<T>(T);
impl<T:Sync> RequiresShare for X<T> { }
use std::sync::mpsc::channel;
use std::fmt;
use std::old_io::{ChanReader, ChanWriter, Reader, Writer};
-use std::thread::Thread;
+use std::thread;
struct MyWriter(ChanWriter);
fn main() {
let (tx, rx) = channel();
let (mut r, w) = (ChanReader::new(rx), ChanWriter::new(tx));
- let _t = Thread::spawn(move|| {
+ let _t = thread::scoped(move|| {
set_logger(box MyWriter(w) as Box<Logger+Send>);
debug!("debug");
info!("info");
#![feature(std_misc)]
-use std::thread::Thread;
+use std::thread;
fn child2(_s: String) { }
pub fn main() {
- let _x = Thread::spawn(move|| child2("hi".to_string()));
+ let _x = thread::spawn(move|| child2("hi".to_string()));
}
use std::cmp;
-#[derive(Copy, Debug)]
+#[derive(Copy, Clone, Debug)]
enum cat_type { tuxedo, tabby, tortoiseshell }
impl cmp::PartialEq for cat_type {
#![allow(unknown_features)]
#![feature(box_syntax, std_misc)]
-use std::thread::Thread;
+use std::thread;
struct Pair {
a: isize,
pub fn main() {
let z: Box<_> = box Pair { a : 10, b : 12};
- let _t = Thread::spawn(move|| {
+ let _t = thread::scoped(move|| {
assert_eq!(z.a, 10);
assert_eq!(z.b, 12);
});
+++ /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.
-
-// aux-build:coherence_lib.rs
-
-// Test that it's ok for T to appear first in the self-type, as long
-// as it's covered somewhere.
-
-// pretty-expanded FIXME #23616
-
-extern crate coherence_lib as lib;
-use lib::{Remote,Pair};
-
-pub struct Cover<T>(T);
-
-impl<T> Remote for Pair<T,Cover<T>> { }
-
-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.
-
-// aux-build:coherence_lib.rs
-
-// Test that it's ok for T to appear second in the self-type, as long
-// as it's covered somewhere.
-
-// pretty-expanded FIXME #23616
-
-extern crate coherence_lib as lib;
-use lib::{Remote,Pair};
-
-pub struct Cover<T>(T);
-
-impl<T> Remote for Pair<Cover<T>,T> { }
-
-fn main() { }
// pretty-expanded FIXME #23616
pub fn main() {
- #[derive(Copy)]
+ #[derive(Copy, Clone)]
enum x { foo }
impl ::std::cmp::PartialEq for x {
fn eq(&self, other: &x) -> bool {
+++ /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.
-
-// aux-build:coherence_lib.rs
-
-// pretty-expanded FIXME #23616
-
-extern crate coherence_lib as lib;
-use lib::Remote;
-
-struct Local;
-
-impl Remote for Vec<Local> { }
-
-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.
-
-// aux-build:coherence_lib.rs
-
-// pretty-expanded FIXME #23616
-
-extern crate coherence_lib as lib;
-use lib::Remote;
-
-struct Local<T>(T);
-
-impl<T> Remote for Vec<Local<T>> { }
-
-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.
+
+// Test that we are able to introduce a negative constraint that
+// `MyType: !MyTrait` along with other "fundamental" wrappers.
+
+// aux-build:coherence_copy_like_lib.rs
+
+extern crate coherence_copy_like_lib as lib;
+
+use std::marker::MarkerTrait;
+
+struct MyType { x: i32 }
+
+trait MyTrait : MarkerTrait { }
+impl<T: lib::MyCopy> MyTrait for T { }
+impl MyTrait for MyType { }
+impl<'a> MyTrait for &'a MyType { }
+impl MyTrait for Box<MyType> { }
+impl<'a> MyTrait for &'a Box<MyType> { }
+
+fn main() { }
#![feature(std_misc)]
-use std::thread::Thread;
+use std::thread;
use std::sync::mpsc::{channel, Sender};
pub fn main() {
let (tx, rx) = channel();
- let _t = Thread::spawn(move|| { child(&tx) });
+ let _t = thread::scoped(move|| { child(&tx) });
let y = rx.recv().unwrap();
println!("received");
println!("{}", y);
// pretty-expanded FIXME #23616
-#[derive(Copy)]
+#[derive(Copy, Clone)]
enum Foo {
Bar = 0xDEADBEE
}
// pretty-expanded FIXME #23616
+#[derive(Copy, Clone)]
struct C { _x: u8 }
-impl Copy for C { }
-
fn main() {
fn d() -> C { C { _x: 0 } }
use std::time::Duration;
use std::str;
use std::sync::mpsc::channel;
-use std::thread::Thread;
+use std::thread;
macro_rules! succeed { ($e:expr) => (
match $e { Ok(..) => {}, Err(e) => panic!("panic: {}", e) }
let (tx, rx1) = channel();
let mut t = timer::Timer::new().unwrap();
let rx2 = t.oneshot(Duration::milliseconds(1000));
- Thread::spawn(move|| {
+ thread::spawn(move|| {
select! {
_ = rx2.recv() => unsafe { libc::exit(1) },
_ = rx1.recv() => {}
+++ /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(tempdir)]
-
-use std::env;
-use std::fs::{self, TempDir};
-
-fn main() {
- let td = TempDir::new("create-dir-all-bare").unwrap();
- env::set_current_dir(td.path()).unwrap();
- fs::create_dir_all("create-dir-all-bare").unwrap();
-}
// pretty-expanded FIXME #23616
-#[derive(Copy)]
+#[derive(Copy, Clone)]
struct Test;
pub fn main() {}
#![allow(unknown_features)]
#![feature(box_syntax)]
-#![feature(old_orphan_check, rustc_private)]
+#![feature(rustc_private)]
extern crate serialize;
// pretty-expanded FIXME #23616
-#![feature(old_orphan_check, rustc_private)]
+#![feature(rustc_private)]
extern crate serialize;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(old_orphan_check, rand, rustc_private)]
+#![feature(rand, rustc_private)]
extern crate serialize;
extern crate rand;
--- /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.
+
+// Issue 23030: Workaround overflowing discriminant
+// with explicit assignments.
+
+// See also compile-fail/overflow-discrim.rs, which shows what
+// happens if you leave the OhNo explicit cases out here.
+
+use std::{i8,u8,i16,u16,i32,u32,i64,u64,isize,usize};
+
+fn f_i8() {
+ #[repr(i8)]
+ enum A {
+ Ok = i8::MAX - 1,
+ Ok2,
+ OhNo = i8::MIN,
+ NotTheEnd = -1,
+ Zero,
+ }
+
+ let _x = (A::Ok, A::Ok2, A::OhNo);
+ let z = (A::NotTheEnd, A::Zero).1 as i8;
+ assert_eq!(z, 0);
+}
+
+fn f_u8() {
+ #[repr(u8)]
+ enum A {
+ Ok = u8::MAX - 1,
+ Ok2,
+ OhNo = u8::MIN,
+ }
+
+ let _x = (A::Ok, A::Ok2, A::OhNo);
+}
+
+fn f_i16() {
+ #[repr(i16)]
+ enum A {
+ Ok = i16::MAX - 1,
+ Ok2,
+ OhNo = i16::MIN,
+ NotTheEnd = -1,
+ Zero,
+ }
+
+ let _x = (A::Ok, A::Ok2, A::OhNo);
+ let z = (A::NotTheEnd, A::Zero).1 as i16;
+ assert_eq!(z, 0);
+}
+
+fn f_u16() {
+ #[repr(u16)]
+ enum A {
+ Ok = u16::MAX - 1,
+ Ok2,
+ OhNo = u16::MIN,
+ }
+
+ let _x = (A::Ok, A::Ok2, A::OhNo);
+}
+
+fn f_i32() {
+ #[repr(i32)]
+ enum A {
+ Ok = i32::MAX - 1,
+ Ok2,
+ OhNo = i32::MIN,
+ NotTheEnd = -1,
+ Zero,
+ }
+
+ let _x = (A::Ok, A::Ok2, A::OhNo);
+ let z = (A::NotTheEnd, A::Zero).1 as i32;
+ assert_eq!(z, 0);
+}
+
+fn f_u32() {
+ #[repr(u32)]
+ enum A {
+ Ok = u32::MAX - 1,
+ Ok2,
+ OhNo = u32::MIN,
+ }
+
+ let _x = (A::Ok, A::Ok2, A::OhNo);
+}
+
+fn f_i64() {
+ #[repr(i64)]
+ enum A {
+ Ok = i64::MAX - 1,
+ Ok2,
+ OhNo = i64::MIN,
+ NotTheEnd = -1,
+ Zero,
+ }
+
+ let _x = (A::Ok, A::Ok2, A::OhNo);
+ let z = (A::NotTheEnd, A::Zero).1 as i64;
+ assert_eq!(z, 0);
+}
+
+fn f_u64() {
+ #[repr(u64)]
+ enum A {
+ Ok = u64::MAX - 1,
+ Ok2,
+ OhNo = u64::MIN,
+ }
+
+ let _x = (A::Ok, A::Ok2, A::OhNo);
+}
+
+fn f_isize() {
+ #[repr(isize)]
+ enum A {
+ Ok = isize::MAX - 1,
+ Ok2,
+ OhNo = isize::MIN,
+ NotTheEnd = -1,
+ Zero,
+ }
+
+ let _x = (A::Ok, A::Ok2, A::OhNo);
+ let z = (A::NotTheEnd, A::Zero).1 as isize;
+ assert_eq!(z, 0);
+}
+
+fn f_usize() {
+ #[repr(usize)]
+ enum A {
+ Ok = usize::MAX - 1,
+ Ok2,
+ OhNo = usize::MIN,
+ }
+
+ let _x = (A::Ok, A::Ok2, A::OhNo);
+}
+
+fn main() {
+ f_i8(); f_u8();
+ f_i16(); f_u16();
+ f_i32(); f_u32();
+ f_i64(); f_u64();
+
+ f_isize(); f_usize();
+}
fn main() {
let args = vec!("foobie", "asdf::asdf");
- let arr: Vec<&str> = args[1].split_str("::").collect();
+ let arr: Vec<&str> = args[1].split("::").collect();
assert_eq!(arr[0], "asdf");
assert_eq!(arr[0], "asdf");
}
assert!(x.ptr[1].to_bar() == bar);
}
-#[derive(Copy, PartialEq, Eq)]
+#[derive(Copy, Clone, PartialEq, Eq)]
struct Bar;
trait ToBar {
}
-#[derive(Copy, PartialEq, Eq)]
+#[derive(Copy, Clone, PartialEq, Eq)]
struct Bar;
trait ToBar {
ptr: T
}
-#[derive(Copy, PartialEq, Eq)]
+#[derive(Copy, Clone, PartialEq, Eq)]
struct Bar;
-#[derive(Copy, PartialEq, Eq)]
+#[derive(Copy, Clone, PartialEq, Eq)]
struct Bar1 {
f: isize
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#[derive(Copy, Debug)]
+#[derive(Copy, Clone, Debug)]
enum chan { chan_t, }
impl PartialEq for chan {
($m:ident, $t:ty, $v:expr) => {{
mod $m {
use std::mem::size_of;
- #[derive(Copy, Debug)]
+ #[derive(Copy, Clone, Debug)]
enum E {
V = $v,
A = 0
// pretty-expanded FIXME #23616
#![feature(path)]
-#![feature(convert)]
use std::env::*;
use std::path::PathBuf;
#![allow(unknown_features)]
#![feature(box_syntax)]
-#[derive(Copy)]
+#[derive(Copy, Clone)]
struct LM { resize_at: usize, size: usize }
enum HashMap<K,V> {
arg.a = 100;
}
-#[derive(Copy)]
+#[derive(Copy, Clone)]
struct A { a: isize }
pub fn main() {
// Tests for if as expressions returning nominal types
-#[derive(Copy)]
+#[derive(Copy, Clone)]
struct I { i: isize }
fn test_rec() {
assert_eq!(rs.i, 100);
}
-#[derive(Copy, Debug)]
+#[derive(Copy, Clone, Debug)]
enum mood { happy, sad, }
impl PartialEq for mood {
// Tests for match as expressions resulting in struct types
-#[derive(Copy)]
+#[derive(Copy, Clone)]
struct R { i: isize }
fn test_rec() {
assert_eq!(rs.i, 100);
}
-#[derive(Copy, Debug)]
+#[derive(Copy, Clone, Debug)]
enum mood { happy, sad, }
impl PartialEq for mood {
use std::cell::Cell;
-#[derive(Copy)]
+#[derive(Copy, Clone)]
struct Point {x: isize, y: isize, z: isize}
fn f(p: &Cell<Point>) {
#![feature(libc, std_misc)]
extern crate libc;
-use std::thread::Thread;
+use std::thread;
mod rustrt {
extern crate libc;
pub fn main() {
// Make sure we're on a task with small Rust stacks (main currently
// has a large stack)
- let _t = Thread::spawn(move|| {
+ let _t = thread::scoped(move|| {
let result = count(12);
println!("result = {}", result);
assert_eq!(result, 2048);
// Test a foreign function that accepts and returns a struct
// by value.
-#[derive(Copy, PartialEq, Debug)]
+#[derive(Copy, Clone, PartialEq, Debug)]
pub struct TwoU16s {
one: u16, two: u16
}
// Test a foreign function that accepts and returns a struct
// by value.
-#[derive(Copy, PartialEq, Debug)]
+#[derive(Copy, Clone, PartialEq, Debug)]
pub struct TwoU32s {
one: u32, two: u32
}
// Test a foreign function that accepts and returns a struct
// by value.
-#[derive(Copy, PartialEq, Debug)]
+#[derive(Copy, Clone, PartialEq, Debug)]
pub struct TwoU64s {
one: u64, two: u64
}
// Test a foreign function that accepts and returns a struct
// by value.
-#[derive(Copy, PartialEq, Debug)]
+#[derive(Copy, Clone, PartialEq, Debug)]
pub struct TwoU8s {
one: u8, two: u8
}
// pretty-expanded FIXME #23616
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub struct S {
x: u64,
y: u64,
fn id<T>(x: T) -> T { return x; }
-#[derive(Copy)]
+#[derive(Copy, Clone)]
struct Triple {x: isize, y: isize, z: isize}
pub fn main() {
// pretty-expanded FIXME #23616
-#[derive(Copy)]
+#[derive(Copy, Clone)]
enum Q { R(Option<usize>) }
fn xyzzy(q: Q) -> usize {
// pretty-expanded FIXME #23616
-#[derive(Copy)]
+#[derive(Copy, Clone)]
struct Pair { x: isize, y: isize }
pub fn main() {
use std::collections::HashMap;
use std::sync::mpsc::{channel, Sender};
use std::str;
- use std::thread::Thread;
+ use std::thread;
pub type putter<'a> = Box<FnMut(String, String) + 'a>;
for i in &inputs {
let ctrl = ctrl.clone();
let i = i.clone();
- Thread::spawn(move|| map_task(ctrl.clone(), i.clone()) );
+ thread::spawn(move|| map_task(ctrl.clone(), i.clone()) );
}
}
use std::marker::PhantomData;
-#[derive(Copy)]
+#[derive(Copy, Clone)]
struct Foo<T> { x: T }
type Ty<'tcx> = &'tcx TyS<'tcx>;
Boop(PhantomData<*mut &'tcx ()>)
}
-#[derive(Copy)]
+#[derive(Copy, Clone)]
enum Bar<'tcx> {
Baz(Foo<Ty<'tcx>>)
}
#![feature(intrinsics, std_misc)]
-use std::thread::Thread;
+use std::thread;
extern "rust-intrinsic" {
pub fn init<T>() -> T;
fn main() {
// do the test in a new thread to avoid (spurious?) stack overflows
- let _ = Thread::scoped(|| {
+ let _ = thread::scoped(|| {
let _memory: [u8; SIZE] = unsafe { init() };
}).join();
}
// pretty-expanded FIXME #23616
+#![feature(negate_unsigned)]
#![feature(intrinsics)]
mod rusti {
let a = slot.take();
let _a = match a {
// `{let .. a(); }` would break
- Some(a) => { let _a = a.invoke(()); },
+ Some(a) => { let _a = a(); },
None => (),
};
}
// pretty-expanded FIXME #23616
-#![feature(old_orphan_check, rustc_private, old_io)]
+#![feature(rustc_private, old_io)]
extern crate rbml;
extern crate serialize;
pub fn main() {
let mut x = 1;
- let _thunk = Thunk::new(move|| { x = 2; });
+ let _thunk = Box::new(move|| { x = 2; });
}
use std::collections::HashSet;
-#[derive(Copy, PartialEq, Eq, Hash)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash)]
struct XYZ {
x: isize,
y: isize,
}
}
-#[derive(Copy)]
+#[derive(Copy, Clone)]
struct JSRef {
node: *const Node
}
fn parent() {
let args: Vec<String> = env::args().collect();
let mut p = Command::new(&args[0]).arg("child")
- .stdout(Stdio::capture())
- .stdin(Stdio::capture())
+ .stdout(Stdio::piped())
+ .stdin(Stdio::piped())
.spawn().unwrap();
p.stdin.as_mut().unwrap().write_all(b"test1\ntest2\ntest3").unwrap();
let out = p.wait_with_output().unwrap();
#![feature(std_misc)]
use std::sync::mpsc::{channel, Sender, Receiver};
-use std::thread::Thread;
+use std::thread;
fn helper(rx: Receiver<Sender<()>>) {
for tx in rx.iter() {
fn main() {
let (tx, rx) = channel();
- let _t = Thread::spawn(move|| { helper(rx) });
+ let _t = thread::scoped(move|| { helper(rx) });
let (snd, rcv) = channel::<isize>();
for _ in 1..100000 {
snd.send(1).unwrap();
_ = rcv.recv() => ()
}
}
+ drop(tx);
}
use std::u8;
-const NUM: usize = u8::BITS as usize;
+const NUM: usize = u8::BITS;
struct MyStruct { nums: [usize; 8] }
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(old_orphan_check, rustc_private)]
+#![feature(rustc_private)]
extern crate serialize;
fn test() {
let args: Vec<String> = env::args().collect();
let mut p = Command::new(&args[0]).arg("child")
- .stdin(Stdio::capture())
- .stdout(Stdio::capture())
- .stderr(Stdio::capture())
+ .stdin(Stdio::piped())
+ .stdout(Stdio::piped())
+ .stderr(Stdio::piped())
.spawn().unwrap();
assert!(p.wait().unwrap().success());
}
// pretty-expanded FIXME #23616
-#![feature(old_orphan_check, core)]
+#![feature(core)]
use std::ops::Index;
// pretty-expanded FIXME #23616
-static X2: u64 = -1 as u16 as u64;
-static Y2: u64 = -1 as u32 as u64;
-const X: u64 = -1 as u16 as u64;
-const Y: u64 = -1 as u32 as u64;
+static X2: u64 = !0 as u16 as u64;
+static Y2: u64 = !0 as u32 as u64;
+const X: u64 = !0 as u16 as u64;
+const Y: u64 = !0 as u32 as u64;
fn main() {
assert_eq!(match 1 {
#![feature(core)]
+trait Str { fn foo(&self) {} }
+impl Str for str {}
+impl<'a, S: ?Sized> Str for &'a S where S: Str {}
+
fn main() {
let _: &Str = &"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.
+
+// Regression test for #17746
+
+fn main() {}
+
+struct A;
+
+impl A {
+ fn b(&mut self) {
+ self.a()
+ }
+}
+
+trait Foo {
+ fn dummy(&self) {}
+}
+trait Bar {
+ fn a(&self);
+}
+
+impl Foo for A {}
+impl<T> Bar for T where T: Foo {
+ fn a(&self) {}
+}
use std::thunk::Thunk;
-fn action(cb: Thunk<usize, usize>) -> usize {
- cb.invoke(1)
+fn action(cb: Thunk<(usize,), usize>) -> usize {
+ cb(1)
}
pub fn main() {
- println!("num: {}", action(Thunk::with_arg(move |u| u)));
+ println!("num: {}", action(Box::new(move |u| u)));
}
pub trait Promisable: Send + Sync {}
impl<T: Send + Sync> Promisable for T {}
-pub fn propagate<'a, T, E, F, G>(action: F) -> Thunk<'a,Result<T, E>, Result<T, E>>
+pub fn propagate<'a, T, E, F, G>(action: F) -> Thunk<'a, (Result<T, E>,), Result<T, E>>
where
T: Promisable + Clone + 'a,
E: Promisable + Clone + 'a,
F: FnOnce(&T) -> Result<T, E> + Send + 'a,
G: FnOnce(Result<T, E>) -> Result<T, E> + 'a {
- Thunk::with_arg(move |result: Result<T, E>| {
+ Box::new(move |result: Result<T, E>| {
match result {
Ok(ref t) => action(t),
Err(ref e) => Err(e.clone()),
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#[derive(Copy)]
+#[derive(Copy, Clone)]
enum Foo {
Bar,
Baz
use std::thread;
-fn main() {
- thread::Thread::spawn(move || { // no need for -> ()
+fn _foo() {
+ let _t = thread::scoped(move || { // no need for -> ()
loop {
println!("hello");
}
});
}
+
+fn main() {}
// pretty-expanded FIXME #23616
-#![feature(convert)]
-
use std::default::Default;
use std::io;
use std::fs;
}
/// The basic fully-recursive strategy. Nothing is pruned.
-#[derive(Copy, Default)]
+#[derive(Copy, Clone, Default)]
pub struct Recursive;
impl Strategy for Recursive {
#[derive(Copy)]
struct Test(*const i32);
+impl Clone for Test {
+ fn clone(&self) -> Test { *self }
+}
+
fn main() {}
static generations: usize = 1024+256+128+49;
fn spawn(f: Thunk<'static>) {
- Builder::new().stack_size(32 * 1024).spawn(move|| f.invoke(()));
+ Builder::new().stack_size(32 * 1024).spawn(move|| f());
}
fn child_no(x: usize) -> Thunk<'static> {
- Thunk::new(move|| {
+ Box::new(move|| {
if x < generations {
spawn(child_no(x+1));
}
raw: <R as Resources>::Buffer,
}
impl<R: Resources> Copy for BufferHandle<R> {}
+impl<R: Resources> Clone for BufferHandle<R> {
+ fn clone(&self) -> BufferHandle<R> { *self }
+}
enum Res {}
impl Resources for Res {
type Buffer = u32;
}
-impl Copy for Res { }
fn main() {
let b: BufferHandle<Res> = BufferHandle { raw: 1 };
use std::{fs, net};
fn assert_both<T: Send + Sync>() {}
+fn assert_send<T: Send>() {}
fn main() {
assert_both::<fs::File>();
assert_both::<fs::Metadata>();
assert_both::<fs::ReadDir>();
assert_both::<fs::DirEntry>();
- assert_both::<fs::WalkDir>();
+ assert_send::<fs::WalkDir>();
assert_both::<fs::OpenOptions>();
assert_both::<fs::Permissions>();
fn chowder(&self, y: A);
}
-#[derive(Copy)]
+#[derive(Copy, Clone)]
struct foo<A> {
x: A,
}
use std::intrinsics;
-#[derive(Copy)]
+#[derive(Copy, Clone)]
struct Wrap(i64);
// These volatile and atomic intrinsics used to cause an ICE
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#[derive(Copy)]
+#[derive(Copy, Clone)]
struct cat {
meow: extern "Rust" fn(),
}
}
}
-#[derive(Copy)]
+#[derive(Copy, Clone)]
struct KittyInfo {kitty: cat}
// Code compiles and runs successfully if we add a + before the first arg
use std::mem::{forget, transmute};
use std::mem::{replace, swap};
use std::mem;
- use std::thread::Thread;
+ use std::thread;
use std::marker::Send;
pub struct Stuff<T> {
let old_state = swap_state_acq(&mut (*p).state,
blocked);
match old_state {
- empty | blocked => { Thread::yield_now(); }
+ empty | blocked => { thread::yield_now(); }
full => {
let payload = replace(&mut p.payload, None);
return Some(payload.unwrap())
#![allow(unknown_features)]
#![feature(box_syntax)]
-#[derive(Copy)]
+#[derive(Copy, Clone)]
enum side { mayo, catsup, vinegar }
-#[derive(Copy)]
+#[derive(Copy, Clone)]
enum order { hamburger, fries(side), shake }
-#[derive(Copy)]
+#[derive(Copy, Clone)]
enum meal { to_go(order), for_here(order) }
fn foo(m: Box<meal>, cond: bool) {
use std::slice;
// Represents a position on a canvas.
-#[derive(Copy)]
+#[derive(Copy, Clone)]
struct Point {
x: isize,
y: isize,
// Represents an offset on a canvas. (This has the same structure as a Point.
// but different semantics).
-#[derive(Copy)]
+#[derive(Copy, Clone)]
struct Size {
width: isize,
height: isize,
}
-#[derive(Copy)]
+#[derive(Copy, Clone)]
struct Rect {
top_left: Point,
size: Size,
#![allow(unknown_features)]
#![feature(std_misc)]
-use std::thread::Thread;
+use std::thread;
use std::sync::mpsc::Sender;
-use std::thunk::Invoke;
type RingBuffer = Vec<f64> ;
type SamplesFn = Box<FnMut(&RingBuffer) + Send>;
}
fn foo(name: String, samples_chan: Sender<Msg>) {
- let _t = Thread::spawn(move|| {
+ let _t = thread::scoped(move|| {
let mut samples_chan = samples_chan;
// FIXME (#22405): Replace `Box::new` with `box` here when/if possible.
// If `Mul` used an associated type for its output, this test would
// work more smoothly.
-#![feature(old_orphan_check)]
use std::ops::Mul;
-#[derive(Copy)]
+#[derive(Copy, Clone)]
struct Vec2 {
x: f64,
y: f64
use std::f64;
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub struct Point {
x: f64,
y: f64
}
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub enum Shape {
Circle(Point, f64),
Rectangle(Point, Point)
failed to typecheck correctly.
*/
-#[derive(Copy)]
+#[derive(Copy, Clone)]
struct X { vec: &'static [isize] }
static V: &'static [X] = &[X { vec: &[1, 2, 3] }];
#![feature(std_misc)]
-use std::thread::Thread;
+use std::thread;
use std::sync::mpsc::{channel, Receiver};
fn periodical(n: isize) -> Receiver<bool> {
let (chan, port) = channel();
- Thread::spawn(move|| {
+ thread::spawn(move|| {
loop {
for _ in 1..n {
match chan.send(false) {
fn integers() -> Receiver<isize> {
let (chan, port) = channel();
- Thread::spawn(move|| {
+ thread::spawn(move|| {
let mut i = 1;
loop {
match chan.send(i) {
use std::sync::mpsc::{TryRecvError, channel};
use std::old_io::timer::Timer;
-use std::thread::Thread;
+use std::thread;
use std::time::Duration;
pub fn main() {
let (tx, rx) = channel();
- let _t = Thread::scoped(move||{
+ let _t = thread::scoped(move||{
let mut timer = Timer::new().unwrap();
timer.sleep(Duration::milliseconds(10));
tx.send(()).unwrap();
#![feature(std_misc)]
-use std::thread::Thread;
+use std::thread;
use std::sync::mpsc::{channel, Sender};
fn producer(tx: &Sender<Vec<u8>>) {
pub fn main() {
let (tx, rx) = channel::<Vec<u8>>();
- let _prod = Thread::spawn(move|| {
+ let _prod = thread::scoped(move|| {
producer(&tx)
});
#![feature(std_misc)]
-use std::thread::Thread;
+use std::thread;
fn user(_i: isize) {}
// Here, i is *copied* into the proc (heap closure).
// Requires allocation. The proc's copy is not mutable.
let mut i = 0;
- let _t = Thread::spawn(move|| {
+ let _t = thread::scoped(move|| {
user(i);
println!("spawned {}", i)
});
// mutable outside of the proc.
let mut i = 0;
while i < 10 {
- let _t = Thread::spawn(move|| {
+ let _t = thread::scoped(move|| {
user(i);
});
i += 1;
// Here, i must be shadowed in the proc to be mutable.
let mut i = 0;
while i < 10 {
- let _t = Thread::spawn(move|| {
+ let _t = thread::scoped(move|| {
let mut i = i;
i += 1;
user(i);
#![feature(std_misc)]
-use std::thread::Thread;
+use std::thread;
macro_rules! expr { ($e: expr) => { $e } }
macro_rules! spawn {
($($code: tt)*) => {
- expr!(Thread::spawn(move|| {$($code)*}))
+ expr!(thread::spawn(move|| {$($code)*}))
}
}
dir: Direction::North };
pub mod glfw {
- #[derive(Copy)]
+ #[derive(Copy, Clone)]
pub struct InputState(usize);
pub const RELEASE : InputState = InputState(0);
static mut COUNT: u64 = 1;
-#[derive(Copy)]
+#[derive(Copy, Clone)]
struct Foo;
trait Bar : Sized {
static mut COUNT: usize = 1;
-#[derive(Copy)]
+#[derive(Copy, Clone)]
struct Foo;
impl Foo {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// Test that we pick which version of `Foo` to run based on whether
-// the type we (ultimately) inferred for `x` is copyable or not.
-//
-// In this case, the two versions are both impls of same trait, and
-// hence we we can resolve method even without knowing yet which
-// version will run (note that the `push` occurs after the call to
-// `foo()`).
+// Test that when we write `x.foo()`, we do nothave to know the
+// complete type of `x` in order to type-check the method call. In
+// this case, we know that `x: Vec<_1>`, but we don't know what type
+// `_1` is (because the call to `push` comes later). To pick between
+// the impls, we would have to know `_1`, since we have to know
+// whether `_1: MyCopy` or `_1 == Box<i32>`. However (and this is the
+// point of the test), we don't have to pick between the two impls --
+// it is enough to know that `foo` comes from the `Foo` trait. We can
+// translate the call as `Foo::foo(&x)` and let the specific impl get
+// chosen later.
// pretty-expanded FIXME #23616
fn foo(&self) -> isize;
}
-impl<T:Copy> Foo for Vec<T> {
+trait MyCopy { fn foo(&self) { } }
+impl MyCopy for i32 { }
+
+impl<T:MyCopy> Foo for Vec<T> {
fn foo(&self) -> isize {1}
}
-impl<T> Foo for Vec<Box<T>> {
+impl Foo for Vec<Box<i32>> {
fn foo(&self) -> isize {2}
}
fn call_foo_copy() -> isize {
let mut x = Vec::new();
let y = x.foo();
- x.push(0_usize);
+ x.push(0_i32);
y
}
fn call_foo_other() -> isize {
- let mut x: Vec<Box<_>> = Vec::new();
+ let mut x: Vec<_> = Vec::new();
let y = x.foo();
- x.push(box 0);
+ let z: Box<i32> = box 0;
+ x.push(z);
y
}
fn main() {
let x: [isize; 4] = [1,2,3,4];
- let xptr = x.as_slice() as *const [isize];
+ let xptr = &x[..] as *const [isize];
xptr.foo();
}
--- /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)]
+use std::fmt::Debug;
+use std::cmp::{self, PartialOrd, Ordering};
+use std::iter::MinMaxResult::MinMax;
+
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+struct Foo {
+ n: u8,
+ name: &'static str
+}
+
+impl PartialOrd for Foo {
+ fn partial_cmp(&self, other: &Foo) -> Option<Ordering> {
+ Some(self.cmp(other))
+ }
+}
+
+impl Ord for Foo {
+ fn cmp(&self, other: &Foo) -> Ordering {
+ self.n.cmp(&other.n)
+ }
+}
+
+fn main() {
+ let a = Foo { n: 4, name: "a" };
+ let b = Foo { n: 4, name: "b" };
+ let c = Foo { n: 8, name: "c" };
+ let d = Foo { n: 8, name: "d" };
+ let e = Foo { n: 22, name: "e" };
+ let f = Foo { n: 22, name: "f" };
+
+ let data = [a, b, c, d, e, f];
+
+ // `min` should return the left when the values are equal
+ assert_eq!(data.iter().min(), Some(&a));
+ assert_eq!(data.iter().min_by(|a| a.n), Some(&a));
+ assert_eq!(cmp::min(a, b), a);
+ assert_eq!(cmp::min(b, a), b);
+ assert_eq!(cmp::partial_min(a, b), Some(a));
+ assert_eq!(cmp::partial_min(b, a), Some(b));
+
+ // `max` should return the right when the values are equal
+ assert_eq!(data.iter().max(), Some(&f));
+ assert_eq!(data.iter().max_by(|a| a.n), Some(&f));
+ assert_eq!(cmp::max(e, f), f);
+ assert_eq!(cmp::max(f, e), e);
+ assert_eq!(cmp::partial_max(e, f), Some(f));
+ assert_eq!(cmp::partial_max(f, e), Some(e));
+
+ // Similar for `min_max`
+ assert_eq!(data.iter().min_max(), MinMax(&a, &f));
+ assert_eq!(data[1..5].iter().min_max(), MinMax(&b, &e));
+ assert_eq!(data[2..4].iter().min_max(), MinMax(&c, &d));
+
+ let mut presorted = data.to_vec();
+ presorted.sort();
+ assert_stable(&presorted);
+
+ let mut presorted = data.to_vec();
+ presorted.sort_by(|a, b| a.cmp(b));
+ assert_stable(&presorted);
+
+ // Assert that sorted and min/max are the same
+ fn assert_stable<T: Ord + Debug>(presorted: &[T]) {
+ for slice in presorted.windows(2) {
+ let a = &slice[0];
+ let b = &slice[1];
+
+ assert_eq!(a, cmp::min(a, b));
+ assert_eq!(b, cmp::max(a, b));
+ }
+ }
+}
* and apply the wrong instance of the method `unwrap`.
*/
-#[derive(Copy)]
+#[derive(Copy, Clone)]
struct S<T> { i:u8, t:T }
impl<T> S<T> {
}
}
-#[derive(Copy, PartialEq, Debug)]
+#[derive(Copy, Clone, PartialEq, Debug)]
struct A((u32, u32));
-#[derive(Copy, PartialEq, Debug)]
+#[derive(Copy, Clone, PartialEq, Debug)]
struct B(u64);
pub fn main() {
#![feature(std_misc)]
-use std::thread::Thread;
+use std::thread;
pub fn main() {
let x = "Hello world!".to_string();
- let _t = Thread::spawn(move|| {
+ let _t = thread::scoped(move|| {
println!("{}", x);
});
}
fn get(&self) -> T;
}
-#[derive(Copy)]
+#[derive(Copy, Clone)]
struct MyType {
dummy: usize
}
}
}
-#[derive(Copy)]
+#[derive(Copy, Clone)]
struct MyType {
dummy: usize
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#[derive(Copy)]
+#[derive(Copy, Clone)]
struct mytype(Mytype);
-#[derive(Copy)]
+#[derive(Copy, Clone)]
struct Mytype {
compute: fn(mytype) -> isize,
val: isize,
use std::cmp;
use std::ops;
-#[derive(Copy, Debug)]
+#[derive(Copy, Clone, Debug)]
struct Point {
x: isize,
y: isize
pub fn main() {
let thing = "{{ f }}";
- let f = thing.find_str("{{");
+ let f = thing.find("{{");
if f.is_none() {
println!("None!");
use std::old_io::process::Command;
use std::env;
-use std::thread::Thread;
+use std::thread;
// lifted from the test module
// Inlining to avoid llvm turning the recursive functions into tail calls,
fn main() {
let args: Vec<String> = env::args().collect();
if args.len() > 1 && args[1] == "recurse" {
- let _t = Thread::scoped(recurse);
+ let _t = thread::scoped(recurse);
} else {
let recurse = Command::new(&args[0]).arg("recurse").output().unwrap();
assert!(!recurse.status.success());
// pretty-expanded FIXME #23616
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub struct Foo {
f1: isize,
_f2: isize,
use std::rc::Rc;
use std::ops::Deref;
-#[derive(Copy)]
+#[derive(Copy, Clone)]
struct DerefWrapper<X, Y> {
x: X,
y: Y
mod priv_test {
use std::ops::Deref;
- #[derive(Copy)]
+ #[derive(Copy, Clone)]
pub struct DerefWrapperHideX<X, Y> {
x: X,
pub y: Y
use std::mem;
#[repr(packed)]
-#[derive(Copy, PartialEq, Debug)]
+#[derive(Copy, Clone, PartialEq, Debug)]
struct Foo {
bar: u8,
baz: u64
--- /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.
+
+use std::env;
+use std::process::{self, Command, Stdio};
+
+fn main() {
+ let args: Vec<String> = env::args().collect();
+ if args.len() > 1 && args[1] == "child" {
+ child();
+ } else {
+ parent();
+ }
+}
+
+fn parent() {
+ let args: Vec<String> = env::args().collect();
+ let status = Command::new(&args[0]).arg("child").status().unwrap();
+ assert_eq!(status.code(), Some(2));
+}
+
+fn child() -> i32 {
+ process::exit(2);
+}
// pretty-expanded FIXME #23616
-#[derive(Copy)]
+#[derive(Copy, Clone)]
struct Point {x: isize, y: isize}
type rect = (Point, Point);
// pretty-expanded FIXME #23616
-#[derive(Copy)]
+#[derive(Copy, Clone)]
struct Rect {x: isize, y: isize, w: isize, h: isize}
fn f(r: Rect, x: isize, y: isize, w: isize, h: isize) {
v6: Option<C>
}
-#[derive(Copy)]
+#[derive(Copy, Clone)]
struct C {
f: isize
}
fn get(&self) -> &'a isize;
}
-#[derive(Copy)]
+#[derive(Copy, Clone)]
struct Box<'a> {
t: &'a isize
}
fn get(&self) -> &'a T;
}
+#[derive(Copy, Clone)]
struct Box<'a, T:'a> {
t: &'a T
}
-impl<'a,T:'a> Copy for Box<'a,T> {}
-
impl<'a,T:Clone> GetRef<'a,T> for Box<'a,T> {
fn get(&self) -> &'a T {
self.t
fn get(&self) -> T;
}
-#[derive(Copy)]
+#[derive(Copy, Clone)]
struct Box<T> {
t: T
}
type Type<'tcx> = &'tcx TypeStructure<'tcx>;
-#[derive(Copy, Debug)]
+#[derive(Copy, Clone, Debug)]
enum TypeStructure<'tcx> {
TypeInt,
TypeFunction(Type<'tcx>, Type<'tcx>),
}
}
-#[derive(Copy, PartialEq, Eq, Hash)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash)]
struct NodeId {
id: usize
}
type Ast<'ast> = &'ast AstStructure<'ast>;
-#[derive(Copy)]
+#[derive(Copy, Clone)]
struct AstStructure<'ast> {
id: NodeId,
kind: AstKind<'ast>
}
-#[derive(Copy)]
+#[derive(Copy, Clone)]
enum AstKind<'ast> {
ExprInt,
ExprVar(usize),
// supposed to match the lifetime `'a`) ...
fn foo<'a>(map: RefCell<HashMap<&'static str, &'a [u8]>>) {
let one = [1];
- assert_eq!(map.borrow().get("one"), Some(&one.as_slice()));
+ assert_eq!(map.borrow().get("one"), Some(&&one[..]));
}
#[cfg(all(not(cannot_use_this_yet),not(cannot_use_this_yet_either)))]
+++ /dev/null
-// Copyright 2013-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.
-
-// This test can't be a unit test in std,
-// because it needs TempDir, which is in extra
-
-// pretty-expanded FIXME #23616
-
-#![feature(tempdir, path_ext)]
-
-use std::ffi::CString;
-use std::fs::{self, TempDir, File, PathExt};
-
-fn rename_directory() {
- 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() }
#![feature(start, os, std_misc, old_io)]
-use std::ffi;
+use std::ffi::CStr;
use std::old_io::process::{Command, ProcessOutput};
use std::os;
use std::rt::unwind::try;
let args = unsafe {
(0..argc as usize).map(|i| {
let ptr = *argv.offset(i as isize) as *const _;
- ffi::c_str_to_bytes(&ptr).to_vec()
+ CStr::from_ptr(ptr).to_bytes().to_vec()
}).collect::<Vec<_>>()
};
let me = &*args[0];
extern crate log;
use std::sync::mpsc::{channel, Sender, Receiver};
-use std::thread::Thread;
+use std::thread;
pub struct ChannelLogger {
tx: Sender<String>
pub fn main() {
let (logger, rx) = ChannelLogger::new();
- let _t = Thread::spawn(move|| {
+ let _t = thread::scoped(move|| {
log::set_logger(logger);
info!("foo");
// pretty-expanded FIXME #23616
-#[derive(Copy)]
+#[derive(Copy, Clone)]
struct Value {
n: isize
}
// pretty-expanded FIXME #23616
#![feature(core, std_misc)]
-use std::thread::Thread;
+use std::thread;
use std::sync::Mutex;
fn par_for<I, F>(iter: I, f: F)
{
let f = &f;
let _guards: Vec<_> = iter.map(|elem| {
- Thread::scoped(move || {
+ thread::scoped(move || {
f(elem)
})
}).collect();
#![feature(std_misc)]
-use std::thread::Thread;
+use std::thread;
use std::sync::mpsc::channel;
struct test {
pub fn main() {
let (tx, rx) = channel();
- let _t = Thread::spawn(move|| {
+ let _t = thread::scoped(move|| {
let (tx2, rx2) = channel();
tx.send(tx2).unwrap();
assert!(eq_u32x4(u32x4(1, 2, 3, 4) + u32x4(4, 3, 2, 1), u32x4(5, 5, 5, 5)));
assert!(eq_u32x4(u32x4(4, 5, 6, 7) - u32x4(4, 3, 2, 1), u32x4(0, 2, 4, 6)));
assert!(eq_u32x4(u32x4(1, 2, 3, 4) * u32x4(4, 3, 2, 1), u32x4(4, 6, 6, 4)));
+ assert!(eq_u32x4(u32x4(1, 2, 3, 4) / u32x4(4, 3, 2, 1), u32x4(0, 0, 1, 4)));
assert!(eq_u32x4(u32x4(1, 2, 3, 4) & u32x4(4, 3, 2, 1), u32x4(0, 2, 2, 0)));
assert!(eq_u32x4(u32x4(1, 2, 3, 4) | u32x4(4, 3, 2, 1), u32x4(5, 3, 3, 5)));
assert!(eq_u32x4(u32x4(1, 2, 3, 4) ^ u32x4(4, 3, 2, 1), u32x4(5, 1, 1, 5)));
assert!(eq_i32x4(i32x4(1, 2, 3, 4) + i32x4(4, 3, 2, 1), i32x4(5, 5, 5, 5)));
assert!(eq_i32x4(i32x4(1, 2, 3, 4) - i32x4(4, 3, 2, 1), i32x4(-3, -1, 1, 3)));
assert!(eq_i32x4(i32x4(1, 2, 3, 4) * i32x4(4, 3, 2, 1), i32x4(4, 6, 6, 4)));
+ assert!(eq_i32x4(i32x4(1, 2, 3, 4) / i32x4(4, 3, 2, 1), i32x4(0, 0, 1, 4)));
assert!(eq_i32x4(i32x4(1, 2, 3, 4) & i32x4(4, 3, 2, 1), i32x4(0, 2, 2, 0)));
assert!(eq_i32x4(i32x4(1, 2, 3, 4) | i32x4(4, 3, 2, 1), i32x4(5, 3, 3, 5)));
assert!(eq_i32x4(i32x4(1, 2, 3, 4) ^ i32x4(4, 3, 2, 1), i32x4(5, 1, 1, 5)));
use std::ops;
#[simd]
-#[derive(Copy)]
+#[derive(Copy, Clone)]
struct f32x4(f32, f32, f32, f32);
fn add<T: ops::Add<Output=T>>(lhs: T, rhs: T) -> T {
// pretty-expanded FIXME #23616
+// this is for the wrapping_add call below.
+#![feature(core)]
+
/*!
* Tests the range assertion wraparound case in trans::middle::adt::load_discr.
*/
#[repr(u8)]
-#[derive(Copy)]
+#[derive(Copy, Clone)]
enum Eu { Lu = 0, Hu = 255 }
static CLu: Eu = Eu::Lu;
static CHu: Eu = Eu::Hu;
#[repr(i8)]
-#[derive(Copy)]
+#[derive(Copy, Clone)]
enum Es { Ls = -128, Hs = 127 }
static CLs: Es = Es::Ls;
static CHs: Es = Es::Hs;
pub fn main() {
- assert_eq!((Eu::Hu as u8) + 1, Eu::Lu as u8);
- assert_eq!((Es::Hs as i8) + 1, Es::Ls as i8);
+ assert_eq!((Eu::Hu as u8).wrapping_add(1), Eu::Lu as u8);
+ assert_eq!((Es::Hs as i8).wrapping_add(1), Es::Ls as i8);
assert_eq!(CLu as u8, Eu::Lu as u8);
assert_eq!(CHu as u8, Eu::Hu as u8);
assert_eq!(CLs as i8, Es::Ls as i8);
+++ /dev/null
-// Copyright 2012-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.
-
-// pretty-expanded FIXME #23616
-
-#![feature(tempdir, path_ext)]
-
-use std::fs::{File, TempDir};
-use std::io::prelude::*;
-
-pub fn main() {
- let dir = TempDir::new_in(".", "").unwrap();
- let path = dir.path().join("file");
-
- {
- match File::create(&path) {
- Err(..) => unreachable!(),
- Ok(f) => {
- let mut f = f;
- for _ in 0..1000 {
- f.write(&[0]);
- }
- }
- }
- }
-
- assert!(path.exists());
- assert_eq!(path.metadata().unwrap().len(), 1000);
-}
//
// ignore-lexer-test FIXME #15883
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub struct Quad { a: u64, b: u64, c: u64, d: u64 }
-#[derive(Copy)]
+#[derive(Copy, Clone)]
pub struct Floats { a: f64, b: u8, c: f64 }
mod rustrt {
-#[derive(Copy, Debug)]
+#[derive(Copy, Clone, Debug)]
enum foo { large, small, }
impl PartialEq for foo {
all_sync_send!(LinkedList::<usize>::new(), iter, iter_mut, into_iter);
- #[derive(Copy)]
+ #[derive(Copy, Clone)]
#[repr(usize)]
#[allow(dead_code)]
enum Foo { A, B, C }
assert!(
include_str!("syntax-extension-source-utils-files/includeme.\
fragment").to_string()
- .as_slice()
.starts_with("/* this is for "));
assert!(
include_bytes!("syntax-extension-source-utils-files/includeme.fragment")
// The Windows tests are wrapped in an extra module for some reason
assert!((m1::m2::where_am_i().ends_with("m1::m2")));
- assert!(match (47, "( 2 * 3 ) + 5") {
- (line!(), stringify!((2*3) + 5)) => true,
- _ => false
- })
+ assert_eq!((46, "( 2 * 3 ) + 5"), (line!(), stringify!((2*3) + 5)));
}
use color::{red, green, blue, black, white, imaginary, purple, orange};
-#[derive(Copy)]
+#[derive(Copy, Clone)]
enum color {
red = 0xff0000,
green = 0x00ff00,
#![feature(std_misc)]
-use std::thread::Thread;
+use std::thread;
use std::sync::mpsc::{channel, Sender};
pub fn main() { test05(); }
fn test05() {
let (tx, rx) = channel();
- let _t = Thread::spawn(move|| { test05_start(&tx) });
+ let _t = thread::scoped(move|| { test05_start(&tx) });
let mut value: isize = rx.recv().unwrap();
println!("{}", value);
value = rx.recv().unwrap();
#![feature(std_misc)]
-use std::thread::Thread;
+use std::thread;
pub fn main() { test00(); }
fn start() { println!("Started / Finished task."); }
fn test00() {
- let _ = Thread::scoped(move|| start() ).join();
+ let _ = thread::scoped(move|| start() ).join();
println!("Completing.");
}
#![feature(std_misc)]
-use std::thread::Thread;
+use std::thread;
use std::sync::mpsc::{channel, Sender};
fn start(tx: &Sender<Sender<String>>) {
pub fn main() {
let (tx, rx) = channel();
- let _child = Thread::spawn(move|| { start(&tx) });
+ let _child = thread::scoped(move|| { start(&tx) });
let mut c = rx.recv().unwrap();
c.send("A".to_string()).unwrap();
c.send("B".to_string()).unwrap();
- Thread::yield_now();
+ thread::yield_now();
}
#![feature(std_misc)]
use std::sync::mpsc::{channel, Sender};
-use std::thread::Thread;
+use std::thread;
fn start(tx: &Sender<Sender<isize>>) {
let (tx2, _rx) = channel();
pub fn main() {
let (tx, rx) = channel();
- let _child = Thread::spawn(move|| {
+ let _child = thread::scoped(move|| {
start(&tx)
});
let _tx = rx.recv().unwrap();
#![feature(std_misc)]
-use std::thread::Thread;
+use std::thread;
pub fn main() { test00(); }
fn test00() {
let i: isize = 0;
- let mut result = Thread::scoped(move|| {
+ let mut result = thread::scoped(move|| {
start(i)
});
// Sleep long enough for the task to finish.
let mut i = 0_usize;
while i < 10000 {
- Thread::yield_now();
+ thread::yield_now();
i += 1;
}
#![feature(std_misc)]
use std::sync::mpsc::{channel, Sender};
-use std::thread::Thread;
+use std::thread;
fn start(tx: &Sender<isize>, start: isize, number_of_messages: isize) {
let mut i: isize = 0;
pub fn main() {
println!("Check that we don't deadlock.");
let (tx, rx) = channel();
- let _ = Thread::scoped(move|| { start(&tx, 0, 10) }).join();
+ let _t = thread::scoped(move|| { start(&tx, 0, 10) }).join();
println!("Joined task");
}
#![feature(std_misc)]
use std::sync::mpsc::{channel, Sender};
-use std::thread::Thread;
+use std::thread;
pub fn main() {
let (tx, rx) = channel();
while (i > 0) {
println!("{}", i);
let tx = tx.clone();
- Thread::spawn({let i = i; move|| { child(i, &tx) }});
+ thread::scoped({let i = i; move|| { child(i, &tx) }});
i = i - 1;
}
#![feature(std_misc)]
use std::sync::mpsc::{channel, Sender};
-use std::thread::Thread;
+use std::thread;
fn start(tx: &Sender<isize>, i0: isize) {
let mut i = i0;
// the child's point of view the receiver may die. We should
// drop messages on the floor in this case, and not crash!
let (tx, rx) = channel();
- let _t = Thread::spawn(move|| {
+ let _t = thread::scoped(move|| {
start(&tx, 10)
});
rx.recv();
// This test is specifically about spawning temporary closures.
-use std::thread::Thread;
+use std::thread;
fn f() {
}
pub fn main() {
- let _t = Thread::scoped(move|| f() ).join();
+ let _t = thread::scoped(move|| f() ).join();
}
// no-pretty-expanded FIXME #15189
-use std::thread::Thread;
+use std::thread;
use std::sync::mpsc::{channel, Sender};
pub fn main() { println!("===== WITHOUT THREADS ====="); test00(); }
let mut results = Vec::new();
while i < number_of_tasks {
let tx = tx.clone();
- results.push(Thread::scoped({
+ results.push(thread::scoped({
let i = i;
move|| {
test00_start(&tx, i, number_of_messages)
#![allow(dead_assignment)]
use std::sync::mpsc::{channel, Sender};
-use std::thread::Thread;
+use std::thread;
pub fn main() { test00(); }
let number_of_messages: isize = 10;
let tx2 = tx.clone();
- let _t = Thread::spawn(move|| {
+ let _t = thread::scoped(move|| {
test00_start(&tx2, number_of_messages * 0, number_of_messages);
});
let tx2 = tx.clone();
- let _t = Thread::spawn(move|| {
+ let _t = thread::scoped(move|| {
test00_start(&tx2, number_of_messages * 1, number_of_messages);
});
let tx2 = tx.clone();
- let _t = Thread::spawn(move|| {
+ let _t = thread::scoped(move|| {
test00_start(&tx2, number_of_messages * 2, number_of_messages);
});
let tx2 = tx.clone();
- let _t = Thread::spawn(move|| {
+ let _t = thread::scoped(move|| {
test00_start(&tx2, number_of_messages * 3, number_of_messages);
});
#![feature(std_misc)]
-use std::thread::Thread;
+use std::thread;
use std::sync::mpsc::{channel, Sender};
pub fn main() { test00(); }
let (tx, rx) = channel();
let number_of_messages: isize = 10;
- let result = Thread::scoped(move|| {
+ let result = thread::scoped(move|| {
test00_start(&tx, number_of_messages);
});
#![feature(std_misc)]
-use std::thread::Thread;
+use std::thread;
pub fn main() {
- let _t = Thread::spawn(move|| child("Hello".to_string()) );
+ let _t = thread::scoped(move|| child("Hello".to_string()) );
}
fn child(_s: String) {
#![allow(unknown_features)]
#![feature(box_syntax, std_misc)]
-use std::thread::Thread;
+use std::thread;
use std::sync::mpsc::channel;
pub fn main() {
let x: Box<isize> = box 1;
let x_in_parent = &(*x) as *const isize as usize;
- let _t = Thread::spawn(move || {
+ let _t = thread::scoped(move || {
let x_in_child = &(*x) as *const isize as usize;
tx.send(x_in_child).unwrap();
});
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::mpsc::channel;
-use std::thread::Thread;
+use std::thread;
static N: usize = 8;
static M: usize = 20;
let a = a.clone();
let cnt = cnt.clone();
let srv_tx = srv_tx.clone();
- Thread::scoped(move|| {
+ thread::scoped(move|| {
let mut a = a;
loop {
match a.accept() {
let _t = (0..N).map(|_| {
let cli_tx = cli_tx.clone();
- Thread::scoped(move|| {
+ thread::scoped(move|| {
for _ in 0..M {
let _s = TcpStream::connect(addr).unwrap();
}
use std::old_io;
use std::time::Duration;
use std::sync::mpsc::channel;
-use std::thread::Thread;
+use std::thread;
#[cfg_attr(target_os = "freebsd", ignore)]
fn eventual_timeout() {
let (tx1, rx1) = channel();
let (_tx2, rx2) = channel::<()>();
- let _t = Thread::spawn(move|| {
+ let _t = thread::scoped(move|| {
let _l = TcpListener::bind(addr).unwrap().listen();
tx1.send(()).unwrap();
let _ = rx2.recv();
use std::sync::mpsc::channel;
use std::old_io::net::tcp::{TcpListener, TcpStream};
use std::old_io::{Acceptor, Listener, Reader, Writer};
-use std::thread::{Builder, Thread};
+use std::thread::{self, Builder};
use std::time::Duration;
fn main() {
// This test has a chance to time out, try to not let it time out
- Thread::spawn(move|| -> () {
+ thread::spawn(move|| -> () {
use std::old_io::timer;
timer::sleep(Duration::milliseconds(30 * 1000));
println!("timed out!");
});
let (tx, rx) = channel();
- Thread::spawn(move || -> () {
+ thread::spawn(move || -> () {
let mut listener = TcpListener::bind("127.0.0.1:0").unwrap();
tx.send(listener.socket_name().unwrap()).unwrap();
let mut acceptor = listener.listen();
use std::old_io::fs::PathExtensions;
use std::old_io::{fs, TempDir};
use std::old_io;
-use std::os;
+use std::env;
use std::sync::mpsc::channel;
use std::thread;
// to depend on std
fn recursive_mkdir_rel() {
let path = Path::new("frob");
- let cwd = os::getcwd().unwrap();
+ let cwd = Path::new(env::current_dir().unwrap().to_str().unwrap());
println!("recursive_mkdir_rel: Making: {} in cwd {} [{}]", path.display(),
cwd.display(), path.exists());
fs::mkdir_recursive(&path, old_io::USER_RWX);
fn recursive_mkdir_rel_2() {
let path = Path::new("./frob/baz");
- let cwd = os::getcwd().unwrap();
+ let cwd = Path::new(env::current_dir().unwrap().to_str().unwrap());
println!("recursive_mkdir_rel_2: Making: {} in cwd {} [{}]", path.display(),
cwd.display(), path.exists());
fs::mkdir_recursive(&path, old_io::USER_RWX);
fn in_tmpdir<F>(f: F) where F: FnOnce() {
let tmpdir = TempDir::new("test").ok().expect("can't make tmpdir");
- assert!(os::change_dir(tmpdir.path()).is_ok());
+ assert!(env::set_current_dir(tmpdir.path().as_str().unwrap()).is_ok());
f();
}
#![feature(std_misc)]
-use std::thread::Thread;
+use std::thread;
pub fn main() {
let mut i = 10;
while i > 0 {
- Thread::scoped({let i = i; move|| child(i)});
+ thread::scoped({let i = i; move|| child(i)});
i = i - 1;
}
println!("main thread exiting");
use std::sync::Arc;
use std::sync::mpsc::channel;
-use std::thread::Thread;
+use std::thread;
trait Pet {
fn name(&self, blk: Box<FnMut(&str)>);
box dogge2 as Box<Pet+Sync+Send>));
let (tx1, rx1) = channel();
let arc1 = arc.clone();
- let _t1 = Thread::spawn(move|| { check_legs(arc1); tx1.send(()); });
+ let _t1 = thread::scoped(move|| { check_legs(arc1); tx1.send(()); });
let (tx2, rx2) = channel();
let arc2 = arc.clone();
- let _t2 = Thread::spawn(move|| { check_names(arc2); tx2.send(()); });
+ let _t2 = thread::scoped(move|| { check_names(arc2); tx2.send(()); });
let (tx3, rx3) = channel();
let arc3 = arc.clone();
- let _t3 = Thread::spawn(move|| { check_pedigree(arc3); tx3.send(()); });
+ let _t3 = thread::scoped(move|| { check_pedigree(arc3); tx3.send(()); });
rx1.recv();
rx2.recv();
rx3.recv();
fn f(&self, x: T);
}
-#[derive(Copy)]
+#[derive(Copy, Clone)]
struct Struct {
x: isize,
y: isize,
fn f(&self);
}
-#[derive(Copy)]
+#[derive(Copy, Clone)]
struct Struct {
x: isize,
y: isize,
#![allow(unknown_features)]
#![feature(box_syntax)]
+use std::marker::MarkerTrait;
+
trait Get {
fn get(&self) -> Self;
}
-impl<T:Copy> Get for T {
- fn get(&self) -> T { *self }
+trait MyCopy : MarkerTrait { fn copy(&self) -> Self; }
+impl MyCopy for u16 { fn copy(&self) -> Self { *self } }
+impl MyCopy for u32 { fn copy(&self) -> Self { *self } }
+impl MyCopy for i32 { fn copy(&self) -> Self { *self } }
+impl<T:Copy> MyCopy for Option<T> { fn copy(&self) -> Self { *self } }
+
+impl<T:MyCopy> Get for T {
+ fn get(&self) -> T { self.copy() }
}
-impl<T:Get> Get for Box<T> {
- fn get(&self) -> Box<T> { box get_it(&**self) }
+impl Get for Box<i32> {
+ fn get(&self) -> Box<i32> { box get_it(&**self) }
}
fn get_it<T:Get>(t: &T) -> T {
#![allow(unknown_features)]
#![feature(box_syntax)]
-#[derive(Copy)]
+#[derive(Copy, Clone)]
struct Foo {
f: isize,
}
}
}
-#[derive(Copy)]
+#[derive(Copy, Clone)]
struct Bar<T> {
f: T,
}
--- /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 you can supply `&F` where `F: FnMut()`.
+
+// pretty-expanded FIXME #23616
+
+#![feature(lang_items, unboxed_closures)]
+
+fn a<F:FnMut() -> i32>(mut f: F) -> i32 {
+ f()
+}
+
+fn b(f: &mut FnMut() -> i32) -> i32 {
+ a(f)
+}
+
+fn c<F:FnMut() -> i32>(f: &mut F) -> i32 {
+ a(f)
+}
+
+fn main() {
+ let z: isize = 7;
+
+ let x = b(&mut || 22);
+ assert_eq!(x, 22);
+
+ let x = c(&mut || 22);
+ assert_eq!(x, 22);
+}
--- /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 you can supply `&F` where `F: Fn()`.
+
+// pretty-expanded FIXME #23616
+
+#![feature(lang_items, unboxed_closures)]
+
+fn a<F:Fn() -> i32>(f: F) -> i32 {
+ f()
+}
+
+fn b(f: &Fn() -> i32) -> i32 {
+ a(f)
+}
+
+fn c<F:Fn() -> i32>(f: &F) -> i32 {
+ a(f)
+}
+
+fn main() {
+ let z: isize = 7;
+
+ let x = b(&|| 22);
+ assert_eq!(x, 22);
+
+ let x = c(&|| 22);
+ assert_eq!(x, 22);
+}
#![feature(alloc)]
-use std::boxed::BoxAny;
use std::thread;
struct Foo;
extern crate libc;
-use std::ffi::{self, CString};
+use std::ffi::{CStr, CString};
use libc::{c_char, c_int};
unsafe fn check<T, F>(expected: &str, f: F) where F: FnOnce(*mut c_char) -> T {
let mut x = [0 as c_char; 50];
f(&mut x[0] as *mut c_char);
- assert_eq!(expected.as_bytes(), ffi::c_str_to_bytes(&x.as_ptr()));
+ assert_eq!(expected.as_bytes(), CStr::from_ptr(x.as_ptr()).to_bytes());
}
pub fn main() {
}
pub fn main() {
- assert!(MAX_LEN <= std::usize::BITS as usize);
+ assert!(MAX_LEN <= std::usize::BITS);
// len can't go above 64.
for len in 2..MAX_LEN {
for _ in 0..REPEATS {