Auto merge of #23936 - pnkfelix:rollup, r=pnkfelix
This is an attempt to fix #23922
This commit is contained in:
commit
8943653624
@ -18,7 +18,6 @@
|
||||
#![feature(std_misc)]
|
||||
#![feature(test)]
|
||||
#![feature(path_ext)]
|
||||
#![feature(convert)]
|
||||
#![feature(str_char)]
|
||||
|
||||
#![deny(warnings)]
|
||||
|
@ -977,7 +977,6 @@ An example of `use` declarations:
|
||||
|
||||
```
|
||||
# #![feature(core)]
|
||||
use std::iter::range_step;
|
||||
use std::option::Option::{Some, None};
|
||||
use std::collections::hash_map::{self, HashMap};
|
||||
|
||||
@ -985,9 +984,6 @@ fn foo<T>(_: T){}
|
||||
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]);
|
||||
|
@ -42,5 +42,6 @@
|
||||
* [Intrinsics](intrinsics.md)
|
||||
* [Lang items](lang-items.md)
|
||||
* [Link args](link-args.md)
|
||||
* [Benchmark Tests](benchmark-tests.md)
|
||||
* [Conclusion](conclusion.md)
|
||||
* [Glossary](glossary.md)
|
||||
|
152
src/doc/trpl/benchmark-tests.md
Normal file
152
src/doc/trpl/benchmark-tests.md
Normal file
@ -0,0 +1,152 @@
|
||||
% 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.
|
@ -280,13 +280,15 @@ it returns an `Result<T, E>`, and because this is just an example, we `unwrap()`
|
||||
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.
|
||||
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.
|
||||
|
||||
Rust's standard library provides a few more mechanisms for two threads to
|
||||
synchronize with each other. Let's talk about one: channels.
|
||||
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
|
||||
|
||||
|
@ -243,11 +243,12 @@ for num in nums.iter() {
|
||||
```
|
||||
|
||||
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
|
||||
@ -292,11 +293,11 @@ just use `for` instead.
|
||||
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);
|
||||
}
|
||||
```
|
||||
|
@ -37,7 +37,7 @@ number of elements.
|
||||
|
||||
```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.
|
||||
@ -51,7 +51,7 @@ let x: Vec<u32> = {
|
||||
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]
|
||||
@ -73,7 +73,7 @@ macro_rules! vec {
|
||||
};
|
||||
}
|
||||
# fn main() {
|
||||
# assert_eq!([1,2,3], vec![1,2,3]);
|
||||
# assert_eq!(vec![1,2,3], [1, 2, 3]);
|
||||
# }
|
||||
```
|
||||
|
||||
|
@ -477,7 +477,7 @@ forbidden in item signatures to allow reasoning about the types just based in
|
||||
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.
|
||||
|
@ -430,149 +430,3 @@ documentation tests: the `_0` is generated for the module test, and `add_two_0`
|
||||
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.
|
||||
|
@ -277,6 +277,29 @@ One last thing about traits: generic functions with a trait bound use
|
||||
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
|
||||
|
@ -110,7 +110,7 @@ use heap::deallocate;
|
||||
/// 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
|
||||
/// });
|
||||
|
@ -51,13 +51,15 @@ use core::prelude::*;
|
||||
use core::any::Any;
|
||||
use core::cmp::Ordering;
|
||||
use core::default::Default;
|
||||
use core::error::{Error, FromError};
|
||||
use core::error::Error;
|
||||
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::{self, Unique};
|
||||
use core::raw::{TraitObject, Slice};
|
||||
|
||||
use heap;
|
||||
|
||||
/// A value that represents the heap. This is the default place that the `box`
|
||||
/// keyword allocates into when no place is supplied.
|
||||
@ -233,24 +235,10 @@ impl<T: ?Sized + Hash> Hash for 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
|
||||
@ -267,10 +255,10 @@ impl BoxAny for Box<Any> {
|
||||
}
|
||||
}
|
||||
|
||||
#[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)
|
||||
}
|
||||
}
|
||||
@ -322,8 +310,48 @@ impl<I: DoubleEndedIterator + ?Sized> DoubleEndedIterator for Box<I> {
|
||||
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> {
|
||||
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(Box<str>);
|
||||
impl Error for StringError {
|
||||
fn description(&self) -> &str { &self.0 }
|
||||
}
|
||||
impl fmt::Display for StringError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
self.0.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
// Unfortunately `String` is located in libcollections, so we construct
|
||||
// a `Box<str>` manually here.
|
||||
unsafe {
|
||||
let alloc = if err.len() == 0 {
|
||||
0 as *mut u8
|
||||
} else {
|
||||
let ptr = heap::allocate(err.len(), 1);
|
||||
if ptr.is_null() { ::oom(); }
|
||||
ptr as *mut u8
|
||||
};
|
||||
ptr::copy(err.as_bytes().as_ptr(), alloc, err.len());
|
||||
Box::new(StringError(mem::transmute(Slice {
|
||||
data: alloc,
|
||||
len: err.len(),
|
||||
})))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -17,7 +17,6 @@ use core::clone::Clone;
|
||||
|
||||
use std::boxed;
|
||||
use std::boxed::Box;
|
||||
use std::boxed::BoxAny;
|
||||
|
||||
#[test]
|
||||
fn test_owned_clone() {
|
||||
|
@ -38,7 +38,7 @@
|
||||
//! [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;
|
||||
@ -60,7 +60,7 @@
|
||||
//! 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)
|
||||
@ -1264,14 +1264,6 @@ impl BitSet {
|
||||
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.
|
||||
///
|
||||
|
@ -40,6 +40,24 @@ use self::Cow::*;
|
||||
#[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;
|
||||
}
|
||||
@ -50,6 +68,20 @@ pub trait Borrow<Borrowed: ?Sized> {
|
||||
#[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;
|
||||
}
|
||||
@ -171,6 +203,18 @@ impl<'a, B: ?Sized> Cow<'a, B> where B: ToOwned {
|
||||
/// 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 {
|
||||
@ -185,6 +229,18 @@ impl<'a, B: ?Sized> Cow<'a, B> where B: ToOwned {
|
||||
/// 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 {
|
||||
@ -192,26 +248,6 @@ impl<'a, B: ?Sized> Cow<'a, B> where B: ToOwned {
|
||||
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")]
|
||||
|
@ -1134,8 +1134,7 @@ impl<'a, K: Ord, V> Entry<'a, K, 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 default if empty, and returns
|
||||
/// a mutable reference to the value in the entry.
|
||||
pub fn or_insert(self, default: V) -> &'a mut V {
|
||||
@ -1145,8 +1144,7 @@ impl<'a, K: Ord, V> Entry<'a, K, 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 {
|
||||
|
@ -38,7 +38,6 @@
|
||||
#![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))]
|
||||
@ -68,22 +67,6 @@ pub use string::String;
|
||||
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;
|
||||
|
||||
@ -108,10 +91,6 @@ pub mod vec_map;
|
||||
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",
|
||||
@ -119,10 +98,6 @@ pub mod bit_vec {
|
||||
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")]
|
||||
|
@ -32,10 +32,6 @@ use core::iter::{self, FromIterator, IntoIterator};
|
||||
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> {
|
||||
@ -252,6 +248,7 @@ impl<T> 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 => {
|
||||
@ -844,7 +841,7 @@ impl<A> ExactSizeIterator for IntoIter<A> {}
|
||||
#[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
|
||||
}
|
||||
@ -1079,7 +1076,7 @@ mod test {
|
||||
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();
|
||||
}
|
||||
|
||||
|
@ -89,8 +89,6 @@ use core::iter::MultiplicativeIterator;
|
||||
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;
|
||||
@ -107,7 +105,6 @@ pub use core::slice::{IntSliceExt, SplitMut, ChunksMut, Split};
|
||||
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
|
||||
@ -281,33 +278,6 @@ impl<T> [T] {
|
||||
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
|
||||
@ -557,7 +527,6 @@ impl<T> [T] {
|
||||
/// ```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));
|
||||
@ -611,42 +580,6 @@ impl<T> [T] {
|
||||
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]
|
||||
@ -924,7 +857,6 @@ impl<T> [T] {
|
||||
/// ```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));
|
||||
@ -937,13 +869,6 @@ impl<T> [T] {
|
||||
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
|
||||
|
@ -10,13 +10,12 @@
|
||||
//
|
||||
// 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
|
||||
//!
|
||||
@ -70,11 +69,11 @@ use vec::Vec;
|
||||
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};
|
||||
@ -536,22 +535,6 @@ impl str {
|
||||
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
|
||||
@ -778,25 +761,6 @@ impl str {
|
||||
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`.
|
||||
@ -848,31 +812,6 @@ impl str {
|
||||
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
|
||||
@ -1306,27 +1245,6 @@ impl str {
|
||||
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
|
||||
@ -1470,12 +1388,12 @@ impl str {
|
||||
/// 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")]
|
||||
@ -1493,7 +1411,7 @@ impl str {
|
||||
/// 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")]
|
||||
|
@ -93,7 +93,7 @@ impl String {
|
||||
/// ```
|
||||
/// # #![feature(collections, core)]
|
||||
/// let s = String::from_str("hello");
|
||||
/// assert_eq!(s.as_slice(), "hello");
|
||||
/// assert_eq!(&s[..], "hello");
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable(feature = "collections",
|
||||
@ -364,6 +364,14 @@ impl String {
|
||||
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
|
||||
@ -848,7 +856,6 @@ impl<'a, 'b> PartialEq<Cow<'a, str>> for &'b str {
|
||||
#[allow(deprecated)]
|
||||
impl Str for String {
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
fn as_slice(&self) -> &str {
|
||||
unsafe { mem::transmute(&*self.vec) }
|
||||
}
|
||||
@ -1072,11 +1079,6 @@ impl<'a> Str for Cow<'a, str> {
|
||||
}
|
||||
}
|
||||
|
||||
/// 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]
|
||||
|
@ -389,7 +389,7 @@ impl<T> Vec<T> {
|
||||
/// 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 {
|
||||
@ -425,11 +425,18 @@ impl<T> Vec<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/// 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[..]
|
||||
}
|
||||
@ -823,13 +830,13 @@ impl<T> Vec<T> {
|
||||
/// # #![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")]
|
||||
@ -1533,22 +1540,22 @@ impl<T> Extend<T> for Vec<T> {
|
||||
}
|
||||
|
||||
__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 }
|
||||
)+
|
||||
}
|
||||
}
|
||||
@ -1642,13 +1649,6 @@ impl<T> AsRef<Vec<T>> for Vec<T> {
|
||||
}
|
||||
}
|
||||
|
||||
#[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] {
|
||||
@ -1679,11 +1679,6 @@ impl<'a> From<&'a str> for Vec<u8> {
|
||||
// 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]> {
|
||||
|
@ -25,8 +25,6 @@ use core::default::Default;
|
||||
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;
|
||||
@ -36,10 +34,6 @@ use core::cmp;
|
||||
|
||||
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
|
||||
|
||||
@ -527,7 +521,8 @@ impl<T> VecDeque<T> {
|
||||
/// 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> {
|
||||
@ -1902,7 +1897,7 @@ mod test {
|
||||
// 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;
|
||||
@ -1935,7 +1930,7 @@ mod test {
|
||||
// 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;
|
||||
@ -1973,7 +1968,7 @@ mod test {
|
||||
|
||||
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;
|
||||
@ -2006,9 +2001,9 @@ mod test {
|
||||
// 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;
|
||||
|
@ -10,7 +10,6 @@
|
||||
|
||||
use std::cmp::Ordering::{Equal, Greater, Less};
|
||||
use std::collections::{BitSet, BitVec};
|
||||
use std::iter::range_step;
|
||||
|
||||
#[test]
|
||||
fn test_bit_set_show() {
|
||||
@ -42,7 +41,7 @@ fn test_bit_set_iterator() {
|
||||
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);
|
||||
|
@ -153,19 +153,19 @@ fn test_iterator() {
|
||||
|
||||
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]);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
@ -183,35 +183,35 @@ fn test_operators() {
|
||||
|
||||
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]
|
||||
|
@ -13,5 +13,5 @@ use std::fmt;
|
||||
#[test]
|
||||
fn test_format() {
|
||||
let s = fmt::format(format_args!("Hello, {}!", "world"));
|
||||
assert_eq!(s.as_slice(), "Hello, world!");
|
||||
assert_eq!(s, "Hello, world!");
|
||||
}
|
||||
|
@ -8,7 +8,6 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![allow(deprecated)]
|
||||
#![feature(box_syntax)]
|
||||
#![feature(collections)]
|
||||
#![feature(core)]
|
||||
@ -21,6 +20,7 @@
|
||||
#![feature(unicode)]
|
||||
#![feature(unsafe_destructor)]
|
||||
#![feature(into_cow)]
|
||||
#![feature(step_by)]
|
||||
#![cfg_attr(test, feature(str_char))]
|
||||
|
||||
#[macro_use] extern crate log;
|
||||
|
@ -59,7 +59,7 @@ fn test_from_elem() {
|
||||
// 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);
|
||||
@ -685,7 +685,7 @@ fn test_capacity() {
|
||||
#[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);
|
||||
|
@ -83,38 +83,38 @@ fn test_collect() {
|
||||
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]
|
||||
@ -297,16 +297,16 @@ fn test_replace_2d() {
|
||||
|
||||
#[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;
|
||||
@ -328,23 +328,23 @@ fn test_slice() {
|
||||
}
|
||||
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
|
||||
@ -360,20 +360,20 @@ fn test_slice_2() {
|
||||
#[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]
|
||||
@ -660,10 +660,10 @@ fn test_contains() {
|
||||
|
||||
#[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]
|
||||
@ -1445,9 +1445,9 @@ fn test_graphemes() {
|
||||
}
|
||||
|
||||
#[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--"]);
|
||||
@ -1470,9 +1470,9 @@ fn test_split_strator() {
|
||||
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>();
|
||||
|
@ -8,10 +8,10 @@
|
||||
// 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;
|
||||
|
||||
@ -52,11 +52,11 @@ fn test_from_utf8() {
|
||||
#[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";
|
||||
|
@ -18,7 +18,6 @@ use self::Taggy::*;
|
||||
use self::Taggypar::*;
|
||||
|
||||
#[test]
|
||||
#[allow(deprecated)]
|
||||
fn test_simple() {
|
||||
let mut d = VecDeque::new();
|
||||
assert_eq!(d.len(), 0);
|
||||
@ -545,7 +544,7 @@ fn test_from_iter() {
|
||||
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);
|
||||
@ -821,7 +820,7 @@ fn test_as_slices() {
|
||||
|
||||
let (left, right) = ring.as_slices();
|
||||
let expected: Vec<_> = (0..i+1).collect();
|
||||
assert_eq!(left, expected);
|
||||
assert_eq!(left, &expected[..]);
|
||||
assert_eq!(right, []);
|
||||
}
|
||||
|
||||
@ -830,8 +829,8 @@ fn test_as_slices() {
|
||||
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);
|
||||
@ -849,7 +848,7 @@ fn test_as_mut_slices() {
|
||||
|
||||
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, []);
|
||||
}
|
||||
|
||||
@ -858,8 +857,8 @@ fn test_as_mut_slices() {
|
||||
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);
|
||||
|
@ -202,8 +202,7 @@ pub struct TypeId {
|
||||
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>() },
|
||||
|
@ -1062,144 +1062,3 @@ pub fn fence(order: Ordering) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[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) }
|
||||
}
|
||||
}
|
||||
|
@ -343,23 +343,6 @@ impl<T> RefCell<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/// 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
|
||||
@ -407,23 +390,6 @@ impl<T> RefCell<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/// 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
|
||||
|
@ -64,7 +64,6 @@ use option::Option::{self, Some, None};
|
||||
/// 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")]
|
||||
@ -360,6 +359,8 @@ pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> {
|
||||
|
||||
/// Compare and return the minimum of two values.
|
||||
///
|
||||
/// Returns the first argument if the comparison determines them to be equal.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
@ -371,11 +372,13 @@ pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> {
|
||||
#[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
|
||||
///
|
||||
/// ```
|
||||
@ -387,7 +390,7 @@ pub fn min<T: Ord>(v1: T, v2: T) -> T {
|
||||
#[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.
|
||||
@ -425,7 +428,7 @@ pub fn partial_min<T: PartialOrd>(v1: T, v2: T) -> Option<T> {
|
||||
|
||||
/// 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
|
||||
///
|
||||
@ -450,8 +453,8 @@ pub fn partial_min<T: PartialOrd>(v1: T, v2: T) -> Option<T> {
|
||||
#[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
|
||||
}
|
||||
}
|
||||
|
@ -15,8 +15,11 @@
|
||||
#[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]
|
||||
@ -31,13 +34,7 @@ macro_rules! __impl_slice_eq2 {
|
||||
__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> {
|
||||
|
@ -14,33 +14,40 @@
|
||||
//! 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;
|
||||
}
|
||||
|
||||
@ -48,14 +55,8 @@ pub trait From<T> {
|
||||
// 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)
|
||||
@ -63,6 +64,7 @@ impl<'a, T: ?Sized, U: ?Sized> AsRef<U> for &'a T where T: AsRef<U> {
|
||||
}
|
||||
|
||||
// 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)
|
||||
@ -77,14 +79,8 @@ impl<'a, T: ?Sized, U: ?Sized> AsRef<U> for &'a mut T where T: AsRef<U> {
|
||||
// }
|
||||
// }
|
||||
|
||||
// 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()
|
||||
@ -100,28 +96,38 @@ impl<'a, T: ?Sized, U: ?Sized> AsMut<U> for &'a mut T where T: AsMut<U> {
|
||||
// }
|
||||
|
||||
// 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
|
||||
|
@ -33,49 +33,6 @@
|
||||
//! 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")]
|
||||
|
||||
@ -97,19 +54,3 @@ pub trait Error: Debug + Display {
|
||||
#[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
|
||||
}
|
||||
}
|
||||
|
@ -1,111 +0,0 @@
|
||||
// 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);
|
||||
}
|
||||
}
|
@ -114,11 +114,6 @@ impl SipHasher {
|
||||
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;
|
||||
|
@ -197,7 +197,6 @@ extern "rust-intrinsic" {
|
||||
/// 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.
|
||||
|
@ -12,39 +12,40 @@
|
||||
//!
|
||||
//! # 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) => {
|
||||
//! Some(x) => {
|
||||
//! println!("{}", x);
|
||||
//! }
|
||||
//! None => { break }
|
||||
@ -52,7 +53,8 @@
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! 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")]
|
||||
|
||||
@ -64,10 +66,9 @@ use cmp::Ord;
|
||||
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;
|
||||
|
||||
@ -85,21 +86,22 @@ fn _assert_is_object_safe(_: &Iterator) {}
|
||||
/// 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) }
|
||||
@ -275,7 +277,8 @@ pub trait Iterator {
|
||||
/// 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
|
||||
///
|
||||
@ -433,7 +436,7 @@ pub trait Iterator {
|
||||
/// # #![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]);
|
||||
@ -530,10 +533,9 @@ pub trait Iterator {
|
||||
/// # 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")]
|
||||
@ -553,8 +555,7 @@ pub trait Iterator {
|
||||
/// 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>,
|
||||
@ -613,7 +614,8 @@ pub trait Iterator {
|
||||
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.
|
||||
///
|
||||
@ -624,7 +626,7 @@ pub trait Iterator {
|
||||
/// 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]
|
||||
@ -648,7 +650,7 @@ pub trait Iterator {
|
||||
/// 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
|
||||
@ -672,7 +674,7 @@ pub trait Iterator {
|
||||
/// 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
|
||||
@ -702,7 +704,7 @@ pub trait Iterator {
|
||||
/// 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
|
||||
@ -722,6 +724,9 @@ pub trait Iterator {
|
||||
|
||||
/// Consumes the entire iterator to return the maximum element.
|
||||
///
|
||||
/// Returns the rightmost element if the comparison determines two elements
|
||||
/// to be equally maximum.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
@ -732,16 +737,19 @@ pub trait Iterator {
|
||||
#[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
|
||||
///
|
||||
/// ```
|
||||
@ -752,10 +760,10 @@ pub trait Iterator {
|
||||
#[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))
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -771,7 +779,8 @@ pub trait Iterator {
|
||||
/// 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
|
||||
///
|
||||
@ -799,16 +808,17 @@ pub trait Iterator {
|
||||
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
|
||||
@ -817,19 +827,19 @@ pub trait Iterator {
|
||||
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 }
|
||||
}
|
||||
}
|
||||
|
||||
@ -839,6 +849,9 @@ pub trait Iterator {
|
||||
/// 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
|
||||
///
|
||||
/// ```
|
||||
@ -854,14 +867,14 @@ pub trait Iterator {
|
||||
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)
|
||||
@ -870,6 +883,9 @@ pub trait Iterator {
|
||||
/// 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
|
||||
///
|
||||
/// ```
|
||||
@ -885,11 +901,11 @@ pub trait Iterator {
|
||||
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))
|
||||
@ -927,10 +943,10 @@ pub trait Iterator {
|
||||
/// # #![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>,
|
||||
@ -1027,7 +1043,8 @@ pub trait FromIterator<A> {
|
||||
/// 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;
|
||||
@ -1041,6 +1058,9 @@ pub trait FromIterator<A> {
|
||||
}
|
||||
|
||||
/// 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
|
||||
@ -1094,12 +1114,13 @@ impl<'a, I: DoubleEndedIterator + ?Sized> DoubleEndedIterator for &'a mut I {
|
||||
|
||||
/// 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.
|
||||
@ -1144,13 +1165,15 @@ impl<I: ExactSizeIterator, F> ExactSizeIterator for Inspect<I, F> where
|
||||
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)]
|
||||
@ -1177,7 +1200,9 @@ impl<I> DoubleEndedIterator for Rev<I> where I: DoubleEndedIterator {
|
||||
}
|
||||
|
||||
#[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]
|
||||
@ -1244,10 +1269,10 @@ pub trait MultiplicativeIterator<A> {
|
||||
///
|
||||
/// ```
|
||||
/// # #![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);
|
||||
@ -1280,7 +1305,8 @@ impl_multiplicative! { usize, 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")]
|
||||
@ -1291,15 +1317,17 @@ pub enum MinMaxResult<T> {
|
||||
/// 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
|
||||
///
|
||||
@ -2511,7 +2539,7 @@ impl<A: Step> RangeFrom<A> {
|
||||
}
|
||||
|
||||
#[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.
|
||||
///
|
||||
@ -2544,26 +2572,6 @@ impl<A: Step> ::ops::Range<A> {
|
||||
}
|
||||
}
|
||||
|
||||
/// 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,
|
||||
@ -2584,108 +2592,12 @@ impl<A> Iterator for StepBy<A, RangeFrom<A>> where
|
||||
}
|
||||
}
|
||||
|
||||
/// 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,
|
||||
}
|
||||
|
||||
@ -2693,18 +2605,18 @@ pub struct RangeInclusive<A> {
|
||||
#[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]
|
||||
@ -2712,9 +2624,9 @@ impl<A: Int + ToPrimitive> Iterator for RangeInclusive<A> {
|
||||
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
|
||||
}
|
||||
@ -2740,46 +2652,28 @@ impl<A: Int + ToPrimitive> Iterator for RangeInclusive<A> {
|
||||
|
||||
#[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]
|
||||
@ -2882,13 +2776,13 @@ impl<A: Int> Iterator for RangeStepInclusive<A> {
|
||||
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]
|
||||
@ -2927,7 +2821,7 @@ range_exact_iter_impl!(usize u8 u16 u32 isize i8 i16 i32);
|
||||
|
||||
#[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]
|
||||
@ -2943,7 +2837,7 @@ impl<A: Step + One + Clone> DoubleEndedIterator for ::ops::Range<A> where
|
||||
|
||||
#[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]
|
||||
|
@ -136,7 +136,6 @@ pub mod atomic;
|
||||
pub mod cell;
|
||||
pub mod char;
|
||||
pub mod panicking;
|
||||
pub mod finally;
|
||||
pub mod iter;
|
||||
pub mod option;
|
||||
pub mod raw;
|
||||
|
@ -66,10 +66,10 @@ macro_rules! assert {
|
||||
);
|
||||
}
|
||||
|
||||
/// 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
|
||||
///
|
||||
@ -84,10 +84,8 @@ macro_rules! assert_eq {
|
||||
($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)
|
||||
}
|
||||
}
|
||||
@ -156,7 +154,7 @@ macro_rules! debug_assert_eq {
|
||||
|
||||
/// 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) => ({
|
||||
@ -233,7 +231,7 @@ macro_rules! writeln {
|
||||
/// ```
|
||||
/// # #![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; }
|
||||
/// }
|
||||
|
@ -415,42 +415,6 @@ mod impls {
|
||||
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,
|
||||
@ -487,9 +451,5 @@ pub struct InvariantType<T>;
|
||||
pub trait Reflect : MarkerTrait {
|
||||
}
|
||||
|
||||
#[cfg(stage0)]
|
||||
impl<T> Reflect for T { }
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
impl Reflect for .. { }
|
||||
|
||||
|
@ -173,11 +173,6 @@ pub unsafe fn zeroed<T>() -> T {
|
||||
#[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() }
|
||||
|
||||
@ -337,38 +332,32 @@ macro_rules! repeat_u8_as_u64 {
|
||||
// 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.
|
||||
/// 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`.
|
||||
/// 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`.
|
||||
/// 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
|
||||
///
|
||||
|
@ -46,7 +46,7 @@ use str::{FromStr, StrExt};
|
||||
/// 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;
|
||||
|
@ -30,6 +30,8 @@ use intrinsics::{i16_mul_with_overflow, u16_mul_with_overflow};
|
||||
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,u8,u16,u32,u64};
|
||||
|
||||
#[unstable(feature = "core", reason = "may be removed, renamed, or relocated")]
|
||||
#[deprecated(since = "1.0.0", reason = "moved to inherent methods")]
|
||||
pub trait WrappingOps {
|
||||
@ -43,6 +45,12 @@ pub trait OverflowingOps {
|
||||
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 {
|
||||
@ -184,6 +192,20 @@ macro_rules! wrapping_impl {
|
||||
|
||||
wrapping_impl! { usize u8 u16 u32 u64 isize i8 i16 i32 i64 }
|
||||
|
||||
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! overflowing_impl {
|
||||
($($t:ident)*) => ($(
|
||||
impl OverflowingOps for $t {
|
||||
@ -205,6 +227,34 @@ macro_rules! overflowing_impl {
|
||||
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))
|
||||
}
|
||||
}
|
||||
)*)
|
||||
}
|
||||
@ -234,6 +284,26 @@ 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")]
|
||||
@ -259,6 +329,26 @@ 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 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")]
|
||||
@ -284,6 +374,26 @@ impl OverflowingOps for isize {
|
||||
(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")]
|
||||
@ -309,4 +419,24 @@ impl OverflowingOps for isize {
|
||||
(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)
|
||||
}
|
||||
}
|
||||
|
@ -154,8 +154,6 @@ use mem;
|
||||
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
|
||||
@ -765,25 +763,6 @@ impl<T: Default> Option<T> {
|
||||
// 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]
|
||||
|
@ -37,10 +37,11 @@ pub use char::CharExt;
|
||||
pub use clone::Clone;
|
||||
pub use cmp::{PartialEq, PartialOrd, Eq, Ord};
|
||||
pub use convert::{AsRef, AsMut, Into, From};
|
||||
pub use iter::Extend;
|
||||
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;
|
||||
|
@ -157,21 +157,6 @@ pub fn null<T>() -> *const T { 0 as *const T }
|
||||
#[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.
|
||||
|
@ -64,19 +64,6 @@ pub struct Slice<T> {
|
||||
|
||||
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 (),
|
||||
}
|
||||
|
||||
/// The representation of a trait object like `&SomeTrait`.
|
||||
///
|
||||
/// This struct has the same layout as types like `&SomeTrait` and
|
||||
|
@ -88,10 +88,6 @@ pub trait SliceExt {
|
||||
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];
|
||||
@ -263,12 +259,6 @@ impl<T> SliceExt for [T] {
|
||||
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 {
|
||||
@ -1502,54 +1492,6 @@ pub unsafe fn from_raw_parts_mut<'a, T>(p: *mut T, len: usize) -> &'a mut [T] {
|
||||
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
|
||||
//
|
||||
|
@ -28,8 +28,6 @@ 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};
|
||||
@ -243,78 +241,6 @@ pub unsafe fn from_utf8_unchecked<'a>(v: &'a [u8]) -> &'a str {
|
||||
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 {
|
||||
@ -1047,22 +973,6 @@ impl<'a, P: Pattern<'a>> Iterator for MatchIndices<'a, P> {
|
||||
}
|
||||
}
|
||||
|
||||
/// 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)]
|
||||
@ -1444,8 +1354,6 @@ pub trait StrExt {
|
||||
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;
|
||||
@ -1565,12 +1473,6 @@ impl StrExt for str {
|
||||
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 }
|
||||
|
@ -8,10 +8,7 @@
|
||||
// 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
|
||||
|
||||
@ -228,6 +225,40 @@ pub trait DoubleEndedSearcher<'a>: ReverseSearcher<'a> {}
|
||||
|
||||
// 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> {
|
||||
@ -425,65 +456,116 @@ fn str_search_step<F, G>(mut m: &mut StrSearcher,
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/// Searches for chars that are equal to any of the chars in the array
|
||||
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]
|
||||
|
||||
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`
|
||||
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
|
||||
{}
|
||||
|
||||
// Pattern for &&str
|
||||
|
||||
impl<'a, 'b> Pattern<'a> for &'b &'b str {
|
||||
type Searcher = <&'b str as Pattern<'a>>::Searcher;
|
||||
associated_items!(<&'b str as Pattern<'a>>::Searcher,
|
||||
s, (*s));
|
||||
}
|
||||
|
||||
/// Searches for chars that match the given predicate
|
||||
impl<'a, F> Pattern<'a> for F where F: FnMut(char) -> bool {
|
||||
type Searcher = <CharEqPattern<Self> as Pattern<'a>>::Searcher;
|
||||
associated_items!(<CharEqPattern<Self> as Pattern<'a>>::Searcher,
|
||||
s, CharEqPattern(s));
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
@ -59,7 +59,6 @@ fn double_imm_borrow() {
|
||||
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);
|
||||
}
|
||||
|
||||
@ -67,7 +66,6 @@ fn no_mut_then_imm_borrow() {
|
||||
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);
|
||||
}
|
||||
|
||||
@ -76,7 +74,6 @@ fn no_double_borrow_mut() {
|
||||
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);
|
||||
}
|
||||
|
||||
@ -105,7 +102,7 @@ fn double_borrow_single_release_no_borrow_mut() {
|
||||
{
|
||||
let _b2 = x.borrow();
|
||||
}
|
||||
assert!(x.try_borrow_mut().is_none());
|
||||
assert_eq!(x.borrow_state(), BorrowState::Reading);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -122,14 +119,14 @@ fn clone_ref_updates_flag() {
|
||||
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]
|
||||
|
@ -1,62 +0,0 @@
|
||||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <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);
|
||||
}
|
@ -72,7 +72,7 @@ fn test_multi_iter() {
|
||||
|
||||
#[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]);
|
||||
}
|
||||
@ -90,7 +90,7 @@ fn test_iterator_chain() {
|
||||
}
|
||||
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 {
|
||||
@ -102,7 +102,7 @@ fn test_iterator_chain() {
|
||||
|
||||
#[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]);
|
||||
}
|
||||
@ -244,7 +244,7 @@ fn test_iterator_scan() {
|
||||
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]);
|
||||
@ -291,13 +291,13 @@ fn test_unfoldr() {
|
||||
#[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);
|
||||
}
|
||||
@ -360,7 +360,7 @@ fn test_iterator_min() {
|
||||
|
||||
#[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();
|
||||
|
@ -39,7 +39,6 @@ mod atomic;
|
||||
mod cell;
|
||||
mod char;
|
||||
mod cmp;
|
||||
mod finally;
|
||||
mod fmt;
|
||||
mod hash;
|
||||
mod iter;
|
||||
|
@ -103,7 +103,7 @@ fn test_transmute() {
|
||||
}
|
||||
|
||||
unsafe {
|
||||
assert_eq!([76], transmute::<_, Vec<u8>>("L".to_string()));
|
||||
assert_eq!(transmute::<_, Vec<u8>>("L".to_string()), [76]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -20,7 +20,7 @@ mod tests {
|
||||
fn test_overflows() {
|
||||
assert!(MAX > 0);
|
||||
assert!(MIN <= 0);
|
||||
assert!(MIN + MAX + 1 == 0);
|
||||
assert!((MIN + MAX).wrapping_add(1) == 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -163,9 +163,9 @@ fn starts_short_long() {
|
||||
|
||||
#[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]
|
||||
@ -347,11 +347,11 @@ malesuada sollicitudin quam eu fermentum!");
|
||||
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;
|
||||
@ -368,11 +368,11 @@ malesuada sollicitudin quam eu fermentum!");
|
||||
|
||||
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());
|
||||
@ -380,6 +380,6 @@ malesuada sollicitudin quam eu fermentum!");
|
||||
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());
|
||||
}
|
||||
|
@ -446,7 +446,7 @@ mod tests {
|
||||
|
||||
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> {
|
||||
|
@ -84,7 +84,7 @@
|
||||
//!
|
||||
//! 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 }
|
||||
|
@ -198,7 +198,7 @@ impl Rand for ChaChaRng {
|
||||
for word in &mut key {
|
||||
*word = other.gen();
|
||||
}
|
||||
SeedableRng::from_seed(key.as_slice())
|
||||
SeedableRng::from_seed(&key[..])
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -154,7 +154,7 @@ pub trait Rng : Sized {
|
||||
///
|
||||
/// 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
|
||||
@ -310,9 +310,9 @@ pub trait Rng : Sized {
|
||||
/// 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();
|
||||
|
@ -123,7 +123,6 @@
|
||||
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)]
|
||||
@ -862,8 +861,8 @@ pub mod writer {
|
||||
} 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)[..]))
|
||||
}
|
||||
}
|
||||
|
||||
@ -876,7 +875,7 @@ pub mod writer {
|
||||
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)[..]))
|
||||
}
|
||||
}
|
||||
|
||||
@ -885,8 +884,8 @@ pub mod writer {
|
||||
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> {
|
||||
@ -1077,8 +1076,8 @@ pub mod writer {
|
||||
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)[..]))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -68,6 +68,8 @@ register_diagnostics! {
|
||||
E0019,
|
||||
E0020,
|
||||
E0022,
|
||||
E0079, // enum variant: expected signed integer constant
|
||||
E0080, // enum variant: constant evaluation error
|
||||
E0109,
|
||||
E0110,
|
||||
E0133,
|
||||
@ -128,7 +130,8 @@ register_diagnostics! {
|
||||
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 }
|
||||
|
@ -37,11 +37,9 @@
|
||||
#![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))]
|
||||
|
@ -1197,7 +1197,7 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext,
|
||||
})
|
||||
}
|
||||
|
||||
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);
|
||||
@ -1884,7 +1884,7 @@ fn decode_side_tables(dcx: &DecodeContext,
|
||||
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 {
|
||||
|
@ -13,6 +13,8 @@
|
||||
|
||||
pub use self::const_val::*;
|
||||
|
||||
use self::ErrKind::*;
|
||||
|
||||
use metadata::csearch;
|
||||
use middle::{astencode, def};
|
||||
use middle::pat_util::def_to_path;
|
||||
@ -27,6 +29,7 @@ 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};
|
||||
@ -234,6 +237,7 @@ pub enum ErrKind {
|
||||
NotOnStruct,
|
||||
NotOnTuple,
|
||||
|
||||
NegateWithOverflow(i64),
|
||||
AddiWithOverflow(i64, i64),
|
||||
SubiWithOverflow(i64, i64),
|
||||
MuliWithOverflow(i64, i64),
|
||||
@ -244,6 +248,8 @@ pub enum ErrKind {
|
||||
DivideWithOverflow,
|
||||
ModuloByZero,
|
||||
ModuloWithOverflow,
|
||||
ShiftLeftWithOverflow,
|
||||
ShiftRightWithOverflow,
|
||||
MissingStructField,
|
||||
NonConstPath,
|
||||
ExpectedConstTuple,
|
||||
@ -257,6 +263,7 @@ pub enum ErrKind {
|
||||
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(),
|
||||
@ -275,6 +282,7 @@ impl ConstEvalErr {
|
||||
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(),
|
||||
@ -285,6 +293,8 @@ impl ConstEvalErr {
|
||||
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(),
|
||||
@ -297,57 +307,294 @@ impl ConstEvalErr {
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! signal {
|
||||
($e:expr, $ctor:ident) => {
|
||||
return Err(ConstEvalErr { span: $e.span, kind: ErrKind::$ctor })
|
||||
};
|
||||
pub type EvalResult = Result<const_val, ConstEvalErr>;
|
||||
pub type CastResult = Result<const_val, ErrKind>;
|
||||
|
||||
($e:expr, $ctor:ident($($arg:expr),*)) => {
|
||||
return Err(ConstEvalErr { span: $e.span, kind: ErrKind::$ctor($($arg),*) })
|
||||
#[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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)) }
|
||||
}
|
||||
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)) }
|
||||
}
|
||||
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)) }
|
||||
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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)) }
|
||||
}
|
||||
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)) }
|
||||
}
|
||||
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)) }
|
||||
macro_rules! signal {
|
||||
($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)),
|
||||
};
|
||||
|
||||
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))
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
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) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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) }
|
||||
}
|
||||
|
||||
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) }
|
||||
}
|
||||
|
||||
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) }
|
||||
}
|
||||
|
||||
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(n) => try!(const_uint_checked_neg(n, e, expr_uint_type)),
|
||||
const_str(_) => signal!(e, NegateOnString),
|
||||
const_bool(_) => signal!(e, NegateOnBoolean),
|
||||
const_binary(_) => signal!(e, NegateOnBinary),
|
||||
@ -391,51 +638,17 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||
}
|
||||
}
|
||||
(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),
|
||||
@ -446,18 +659,16 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||
}
|
||||
(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),
|
||||
@ -469,15 +680,15 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||
// 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)),
|
||||
}
|
||||
}
|
||||
@ -506,10 +717,15 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||
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 }),
|
||||
}
|
||||
@ -607,39 +823,49 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||
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))),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
// 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"),
|
||||
|
||||
_ => {}
|
||||
}
|
||||
|
||||
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),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -68,11 +68,12 @@ use util::nodemap::FnvHashMap;
|
||||
|
||||
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;
|
||||
@ -83,9 +84,11 @@ use syntax::ast::{CrateNum, DefId, Ident, ItemTrait, LOCAL_CRATE};
|
||||
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::print::pprust;
|
||||
use syntax::ptr::P;
|
||||
use syntax::{ast, ast_map};
|
||||
|
||||
pub type Disr = u64;
|
||||
@ -685,7 +688,7 @@ pub struct ctxt<'tcx> {
|
||||
/// 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
|
||||
@ -850,6 +853,13 @@ pub struct ctxt<'tcx> {
|
||||
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
|
||||
@ -5489,63 +5499,268 @@ pub fn type_is_empty(cx: &ctxt, ty: Ty) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
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")
|
||||
@ -5831,19 +6046,20 @@ pub fn eval_repeat_count(tcx: &ctxt, count_expr: &ast::Expr) -> usize {
|
||||
"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);
|
||||
}
|
||||
}
|
||||
|
@ -228,8 +228,9 @@ pub fn memoized<T, U, S, F>(cache: &RefCell<HashMap<T, U, S>>, arg: T, f: F) ->
|
||||
#[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 {
|
||||
|
@ -9,6 +9,7 @@
|
||||
// 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};
|
||||
@ -20,18 +21,16 @@ pub fn realpath(original: &Path) -> io::Result<PathBuf> {
|
||||
let old = old_path::Path::new(original.to_str().unwrap());
|
||||
match old_realpath(&old) {
|
||||
Ok(p) => Ok(PathBuf::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) {
|
||||
|
@ -36,17 +36,13 @@
|
||||
#![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;
|
||||
|
@ -14,7 +14,7 @@
|
||||
|
||||
#![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;
|
||||
@ -368,7 +368,7 @@ impl Engine256State {
|
||||
|
||||
// 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);
|
||||
@ -388,7 +388,7 @@ impl Engine256State {
|
||||
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);
|
||||
|
@ -47,9 +47,10 @@ pub fn get_sdk_root(sdk_name: &str) -> String {
|
||||
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[..]))
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -11,7 +11,7 @@
|
||||
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
|
||||
@ -36,10 +36,10 @@ impl TempDir {
|
||||
///
|
||||
/// 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);
|
||||
@ -67,8 +67,7 @@ impl TempDir {
|
||||
}
|
||||
|
||||
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
|
||||
|
@ -27,7 +27,6 @@
|
||||
|
||||
#![feature(box_syntax)]
|
||||
#![feature(collections)]
|
||||
#![feature(core)]
|
||||
#![feature(libc)]
|
||||
#![feature(quote)]
|
||||
#![feature(rustc_diagnostic_macros)]
|
||||
@ -35,10 +34,8 @@
|
||||
#![feature(unsafe_destructor)]
|
||||
#![feature(staged_api)]
|
||||
#![feature(exit_status)]
|
||||
#![feature(io)]
|
||||
#![feature(set_stdio)]
|
||||
#![feature(unicode)]
|
||||
#![feature(convert)]
|
||||
|
||||
extern crate arena;
|
||||
extern crate flate;
|
||||
|
@ -699,8 +699,8 @@ fn print_flowgraph<W: Write>(variants: Vec<borrowck_dot::Variant>,
|
||||
|
||||
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)[..])
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -808,12 +808,11 @@ fn walk_ty() {
|
||||
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]);
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -42,8 +42,9 @@ impl ArchiveRO {
|
||||
#[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 {
|
||||
|
@ -30,7 +30,6 @@
|
||||
#![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;
|
||||
@ -1976,6 +1975,7 @@ extern {
|
||||
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();
|
||||
|
@ -39,7 +39,6 @@
|
||||
#![feature(unicode)]
|
||||
#![feature(path_ext)]
|
||||
#![feature(fs)]
|
||||
#![feature(convert)]
|
||||
#![feature(path_relative_from)]
|
||||
|
||||
#![allow(trivial_casts)]
|
||||
|
@ -272,7 +272,7 @@ impl <'l, 'tcx> DxrVisitor<'l, 'tcx> {
|
||||
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,
|
||||
@ -436,7 +436,7 @@ impl <'l, 'tcx> DxrVisitor<'l, 'tcx> {
|
||||
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),
|
||||
@ -1471,7 +1471,7 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DxrVisitor<'l, 'tcx> {
|
||||
|
||||
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?).
|
||||
|
@ -41,7 +41,7 @@ use middle::cfg;
|
||||
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;
|
||||
@ -52,7 +52,7 @@ use trans::callee;
|
||||
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};
|
||||
@ -824,6 +824,15 @@ pub fn fail_if_zero_or_overflows<'blk, 'tcx>(
|
||||
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)));
|
||||
|
@ -963,6 +963,32 @@ pub fn const_to_uint(v: ValueRef) -> u64 {
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
|
@ -14,6 +14,14 @@ use llvm;
|
||||
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::*;
|
||||
@ -336,6 +344,7 @@ pub fn const_expr<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
||||
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);
|
||||
@ -348,6 +357,100 @@ pub fn const_expr<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
||||
(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>,
|
||||
@ -386,7 +489,8 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, '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 => {
|
||||
@ -416,8 +520,12 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
||||
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) }
|
||||
}
|
||||
@ -439,8 +547,11 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
||||
}
|
||||
}
|
||||
},
|
||||
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 => {
|
||||
@ -661,11 +772,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
||||
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 {
|
||||
|
@ -3207,7 +3207,7 @@ fn fn_should_be_ignored(fcx: &FunctionContext) -> bool {
|
||||
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!");
|
||||
}
|
||||
|
@ -85,7 +85,7 @@ use astconv::{self, ast_region_to_region, ast_ty_to_ty, AstConv, PathParamMode};
|
||||
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;
|
||||
@ -94,7 +94,7 @@ use middle::privacy::{AllPublic, LastMod};
|
||||
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;
|
||||
@ -4283,68 +4283,30 @@ pub fn check_enum_variants<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
|
||||
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) {
|
||||
@ -4372,15 +4334,7 @@ pub fn check_enum_variants<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
|
||||
}
|
||||
}
|
||||
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 })
|
||||
@ -4396,10 +4350,7 @@ pub fn check_enum_variants<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
|
||||
};
|
||||
}
|
||||
|
||||
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");
|
||||
|
||||
|
@ -215,25 +215,21 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -51,8 +51,6 @@ register_diagnostics! {
|
||||
E0075,
|
||||
E0076,
|
||||
E0077,
|
||||
E0079,
|
||||
E0080,
|
||||
E0081,
|
||||
E0082,
|
||||
E0083,
|
||||
|
@ -146,7 +146,7 @@ pub struct CrateCtxt<'a, 'tcx: 'a> {
|
||||
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>,
|
||||
|
@ -20,7 +20,7 @@ pub use self::imp::Lock;
|
||||
|
||||
#[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;
|
||||
@ -116,7 +116,8 @@ mod imp {
|
||||
|
||||
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)
|
||||
@ -164,9 +165,9 @@ mod imp {
|
||||
#[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;
|
||||
@ -194,7 +195,8 @@ mod imp {
|
||||
|
||||
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(),
|
||||
|
@ -23,7 +23,6 @@
|
||||
#![feature(box_patterns)]
|
||||
#![feature(box_syntax)]
|
||||
#![feature(collections)]
|
||||
#![feature(core)]
|
||||
#![feature(exit_status)]
|
||||
#![feature(set_stdio)]
|
||||
#![feature(libc)]
|
||||
@ -36,7 +35,6 @@
|
||||
#![feature(file_path)]
|
||||
#![feature(path_ext)]
|
||||
#![feature(path_relative_from)]
|
||||
#![feature(convert)]
|
||||
#![feature(slice_patterns)]
|
||||
|
||||
extern crate arena;
|
||||
|
@ -100,7 +100,7 @@
|
||||
//! 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();
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
@ -367,8 +367,8 @@ impl std::error::Error for EncoderError {
|
||||
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>;
|
||||
|
@ -36,7 +36,6 @@ Core encoding and decoding interfaces.
|
||||
#![feature(std_misc)]
|
||||
#![feature(unicode)]
|
||||
#![feature(str_char)]
|
||||
#![feature(convert)]
|
||||
#![cfg_attr(test, feature(test, old_io))]
|
||||
|
||||
// test harness access
|
||||
|
@ -1482,8 +1482,7 @@ impl<'a, K, V> Entry<'a, K, 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 default if empty, and returns
|
||||
/// a mutable reference to the value in the entry.
|
||||
pub fn or_insert(self, default: V) -> &'a mut V {
|
||||
@ -1493,8 +1492,7 @@ impl<'a, K, V> Entry<'a, K, 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 {
|
||||
|
@ -1192,7 +1192,7 @@ mod test_set {
|
||||
};
|
||||
|
||||
let v = hs.into_iter().collect::<Vec<char>>();
|
||||
assert!(['a', 'b'] == v || ['b', 'a'] == v);
|
||||
assert!(v == ['a', 'b'] || v == ['b', 'a']);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -15,7 +15,7 @@ use self::BucketState::*;
|
||||
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;
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user