Auto merge of #24674 - alexcrichton:rollup, r=alexcrichton
This commit is contained in:
commit
c0eb9384af
315 changed files with 2569 additions and 8304 deletions
|
@ -13,12 +13,12 @@
|
||||||
######################################################################
|
######################################################################
|
||||||
|
|
||||||
# The version number
|
# The version number
|
||||||
CFG_RELEASE_NUM=1.0.0
|
CFG_RELEASE_NUM=1.1.0
|
||||||
|
|
||||||
# An optional number to put after the label, e.g. '.2' -> '-beta.2'
|
# An optional number to put after the label, e.g. '.2' -> '-beta.2'
|
||||||
# NB Make sure it starts with a dot to conform to semver pre-release
|
# NB Make sure it starts with a dot to conform to semver pre-release
|
||||||
# versions (section 9)
|
# versions (section 9)
|
||||||
CFG_PRERELEASE_VERSION=.3
|
CFG_PRERELEASE_VERSION=.1
|
||||||
|
|
||||||
CFG_FILENAME_EXTRA=4e7c5e5c
|
CFG_FILENAME_EXTRA=4e7c5e5c
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,7 @@ is the first. After this:
|
||||||
* [Syntax and Semantics][ss] - Each bit of Rust, broken down into small chunks.
|
* [Syntax and Semantics][ss] - Each bit of Rust, broken down into small chunks.
|
||||||
* [Nightly Rust][nr] - Cutting-edge features that aren’t in stable builds yet.
|
* [Nightly Rust][nr] - Cutting-edge features that aren’t in stable builds yet.
|
||||||
* [Glossary][gl] - A reference of terms used in the book.
|
* [Glossary][gl] - A reference of terms used in the book.
|
||||||
|
* [Academic Research][ar] - Literature that influenced Rust.
|
||||||
|
|
||||||
[gs]: getting-started.html
|
[gs]: getting-started.html
|
||||||
[lr]: learn-rust.html
|
[lr]: learn-rust.html
|
||||||
|
@ -31,6 +32,7 @@ is the first. After this:
|
||||||
[ss]: syntax-and-semantics.html
|
[ss]: syntax-and-semantics.html
|
||||||
[nr]: nightly-rust.html
|
[nr]: nightly-rust.html
|
||||||
[gl]: glossary.html
|
[gl]: glossary.html
|
||||||
|
[ar]: academic-research.html
|
||||||
|
|
||||||
After reading this introduction, you’ll want to dive into either ‘Learn Rust’
|
After reading this introduction, you’ll want to dive into either ‘Learn Rust’
|
||||||
or ‘Syntax and Semantics’, depending on your preference: ‘Learn Rust’ if you
|
or ‘Syntax and Semantics’, depending on your preference: ‘Learn Rust’ if you
|
||||||
|
|
|
@ -55,6 +55,7 @@
|
||||||
* [Deref coercions](deref-coercions.md)
|
* [Deref coercions](deref-coercions.md)
|
||||||
* [Macros](macros.md)
|
* [Macros](macros.md)
|
||||||
* [Raw Pointers](raw-pointers.md)
|
* [Raw Pointers](raw-pointers.md)
|
||||||
|
* [`unsafe`](unsafe.md)
|
||||||
* [Nightly Rust](nightly-rust.md)
|
* [Nightly Rust](nightly-rust.md)
|
||||||
* [Compiler Plugins](compiler-plugins.md)
|
* [Compiler Plugins](compiler-plugins.md)
|
||||||
* [Inline Assembly](inline-assembly.md)
|
* [Inline Assembly](inline-assembly.md)
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
% Associated Types
|
% Associated Types
|
||||||
|
|
||||||
Associated types are a powerful part of Rust's type system. They're related to
|
Associated types are a powerful part of Rust’s type system. They’re related to
|
||||||
the idea of a 'type family', in other words, grouping multiple types together. That
|
the idea of a ‘type family’, in other words, grouping multiple types together. That
|
||||||
description is a bit abstract, so let's dive right into an example. If you want
|
description is a bit abstract, so let’s dive right into an example. If you want
|
||||||
to write a `Graph` trait, you have two types to be generic over: the node type
|
to write a `Graph` trait, you have two types to be generic over: the node type
|
||||||
and the edge type. So you might write a trait, `Graph<N, E>`, that looks like
|
and the edge type. So you might write a trait, `Graph<N, E>`, that looks like
|
||||||
this:
|
this:
|
||||||
|
@ -48,11 +48,11 @@ fn distance<G: Graph>(graph: &G, start: &G::N, end: &G::N) -> uint { ... }
|
||||||
|
|
||||||
No need to deal with the `E`dge type here!
|
No need to deal with the `E`dge type here!
|
||||||
|
|
||||||
Let's go over all this in more detail.
|
Let’s go over all this in more detail.
|
||||||
|
|
||||||
## Defining associated types
|
## Defining associated types
|
||||||
|
|
||||||
Let's build that `Graph` trait. Here's the definition:
|
Let’s build that `Graph` trait. Here’s the definition:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
trait Graph {
|
trait Graph {
|
||||||
|
@ -86,7 +86,7 @@ trait Graph {
|
||||||
## Implementing associated types
|
## Implementing associated types
|
||||||
|
|
||||||
Just like any trait, traits that use associated types use the `impl` keyword to
|
Just like any trait, traits that use associated types use the `impl` keyword to
|
||||||
provide implementations. Here's a simple implementation of Graph:
|
provide implementations. Here’s a simple implementation of Graph:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
# trait Graph {
|
# trait Graph {
|
||||||
|
@ -118,13 +118,13 @@ impl Graph for MyGraph {
|
||||||
This silly implementation always returns `true` and an empty `Vec<Edge>`, but it
|
This silly implementation always returns `true` and an empty `Vec<Edge>`, but it
|
||||||
gives you an idea of how to implement this kind of thing. We first need three
|
gives you an idea of how to implement this kind of thing. We first need three
|
||||||
`struct`s, one for the graph, one for the node, and one for the edge. If it made
|
`struct`s, one for the graph, one for the node, and one for the edge. If it made
|
||||||
more sense to use a different type, that would work as well, we're just going to
|
more sense to use a different type, that would work as well, we’re just going to
|
||||||
use `struct`s for all three here.
|
use `struct`s for all three here.
|
||||||
|
|
||||||
Next is the `impl` line, which is just like implementing any other trait.
|
Next is the `impl` line, which is just like implementing any other trait.
|
||||||
|
|
||||||
From here, we use `=` to define our associated types. The name the trait uses
|
From here, we use `=` to define our associated types. The name the trait uses
|
||||||
goes on the left of the `=`, and the concrete type we're `impl`ementing this
|
goes on the left of the `=`, and the concrete type we’re `impl`ementing this
|
||||||
for goes on the right. Finally, we use the concrete types in our function
|
for goes on the right. Finally, we use the concrete types in our function
|
||||||
declarations.
|
declarations.
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,7 @@ let b = a as u32; // four eights makes 32
|
||||||
|
|
||||||
It’s a ‘non-scalar cast’ because we have multiple values here: the four
|
It’s a ‘non-scalar cast’ because we have multiple values here: the four
|
||||||
elements of the array. These kinds of casts are very dangerous, because they
|
elements of the array. These kinds of casts are very dangerous, because they
|
||||||
make assumptions about the way that multiple underlying strucutres are
|
make assumptions about the way that multiple underlying structures are
|
||||||
implemented. For this, we need something more dangerous.
|
implemented. For this, we need something more dangerous.
|
||||||
|
|
||||||
# `transmute`
|
# `transmute`
|
||||||
|
@ -59,7 +59,7 @@ unsafe {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
We have to wrap the operation in an `unsafe` block, but this will compile
|
We have to wrap the operation in an `unsafe` block for this to compile
|
||||||
successfully. Technically, only the `mem::transmute` call itself needs to be in
|
successfully. Technically, only the `mem::transmute` call itself needs to be in
|
||||||
the block, but it's nice in this case to enclose everything related, so you
|
the block, but it's nice in this case to enclose everything related, so you
|
||||||
know where to look. In this case, the details about `a` are also important, and
|
know where to look. In this case, the details about `a` are also important, and
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
% Closures
|
% Closures
|
||||||
|
|
||||||
Rust not only has named functions, but anonymous functions as well. Anonymous
|
Rust not only has named functions, but anonymous functions as well. Anonymous
|
||||||
functions that have an associated environment are called 'closures', because they
|
functions that have an associated environment are called ‘closures’, because they
|
||||||
close over an environment. Rust has a really great implementation of them, as
|
close over an environment. Rust has a really great implementation of them, as
|
||||||
we'll see.
|
we’ll see.
|
||||||
|
|
||||||
# Syntax
|
# Syntax
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ let plus_one = |x: i32| x + 1;
|
||||||
assert_eq!(2, plus_one(1));
|
assert_eq!(2, plus_one(1));
|
||||||
```
|
```
|
||||||
|
|
||||||
We create a binding, `plus_one`, and assign it to a closure. The closure's
|
We create a binding, `plus_one`, and assign it to a closure. The closure’s
|
||||||
arguments go between the pipes (`|`), and the body is an expression, in this
|
arguments go between the pipes (`|`), and the body is an expression, in this
|
||||||
case, `x + 1`. Remember that `{ }` is an expression, so we can have multi-line
|
case, `x + 1`. Remember that `{ }` is an expression, so we can have multi-line
|
||||||
closures too:
|
closures too:
|
||||||
|
@ -33,7 +33,7 @@ let plus_two = |x| {
|
||||||
assert_eq!(4, plus_two(2));
|
assert_eq!(4, plus_two(2));
|
||||||
```
|
```
|
||||||
|
|
||||||
You'll notice a few things about closures that are a bit different than regular
|
You’ll notice a few things about closures that are a bit different than regular
|
||||||
functions defined with `fn`. The first of which is that we did not need to
|
functions defined with `fn`. The first of which is that we did not need to
|
||||||
annotate the types of arguments the closure takes or the values it returns. We
|
annotate the types of arguments the closure takes or the values it returns. We
|
||||||
can:
|
can:
|
||||||
|
@ -44,13 +44,13 @@ let plus_one = |x: i32| -> i32 { x + 1 };
|
||||||
assert_eq!(2, plus_one(1));
|
assert_eq!(2, plus_one(1));
|
||||||
```
|
```
|
||||||
|
|
||||||
But we don't have to. Why is this? Basically, it was chosen for ergonomic reasons.
|
But we don’t have to. Why is this? Basically, it was chosen for ergonomic reasons.
|
||||||
While specifying the full type for named functions is helpful with things like
|
While specifying the full type for named functions is helpful with things like
|
||||||
documentation and type inference, the types of closures are rarely documented
|
documentation and type inference, the types of closures are rarely documented
|
||||||
since they’re anonymous, and they don’t cause the kinds of error-at-a-distance
|
since they’re anonymous, and they don’t cause the kinds of error-at-a-distance
|
||||||
that inferring named function types can.
|
that inferring named function types can.
|
||||||
|
|
||||||
The second is that the syntax is similar, but a bit different. I've added spaces
|
The second is that the syntax is similar, but a bit different. I’ve added spaces
|
||||||
here to make them look a little closer:
|
here to make them look a little closer:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
|
@ -59,11 +59,11 @@ let plus_one_v2 = |x: i32 | -> i32 { x + 1 };
|
||||||
let plus_one_v3 = |x: i32 | x + 1 ;
|
let plus_one_v3 = |x: i32 | x + 1 ;
|
||||||
```
|
```
|
||||||
|
|
||||||
Small differences, but they're similar in ways.
|
Small differences, but they’re similar in ways.
|
||||||
|
|
||||||
# Closures and their environment
|
# Closures and their environment
|
||||||
|
|
||||||
Closures are called such because they 'close over their environment.' It
|
Closures are called such because they ‘close over their environment’. It
|
||||||
looks like this:
|
looks like this:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
|
@ -105,7 +105,7 @@ fn main() {
|
||||||
^
|
^
|
||||||
```
|
```
|
||||||
|
|
||||||
A verbose yet helpful error message! As it says, we can't take a mutable borrow
|
A verbose yet helpful error message! As it says, we can’t take a mutable borrow
|
||||||
on `num` because the closure is already borrowing it. If we let the closure go
|
on `num` because the closure is already borrowing it. If we let the closure go
|
||||||
out of scope, we can:
|
out of scope, we can:
|
||||||
|
|
||||||
|
@ -140,7 +140,7 @@ let takes_nums = || nums;
|
||||||
```
|
```
|
||||||
|
|
||||||
`Vec<T>` has ownership over its contents, and therefore, when we refer to it
|
`Vec<T>` has ownership over its contents, and therefore, when we refer to it
|
||||||
in our closure, we have to take ownership of `nums`. It's the same as if we'd
|
in our closure, we have to take ownership of `nums`. It’s the same as if we’d
|
||||||
passed `nums` to a function that took ownership of it.
|
passed `nums` to a function that took ownership of it.
|
||||||
|
|
||||||
## `move` closures
|
## `move` closures
|
||||||
|
@ -156,7 +156,7 @@ let owns_num = move |x: i32| x + num;
|
||||||
|
|
||||||
Now, even though the keyword is `move`, the variables follow normal move semantics.
|
Now, even though the keyword is `move`, the variables follow normal move semantics.
|
||||||
In this case, `5` implements `Copy`, and so `owns_num` takes ownership of a copy
|
In this case, `5` implements `Copy`, and so `owns_num` takes ownership of a copy
|
||||||
of `num`. So what's the difference?
|
of `num`. So what’s the difference?
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
let mut num = 5;
|
let mut num = 5;
|
||||||
|
@ -171,11 +171,11 @@ assert_eq!(10, num);
|
||||||
```
|
```
|
||||||
|
|
||||||
So in this case, our closure took a mutable reference to `num`, and then when
|
So in this case, our closure took a mutable reference to `num`, and then when
|
||||||
we called `add_num`, it mutated the underlying value, as we'd expect. We also
|
we called `add_num`, it mutated the underlying value, as we’d expect. We also
|
||||||
needed to declare `add_num` as `mut` too, because we’re mutating its
|
needed to declare `add_num` as `mut` too, because we’re mutating its
|
||||||
environment.
|
environment.
|
||||||
|
|
||||||
If we change to a `move` closure, it's different:
|
If we change to a `move` closure, it’s different:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
let mut num = 5;
|
let mut num = 5;
|
||||||
|
@ -203,8 +203,8 @@ you tons of control over what your code does, and closures are no different.
|
||||||
|
|
||||||
# Closure implementation
|
# Closure implementation
|
||||||
|
|
||||||
Rust's implementation of closures is a bit different than other languages. They
|
Rust’s implementation of closures is a bit different than other languages. They
|
||||||
are effectively syntax sugar for traits. You'll want to make sure to have read
|
are effectively syntax sugar for traits. You’ll want to make sure to have read
|
||||||
the [traits chapter][traits] before this one, as well as the chapter on [trait
|
the [traits chapter][traits] before this one, as well as the chapter on [trait
|
||||||
objects][trait-objects].
|
objects][trait-objects].
|
||||||
|
|
||||||
|
@ -237,9 +237,9 @@ pub trait FnOnce<Args> {
|
||||||
# }
|
# }
|
||||||
```
|
```
|
||||||
|
|
||||||
You'll notice a few differences between these traits, but a big one is `self`:
|
You’ll notice a few differences between these traits, but a big one is `self`:
|
||||||
`Fn` takes `&self`, `FnMut` takes `&mut self`, and `FnOnce` takes `self`. This
|
`Fn` takes `&self`, `FnMut` takes `&mut self`, and `FnOnce` takes `self`. This
|
||||||
covers all three kinds of `self` via the usual method call syntax. But we've
|
covers all three kinds of `self` via the usual method call syntax. But we’ve
|
||||||
split them up into three traits, rather than having a single one. This gives us
|
split them up into three traits, rather than having a single one. This gives us
|
||||||
a large amount of control over what kind of closures we can take.
|
a large amount of control over what kind of closures we can take.
|
||||||
|
|
||||||
|
@ -253,7 +253,7 @@ Now that we know that closures are traits, we already know how to accept and
|
||||||
return closures: just like any other trait!
|
return closures: just like any other trait!
|
||||||
|
|
||||||
This also means that we can choose static vs dynamic dispatch as well. First,
|
This also means that we can choose static vs dynamic dispatch as well. First,
|
||||||
let's write a function which takes something callable, calls it, and returns
|
let’s write a function which takes something callable, calls it, and returns
|
||||||
the result:
|
the result:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
|
@ -271,7 +271,7 @@ assert_eq!(3, answer);
|
||||||
We pass our closure, `|x| x + 2`, to `call_with_one`. It just does what it
|
We pass our closure, `|x| x + 2`, to `call_with_one`. It just does what it
|
||||||
suggests: it calls the closure, giving it `1` as an argument.
|
suggests: it calls the closure, giving it `1` as an argument.
|
||||||
|
|
||||||
Let's examine the signature of `call_with_one` in more depth:
|
Let’s examine the signature of `call_with_one` in more depth:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
fn call_with_one<F>(some_closure: F) -> i32
|
fn call_with_one<F>(some_closure: F) -> i32
|
||||||
|
@ -280,7 +280,7 @@ fn call_with_one<F>(some_closure: F) -> i32
|
||||||
```
|
```
|
||||||
|
|
||||||
We take one parameter, and it has the type `F`. We also return a `i32`. This part
|
We take one parameter, and it has the type `F`. We also return a `i32`. This part
|
||||||
isn't interesting. The next part is:
|
isn’t interesting. The next part is:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
# fn call_with_one<F>(some_closure: F) -> i32
|
# fn call_with_one<F>(some_closure: F) -> i32
|
||||||
|
@ -292,9 +292,9 @@ Because `Fn` is a trait, we can bound our generic with it. In this case, our clo
|
||||||
takes a `i32` as an argument and returns an `i32`, and so the generic bound we use
|
takes a `i32` as an argument and returns an `i32`, and so the generic bound we use
|
||||||
is `Fn(i32) -> i32`.
|
is `Fn(i32) -> i32`.
|
||||||
|
|
||||||
There's one other key point here: because we're bounding a generic with a
|
There’s one other key point here: because we’re bounding a generic with a
|
||||||
trait, this will get monomorphized, and therefore, we'll be doing static
|
trait, this will get monomorphized, and therefore, we’ll be doing static
|
||||||
dispatch into the closure. That's pretty neat. In many langauges, closures are
|
dispatch into the closure. That’s pretty neat. In many langauges, closures are
|
||||||
inherently heap allocated, and will always involve dynamic dispatch. In Rust,
|
inherently heap allocated, and will always involve dynamic dispatch. In Rust,
|
||||||
we can stack allocate our closure environment, and statically dispatch the
|
we can stack allocate our closure environment, and statically dispatch the
|
||||||
call. This happens quite often with iterators and their adapters, which often
|
call. This happens quite often with iterators and their adapters, which often
|
||||||
|
@ -320,7 +320,7 @@ to our closure when we pass it to `call_with_one`, so we use `&||`.
|
||||||
|
|
||||||
It’s very common for functional-style code to return closures in various
|
It’s very common for functional-style code to return closures in various
|
||||||
situations. If you try to return a closure, you may run into an error. At
|
situations. If you try to return a closure, you may run into an error. At
|
||||||
first, it may seem strange, but we'll figure it out. Here's how you'd probably
|
first, it may seem strange, but we’ll figure it out. Here’s how you’d probably
|
||||||
try to return a closure from a function:
|
try to return a closure from a function:
|
||||||
|
|
||||||
```rust,ignore
|
```rust,ignore
|
||||||
|
@ -361,7 +361,7 @@ In order to return something from a function, Rust needs to know what
|
||||||
size the return type is. But since `Fn` is a trait, it could be various
|
size the return type is. But since `Fn` is a trait, it could be various
|
||||||
things of various sizes: many different types can implement `Fn`. An easy
|
things of various sizes: many different types can implement `Fn`. An easy
|
||||||
way to give something a size is to take a reference to it, as references
|
way to give something a size is to take a reference to it, as references
|
||||||
have a known size. So we'd write this:
|
have a known size. So we’d write this:
|
||||||
|
|
||||||
```rust,ignore
|
```rust,ignore
|
||||||
fn factory() -> &(Fn(i32) -> Vec<i32>) {
|
fn factory() -> &(Fn(i32) -> Vec<i32>) {
|
||||||
|
@ -385,7 +385,7 @@ fn factory() -> &(Fn(i32) -> i32) {
|
||||||
```
|
```
|
||||||
|
|
||||||
Right. Because we have a reference, we need to give it a lifetime. But
|
Right. Because we have a reference, we need to give it a lifetime. But
|
||||||
our `factory()` function takes no arguments, so elision doesn't kick in
|
our `factory()` function takes no arguments, so elision doesn’t kick in
|
||||||
here. What lifetime can we choose? `'static`:
|
here. What lifetime can we choose? `'static`:
|
||||||
|
|
||||||
```rust,ignore
|
```rust,ignore
|
||||||
|
@ -414,7 +414,7 @@ error: mismatched types:
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
This error is letting us know that we don't have a `&'static Fn(i32) -> i32`,
|
This error is letting us know that we don’t have a `&'static Fn(i32) -> i32`,
|
||||||
we have a `[closure <anon>:7:9: 7:20]`. Wait, what?
|
we have a `[closure <anon>:7:9: 7:20]`. Wait, what?
|
||||||
|
|
||||||
Because each closure generates its own environment `struct` and implementation
|
Because each closure generates its own environment `struct` and implementation
|
||||||
|
@ -422,7 +422,7 @@ of `Fn` and friends, these types are anonymous. They exist just solely for
|
||||||
this closure. So Rust shows them as `closure <anon>`, rather than some
|
this closure. So Rust shows them as `closure <anon>`, rather than some
|
||||||
autogenerated name.
|
autogenerated name.
|
||||||
|
|
||||||
But why doesn't our closure implement `&'static Fn`? Well, as we discussed before,
|
But why doesn’t our closure implement `&'static Fn`? Well, as we discussed before,
|
||||||
closures borrow their environment. And in this case, our environment is based
|
closures borrow their environment. And in this case, our environment is based
|
||||||
on a stack-allocated `5`, the `num` variable binding. So the borrow has a lifetime
|
on a stack-allocated `5`, the `num` variable binding. So the borrow has a lifetime
|
||||||
of the stack frame. So if we returned this closure, the function call would be
|
of the stack frame. So if we returned this closure, the function call would be
|
||||||
|
@ -445,7 +445,7 @@ assert_eq!(6, answer);
|
||||||
# }
|
# }
|
||||||
```
|
```
|
||||||
|
|
||||||
We use a trait object, by `Box`ing up the `Fn`. There's just one last problem:
|
We use a trait object, by `Box`ing up the `Fn`. There’s just one last problem:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
error: `num` does not live long enough
|
error: `num` does not live long enough
|
||||||
|
@ -471,5 +471,5 @@ assert_eq!(6, answer);
|
||||||
```
|
```
|
||||||
|
|
||||||
By making the inner closure a `move Fn`, we create a new stack frame for our
|
By making the inner closure a `move Fn`, we create a new stack frame for our
|
||||||
closure. By `Box`ing it up, we've given it a known size, and allowing it to
|
closure. By `Box`ing it up, we’ve given it a known size, and allowing it to
|
||||||
escape our stack frame.
|
escape our stack frame.
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
% Crates and Modules
|
% Crates and Modules
|
||||||
|
|
||||||
When a project starts getting large, it's considered good software
|
When a project starts getting large, it’s considered good software
|
||||||
engineering practice to split it up into a bunch of smaller pieces, and then
|
engineering practice to split it up into a bunch of smaller pieces, and then
|
||||||
fit them together. It's also important to have a well-defined interface, so
|
fit them together. It’s also important to have a well-defined interface, so
|
||||||
that some of your functionality is private, and some is public. To facilitate
|
that some of your functionality is private, and some is public. To facilitate
|
||||||
these kinds of things, Rust has a module system.
|
these kinds of things, Rust has a module system.
|
||||||
|
|
||||||
# Basic terminology: Crates and Modules
|
# Basic terminology: Crates and Modules
|
||||||
|
|
||||||
Rust has two distinct terms that relate to the module system: *crate* and
|
Rust has two distinct terms that relate to the module system: ‘crate’ and
|
||||||
*module*. A crate is synonymous with a *library* or *package* in other
|
‘module’. A crate is synonymous with a ‘library’ or ‘package’ in other
|
||||||
languages. Hence "Cargo" as the name of Rust's package management tool: you
|
languages. Hence “Cargo” as the name of Rust’s package management tool: you
|
||||||
ship your crates to others with Cargo. Crates can produce an executable or a
|
ship your crates to others with Cargo. Crates can produce an executable or a
|
||||||
library, depending on the project.
|
library, depending on the project.
|
||||||
|
|
||||||
|
@ -18,10 +18,10 @@ Each crate has an implicit *root module* that contains the code for that crate.
|
||||||
You can then define a tree of sub-modules under that root module. Modules allow
|
You can then define a tree of sub-modules under that root module. Modules allow
|
||||||
you to partition your code within the crate itself.
|
you to partition your code within the crate itself.
|
||||||
|
|
||||||
As an example, let's make a *phrases* crate, which will give us various phrases
|
As an example, let’s make a *phrases* crate, which will give us various phrases
|
||||||
in different languages. To keep things simple, we'll stick to "greetings" and
|
in different languages. To keep things simple, we’ll stick to ‘greetings’ and
|
||||||
"farewells" as two kinds of phrases, and use English and Japanese (日本語) as
|
‘farewells’ as two kinds of phrases, and use English and Japanese (日本語) as
|
||||||
two languages for those phrases to be in. We'll use this module layout:
|
two languages for those phrases to be in. We’ll use this module layout:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
+-----------+
|
+-----------+
|
||||||
|
@ -47,7 +47,7 @@ In this example, `phrases` is the name of our crate. All of the rest are
|
||||||
modules. You can see that they form a tree, branching out from the crate
|
modules. You can see that they form a tree, branching out from the crate
|
||||||
*root*, which is the root of the tree: `phrases` itself.
|
*root*, which is the root of the tree: `phrases` itself.
|
||||||
|
|
||||||
Now that we have a plan, let's define these modules in code. To start,
|
Now that we have a plan, let’s define these modules in code. To start,
|
||||||
generate a new crate with Cargo:
|
generate a new crate with Cargo:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
@ -72,7 +72,7 @@ above.
|
||||||
|
|
||||||
# Defining Modules
|
# Defining Modules
|
||||||
|
|
||||||
To define each of our modules, we use the `mod` keyword. Let's make our
|
To define each of our modules, we use the `mod` keyword. Let’s make our
|
||||||
`src/lib.rs` look like this:
|
`src/lib.rs` look like this:
|
||||||
|
|
||||||
```
|
```
|
||||||
|
@ -101,7 +101,7 @@ Within a given `mod`, you can declare sub-`mod`s. We can refer to sub-modules
|
||||||
with double-colon (`::`) notation: our four nested modules are
|
with double-colon (`::`) notation: our four nested modules are
|
||||||
`english::greetings`, `english::farewells`, `japanese::greetings`, and
|
`english::greetings`, `english::farewells`, `japanese::greetings`, and
|
||||||
`japanese::farewells`. Because these sub-modules are namespaced under their
|
`japanese::farewells`. Because these sub-modules are namespaced under their
|
||||||
parent module, the names don't conflict: `english::greetings` and
|
parent module, the names don’t conflict: `english::greetings` and
|
||||||
`japanese::greetings` are distinct, even though their names are both
|
`japanese::greetings` are distinct, even though their names are both
|
||||||
`greetings`.
|
`greetings`.
|
||||||
|
|
||||||
|
@ -116,11 +116,11 @@ build deps examples libphrases-a7448e02a0468eaa.rlib native
|
||||||
```
|
```
|
||||||
|
|
||||||
`libphrase-hash.rlib` is the compiled crate. Before we see how to use this
|
`libphrase-hash.rlib` is the compiled crate. Before we see how to use this
|
||||||
crate from another crate, let's break it up into multiple files.
|
crate from another crate, let’s break it up into multiple files.
|
||||||
|
|
||||||
# Multiple file crates
|
# Multiple file crates
|
||||||
|
|
||||||
If each crate were just one file, these files would get very large. It's often
|
If each crate were just one file, these files would get very large. It’s often
|
||||||
easier to split up crates into multiple files, and Rust supports this in two
|
easier to split up crates into multiple files, and Rust supports this in two
|
||||||
ways.
|
ways.
|
||||||
|
|
||||||
|
@ -141,7 +141,7 @@ mod english;
|
||||||
If we do that, Rust will expect to find either a `english.rs` file, or a
|
If we do that, Rust will expect to find either a `english.rs` file, or a
|
||||||
`english/mod.rs` file with the contents of our module.
|
`english/mod.rs` file with the contents of our module.
|
||||||
|
|
||||||
Note that in these files, you don't need to re-declare the module: that's
|
Note that in these files, you don’t need to re-declare the module: that’s
|
||||||
already been done with the initial `mod` declaration.
|
already been done with the initial `mod` declaration.
|
||||||
|
|
||||||
Using these two techniques, we can break up our crate into two directories and
|
Using these two techniques, we can break up our crate into two directories and
|
||||||
|
@ -180,7 +180,7 @@ mod japanese;
|
||||||
|
|
||||||
These two declarations tell Rust to look for either `src/english.rs` and
|
These two declarations tell Rust to look for either `src/english.rs` and
|
||||||
`src/japanese.rs`, or `src/english/mod.rs` and `src/japanese/mod.rs`, depending
|
`src/japanese.rs`, or `src/english/mod.rs` and `src/japanese/mod.rs`, depending
|
||||||
on our preference. In this case, because our modules have sub-modules, we've
|
on our preference. In this case, because our modules have sub-modules, we’ve
|
||||||
chosen the second. Both `src/english/mod.rs` and `src/japanese/mod.rs` look
|
chosen the second. Both `src/english/mod.rs` and `src/japanese/mod.rs` look
|
||||||
like this:
|
like this:
|
||||||
|
|
||||||
|
@ -192,11 +192,11 @@ mod farewells;
|
||||||
Again, these declarations tell Rust to look for either
|
Again, these declarations tell Rust to look for either
|
||||||
`src/english/greetings.rs` and `src/japanese/greetings.rs` or
|
`src/english/greetings.rs` and `src/japanese/greetings.rs` or
|
||||||
`src/english/farewells/mod.rs` and `src/japanese/farewells/mod.rs`. Because
|
`src/english/farewells/mod.rs` and `src/japanese/farewells/mod.rs`. Because
|
||||||
these sub-modules don't have their own sub-modules, we've chosen to make them
|
these sub-modules don’t have their own sub-modules, we’ve chosen to make them
|
||||||
`src/english/greetings.rs` and `src/japanese/farewells.rs`. Whew!
|
`src/english/greetings.rs` and `src/japanese/farewells.rs`. Whew!
|
||||||
|
|
||||||
The contents of `src/english/greetings.rs` and `src/japanese/farewells.rs` are
|
The contents of `src/english/greetings.rs` and `src/japanese/farewells.rs` are
|
||||||
both empty at the moment. Let's add some functions.
|
both empty at the moment. Let’s add some functions.
|
||||||
|
|
||||||
Put this in `src/english/greetings.rs`:
|
Put this in `src/english/greetings.rs`:
|
||||||
|
|
||||||
|
@ -223,7 +223,7 @@ fn hello() -> String {
|
||||||
```
|
```
|
||||||
|
|
||||||
Of course, you can copy and paste this from this web page, or just type
|
Of course, you can copy and paste this from this web page, or just type
|
||||||
something else. It's not important that you actually put "konnichiwa" to learn
|
something else. It’s not important that you actually put ‘konnichiwa’ to learn
|
||||||
about the module system.
|
about the module system.
|
||||||
|
|
||||||
Put this in `src/japanese/farewells.rs`:
|
Put this in `src/japanese/farewells.rs`:
|
||||||
|
@ -234,17 +234,17 @@ fn goodbye() -> String {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
(This is "Sayōnara", if you're curious.)
|
(This is ‘Sayōnara’, if you’re curious.)
|
||||||
|
|
||||||
Now that we have some functionality in our crate, let's try to use it from
|
Now that we have some functionality in our crate, let’s try to use it from
|
||||||
another crate.
|
another crate.
|
||||||
|
|
||||||
# Importing External Crates
|
# Importing External Crates
|
||||||
|
|
||||||
We have a library crate. Let's make an executable crate that imports and uses
|
We have a library crate. Let’s make an executable crate that imports and uses
|
||||||
our library.
|
our library.
|
||||||
|
|
||||||
Make a `src/main.rs` and put this in it (it won't quite compile yet):
|
Make a `src/main.rs` and put this in it (it won’t quite compile yet):
|
||||||
|
|
||||||
```rust,ignore
|
```rust,ignore
|
||||||
extern crate phrases;
|
extern crate phrases;
|
||||||
|
@ -259,7 +259,7 @@ fn main() {
|
||||||
```
|
```
|
||||||
|
|
||||||
The `extern crate` declaration tells Rust that we need to compile and link to
|
The `extern crate` declaration tells Rust that we need to compile and link to
|
||||||
the `phrases` crate. We can then use `phrases`' modules in this one. As we
|
the `phrases` crate. We can then use `phrases`’ modules in this one. As we
|
||||||
mentioned earlier, you can use double colons to refer to sub-modules and the
|
mentioned earlier, you can use double colons to refer to sub-modules and the
|
||||||
functions inside of them.
|
functions inside of them.
|
||||||
|
|
||||||
|
@ -267,10 +267,10 @@ Also, Cargo assumes that `src/main.rs` is the crate root of a binary crate,
|
||||||
rather than a library crate. Our package now has two crates: `src/lib.rs` and
|
rather than a library crate. Our package now has two crates: `src/lib.rs` and
|
||||||
`src/main.rs`. This pattern is quite common for executable crates: most
|
`src/main.rs`. This pattern is quite common for executable crates: most
|
||||||
functionality is in a library crate, and the executable crate uses that
|
functionality is in a library crate, and the executable crate uses that
|
||||||
library. This way, other programs can also use the library crate, and it's also
|
library. This way, other programs can also use the library crate, and it’s also
|
||||||
a nice separation of concerns.
|
a nice separation of concerns.
|
||||||
|
|
||||||
This doesn't quite work yet, though. We get four errors that look similar to
|
This doesn’t quite work yet, though. We get four errors that look similar to
|
||||||
this:
|
this:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
@ -287,14 +287,14 @@ note: in expansion of format_args!
|
||||||
phrases/src/main.rs:4:5: 4:76 note: expansion site
|
phrases/src/main.rs:4:5: 4:76 note: expansion site
|
||||||
```
|
```
|
||||||
|
|
||||||
By default, everything is private in Rust. Let's talk about this in some more
|
By default, everything is private in Rust. Let’s talk about this in some more
|
||||||
depth.
|
depth.
|
||||||
|
|
||||||
# Exporting a Public Interface
|
# Exporting a Public Interface
|
||||||
|
|
||||||
Rust allows you to precisely control which aspects of your interface are
|
Rust allows you to precisely control which aspects of your interface are
|
||||||
public, and so private is the default. To make things public, you use the `pub`
|
public, and so private is the default. To make things public, you use the `pub`
|
||||||
keyword. Let's focus on the `english` module first, so let's reduce our `src/main.rs`
|
keyword. Let’s focus on the `english` module first, so let’s reduce our `src/main.rs`
|
||||||
to just this:
|
to just this:
|
||||||
|
|
||||||
```{rust,ignore}
|
```{rust,ignore}
|
||||||
|
@ -306,21 +306,21 @@ fn main() {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
In our `src/lib.rs`, let's add `pub` to the `english` module declaration:
|
In our `src/lib.rs`, let’s add `pub` to the `english` module declaration:
|
||||||
|
|
||||||
```{rust,ignore}
|
```{rust,ignore}
|
||||||
pub mod english;
|
pub mod english;
|
||||||
mod japanese;
|
mod japanese;
|
||||||
```
|
```
|
||||||
|
|
||||||
And in our `src/english/mod.rs`, let's make both `pub`:
|
And in our `src/english/mod.rs`, let’s make both `pub`:
|
||||||
|
|
||||||
```{rust,ignore}
|
```{rust,ignore}
|
||||||
pub mod greetings;
|
pub mod greetings;
|
||||||
pub mod farewells;
|
pub mod farewells;
|
||||||
```
|
```
|
||||||
|
|
||||||
In our `src/english/greetings.rs`, let's add `pub` to our `fn` declaration:
|
In our `src/english/greetings.rs`, let’s add `pub` to our `fn` declaration:
|
||||||
|
|
||||||
```{rust,ignore}
|
```{rust,ignore}
|
||||||
pub fn hello() -> String {
|
pub fn hello() -> String {
|
||||||
|
@ -358,12 +358,12 @@ Goodbye in English: Goodbye.
|
||||||
Now that our functions are public, we can use them. Great! However, typing out
|
Now that our functions are public, we can use them. Great! However, typing out
|
||||||
`phrases::english::greetings::hello()` is very long and repetitive. Rust has
|
`phrases::english::greetings::hello()` is very long and repetitive. Rust has
|
||||||
another keyword for importing names into the current scope, so that you can
|
another keyword for importing names into the current scope, so that you can
|
||||||
refer to them with shorter names. Let's talk about `use`.
|
refer to them with shorter names. Let’s talk about `use`.
|
||||||
|
|
||||||
# Importing Modules with `use`
|
# Importing Modules with `use`
|
||||||
|
|
||||||
Rust has a `use` keyword, which allows us to import names into our local scope.
|
Rust has a `use` keyword, which allows us to import names into our local scope.
|
||||||
Let's change our `src/main.rs` to look like this:
|
Let’s change our `src/main.rs` to look like this:
|
||||||
|
|
||||||
```{rust,ignore}
|
```{rust,ignore}
|
||||||
extern crate phrases;
|
extern crate phrases;
|
||||||
|
@ -378,7 +378,7 @@ fn main() {
|
||||||
```
|
```
|
||||||
|
|
||||||
The two `use` lines import each module into the local scope, so we can refer to
|
The two `use` lines import each module into the local scope, so we can refer to
|
||||||
the functions by a much shorter name. By convention, when importing functions, it's
|
the functions by a much shorter name. By convention, when importing functions, it’s
|
||||||
considered best practice to import the module, rather than the function directly. In
|
considered best practice to import the module, rather than the function directly. In
|
||||||
other words, you _can_ do this:
|
other words, you _can_ do this:
|
||||||
|
|
||||||
|
@ -395,7 +395,7 @@ fn main() {
|
||||||
```
|
```
|
||||||
|
|
||||||
But it is not idiomatic. This is significantly more likely to introduce a
|
But it is not idiomatic. This is significantly more likely to introduce a
|
||||||
naming conflict. In our short program, it's not a big deal, but as it grows, it
|
naming conflict. In our short program, it’s not a big deal, but as it grows, it
|
||||||
becomes a problem. If we have conflicting names, Rust will give a compilation
|
becomes a problem. If we have conflicting names, Rust will give a compilation
|
||||||
error. For example, if we made the `japanese` functions public, and tried to do
|
error. For example, if we made the `japanese` functions public, and tried to do
|
||||||
this:
|
this:
|
||||||
|
@ -423,7 +423,7 @@ error: aborting due to previous error
|
||||||
Could not compile `phrases`.
|
Could not compile `phrases`.
|
||||||
```
|
```
|
||||||
|
|
||||||
If we're importing multiple names from the same module, we don't have to type it out
|
If we’re importing multiple names from the same module, we don’t have to type it out
|
||||||
twice. Instead of this:
|
twice. Instead of this:
|
||||||
|
|
||||||
```{rust,ignore}
|
```{rust,ignore}
|
||||||
|
@ -439,11 +439,11 @@ use phrases::english::{greetings, farewells};
|
||||||
|
|
||||||
## Re-exporting with `pub use`
|
## Re-exporting with `pub use`
|
||||||
|
|
||||||
You don't just use `use` to shorten identifiers. You can also use it inside of your crate
|
You don’t just use `use` to shorten identifiers. You can also use it inside of your crate
|
||||||
to re-export a function inside another module. This allows you to present an external
|
to re-export a function inside another module. This allows you to present an external
|
||||||
interface that may not directly map to your internal code organization.
|
interface that may not directly map to your internal code organization.
|
||||||
|
|
||||||
Let's look at an example. Modify your `src/main.rs` to read like this:
|
Let’s look at an example. Modify your `src/main.rs` to read like this:
|
||||||
|
|
||||||
```{rust,ignore}
|
```{rust,ignore}
|
||||||
extern crate phrases;
|
extern crate phrases;
|
||||||
|
@ -494,11 +494,11 @@ mod farewells;
|
||||||
```
|
```
|
||||||
|
|
||||||
The `pub use` declaration brings the function into scope at this part of our
|
The `pub use` declaration brings the function into scope at this part of our
|
||||||
module hierarchy. Because we've `pub use`d this inside of our `japanese`
|
module hierarchy. Because we’ve `pub use`d this inside of our `japanese`
|
||||||
module, we now have a `phrases::japanese::hello()` function and a
|
module, we now have a `phrases::japanese::hello()` function and a
|
||||||
`phrases::japanese::goodbye()` function, even though the code for them lives in
|
`phrases::japanese::goodbye()` function, even though the code for them lives in
|
||||||
`phrases::japanese::greetings::hello()` and
|
`phrases::japanese::greetings::hello()` and
|
||||||
`phrases::japanese::farewells::goodbye()`. Our internal organization doesn't
|
`phrases::japanese::farewells::goodbye()`. Our internal organization doesn’t
|
||||||
define our external interface.
|
define our external interface.
|
||||||
|
|
||||||
Here we have a `pub use` for each function we want to bring into the
|
Here we have a `pub use` for each function we want to bring into the
|
||||||
|
@ -507,13 +507,13 @@ everything from `greetings` into the current scope: `pub use self::greetings::*`
|
||||||
|
|
||||||
What about the `self`? Well, by default, `use` declarations are absolute paths,
|
What about the `self`? Well, by default, `use` declarations are absolute paths,
|
||||||
starting from your crate root. `self` makes that path relative to your current
|
starting from your crate root. `self` makes that path relative to your current
|
||||||
place in the hierarchy instead. There's one more special form of `use`: you can
|
place in the hierarchy instead. There’s one more special form of `use`: you can
|
||||||
`use super::` to reach one level up the tree from your current location. Some
|
`use super::` to reach one level up the tree from your current location. Some
|
||||||
people like to think of `self` as `.` and `super` as `..`, from many shells'
|
people like to think of `self` as `.` and `super` as `..`, from many shells’
|
||||||
display for the current directory and the parent directory.
|
display for the current directory and the parent directory.
|
||||||
|
|
||||||
Outside of `use`, paths are relative: `foo::bar()` refers to a function inside
|
Outside of `use`, paths are relative: `foo::bar()` refers to a function inside
|
||||||
of `foo` relative to where we are. If that's prefixed with `::`, as in
|
of `foo` relative to where we are. If that’s prefixed with `::`, as in
|
||||||
`::foo::bar()`, it refers to a different `foo`, an absolute path from your
|
`::foo::bar()`, it refers to a different `foo`, an absolute path from your
|
||||||
crate root.
|
crate root.
|
||||||
|
|
||||||
|
|
|
@ -1,20 +1,20 @@
|
||||||
% Macros
|
% Macros
|
||||||
|
|
||||||
By now you've learned about many of the tools Rust provides for abstracting and
|
By now you’ve learned about many of the tools Rust provides for abstracting and
|
||||||
reusing code. These units of code reuse have a rich semantic structure. For
|
reusing code. These units of code reuse have a rich semantic structure. For
|
||||||
example, functions have a type signature, type parameters have trait bounds,
|
example, functions have a type signature, type parameters have trait bounds,
|
||||||
and overloaded functions must belong to a particular trait.
|
and overloaded functions must belong to a particular trait.
|
||||||
|
|
||||||
This structure means that Rust's core abstractions have powerful compile-time
|
This structure means that Rust’s core abstractions have powerful compile-time
|
||||||
correctness checking. But this comes at the price of reduced flexibility. If
|
correctness checking. But this comes at the price of reduced flexibility. If
|
||||||
you visually identify a pattern of repeated code, you may find it's difficult
|
you visually identify a pattern of repeated code, you may find it’s difficult
|
||||||
or cumbersome to express that pattern as a generic function, a trait, or
|
or cumbersome to express that pattern as a generic function, a trait, or
|
||||||
anything else within Rust's semantics.
|
anything else within Rust’s semantics.
|
||||||
|
|
||||||
Macros allow us to abstract at a *syntactic* level. A macro invocation is
|
Macros allow us to abstract at a syntactic level. A macro invocation is
|
||||||
shorthand for an "expanded" syntactic form. This expansion happens early in
|
shorthand for an "expanded" syntactic form. This expansion happens early in
|
||||||
compilation, before any static checking. As a result, macros can capture many
|
compilation, before any static checking. As a result, macros can capture many
|
||||||
patterns of code reuse that Rust's core abstractions cannot.
|
patterns of code reuse that Rust’s core abstractions cannot.
|
||||||
|
|
||||||
The drawback is that macro-based code can be harder to understand, because
|
The drawback is that macro-based code can be harder to understand, because
|
||||||
fewer of the built-in rules apply. Like an ordinary function, a well-behaved
|
fewer of the built-in rules apply. Like an ordinary function, a well-behaved
|
||||||
|
@ -23,8 +23,8 @@ difficult to design a well-behaved macro! Additionally, compiler errors in
|
||||||
macro code are harder to interpret, because they describe problems in the
|
macro code are harder to interpret, because they describe problems in the
|
||||||
expanded code, not the source-level form that developers use.
|
expanded code, not the source-level form that developers use.
|
||||||
|
|
||||||
These drawbacks make macros something of a "feature of last resort". That's not
|
These drawbacks make macros something of a "feature of last resort". That’s not
|
||||||
to say that macros are bad; they are part of Rust because sometimes they're
|
to say that macros are bad; they are part of Rust because sometimes they’re
|
||||||
needed for truly concise, well-abstracted code. Just keep this tradeoff in
|
needed for truly concise, well-abstracted code. Just keep this tradeoff in
|
||||||
mind.
|
mind.
|
||||||
|
|
||||||
|
@ -40,7 +40,7 @@ let x: Vec<u32> = vec![1, 2, 3];
|
||||||
# assert_eq!(x, [1, 2, 3]);
|
# assert_eq!(x, [1, 2, 3]);
|
||||||
```
|
```
|
||||||
|
|
||||||
This can't be an ordinary function, because it takes any number of arguments.
|
This can’t be an ordinary function, because it takes any number of arguments.
|
||||||
But we can imagine it as syntactic shorthand for
|
But we can imagine it as syntactic shorthand for
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
|
@ -77,20 +77,20 @@ macro_rules! vec {
|
||||||
# }
|
# }
|
||||||
```
|
```
|
||||||
|
|
||||||
Whoa, that's a lot of new syntax! Let's break it down.
|
Whoa, that’s a lot of new syntax! Let’s break it down.
|
||||||
|
|
||||||
```ignore
|
```ignore
|
||||||
macro_rules! vec { ... }
|
macro_rules! vec { ... }
|
||||||
```
|
```
|
||||||
|
|
||||||
This says we're defining a macro named `vec`, much as `fn vec` would define a
|
This says we’re defining a macro named `vec`, much as `fn vec` would define a
|
||||||
function named `vec`. In prose, we informally write a macro's name with an
|
function named `vec`. In prose, we informally write a macro’s name with an
|
||||||
exclamation point, e.g. `vec!`. The exclamation point is part of the invocation
|
exclamation point, e.g. `vec!`. The exclamation point is part of the invocation
|
||||||
syntax and serves to distinguish a macro from an ordinary function.
|
syntax and serves to distinguish a macro from an ordinary function.
|
||||||
|
|
||||||
## Matching
|
## Matching
|
||||||
|
|
||||||
The macro is defined through a series of *rules*, which are pattern-matching
|
The macro is defined through a series of rules, which are pattern-matching
|
||||||
cases. Above, we had
|
cases. Above, we had
|
||||||
|
|
||||||
```ignore
|
```ignore
|
||||||
|
@ -99,13 +99,13 @@ cases. Above, we had
|
||||||
|
|
||||||
This is like a `match` expression arm, but the matching happens on Rust syntax
|
This is like a `match` expression arm, but the matching happens on Rust syntax
|
||||||
trees, at compile time. The semicolon is optional on the last (here, only)
|
trees, at compile time. The semicolon is optional on the last (here, only)
|
||||||
case. The "pattern" on the left-hand side of `=>` is known as a *matcher*.
|
case. The "pattern" on the left-hand side of `=>` is known as a ‘matcher’.
|
||||||
These have [their own little grammar] within the language.
|
These have [their own little grammar] within the language.
|
||||||
|
|
||||||
[their own little grammar]: ../reference.html#macros
|
[their own little grammar]: ../reference.html#macros
|
||||||
|
|
||||||
The matcher `$x:expr` will match any Rust expression, binding that syntax tree
|
The matcher `$x:expr` will match any Rust expression, binding that syntax tree
|
||||||
to the *metavariable* `$x`. The identifier `expr` is a *fragment specifier*;
|
to the ‘metavariable’ `$x`. The identifier `expr` is a ‘fragment specifier’;
|
||||||
the full possibilities are enumerated in the [advanced macros chapter][].
|
the full possibilities are enumerated in the [advanced macros chapter][].
|
||||||
Surrounding the matcher with `$(...),*` will match zero or more expressions,
|
Surrounding the matcher with `$(...),*` will match zero or more expressions,
|
||||||
separated by commas.
|
separated by commas.
|
||||||
|
@ -158,8 +158,8 @@ Each matched expression `$x` will produce a single `push` statement in the
|
||||||
macro expansion. The repetition in the expansion proceeds in "lockstep" with
|
macro expansion. The repetition in the expansion proceeds in "lockstep" with
|
||||||
repetition in the matcher (more on this in a moment).
|
repetition in the matcher (more on this in a moment).
|
||||||
|
|
||||||
Because `$x` was already declared as matching an expression, we don't repeat
|
Because `$x` was already declared as matching an expression, we don’t repeat
|
||||||
`:expr` on the right-hand side. Also, we don't include a separating comma as
|
`:expr` on the right-hand side. Also, we don’t include a separating comma as
|
||||||
part of the repetition operator. Instead, we have a terminating semicolon
|
part of the repetition operator. Instead, we have a terminating semicolon
|
||||||
within the repeated block.
|
within the repeated block.
|
||||||
|
|
||||||
|
@ -180,7 +180,7 @@ The outer braces are part of the syntax of `macro_rules!`. In fact, you can use
|
||||||
The inner braces are part of the expanded syntax. Remember, the `vec!` macro is
|
The inner braces are part of the expanded syntax. Remember, the `vec!` macro is
|
||||||
used in an expression context. To write an expression with multiple statements,
|
used in an expression context. To write an expression with multiple statements,
|
||||||
including `let`-bindings, we use a block. If your macro expands to a single
|
including `let`-bindings, we use a block. If your macro expands to a single
|
||||||
expression, you don't need this extra layer of braces.
|
expression, you don’t need this extra layer of braces.
|
||||||
|
|
||||||
Note that we never *declared* that the macro produces an expression. In fact,
|
Note that we never *declared* that the macro produces an expression. In fact,
|
||||||
this is not determined until we use the macro as an expression. With care, you
|
this is not determined until we use the macro as an expression. With care, you
|
||||||
|
@ -194,7 +194,7 @@ The repetition operator follows two principal rules:
|
||||||
1. `$(...)*` walks through one "layer" of repetitions, for all of the `$name`s
|
1. `$(...)*` walks through one "layer" of repetitions, for all of the `$name`s
|
||||||
it contains, in lockstep, and
|
it contains, in lockstep, and
|
||||||
2. each `$name` must be under at least as many `$(...)*`s as it was matched
|
2. each `$name` must be under at least as many `$(...)*`s as it was matched
|
||||||
against. If it is under more, it'll be duplicated, as appropriate.
|
against. If it is under more, it’ll be duplicated, as appropriate.
|
||||||
|
|
||||||
This baroque macro illustrates the duplication of variables from outer
|
This baroque macro illustrates the duplication of variables from outer
|
||||||
repetition levels.
|
repetition levels.
|
||||||
|
@ -219,7 +219,7 @@ fn main() {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
That's most of the matcher syntax. These examples use `$(...)*`, which is a
|
That’s most of the matcher syntax. These examples use `$(...)*`, which is a
|
||||||
"zero or more" match. Alternatively you can write `$(...)+` for a "one or
|
"zero or more" match. Alternatively you can write `$(...)+` for a "one or
|
||||||
more" match. Both forms optionally include a separator, which can be any token
|
more" match. Both forms optionally include a separator, which can be any token
|
||||||
except `+` or `*`.
|
except `+` or `*`.
|
||||||
|
@ -244,9 +244,9 @@ int main() {
|
||||||
```
|
```
|
||||||
|
|
||||||
After expansion we have `5 * 2 + 3`, and multiplication has greater precedence
|
After expansion we have `5 * 2 + 3`, and multiplication has greater precedence
|
||||||
than addition. If you've used C macros a lot, you probably know the standard
|
than addition. If you’ve used C macros a lot, you probably know the standard
|
||||||
idioms for avoiding this problem, as well as five or six others. In Rust, we
|
idioms for avoiding this problem, as well as five or six others. In Rust, we
|
||||||
don't have to worry about it.
|
don’t have to worry about it.
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
macro_rules! five_times {
|
macro_rules! five_times {
|
||||||
|
@ -261,8 +261,8 @@ fn main() {
|
||||||
The metavariable `$x` is parsed as a single expression node, and keeps its
|
The metavariable `$x` is parsed as a single expression node, and keeps its
|
||||||
place in the syntax tree even after substitution.
|
place in the syntax tree even after substitution.
|
||||||
|
|
||||||
Another common problem in macro systems is *variable capture*. Here's a C
|
Another common problem in macro systems is ‘variable capture’. Here’s a C
|
||||||
macro, using [a GNU C extension] to emulate Rust's expression blocks.
|
macro, using [a GNU C extension] to emulate Rust’s expression blocks.
|
||||||
|
|
||||||
[a GNU C extension]: https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html
|
[a GNU C extension]: https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html
|
||||||
|
|
||||||
|
@ -275,7 +275,7 @@ macro, using [a GNU C extension] to emulate Rust's expression blocks.
|
||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
Here's a simple use case that goes terribly wrong:
|
Here’s a simple use case that goes terribly wrong:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
const char *state = "reticulating splines";
|
const char *state = "reticulating splines";
|
||||||
|
@ -315,10 +315,10 @@ fn main() {
|
||||||
```
|
```
|
||||||
|
|
||||||
This works because Rust has a [hygienic macro system][]. Each macro expansion
|
This works because Rust has a [hygienic macro system][]. Each macro expansion
|
||||||
happens in a distinct *syntax context*, and each variable is tagged with the
|
happens in a distinct ‘syntax context’, and each variable is tagged with the
|
||||||
syntax context where it was introduced. It's as though the variable `state`
|
syntax context where it was introduced. It’s as though the variable `state`
|
||||||
inside `main` is painted a different "color" from the variable `state` inside
|
inside `main` is painted a different "color" from the variable `state` inside
|
||||||
the macro, and therefore they don't conflict.
|
the macro, and therefore they don’t conflict.
|
||||||
|
|
||||||
[hygienic macro system]: http://en.wikipedia.org/wiki/Hygienic_macro
|
[hygienic macro system]: http://en.wikipedia.org/wiki/Hygienic_macro
|
||||||
|
|
||||||
|
@ -336,7 +336,7 @@ fn main() {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Instead you need to pass the variable name into the invocation, so it's tagged
|
Instead you need to pass the variable name into the invocation, so it’s tagged
|
||||||
with the right syntax context.
|
with the right syntax context.
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
|
@ -368,7 +368,7 @@ fn main() {
|
||||||
|
|
||||||
# Recursive macros
|
# Recursive macros
|
||||||
|
|
||||||
A macro's expansion can include more macro invocations, including invocations
|
A macro’s expansion can include more macro invocations, including invocations
|
||||||
of the very same macro being expanded. These recursive macros are useful for
|
of the very same macro being expanded. These recursive macros are useful for
|
||||||
processing tree-structured input, as illustrated by this (simplistic) HTML
|
processing tree-structured input, as illustrated by this (simplistic) HTML
|
||||||
shorthand:
|
shorthand:
|
||||||
|
@ -429,7 +429,7 @@ they are unstable and require feature gates.
|
||||||
Even when Rust code contains un-expanded macros, it can be parsed as a full
|
Even when Rust code contains un-expanded macros, it can be parsed as a full
|
||||||
[syntax tree][ast]. This property can be very useful for editors and other
|
[syntax tree][ast]. This property can be very useful for editors and other
|
||||||
tools that process code. It also has a few consequences for the design of
|
tools that process code. It also has a few consequences for the design of
|
||||||
Rust's macro system.
|
Rust’s macro system.
|
||||||
|
|
||||||
[ast]: glossary.html#abstract-syntax-tree
|
[ast]: glossary.html#abstract-syntax-tree
|
||||||
|
|
||||||
|
@ -454,13 +454,13 @@ consist of valid Rust tokens. Furthermore, parentheses, brackets, and braces
|
||||||
must be balanced within a macro invocation. For example, `foo!([)` is
|
must be balanced within a macro invocation. For example, `foo!([)` is
|
||||||
forbidden. This allows Rust to know where the macro invocation ends.
|
forbidden. This allows Rust to know where the macro invocation ends.
|
||||||
|
|
||||||
More formally, the macro invocation body must be a sequence of *token trees*.
|
More formally, the macro invocation body must be a sequence of ‘token trees’.
|
||||||
A token tree is defined recursively as either
|
A token tree is defined recursively as either
|
||||||
|
|
||||||
* a sequence of token trees surrounded by matching `()`, `[]`, or `{}`, or
|
* a sequence of token trees surrounded by matching `()`, `[]`, or `{}`, or
|
||||||
* any other single token.
|
* any other single token.
|
||||||
|
|
||||||
Within a matcher, each metavariable has a *fragment specifier*, identifying
|
Within a matcher, each metavariable has a ‘fragment specifier’, identifying
|
||||||
which syntactic form it matches.
|
which syntactic form it matches.
|
||||||
|
|
||||||
* `ident`: an identifier. Examples: `x`; `foo`.
|
* `ident`: an identifier. Examples: `x`; `foo`.
|
||||||
|
@ -482,7 +482,7 @@ There are additional rules regarding the next token after a metavariable:
|
||||||
* `pat` variables must be followed by one of: `=> , =`
|
* `pat` variables must be followed by one of: `=> , =`
|
||||||
* Other variables may be followed by any token.
|
* Other variables may be followed by any token.
|
||||||
|
|
||||||
These rules provide some flexibility for Rust's syntax to evolve without
|
These rules provide some flexibility for Rust’s syntax to evolve without
|
||||||
breaking existing macros.
|
breaking existing macros.
|
||||||
|
|
||||||
The macro system does not deal with parse ambiguity at all. For example, the
|
The macro system does not deal with parse ambiguity at all. For example, the
|
||||||
|
@ -500,7 +500,7 @@ One downside is that scoping works differently for macros, compared to other
|
||||||
constructs in the language.
|
constructs in the language.
|
||||||
|
|
||||||
Definition and expansion of macros both happen in a single depth-first,
|
Definition and expansion of macros both happen in a single depth-first,
|
||||||
lexical-order traversal of a crate's source. So a macro defined at module scope
|
lexical-order traversal of a crate’s source. So a macro defined at module scope
|
||||||
is visible to any subsequent code in the same module, which includes the body
|
is visible to any subsequent code in the same module, which includes the body
|
||||||
of any subsequent child `mod` items.
|
of any subsequent child `mod` items.
|
||||||
|
|
||||||
|
@ -508,8 +508,8 @@ A macro defined within the body of a single `fn`, or anywhere else not at
|
||||||
module scope, is visible only within that item.
|
module scope, is visible only within that item.
|
||||||
|
|
||||||
If a module has the `macro_use` attribute, its macros are also visible in its
|
If a module has the `macro_use` attribute, its macros are also visible in its
|
||||||
parent module after the child's `mod` item. If the parent also has `macro_use`
|
parent module after the child’s `mod` item. If the parent also has `macro_use`
|
||||||
then the macros will be visible in the grandparent after the parent's `mod`
|
then the macros will be visible in the grandparent after the parent’s `mod`
|
||||||
item, and so forth.
|
item, and so forth.
|
||||||
|
|
||||||
The `macro_use` attribute can also appear on `extern crate`. In this context
|
The `macro_use` attribute can also appear on `extern crate`. In this context
|
||||||
|
@ -524,7 +524,7 @@ If the attribute is given simply as `#[macro_use]`, all macros are loaded. If
|
||||||
there is no `#[macro_use]` attribute then no macros are loaded. Only macros
|
there is no `#[macro_use]` attribute then no macros are loaded. Only macros
|
||||||
defined with the `#[macro_export]` attribute may be loaded.
|
defined with the `#[macro_export]` attribute may be loaded.
|
||||||
|
|
||||||
To load a crate's macros *without* linking it into the output, use `#[no_link]`
|
To load a crate’s macros without linking it into the output, use `#[no_link]`
|
||||||
as well.
|
as well.
|
||||||
|
|
||||||
An example:
|
An example:
|
||||||
|
@ -619,12 +619,12 @@ only appear at the root of your crate, not inside `mod`. This ensures that
|
||||||
|
|
||||||
The introductory chapter mentioned recursive macros, but it did not give the
|
The introductory chapter mentioned recursive macros, but it did not give the
|
||||||
full story. Recursive macros are useful for another reason: Each recursive
|
full story. Recursive macros are useful for another reason: Each recursive
|
||||||
invocation gives you another opportunity to pattern-match the macro's
|
invocation gives you another opportunity to pattern-match the macro’s
|
||||||
arguments.
|
arguments.
|
||||||
|
|
||||||
As an extreme example, it is possible, though hardly advisable, to implement
|
As an extreme example, it is possible, though hardly advisable, to implement
|
||||||
the [Bitwise Cyclic Tag](http://esolangs.org/wiki/Bitwise_Cyclic_Tag) automaton
|
the [Bitwise Cyclic Tag](http://esolangs.org/wiki/Bitwise_Cyclic_Tag) automaton
|
||||||
within Rust's macro system.
|
within Rust’s macro system.
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
macro_rules! bct {
|
macro_rules! bct {
|
||||||
|
@ -765,9 +765,9 @@ as `unimplemented!` until you’re ready to write them.
|
||||||
|
|
||||||
# Procedural macros
|
# Procedural macros
|
||||||
|
|
||||||
If Rust's macro system can't do what you need, you may want to write a
|
If Rust’s macro system can’t do what you need, you may want to write a
|
||||||
[compiler plugin](plugins.html) instead. Compared to `macro_rules!`
|
[compiler plugin](plugins.html) instead. Compared to `macro_rules!`
|
||||||
macros, this is significantly more work, the interfaces are much less stable,
|
macros, this is significantly more work, the interfaces are much less stable,
|
||||||
and bugs can be much harder to track down. In exchange you get the
|
and bugs can be much harder to track down. In exchange you get the
|
||||||
flexibility of running arbitrary Rust code within the compiler. Syntax
|
flexibility of running arbitrary Rust code within the compiler. Syntax
|
||||||
extension plugins are sometimes called *procedural macros* for this reason.
|
extension plugins are sometimes called ‘procedural macros’ for this reason.
|
||||||
|
|
|
@ -168,6 +168,7 @@ like arrays:
|
||||||
```rust
|
```rust
|
||||||
let a = [0, 1, 2, 3, 4];
|
let a = [0, 1, 2, 3, 4];
|
||||||
let middle = &a[1..4]; // A slice of a: just the elements 1, 2, and 3
|
let middle = &a[1..4]; // A slice of a: just the elements 1, 2, and 3
|
||||||
|
let complete = &a[..]; // A slice containing all of the elements in a
|
||||||
```
|
```
|
||||||
|
|
||||||
Slices have type `&[T]`. We’ll talk about that `T` when we cover
|
Slices have type `&[T]`. We’ll talk about that `T` when we cover
|
||||||
|
|
|
@ -87,3 +87,33 @@ fn main() {
|
||||||
point.y = 6; // this causes an error
|
point.y = 6; // this causes an error
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
# Update syntax
|
||||||
|
|
||||||
|
A `struct` can include `..` to indicate that you want to use a copy of some
|
||||||
|
other struct for some of the values. For example:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
struct Point3d {
|
||||||
|
x: i32,
|
||||||
|
y: i32,
|
||||||
|
z: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut point = Point3d { x: 0, y: 0, z: 0 };
|
||||||
|
point = Point3d { y: 1, .. point };
|
||||||
|
```
|
||||||
|
|
||||||
|
This gives `point` a new `y`, but keeps the old `x` and `z` values. It doesn’t
|
||||||
|
have to be the same `struct` either, you can use this syntax when making new
|
||||||
|
ones, and it will copy the values you don’t specify:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
# struct Point3d {
|
||||||
|
# x: i32,
|
||||||
|
# y: i32,
|
||||||
|
# z: i32,
|
||||||
|
# }
|
||||||
|
let origin = Point3d { x: 0, y: 0, z: 0 };
|
||||||
|
let point = Point3d { z: 1, x: 2, .. origin };
|
||||||
|
```
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
% Trait Objects
|
% Trait Objects
|
||||||
|
|
||||||
When code involves polymorphism, there needs to be a mechanism to determine
|
When code involves polymorphism, there needs to be a mechanism to determine
|
||||||
which specific version is actually run. This is called 'dispatch.' There are
|
which specific version is actually run. This is called ‘dispatch’. There are
|
||||||
two major forms of dispatch: static dispatch and dynamic dispatch. While Rust
|
two major forms of dispatch: static dispatch and dynamic dispatch. While Rust
|
||||||
favors static dispatch, it also supports dynamic dispatch through a mechanism
|
favors static dispatch, it also supports dynamic dispatch through a mechanism
|
||||||
called 'trait objects.'
|
called ‘trait objects’.
|
||||||
|
|
||||||
## Background
|
## Background
|
||||||
|
|
||||||
For the rest of this chapter, we'll need a trait and some implementations.
|
For the rest of this chapter, we’ll need a trait and some implementations.
|
||||||
Let's make a simple one, `Foo`. It has one method that is expected to return a
|
Let’s make a simple one, `Foo`. It has one method that is expected to return a
|
||||||
`String`.
|
`String`.
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
|
@ -18,7 +18,7 @@ trait Foo {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
We'll also implement this trait for `u8` and `String`:
|
We’ll also implement this trait for `u8` and `String`:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
# trait Foo { fn method(&self) -> String; }
|
# trait Foo { fn method(&self) -> String; }
|
||||||
|
@ -53,7 +53,7 @@ fn main() {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Rust uses 'monomorphization' to perform static dispatch here. This means that
|
Rust uses ‘monomorphization’ to perform static dispatch here. This means that
|
||||||
Rust will create a special version of `do_something()` for both `u8` and
|
Rust will create a special version of `do_something()` for both `u8` and
|
||||||
`String`, and then replace the call sites with calls to these specialized
|
`String`, and then replace the call sites with calls to these specialized
|
||||||
functions. In other words, Rust generates something like this:
|
functions. In other words, Rust generates something like this:
|
||||||
|
@ -82,7 +82,7 @@ fn main() {
|
||||||
This has a great upside: static dispatch allows function calls to be
|
This has a great upside: static dispatch allows function calls to be
|
||||||
inlined because the callee is known at compile time, and inlining is
|
inlined because the callee is known at compile time, and inlining is
|
||||||
the key to good optimization. Static dispatch is fast, but it comes at
|
the key to good optimization. Static dispatch is fast, but it comes at
|
||||||
a tradeoff: 'code bloat', due to many copies of the same function
|
a tradeoff: ‘code bloat’, due to many copies of the same function
|
||||||
existing in the binary, one for each type.
|
existing in the binary, one for each type.
|
||||||
|
|
||||||
Furthermore, compilers aren’t perfect and may “optimize” code to become slower.
|
Furthermore, compilers aren’t perfect and may “optimize” code to become slower.
|
||||||
|
@ -99,7 +99,7 @@ reason.
|
||||||
|
|
||||||
## Dynamic dispatch
|
## Dynamic dispatch
|
||||||
|
|
||||||
Rust provides dynamic dispatch through a feature called 'trait objects.' Trait
|
Rust provides dynamic dispatch through a feature called ‘trait objects’. Trait
|
||||||
objects, like `&Foo` or `Box<Foo>`, are normal values that store a value of
|
objects, like `&Foo` or `Box<Foo>`, are normal values that store a value of
|
||||||
*any* type that implements the given trait, where the precise type can only be
|
*any* type that implements the given trait, where the precise type can only be
|
||||||
known at runtime.
|
known at runtime.
|
||||||
|
@ -109,12 +109,12 @@ implements the trait by *casting* it (e.g. `&x as &Foo`) or *coercing* it
|
||||||
(e.g. using `&x` as an argument to a function that takes `&Foo`).
|
(e.g. using `&x` as an argument to a function that takes `&Foo`).
|
||||||
|
|
||||||
These trait object coercions and casts also work for pointers like `&mut T` to
|
These trait object coercions and casts also work for pointers like `&mut T` to
|
||||||
`&mut Foo` and `Box<T>` to `Box<Foo>`, but that's all at the moment. Coercions
|
`&mut Foo` and `Box<T>` to `Box<Foo>`, but that’s all at the moment. Coercions
|
||||||
and casts are identical.
|
and casts are identical.
|
||||||
|
|
||||||
This operation can be seen as "erasing" the compiler's knowledge about the
|
This operation can be seen as ‘erasing’ the compiler’s knowledge about the
|
||||||
specific type of the pointer, and hence trait objects are sometimes referred to
|
specific type of the pointer, and hence trait objects are sometimes referred to
|
||||||
as "type erasure".
|
as ‘type erasure’.
|
||||||
|
|
||||||
Coming back to the example above, we can use the same trait to perform dynamic
|
Coming back to the example above, we can use the same trait to perform dynamic
|
||||||
dispatch with trait objects by casting:
|
dispatch with trait objects by casting:
|
||||||
|
@ -167,7 +167,7 @@ on the heap to store it.
|
||||||
|
|
||||||
For `Foo`, we would need to have a value that could be at least either a
|
For `Foo`, we would need to have a value that could be at least either a
|
||||||
`String` (24 bytes) or a `u8` (1 byte), as well as any other type for which
|
`String` (24 bytes) or a `u8` (1 byte), as well as any other type for which
|
||||||
dependent crates may implement `Foo` (any number of bytes at all). There's no
|
dependent crates may implement `Foo` (any number of bytes at all). There’s no
|
||||||
way to guarantee that this last point can work if the values are stored without
|
way to guarantee that this last point can work if the values are stored without
|
||||||
a pointer, because those other types can be arbitrarily large.
|
a pointer, because those other types can be arbitrarily large.
|
||||||
|
|
||||||
|
@ -177,14 +177,14 @@ when we are tossing a trait object around, only the size of the pointer itself.
|
||||||
### Representation
|
### Representation
|
||||||
|
|
||||||
The methods of the trait can be called on a trait object via a special record
|
The methods of the trait can be called on a trait object via a special record
|
||||||
of function pointers traditionally called a 'vtable' (created and managed by
|
of function pointers traditionally called a ‘vtable’ (created and managed by
|
||||||
the compiler).
|
the compiler).
|
||||||
|
|
||||||
Trait objects are both simple and complicated: their core representation and
|
Trait objects are both simple and complicated: their core representation and
|
||||||
layout is quite straight-forward, but there are some curly error messages and
|
layout is quite straight-forward, but there are some curly error messages and
|
||||||
surprising behaviors to discover.
|
surprising behaviors to discover.
|
||||||
|
|
||||||
Let's start simple, with the runtime representation of a trait object. The
|
Let’s start simple, with the runtime representation of a trait object. The
|
||||||
`std::raw` module contains structs with layouts that are the same as the
|
`std::raw` module contains structs with layouts that are the same as the
|
||||||
complicated built-in types, [including trait objects][stdraw]:
|
complicated built-in types, [including trait objects][stdraw]:
|
||||||
|
|
||||||
|
@ -199,12 +199,12 @@ pub struct TraitObject {
|
||||||
|
|
||||||
[stdraw]: ../std/raw/struct.TraitObject.html
|
[stdraw]: ../std/raw/struct.TraitObject.html
|
||||||
|
|
||||||
That is, a trait object like `&Foo` consists of a "data" pointer and a "vtable"
|
That is, a trait object like `&Foo` consists of a ‘data’ pointer and a ‘vtable’
|
||||||
pointer.
|
pointer.
|
||||||
|
|
||||||
The data pointer addresses the data (of some unknown type `T`) that the trait
|
The data pointer addresses the data (of some unknown type `T`) that the trait
|
||||||
object is storing, and the vtable pointer points to the vtable ("virtual method
|
object is storing, and the vtable pointer points to the vtable (‘virtual method
|
||||||
table") corresponding to the implementation of `Foo` for `T`.
|
table’) corresponding to the implementation of `Foo` for `T`.
|
||||||
|
|
||||||
|
|
||||||
A vtable is essentially a struct of function pointers, pointing to the concrete
|
A vtable is essentially a struct of function pointers, pointing to the concrete
|
||||||
|
@ -212,7 +212,7 @@ piece of machine code for each method in the implementation. A method call like
|
||||||
`trait_object.method()` will retrieve the correct pointer out of the vtable and
|
`trait_object.method()` will retrieve the correct pointer out of the vtable and
|
||||||
then do a dynamic call of it. For example:
|
then do a dynamic call of it. For example:
|
||||||
|
|
||||||
```{rust,ignore}
|
```rust,ignore
|
||||||
struct FooVtable {
|
struct FooVtable {
|
||||||
destructor: fn(*mut ()),
|
destructor: fn(*mut ()),
|
||||||
size: usize,
|
size: usize,
|
||||||
|
@ -261,7 +261,7 @@ static Foo_for_String_vtable: FooVtable = FooVtable {
|
||||||
```
|
```
|
||||||
|
|
||||||
The `destructor` field in each vtable points to a function that will clean up
|
The `destructor` field in each vtable points to a function that will clean up
|
||||||
any resources of the vtable's type, for `u8` it is trivial, but for `String` it
|
any resources of the vtable’s type, for `u8` it is trivial, but for `String` it
|
||||||
will free the memory. This is necessary for owning trait objects like
|
will free the memory. This is necessary for owning trait objects like
|
||||||
`Box<Foo>`, which need to clean-up both the `Box` allocation as well as the
|
`Box<Foo>`, which need to clean-up both the `Box` allocation as well as the
|
||||||
internal type when they go out of scope. The `size` and `align` fields store
|
internal type when they go out of scope. The `size` and `align` fields store
|
||||||
|
@ -270,11 +270,11 @@ essentially unused at the moment since the information is embedded in the
|
||||||
destructor, but will be used in the future, as trait objects are progressively
|
destructor, but will be used in the future, as trait objects are progressively
|
||||||
made more flexible.
|
made more flexible.
|
||||||
|
|
||||||
Suppose we've got some values that implement `Foo`, then the explicit form of
|
Suppose we’ve got some values that implement `Foo`, then the explicit form of
|
||||||
construction and use of `Foo` trait objects might look a bit like (ignoring the
|
construction and use of `Foo` trait objects might look a bit like (ignoring the
|
||||||
type mismatches: they're all just pointers anyway):
|
type mismatches: they’re all just pointers anyway):
|
||||||
|
|
||||||
```{rust,ignore}
|
```rust,ignore
|
||||||
let a: String = "foo".to_string();
|
let a: String = "foo".to_string();
|
||||||
let x: u8 = 1;
|
let x: u8 = 1;
|
||||||
|
|
||||||
|
|
|
@ -336,7 +336,7 @@ This shows off the additional feature of `where` clauses: they allow bounds
|
||||||
where the left-hand side is an arbitrary type (`i32` in this case), not just a
|
where the left-hand side is an arbitrary type (`i32` in this case), not just a
|
||||||
plain type parameter (like `T`).
|
plain type parameter (like `T`).
|
||||||
|
|
||||||
# Default methods
|
## Default methods
|
||||||
|
|
||||||
There’s one last feature of traits we should cover: default methods. It’s
|
There’s one last feature of traits we should cover: default methods. It’s
|
||||||
easiest just to show an example:
|
easiest just to show an example:
|
||||||
|
|
|
@ -1,16 +1,20 @@
|
||||||
% Tuple Structs
|
% Tuple Structs
|
||||||
|
|
||||||
Rust has another data type that's like a hybrid between a tuple and a struct,
|
Rust has another data type that's like a hybrid between a [tuple][tuple] and a
|
||||||
called a *tuple struct*. Tuple structs do have a name, but their fields don't:
|
[struct][struct], called a ‘tuple struct’. Tuple structs have a name, but
|
||||||
|
their fields don’t:
|
||||||
|
|
||||||
```{rust}
|
```rust
|
||||||
struct Color(i32, i32, i32);
|
struct Color(i32, i32, i32);
|
||||||
struct Point(i32, i32, i32);
|
struct Point(i32, i32, i32);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
[tuple]: primitive-types.html#tuples
|
||||||
|
[struct]: structs.html
|
||||||
|
|
||||||
These two will not be equal, even if they have the same values:
|
These two will not be equal, even if they have the same values:
|
||||||
|
|
||||||
```{rust}
|
```rust
|
||||||
# struct Color(i32, i32, i32);
|
# struct Color(i32, i32, i32);
|
||||||
# struct Point(i32, i32, i32);
|
# struct Point(i32, i32, i32);
|
||||||
let black = Color(0, 0, 0);
|
let black = Color(0, 0, 0);
|
||||||
|
@ -20,7 +24,7 @@ let origin = Point(0, 0, 0);
|
||||||
It is almost always better to use a struct than a tuple struct. We would write
|
It is almost always better to use a struct than a tuple struct. We would write
|
||||||
`Color` and `Point` like this instead:
|
`Color` and `Point` like this instead:
|
||||||
|
|
||||||
```{rust}
|
```rust
|
||||||
struct Color {
|
struct Color {
|
||||||
red: i32,
|
red: i32,
|
||||||
blue: i32,
|
blue: i32,
|
||||||
|
@ -37,12 +41,12 @@ struct Point {
|
||||||
Now, we have actual names, rather than positions. Good names are important,
|
Now, we have actual names, rather than positions. Good names are important,
|
||||||
and with a struct, we have actual names.
|
and with a struct, we have actual names.
|
||||||
|
|
||||||
There _is_ one case when a tuple struct is very useful, though, and that's a
|
There _is_ one case when a tuple struct is very useful, though, and that’s a
|
||||||
tuple struct with only one element. We call this the *newtype* pattern, because
|
tuple struct with only one element. We call this the ‘newtype’ pattern, because
|
||||||
it allows you to create a new type, distinct from that of its contained value
|
it allows you to create a new type, distinct from that of its contained value
|
||||||
and expressing its own semantic meaning:
|
and expressing its own semantic meaning:
|
||||||
|
|
||||||
```{rust}
|
```rust
|
||||||
struct Inches(i32);
|
struct Inches(i32);
|
||||||
|
|
||||||
let length = Inches(10);
|
let length = Inches(10);
|
||||||
|
@ -52,5 +56,5 @@ println!("length is {} inches", integer_length);
|
||||||
```
|
```
|
||||||
|
|
||||||
As you can see here, you can extract the inner integer type through a
|
As you can see here, you can extract the inner integer type through a
|
||||||
destructuring `let`, as we discussed previously in 'tuples.' In this case, the
|
destructuring `let`, as we discussed previously in ‘tuples’. In this case, the
|
||||||
`let Inches(integer_length)` assigns `10` to `integer_length`.
|
`let Inches(integer_length)` assigns `10` to `integer_length`.
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
% Unsafe Code
|
% Unsafe
|
||||||
|
|
||||||
Rust’s main draw is its powerful static guarantees about behavior. But safety
|
Rust’s main draw is its powerful static guarantees about behavior. But safety
|
||||||
checks are conservative by nature: there are some programs that are actually
|
checks are conservative by nature: there are some programs that are actually
|
||||||
|
@ -76,7 +76,7 @@ behaviors that are certainly bad, but are expressly _not_ unsafe:
|
||||||
* Integer overflow
|
* Integer overflow
|
||||||
|
|
||||||
Rust cannot prevent all kinds of software problems. Buggy code can and will be
|
Rust cannot prevent all kinds of software problems. Buggy code can and will be
|
||||||
written in Rust. These things arne’t great, but they don’t qualify as `unsafe`
|
written in Rust. These things aren’t great, but they don’t qualify as `unsafe`
|
||||||
specifically.
|
specifically.
|
||||||
|
|
||||||
# Unsafe Superpowers
|
# Unsafe Superpowers
|
|
@ -46,13 +46,8 @@ def run(args):
|
||||||
|
|
||||||
f.write("\n")
|
f.write("\n")
|
||||||
|
|
||||||
version = run([llconfig, '--version']).strip()
|
|
||||||
|
|
||||||
# LLVM libs
|
# LLVM libs
|
||||||
if version < '3.5':
|
args = [llconfig, '--libs', '--system-libs']
|
||||||
args = [llconfig, '--libs']
|
|
||||||
else:
|
|
||||||
args = [llconfig, '--libs', '--system-libs']
|
|
||||||
|
|
||||||
args.extend(components)
|
args.extend(components)
|
||||||
out = run(args)
|
out = run(args)
|
||||||
|
@ -73,11 +68,6 @@ for lib in out.strip().replace("\n", ' ').split(' '):
|
||||||
f.write(", kind = \"static\"")
|
f.write(", kind = \"static\"")
|
||||||
f.write(")]\n")
|
f.write(")]\n")
|
||||||
|
|
||||||
# llvm-config before 3.5 didn't have a system-libs flag
|
|
||||||
if version < '3.5':
|
|
||||||
if os == 'win32':
|
|
||||||
f.write("#[link(name = \"imagehlp\")]")
|
|
||||||
|
|
||||||
# LLVM ldflags
|
# LLVM ldflags
|
||||||
out = run([llconfig, '--ldflags'])
|
out = run([llconfig, '--ldflags'])
|
||||||
for lib in out.strip().split(' '):
|
for lib in out.strip().split(' '):
|
||||||
|
|
|
@ -77,7 +77,6 @@ use core::atomic;
|
||||||
use core::atomic::Ordering::{Relaxed, Release, Acquire, SeqCst};
|
use core::atomic::Ordering::{Relaxed, Release, Acquire, SeqCst};
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
use core::cmp::Ordering;
|
use core::cmp::Ordering;
|
||||||
use core::default::Default;
|
|
||||||
use core::mem::{min_align_of, size_of};
|
use core::mem::{min_align_of, size_of};
|
||||||
use core::mem;
|
use core::mem;
|
||||||
use core::nonzero::NonZero;
|
use core::nonzero::NonZero;
|
||||||
|
|
|
@ -55,7 +55,6 @@ use core::prelude::*;
|
||||||
|
|
||||||
use core::any::Any;
|
use core::any::Any;
|
||||||
use core::cmp::Ordering;
|
use core::cmp::Ordering;
|
||||||
use core::default::Default;
|
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
use core::hash::{self, Hash};
|
use core::hash::{self, Hash};
|
||||||
use core::mem;
|
use core::mem;
|
||||||
|
|
|
@ -152,8 +152,7 @@
|
||||||
|
|
||||||
use core::prelude::*;
|
use core::prelude::*;
|
||||||
|
|
||||||
use core::default::Default;
|
use core::iter::{FromIterator};
|
||||||
use core::iter::{FromIterator, IntoIterator};
|
|
||||||
use core::mem::{zeroed, replace, swap};
|
use core::mem::{zeroed, replace, swap};
|
||||||
use core::ptr;
|
use core::ptr;
|
||||||
|
|
||||||
|
@ -250,28 +249,6 @@ impl<T: Ord> BinaryHeap<T> {
|
||||||
Iter { iter: self.data.iter() }
|
Iter { iter: self.data.iter() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a consuming iterator, that is, one that moves each value out of
|
|
||||||
/// the binary heap in arbitrary order. The binary heap cannot be used
|
|
||||||
/// after calling this.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// # #![feature(collections)]
|
|
||||||
/// use std::collections::BinaryHeap;
|
|
||||||
/// let heap = BinaryHeap::from_vec(vec![1, 2, 3, 4]);
|
|
||||||
///
|
|
||||||
/// // Print 1, 2, 3, 4 in arbitrary order
|
|
||||||
/// for x in heap.into_iter() {
|
|
||||||
/// // x has type i32, not &i32
|
|
||||||
/// println!("{}", x);
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
|
||||||
pub fn into_iter(self) -> IntoIter<T> {
|
|
||||||
IntoIter { iter: self.data.into_iter() }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the greatest item in the binary heap, or `None` if it is empty.
|
/// Returns the greatest item in the binary heap, or `None` if it is empty.
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
|
@ -675,8 +652,25 @@ impl<T: Ord> IntoIterator for BinaryHeap<T> {
|
||||||
type Item = T;
|
type Item = T;
|
||||||
type IntoIter = IntoIter<T>;
|
type IntoIter = IntoIter<T>;
|
||||||
|
|
||||||
|
/// Creates a consuming iterator, that is, one that moves each value out of
|
||||||
|
/// the binary heap in arbitrary order. The binary heap cannot be used
|
||||||
|
/// after calling this.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # #![feature(collections)]
|
||||||
|
/// use std::collections::BinaryHeap;
|
||||||
|
/// let heap = BinaryHeap::from_vec(vec![1, 2, 3, 4]);
|
||||||
|
///
|
||||||
|
/// // Print 1, 2, 3, 4 in arbitrary order
|
||||||
|
/// for x in heap.into_iter() {
|
||||||
|
/// // x has type i32, not &i32
|
||||||
|
/// println!("{}", x);
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
fn into_iter(self) -> IntoIter<T> {
|
fn into_iter(self) -> IntoIter<T> {
|
||||||
self.into_iter()
|
IntoIter { iter: self.data.into_iter() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -40,7 +40,6 @@
|
||||||
//! ```
|
//! ```
|
||||||
//! # #![feature(collections, core, step_by)]
|
//! # #![feature(collections, core, step_by)]
|
||||||
//! use std::collections::{BitSet, BitVec};
|
//! use std::collections::{BitSet, BitVec};
|
||||||
//! use std::num::Float;
|
|
||||||
//! use std::iter;
|
//! use std::iter;
|
||||||
//!
|
//!
|
||||||
//! let max_prime = 10000;
|
//! let max_prime = 10000;
|
||||||
|
@ -85,12 +84,11 @@ use core::prelude::*;
|
||||||
|
|
||||||
use core::cmp::Ordering;
|
use core::cmp::Ordering;
|
||||||
use core::cmp;
|
use core::cmp;
|
||||||
use core::default::Default;
|
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
use core::hash;
|
use core::hash;
|
||||||
use core::iter::RandomAccessIterator;
|
use core::iter::RandomAccessIterator;
|
||||||
use core::iter::{Chain, Enumerate, Repeat, Skip, Take, repeat, Cloned};
|
use core::iter::{Chain, Enumerate, Repeat, Skip, Take, repeat, Cloned};
|
||||||
use core::iter::{self, FromIterator, IntoIterator};
|
use core::iter::{self, FromIterator};
|
||||||
use core::ops::Index;
|
use core::ops::Index;
|
||||||
use core::slice;
|
use core::slice;
|
||||||
use core::{u8, u32, usize};
|
use core::{u8, u32, usize};
|
||||||
|
|
|
@ -20,10 +20,9 @@ use self::Entry::*;
|
||||||
use core::prelude::*;
|
use core::prelude::*;
|
||||||
|
|
||||||
use core::cmp::Ordering;
|
use core::cmp::Ordering;
|
||||||
use core::default::Default;
|
|
||||||
use core::fmt::Debug;
|
use core::fmt::Debug;
|
||||||
use core::hash::{Hash, Hasher};
|
use core::hash::{Hash, Hasher};
|
||||||
use core::iter::{Map, FromIterator, IntoIterator};
|
use core::iter::{Map, FromIterator};
|
||||||
use core::ops::Index;
|
use core::ops::Index;
|
||||||
use core::{iter, fmt, mem, usize};
|
use core::{iter, fmt, mem, usize};
|
||||||
use Bound::{self, Included, Excluded, Unbounded};
|
use Bound::{self, Included, Excluded, Unbounded};
|
||||||
|
@ -471,8 +470,32 @@ impl<K, V> IntoIterator for BTreeMap<K, V> {
|
||||||
type Item = (K, V);
|
type Item = (K, V);
|
||||||
type IntoIter = IntoIter<K, V>;
|
type IntoIter = IntoIter<K, V>;
|
||||||
|
|
||||||
|
/// Gets an owning iterator over the entries of the map.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use std::collections::BTreeMap;
|
||||||
|
///
|
||||||
|
/// let mut map = BTreeMap::new();
|
||||||
|
/// map.insert(1, "a");
|
||||||
|
/// map.insert(2, "b");
|
||||||
|
/// map.insert(3, "c");
|
||||||
|
///
|
||||||
|
/// for (key, value) in map.into_iter() {
|
||||||
|
/// println!("{}: {}", key, value);
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
fn into_iter(self) -> IntoIter<K, V> {
|
fn into_iter(self) -> IntoIter<K, V> {
|
||||||
self.into_iter()
|
let len = self.len();
|
||||||
|
let mut lca = VecDeque::new();
|
||||||
|
lca.push_back(Traverse::traverse(self.root));
|
||||||
|
IntoIter {
|
||||||
|
inner: AbsIter {
|
||||||
|
traversals: lca,
|
||||||
|
size: len,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1263,35 +1286,6 @@ impl<K, V> BTreeMap<K, V> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets an owning iterator over the entries of the map.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use std::collections::BTreeMap;
|
|
||||||
///
|
|
||||||
/// let mut map = BTreeMap::new();
|
|
||||||
/// map.insert(1, "a");
|
|
||||||
/// map.insert(2, "b");
|
|
||||||
/// map.insert(3, "c");
|
|
||||||
///
|
|
||||||
/// for (key, value) in map.into_iter() {
|
|
||||||
/// println!("{}: {}", key, value);
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
|
||||||
pub fn into_iter(self) -> IntoIter<K, V> {
|
|
||||||
let len = self.len();
|
|
||||||
let mut lca = VecDeque::new();
|
|
||||||
lca.push_back(Traverse::traverse(self.root));
|
|
||||||
IntoIter {
|
|
||||||
inner: AbsIter {
|
|
||||||
traversals: lca,
|
|
||||||
size: len,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Gets an iterator over the keys of the map.
|
/// Gets an iterator over the keys of the map.
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
|
|
|
@ -14,10 +14,9 @@
|
||||||
use core::prelude::*;
|
use core::prelude::*;
|
||||||
|
|
||||||
use core::cmp::Ordering::{self, Less, Greater, Equal};
|
use core::cmp::Ordering::{self, Less, Greater, Equal};
|
||||||
use core::default::Default;
|
|
||||||
use core::fmt::Debug;
|
use core::fmt::Debug;
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
use core::iter::{Peekable, Map, FromIterator, IntoIterator};
|
use core::iter::{Peekable, Map, FromIterator};
|
||||||
use core::ops::{BitOr, BitAnd, BitXor, Sub};
|
use core::ops::{BitOr, BitAnd, BitXor, Sub};
|
||||||
|
|
||||||
use borrow::Borrow;
|
use borrow::Borrow;
|
||||||
|
@ -132,27 +131,6 @@ impl<T> BTreeSet<T> {
|
||||||
pub fn iter(&self) -> Iter<T> {
|
pub fn iter(&self) -> Iter<T> {
|
||||||
Iter { iter: self.map.keys() }
|
Iter { iter: self.map.keys() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets an iterator for moving out the BtreeSet's contents.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// # #![feature(core)]
|
|
||||||
/// use std::collections::BTreeSet;
|
|
||||||
///
|
|
||||||
/// let set: BTreeSet<usize> = [1, 2, 3, 4].iter().cloned().collect();
|
|
||||||
///
|
|
||||||
/// let v: Vec<usize> = set.into_iter().collect();
|
|
||||||
/// assert_eq!(v, [1, 2, 3, 4]);
|
|
||||||
/// ```
|
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
|
||||||
pub fn into_iter(self) -> IntoIter<T> {
|
|
||||||
fn first<A, B>((a, _): (A, B)) -> A { a }
|
|
||||||
let first: fn((T, ())) -> T = first; // coerce to fn pointer
|
|
||||||
|
|
||||||
IntoIter { iter: self.map.into_iter().map(first) }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Ord> BTreeSet<T> {
|
impl<T: Ord> BTreeSet<T> {
|
||||||
|
@ -500,8 +478,24 @@ impl<T> IntoIterator for BTreeSet<T> {
|
||||||
type Item = T;
|
type Item = T;
|
||||||
type IntoIter = IntoIter<T>;
|
type IntoIter = IntoIter<T>;
|
||||||
|
|
||||||
|
/// Gets an iterator for moving out the BtreeSet's contents.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # #![feature(core)]
|
||||||
|
/// use std::collections::BTreeSet;
|
||||||
|
///
|
||||||
|
/// let set: BTreeSet<usize> = [1, 2, 3, 4].iter().cloned().collect();
|
||||||
|
///
|
||||||
|
/// let v: Vec<usize> = set.into_iter().collect();
|
||||||
|
/// assert_eq!(v, [1, 2, 3, 4]);
|
||||||
|
/// ```
|
||||||
fn into_iter(self) -> IntoIter<T> {
|
fn into_iter(self) -> IntoIter<T> {
|
||||||
self.into_iter()
|
fn first<A, B>((a, _): (A, B)) -> A { a }
|
||||||
|
let first: fn((T, ())) -> T = first; // coerce to fn pointer
|
||||||
|
|
||||||
|
IntoIter { iter: self.map.into_iter().map(first) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
use core::prelude::*;
|
use core::prelude::*;
|
||||||
use core::marker;
|
use core::marker;
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
use core::iter::{FromIterator, IntoIterator};
|
use core::iter::{FromIterator};
|
||||||
use core::ops::{Sub, BitOr, BitAnd, BitXor};
|
use core::ops::{Sub, BitOr, BitAnd, BitXor};
|
||||||
|
|
||||||
// FIXME(contentions): implement union family of methods? (general design may be wrong here)
|
// FIXME(contentions): implement union family of methods? (general design may be wrong here)
|
||||||
|
|
|
@ -175,7 +175,6 @@
|
||||||
//! # #![feature(core, std_misc)]
|
//! # #![feature(core, std_misc)]
|
||||||
//! use std::fmt;
|
//! use std::fmt;
|
||||||
//! use std::f64;
|
//! use std::f64;
|
||||||
//! use std::num::Float;
|
|
||||||
//!
|
//!
|
||||||
//! #[derive(Debug)]
|
//! #[derive(Debug)]
|
||||||
//! struct Vector2D {
|
//! struct Vector2D {
|
||||||
|
@ -200,10 +199,11 @@
|
||||||
//! let magnitude = magnitude.sqrt();
|
//! let magnitude = magnitude.sqrt();
|
||||||
//!
|
//!
|
||||||
//! // Respect the formatting flags by using the helper method
|
//! // Respect the formatting flags by using the helper method
|
||||||
//! // `pad_integral` on the Formatter object. See the method documentation
|
//! // `pad_integral` on the Formatter object. See the method
|
||||||
//! // for details, and the function `pad` can be used to pad strings.
|
//! // documentation for details, and the function `pad` can be used
|
||||||
|
//! // to pad strings.
|
||||||
//! let decimals = f.precision().unwrap_or(3);
|
//! let decimals = f.precision().unwrap_or(3);
|
||||||
//! let string = f64::to_str_exact(magnitude, decimals);
|
//! let string = format!("{:.*}", decimals, magnitude);
|
||||||
//! f.pad_integral(true, "", &string)
|
//! f.pad_integral(true, "", &string)
|
||||||
//! }
|
//! }
|
||||||
//! }
|
//! }
|
||||||
|
@ -260,7 +260,6 @@
|
||||||
//! Example usage is:
|
//! Example usage is:
|
||||||
//!
|
//!
|
||||||
//! ```
|
//! ```
|
||||||
//! # #![feature(old_io)]
|
|
||||||
//! # #![allow(unused_must_use)]
|
//! # #![allow(unused_must_use)]
|
||||||
//! use std::io::Write;
|
//! use std::io::Write;
|
||||||
//! let mut w = Vec::new();
|
//! let mut w = Vec::new();
|
||||||
|
@ -288,7 +287,6 @@
|
||||||
//! off, some example usage is:
|
//! off, some example usage is:
|
||||||
//!
|
//!
|
||||||
//! ```
|
//! ```
|
||||||
//! # #![feature(old_io)]
|
|
||||||
//! use std::fmt;
|
//! use std::fmt;
|
||||||
//! use std::io::{self, Write};
|
//! use std::io::{self, Write};
|
||||||
//!
|
//!
|
||||||
|
|
|
@ -38,6 +38,7 @@
|
||||||
#![feature(unsafe_no_drop_flag, filling_drop)]
|
#![feature(unsafe_no_drop_flag, filling_drop)]
|
||||||
#![feature(step_by)]
|
#![feature(step_by)]
|
||||||
#![feature(str_char)]
|
#![feature(str_char)]
|
||||||
|
#![feature(str_words)]
|
||||||
#![feature(slice_patterns)]
|
#![feature(slice_patterns)]
|
||||||
#![feature(debug_builders)]
|
#![feature(debug_builders)]
|
||||||
#![feature(utf8_error)]
|
#![feature(utf8_error)]
|
||||||
|
|
|
@ -25,10 +25,9 @@ use core::prelude::*;
|
||||||
|
|
||||||
use alloc::boxed::Box;
|
use alloc::boxed::Box;
|
||||||
use core::cmp::Ordering;
|
use core::cmp::Ordering;
|
||||||
use core::default::Default;
|
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
use core::hash::{Hasher, Hash};
|
use core::hash::{Hasher, Hash};
|
||||||
use core::iter::{self, FromIterator, IntoIterator};
|
use core::iter::{self, FromIterator};
|
||||||
use core::mem;
|
use core::mem;
|
||||||
use core::ptr;
|
use core::ptr;
|
||||||
|
|
||||||
|
@ -296,13 +295,6 @@ impl<T> LinkedList<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Consumes the list into an iterator yielding elements by value.
|
|
||||||
#[inline]
|
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
|
||||||
pub fn into_iter(self) -> IntoIter<T> {
|
|
||||||
IntoIter{list: self}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns `true` if the `LinkedList` is empty.
|
/// Returns `true` if the `LinkedList` is empty.
|
||||||
///
|
///
|
||||||
/// This operation should compute in O(1) time.
|
/// This operation should compute in O(1) time.
|
||||||
|
@ -852,8 +844,10 @@ impl<T> IntoIterator for LinkedList<T> {
|
||||||
type Item = T;
|
type Item = T;
|
||||||
type IntoIter = IntoIter<T>;
|
type IntoIter = IntoIter<T>;
|
||||||
|
|
||||||
|
/// Consumes the list into an iterator yielding elements by value.
|
||||||
|
#[inline]
|
||||||
fn into_iter(self) -> IntoIter<T> {
|
fn into_iter(self) -> IntoIter<T> {
|
||||||
self.into_iter()
|
IntoIter{list: self}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -941,7 +935,7 @@ impl<A: Hash> Hash for LinkedList<A> {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use std::clone::Clone;
|
use std::clone::Clone;
|
||||||
use std::iter::Iterator;
|
use std::iter::{Iterator, IntoIterator};
|
||||||
use std::option::Option::{Some, None, self};
|
use std::option::Option::{Some, None, self};
|
||||||
use std::__rand::{thread_rng, Rng};
|
use std::__rand::{thread_rng, Rng};
|
||||||
use std::thread;
|
use std::thread;
|
||||||
|
|
|
@ -98,7 +98,7 @@ use self::Direction::*;
|
||||||
use borrow::{Borrow, BorrowMut, ToOwned};
|
use borrow::{Borrow, BorrowMut, ToOwned};
|
||||||
use vec::Vec;
|
use vec::Vec;
|
||||||
|
|
||||||
pub use core::slice::{Chunks, AsSlice, Windows};
|
pub use core::slice::{Chunks, Windows};
|
||||||
pub use core::slice::{Iter, IterMut};
|
pub use core::slice::{Iter, IterMut};
|
||||||
pub use core::slice::{IntSliceExt, SplitMut, ChunksMut, Split};
|
pub use core::slice::{IntSliceExt, SplitMut, ChunksMut, Split};
|
||||||
pub use core::slice::{SplitN, RSplitN, SplitNMut, RSplitNMut};
|
pub use core::slice::{SplitN, RSplitN, SplitNMut, RSplitNMut};
|
||||||
|
|
|
@ -67,7 +67,7 @@ use rustc_unicode;
|
||||||
use vec::Vec;
|
use vec::Vec;
|
||||||
use slice::SliceConcatExt;
|
use slice::SliceConcatExt;
|
||||||
|
|
||||||
pub use core::str::{FromStr, Utf8Error, Str};
|
pub use core::str::{FromStr, Utf8Error};
|
||||||
pub use core::str::{Lines, LinesAny, CharRange};
|
pub use core::str::{Lines, LinesAny, CharRange};
|
||||||
pub use core::str::{Split, RSplit};
|
pub use core::str::{Split, RSplit};
|
||||||
pub use core::str::{SplitN, RSplitN};
|
pub use core::str::{SplitN, RSplitN};
|
||||||
|
@ -76,7 +76,7 @@ pub use core::str::{Matches, RMatches};
|
||||||
pub use core::str::{MatchIndices, RMatchIndices};
|
pub use core::str::{MatchIndices, RMatchIndices};
|
||||||
pub use core::str::{from_utf8, Chars, CharIndices, Bytes};
|
pub use core::str::{from_utf8, Chars, CharIndices, Bytes};
|
||||||
pub use core::str::{from_utf8_unchecked, ParseBoolError};
|
pub use core::str::{from_utf8_unchecked, ParseBoolError};
|
||||||
pub use rustc_unicode::str::{Words, Graphemes, GraphemeIndices};
|
pub use rustc_unicode::str::{SplitWhitespace, Words, Graphemes, GraphemeIndices};
|
||||||
pub use core::str::pattern;
|
pub use core::str::pattern;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1737,27 +1737,44 @@ impl str {
|
||||||
UnicodeStr::grapheme_indices(&self[..], is_extended)
|
UnicodeStr::grapheme_indices(&self[..], is_extended)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An iterator over the non-empty words of `self`.
|
/// An iterator over the non-empty substrings of `self` which contain no whitespace,
|
||||||
///
|
/// and which are separated by any amount of whitespace.
|
||||||
/// A 'word' is a subsequence separated by any sequence of whitespace.
|
|
||||||
/// Sequences of whitespace
|
|
||||||
/// are collapsed, so empty "words" are not included.
|
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # #![feature(str_words)]
|
/// # #![feature(str_words)]
|
||||||
|
/// # #![allow(deprecated)]
|
||||||
/// let some_words = " Mary had\ta little \n\t lamb";
|
/// let some_words = " Mary had\ta little \n\t lamb";
|
||||||
/// let v: Vec<&str> = some_words.words().collect();
|
/// let v: Vec<&str> = some_words.words().collect();
|
||||||
///
|
///
|
||||||
/// assert_eq!(v, ["Mary", "had", "a", "little", "lamb"]);
|
/// assert_eq!(v, ["Mary", "had", "a", "little", "lamb"]);
|
||||||
/// ```
|
/// ```
|
||||||
|
#[deprecated(reason = "words() will be removed. Use split_whitespace() instead",
|
||||||
|
since = "1.1.0")]
|
||||||
#[unstable(feature = "str_words",
|
#[unstable(feature = "str_words",
|
||||||
reason = "the precise algorithm to use is unclear")]
|
reason = "the precise algorithm to use is unclear")]
|
||||||
|
#[allow(deprecated)]
|
||||||
pub fn words(&self) -> Words {
|
pub fn words(&self) -> Words {
|
||||||
UnicodeStr::words(&self[..])
|
UnicodeStr::words(&self[..])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An iterator over the non-empty substrings of `self` which contain no whitespace,
|
||||||
|
/// and which are separated by any amount of whitespace.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// let some_words = " Mary had\ta little \n\t lamb";
|
||||||
|
/// let v: Vec<&str> = some_words.split_whitespace().collect();
|
||||||
|
///
|
||||||
|
/// assert_eq!(v, ["Mary", "had", "a", "little", "lamb"]);
|
||||||
|
/// ```
|
||||||
|
#[stable(feature = "split_whitespace", since = "1.1.0")]
|
||||||
|
pub fn split_whitespace(&self) -> SplitWhitespace {
|
||||||
|
UnicodeStr::split_whitespace(&self[..])
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns a string's displayed width in columns.
|
/// Returns a string's displayed width in columns.
|
||||||
///
|
///
|
||||||
/// Control characters have zero width.
|
/// Control characters have zero width.
|
||||||
|
|
|
@ -14,10 +14,9 @@
|
||||||
|
|
||||||
use core::prelude::*;
|
use core::prelude::*;
|
||||||
|
|
||||||
use core::default::Default;
|
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
use core::hash;
|
use core::hash;
|
||||||
use core::iter::{IntoIterator, FromIterator};
|
use core::iter::FromIterator;
|
||||||
use core::mem;
|
use core::mem;
|
||||||
use core::ops::{self, Deref, Add, Index};
|
use core::ops::{self, Deref, Add, Index};
|
||||||
use core::ptr;
|
use core::ptr;
|
||||||
|
@ -837,15 +836,6 @@ impl<'a, 'b> PartialEq<Cow<'a, str>> for &'b str {
|
||||||
fn ne(&self, other: &Cow<'a, str>) -> bool { PartialEq::ne(&self[..], &other[..]) }
|
fn ne(&self, other: &Cow<'a, str>) -> bool { PartialEq::ne(&self[..], &other[..]) }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[unstable(feature = "collections", reason = "waiting on Str stabilization")]
|
|
||||||
#[allow(deprecated)]
|
|
||||||
impl Str for String {
|
|
||||||
#[inline]
|
|
||||||
fn as_slice(&self) -> &str {
|
|
||||||
unsafe { mem::transmute(&*self.vec) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
impl Default for String {
|
impl Default for String {
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -1067,14 +1057,6 @@ impl<'a> IntoCow<'a, str> for &'a str {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(deprecated)]
|
|
||||||
impl<'a> Str for Cow<'a, str> {
|
|
||||||
#[inline]
|
|
||||||
fn as_slice<'b>(&'b self) -> &'b str {
|
|
||||||
&**self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
impl fmt::Write for String {
|
impl fmt::Write for String {
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -1082,4 +1064,10 @@ impl fmt::Write for String {
|
||||||
self.push_str(s);
|
self.push_str(s);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn write_char(&mut self, c: char) -> fmt::Result {
|
||||||
|
self.push(c);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,11 +53,10 @@ use alloc::boxed::Box;
|
||||||
use alloc::heap::{EMPTY, allocate, reallocate, deallocate};
|
use alloc::heap::{EMPTY, allocate, reallocate, deallocate};
|
||||||
use core::cmp::max;
|
use core::cmp::max;
|
||||||
use core::cmp::Ordering;
|
use core::cmp::Ordering;
|
||||||
use core::default::Default;
|
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
use core::hash::{self, Hash};
|
use core::hash::{self, Hash};
|
||||||
use core::intrinsics::assume;
|
use core::intrinsics::assume;
|
||||||
use core::iter::{repeat, FromIterator, IntoIterator};
|
use core::iter::{repeat, FromIterator};
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
use core::mem;
|
use core::mem;
|
||||||
use core::ops::{Index, IndexMut, Deref, Add};
|
use core::ops::{Index, IndexMut, Deref, Add};
|
||||||
|
@ -450,37 +449,6 @@ impl<T> Vec<T> {
|
||||||
&mut self[..]
|
&mut self[..]
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a consuming iterator, that is, one that moves each value out of
|
|
||||||
/// the vector (from start to end). The vector cannot be used after calling
|
|
||||||
/// this.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// let v = vec!["a".to_string(), "b".to_string()];
|
|
||||||
/// for s in v.into_iter() {
|
|
||||||
/// // s has type String, not &String
|
|
||||||
/// println!("{}", s);
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
#[inline]
|
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
|
||||||
pub fn into_iter(self) -> IntoIter<T> {
|
|
||||||
unsafe {
|
|
||||||
let ptr = *self.ptr;
|
|
||||||
assume(!ptr.is_null());
|
|
||||||
let cap = self.cap;
|
|
||||||
let begin = ptr as *const T;
|
|
||||||
let end = if mem::size_of::<T>() == 0 {
|
|
||||||
(ptr as usize + self.len()) as *const T
|
|
||||||
} else {
|
|
||||||
ptr.offset(self.len() as isize) as *const T
|
|
||||||
};
|
|
||||||
mem::forget(self);
|
|
||||||
IntoIter { allocation: ptr, cap: cap, ptr: begin, end: end }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sets the length of a vector.
|
/// Sets the length of a vector.
|
||||||
///
|
///
|
||||||
/// This will explicitly set the size of the vector, without actually
|
/// This will explicitly set the size of the vector, without actually
|
||||||
|
@ -1512,8 +1480,34 @@ impl<T> IntoIterator for Vec<T> {
|
||||||
type Item = T;
|
type Item = T;
|
||||||
type IntoIter = IntoIter<T>;
|
type IntoIter = IntoIter<T>;
|
||||||
|
|
||||||
|
/// Creates a consuming iterator, that is, one that moves each value out of
|
||||||
|
/// the vector (from start to end). The vector cannot be used after calling
|
||||||
|
/// this.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// let v = vec!["a".to_string(), "b".to_string()];
|
||||||
|
/// for s in v.into_iter() {
|
||||||
|
/// // s has type String, not &String
|
||||||
|
/// println!("{}", s);
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
#[inline]
|
||||||
fn into_iter(self) -> IntoIter<T> {
|
fn into_iter(self) -> IntoIter<T> {
|
||||||
self.into_iter()
|
unsafe {
|
||||||
|
let ptr = *self.ptr;
|
||||||
|
assume(!ptr.is_null());
|
||||||
|
let cap = self.cap;
|
||||||
|
let begin = ptr as *const T;
|
||||||
|
let end = if mem::size_of::<T>() == 0 {
|
||||||
|
(ptr as usize + self.len()) as *const T
|
||||||
|
} else {
|
||||||
|
ptr.offset(self.len() as isize) as *const T
|
||||||
|
};
|
||||||
|
mem::forget(self);
|
||||||
|
IntoIter { allocation: ptr, cap: cap, ptr: begin, end: end }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1597,18 +1591,6 @@ impl<T: Ord> Ord for Vec<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[unstable(feature = "collections",
|
|
||||||
reason = "will be replaced by slice syntax")]
|
|
||||||
#[deprecated(since = "1.0.0", reason = "use &mut s[..] instead")]
|
|
||||||
#[allow(deprecated)]
|
|
||||||
impl<T> AsSlice<T> for Vec<T> {
|
|
||||||
/// Deprecated: use `&mut s[..]` instead.
|
|
||||||
#[inline]
|
|
||||||
fn as_slice(&self) -> &[T] {
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[unstable(feature = "collections",
|
#[unstable(feature = "collections",
|
||||||
reason = "recent addition, needs more experience")]
|
reason = "recent addition, needs more experience")]
|
||||||
impl<'a, T: Clone> Add<&'a [T]> for Vec<T> {
|
impl<'a, T: Clone> Add<&'a [T]> for Vec<T> {
|
||||||
|
|
|
@ -21,9 +21,8 @@
|
||||||
use core::prelude::*;
|
use core::prelude::*;
|
||||||
|
|
||||||
use core::cmp::Ordering;
|
use core::cmp::Ordering;
|
||||||
use core::default::Default;
|
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
use core::iter::{self, repeat, FromIterator, IntoIterator, RandomAccessIterator};
|
use core::iter::{self, repeat, FromIterator, RandomAccessIterator};
|
||||||
use core::mem;
|
use core::mem;
|
||||||
use core::ops::{Index, IndexMut};
|
use core::ops::{Index, IndexMut};
|
||||||
use core::ptr::{self, Unique};
|
use core::ptr::{self, Unique};
|
||||||
|
@ -557,14 +556,6 @@ impl<T> VecDeque<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Consumes the list into a front-to-back iterator yielding elements by value.
|
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
|
||||||
pub fn into_iter(self) -> IntoIter<T> {
|
|
||||||
IntoIter {
|
|
||||||
inner: self,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns a pair of slices which contain, in order, the contents of the
|
/// Returns a pair of slices which contain, in order, the contents of the
|
||||||
/// `VecDeque`.
|
/// `VecDeque`.
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -1728,8 +1719,12 @@ impl<T> IntoIterator for VecDeque<T> {
|
||||||
type Item = T;
|
type Item = T;
|
||||||
type IntoIter = IntoIter<T>;
|
type IntoIter = IntoIter<T>;
|
||||||
|
|
||||||
|
/// Consumes the list into a front-to-back iterator yielding elements by
|
||||||
|
/// value.
|
||||||
fn into_iter(self) -> IntoIter<T> {
|
fn into_iter(self) -> IntoIter<T> {
|
||||||
self.into_iter()
|
IntoIter {
|
||||||
|
inner: self,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,10 +18,9 @@ use self::Entry::*;
|
||||||
use core::prelude::*;
|
use core::prelude::*;
|
||||||
|
|
||||||
use core::cmp::{max, Ordering};
|
use core::cmp::{max, Ordering};
|
||||||
use core::default::Default;
|
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
use core::hash::{Hash, Hasher};
|
use core::hash::{Hash, Hasher};
|
||||||
use core::iter::{Enumerate, FilterMap, Map, FromIterator, IntoIterator};
|
use core::iter::{Enumerate, FilterMap, Map, FromIterator};
|
||||||
use core::iter;
|
use core::iter;
|
||||||
use core::mem::{replace, swap};
|
use core::mem::{replace, swap};
|
||||||
use core::ops::{Index, IndexMut};
|
use core::ops::{Index, IndexMut};
|
||||||
|
@ -301,35 +300,6 @@ impl<V> VecMap<V> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns an iterator visiting all key-value pairs in ascending order of
|
|
||||||
/// the keys, consuming the original `VecMap`.
|
|
||||||
/// The iterator's element type is `(usize, &'r V)`.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// # #![feature(collections)]
|
|
||||||
/// use std::collections::VecMap;
|
|
||||||
///
|
|
||||||
/// let mut map = VecMap::new();
|
|
||||||
/// map.insert(1, "a");
|
|
||||||
/// map.insert(3, "c");
|
|
||||||
/// map.insert(2, "b");
|
|
||||||
///
|
|
||||||
/// let vec: Vec<(usize, &str)> = map.into_iter().collect();
|
|
||||||
///
|
|
||||||
/// assert_eq!(vec, [(1, "a"), (2, "b"), (3, "c")]);
|
|
||||||
/// ```
|
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
|
||||||
pub fn into_iter(self) -> IntoIter<V> {
|
|
||||||
fn filter<A>((i, v): (usize, Option<A>)) -> Option<(usize, A)> {
|
|
||||||
v.map(|v| (i, v))
|
|
||||||
}
|
|
||||||
let filter: fn((usize, Option<V>)) -> Option<(usize, V)> = filter; // coerce to fn ptr
|
|
||||||
|
|
||||||
IntoIter { iter: self.v.into_iter().enumerate().filter_map(filter) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Moves all elements from `other` into the map while overwriting existing keys.
|
/// Moves all elements from `other` into the map while overwriting existing keys.
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
|
@ -800,8 +770,32 @@ impl<T> IntoIterator for VecMap<T> {
|
||||||
type Item = (usize, T);
|
type Item = (usize, T);
|
||||||
type IntoIter = IntoIter<T>;
|
type IntoIter = IntoIter<T>;
|
||||||
|
|
||||||
|
/// Returns an iterator visiting all key-value pairs in ascending order of
|
||||||
|
/// the keys, consuming the original `VecMap`.
|
||||||
|
/// The iterator's element type is `(usize, &'r V)`.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # #![feature(collections)]
|
||||||
|
/// use std::collections::VecMap;
|
||||||
|
///
|
||||||
|
/// let mut map = VecMap::new();
|
||||||
|
/// map.insert(1, "a");
|
||||||
|
/// map.insert(3, "c");
|
||||||
|
/// map.insert(2, "b");
|
||||||
|
///
|
||||||
|
/// let vec: Vec<(usize, &str)> = map.into_iter().collect();
|
||||||
|
///
|
||||||
|
/// assert_eq!(vec, [(1, "a"), (2, "b"), (3, "c")]);
|
||||||
|
/// ```
|
||||||
fn into_iter(self) -> IntoIter<T> {
|
fn into_iter(self) -> IntoIter<T> {
|
||||||
self.into_iter()
|
fn filter<A>((i, v): (usize, Option<A>)) -> Option<(usize, A)> {
|
||||||
|
v.map(|v| (i, v))
|
||||||
|
}
|
||||||
|
let filter: fn((usize, Option<T>)) -> Option<(usize, T)> = filter; // coerce to fn ptr
|
||||||
|
|
||||||
|
IntoIter { iter: self.v.into_iter().enumerate().filter_map(filter) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,6 @@
|
||||||
#![feature(hash)]
|
#![feature(hash)]
|
||||||
#![feature(rand)]
|
#![feature(rand)]
|
||||||
#![feature(rustc_private)]
|
#![feature(rustc_private)]
|
||||||
#![feature(str_words)]
|
|
||||||
#![feature(test)]
|
#![feature(test)]
|
||||||
#![feature(unboxed_closures)]
|
#![feature(unboxed_closures)]
|
||||||
#![feature(unicode)]
|
#![feature(unicode)]
|
||||||
|
|
|
@ -939,9 +939,9 @@ fn test_rsplitn() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_words() {
|
fn test_split_whitespace() {
|
||||||
let data = "\n \tMäry häd\tä little lämb\nLittle lämb\n";
|
let data = "\n \tMäry häd\tä little lämb\nLittle lämb\n";
|
||||||
let words: Vec<&str> = data.words().collect();
|
let words: Vec<&str> = data.split_whitespace().collect();
|
||||||
assert_eq!(words, ["Märy", "häd", "ä", "little", "lämb", "Little", "lämb"])
|
assert_eq!(words, ["Märy", "häd", "ä", "little", "lämb", "Little", "lämb"])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,15 +11,15 @@
|
||||||
pub use self::ExponentFormat::*;
|
pub use self::ExponentFormat::*;
|
||||||
pub use self::SignificantDigits::*;
|
pub use self::SignificantDigits::*;
|
||||||
|
|
||||||
use char::{self, CharExt};
|
use prelude::*;
|
||||||
|
|
||||||
|
use char;
|
||||||
use fmt;
|
use fmt;
|
||||||
use iter::Iterator;
|
use num::Float;
|
||||||
use num::{cast, Float, ToPrimitive};
|
|
||||||
use num::FpCategory as Fp;
|
use num::FpCategory as Fp;
|
||||||
use ops::FnOnce;
|
use ops::{Div, Rem, Mul};
|
||||||
use result::Result::Ok;
|
use slice;
|
||||||
use slice::{self, SliceExt};
|
use str;
|
||||||
use str::{self, StrExt};
|
|
||||||
|
|
||||||
/// A flag that specifies whether to use exponential (scientific) notation.
|
/// A flag that specifies whether to use exponential (scientific) notation.
|
||||||
pub enum ExponentFormat {
|
pub enum ExponentFormat {
|
||||||
|
@ -42,6 +42,21 @@ pub enum SignificantDigits {
|
||||||
DigExact(usize)
|
DigExact(usize)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub trait MyFloat: Float + PartialEq + PartialOrd + Div<Output=Self> +
|
||||||
|
Mul<Output=Self> + Rem<Output=Self> + Copy {
|
||||||
|
fn from_u32(u: u32) -> Self;
|
||||||
|
fn to_i32(&self) -> i32;
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! doit {
|
||||||
|
($($t:ident)*) => ($(impl MyFloat for $t {
|
||||||
|
fn from_u32(u: u32) -> $t { u as $t }
|
||||||
|
fn to_i32(&self) -> i32 { *self as i32 }
|
||||||
|
})*)
|
||||||
|
}
|
||||||
|
doit! { f32 f64 }
|
||||||
|
|
||||||
/// Converts a float number to its string representation.
|
/// Converts a float number to its string representation.
|
||||||
/// This is meant to be a common base implementation for various formatting styles.
|
/// This is meant to be a common base implementation for various formatting styles.
|
||||||
/// The number is assumed to be non-negative, callers use `Formatter::pad_integral`
|
/// The number is assumed to be non-negative, callers use `Formatter::pad_integral`
|
||||||
|
@ -63,7 +78,7 @@ pub enum SignificantDigits {
|
||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// - Panics if `num` is negative.
|
/// - Panics if `num` is negative.
|
||||||
pub fn float_to_str_bytes_common<T: Float, U, F>(
|
pub fn float_to_str_bytes_common<T: MyFloat, U, F>(
|
||||||
num: T,
|
num: T,
|
||||||
digits: SignificantDigits,
|
digits: SignificantDigits,
|
||||||
exp_format: ExponentFormat,
|
exp_format: ExponentFormat,
|
||||||
|
@ -72,10 +87,10 @@ pub fn float_to_str_bytes_common<T: Float, U, F>(
|
||||||
) -> U where
|
) -> U where
|
||||||
F: FnOnce(&str) -> U,
|
F: FnOnce(&str) -> U,
|
||||||
{
|
{
|
||||||
let _0: T = Float::zero();
|
let _0: T = T::zero();
|
||||||
let _1: T = Float::one();
|
let _1: T = T::one();
|
||||||
let radix: u32 = 10;
|
let radix: u32 = 10;
|
||||||
let radix_f: T = cast(radix).unwrap();
|
let radix_f = T::from_u32(radix);
|
||||||
|
|
||||||
assert!(num.is_nan() || num >= _0, "float_to_str_bytes_common: number is negative");
|
assert!(num.is_nan() || num >= _0, "float_to_str_bytes_common: number is negative");
|
||||||
|
|
||||||
|
@ -99,7 +114,7 @@ pub fn float_to_str_bytes_common<T: Float, U, F>(
|
||||||
let (num, exp) = match exp_format {
|
let (num, exp) = match exp_format {
|
||||||
ExpDec if num != _0 => {
|
ExpDec if num != _0 => {
|
||||||
let exp = num.log10().floor();
|
let exp = num.log10().floor();
|
||||||
(num / radix_f.powf(exp), cast::<T, i32>(exp).unwrap())
|
(num / radix_f.powf(exp), exp.to_i32())
|
||||||
}
|
}
|
||||||
_ => (num, 0)
|
_ => (num, 0)
|
||||||
};
|
};
|
||||||
|
@ -114,7 +129,7 @@ pub fn float_to_str_bytes_common<T: Float, U, F>(
|
||||||
deccum = deccum / radix_f;
|
deccum = deccum / radix_f;
|
||||||
deccum = deccum.trunc();
|
deccum = deccum.trunc();
|
||||||
|
|
||||||
let c = char::from_digit(current_digit.to_isize().unwrap() as u32, radix);
|
let c = char::from_digit(current_digit.to_i32() as u32, radix);
|
||||||
buf[end] = c.unwrap() as u8;
|
buf[end] = c.unwrap() as u8;
|
||||||
end += 1;
|
end += 1;
|
||||||
|
|
||||||
|
@ -158,7 +173,7 @@ pub fn float_to_str_bytes_common<T: Float, U, F>(
|
||||||
|
|
||||||
let current_digit = deccum.trunc();
|
let current_digit = deccum.trunc();
|
||||||
|
|
||||||
let c = char::from_digit(current_digit.to_isize().unwrap() as u32, radix);
|
let c = char::from_digit(current_digit.to_i32() as u32, radix);
|
||||||
buf[end] = c.unwrap() as u8;
|
buf[end] = c.unwrap() as u8;
|
||||||
end += 1;
|
end += 1;
|
||||||
|
|
||||||
|
|
|
@ -12,21 +12,16 @@
|
||||||
|
|
||||||
#![stable(feature = "rust1", since = "1.0.0")]
|
#![stable(feature = "rust1", since = "1.0.0")]
|
||||||
|
|
||||||
|
use prelude::*;
|
||||||
|
|
||||||
use cell::{Cell, RefCell, Ref, RefMut, BorrowState};
|
use cell::{Cell, RefCell, Ref, RefMut, BorrowState};
|
||||||
use char::CharExt;
|
use marker::PhantomData;
|
||||||
use clone::Clone;
|
|
||||||
use iter::Iterator;
|
|
||||||
use marker::{Copy, PhantomData, Sized};
|
|
||||||
use mem;
|
use mem;
|
||||||
use num::Float;
|
use ops::Deref;
|
||||||
use option::Option;
|
|
||||||
use option::Option::{Some, None};
|
|
||||||
use result::Result::Ok;
|
|
||||||
use ops::{Deref, FnOnce};
|
|
||||||
use result;
|
use result;
|
||||||
use slice::SliceExt;
|
use num::Float;
|
||||||
use slice;
|
use slice;
|
||||||
use str::{self, StrExt};
|
use str;
|
||||||
use self::rt::v1::Alignment;
|
use self::rt::v1::Alignment;
|
||||||
|
|
||||||
pub use self::num::radix;
|
pub use self::num::radix;
|
||||||
|
@ -83,6 +78,23 @@ pub trait Write {
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
fn write_str(&mut self, s: &str) -> Result;
|
fn write_str(&mut self, s: &str) -> Result;
|
||||||
|
|
||||||
|
/// Writes a `char` into this writer, returning whether the write succeeded.
|
||||||
|
///
|
||||||
|
/// A single `char` may be encoded as more than one byte.
|
||||||
|
/// This method can only succeed if the entire byte sequence was successfully
|
||||||
|
/// written, and this method will not return until all data has been
|
||||||
|
/// written or an error occurs.
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// This function will return an instance of `FormatError` on error.
|
||||||
|
#[stable(feature = "fmt_write_char", since = "1.1.0")]
|
||||||
|
fn write_char(&mut self, c: char) -> Result {
|
||||||
|
let mut utf_8 = [0u8; 4];
|
||||||
|
let bytes_written = c.encode_utf8(&mut utf_8).unwrap_or(0);
|
||||||
|
self.write_str(unsafe { mem::transmute(&utf_8[..bytes_written]) })
|
||||||
|
}
|
||||||
|
|
||||||
/// Glue for usage of the `write!` macro with implementers of this trait.
|
/// Glue for usage of the `write!` macro with implementers of this trait.
|
||||||
///
|
///
|
||||||
/// This method should generally not be invoked manually, but rather through
|
/// This method should generally not be invoked manually, but rather through
|
||||||
|
@ -912,7 +924,8 @@ impl<'a, T> Pointer for &'a mut T {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Common code of floating point Debug and Display.
|
// Common code of floating point Debug and Display.
|
||||||
fn float_to_str_common<T: Float, F>(num: &T, precision: Option<usize>, post: F) -> Result
|
fn float_to_str_common<T: float::MyFloat, F>(num: &T, precision: Option<usize>,
|
||||||
|
post: F) -> Result
|
||||||
where F : FnOnce(&str) -> Result {
|
where F : FnOnce(&str) -> Result {
|
||||||
let digits = match precision {
|
let digits = match precision {
|
||||||
Some(i) => float::DigExact(i),
|
Some(i) => float::DigExact(i),
|
||||||
|
@ -950,8 +963,6 @@ macro_rules! floating { ($ty:ident) => {
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
impl LowerExp for $ty {
|
impl LowerExp for $ty {
|
||||||
fn fmt(&self, fmt: &mut Formatter) -> Result {
|
fn fmt(&self, fmt: &mut Formatter) -> Result {
|
||||||
use num::Float;
|
|
||||||
|
|
||||||
let digits = match fmt.precision {
|
let digits = match fmt.precision {
|
||||||
Some(i) => float::DigExact(i),
|
Some(i) => float::DigExact(i),
|
||||||
None => float::DigMax(6),
|
None => float::DigMax(6),
|
||||||
|
@ -969,8 +980,6 @@ macro_rules! floating { ($ty:ident) => {
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
impl UpperExp for $ty {
|
impl UpperExp for $ty {
|
||||||
fn fmt(&self, fmt: &mut Formatter) -> Result {
|
fn fmt(&self, fmt: &mut Formatter) -> Result {
|
||||||
use num::Float;
|
|
||||||
|
|
||||||
let digits = match fmt.precision {
|
let digits = match fmt.precision {
|
||||||
Some(i) => float::DigExact(i),
|
Some(i) => float::DigExact(i),
|
||||||
None => float::DigMax(6),
|
None => float::DigMax(6),
|
||||||
|
|
|
@ -14,12 +14,28 @@
|
||||||
|
|
||||||
#![allow(unsigned_negation)]
|
#![allow(unsigned_negation)]
|
||||||
|
|
||||||
|
use prelude::*;
|
||||||
|
|
||||||
use fmt;
|
use fmt;
|
||||||
use iter::Iterator;
|
use num::Zero;
|
||||||
use num::{Int, cast};
|
use ops::{Div, Rem, Sub};
|
||||||
use slice::SliceExt;
|
|
||||||
use str;
|
use str;
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
|
trait Int: Zero + PartialEq + PartialOrd + Div<Output=Self> + Rem<Output=Self> +
|
||||||
|
Sub<Output=Self> + Copy {
|
||||||
|
fn from_u8(u: u8) -> Self;
|
||||||
|
fn to_u8(&self) -> u8;
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! doit {
|
||||||
|
($($t:ident)*) => ($(impl Int for $t {
|
||||||
|
fn from_u8(u: u8) -> $t { u as $t }
|
||||||
|
fn to_u8(&self) -> u8 { *self as u8 }
|
||||||
|
})*)
|
||||||
|
}
|
||||||
|
doit! { i8 i16 i32 i64 isize u8 u16 u32 u64 usize }
|
||||||
|
|
||||||
/// A type that represents a specific radix
|
/// A type that represents a specific radix
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
trait GenericRadix {
|
trait GenericRadix {
|
||||||
|
@ -33,33 +49,32 @@ trait GenericRadix {
|
||||||
fn digit(&self, x: u8) -> u8;
|
fn digit(&self, x: u8) -> u8;
|
||||||
|
|
||||||
/// Format an integer using the radix using a formatter.
|
/// Format an integer using the radix using a formatter.
|
||||||
#[allow(deprecated)] // Int
|
|
||||||
fn fmt_int<T: Int>(&self, mut x: T, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt_int<T: Int>(&self, mut x: T, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
// The radix can be as low as 2, so we need a buffer of at least 64
|
// The radix can be as low as 2, so we need a buffer of at least 64
|
||||||
// characters for a base 2 number.
|
// characters for a base 2 number.
|
||||||
let zero = Int::zero();
|
let zero = T::zero();
|
||||||
let is_positive = x >= zero;
|
let is_positive = x >= zero;
|
||||||
let mut buf = [0; 64];
|
let mut buf = [0; 64];
|
||||||
let mut curr = buf.len();
|
let mut curr = buf.len();
|
||||||
let base = cast(self.base()).unwrap();
|
let base = T::from_u8(self.base());
|
||||||
if is_positive {
|
if is_positive {
|
||||||
// Accumulate each digit of the number from the least significant
|
// Accumulate each digit of the number from the least significant
|
||||||
// to the most significant figure.
|
// to the most significant figure.
|
||||||
for byte in buf.iter_mut().rev() {
|
for byte in buf.iter_mut().rev() {
|
||||||
let n = x % base; // Get the current place value.
|
let n = x % base; // Get the current place value.
|
||||||
x = x / base; // Deaccumulate the number.
|
x = x / base; // Deaccumulate the number.
|
||||||
*byte = self.digit(cast(n).unwrap()); // Store the digit in the buffer.
|
*byte = self.digit(n.to_u8()); // Store the digit in the buffer.
|
||||||
curr -= 1;
|
curr -= 1;
|
||||||
if x == zero { break }; // No more digits left to accumulate.
|
if x == zero { break }; // No more digits left to accumulate.
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Do the same as above, but accounting for two's complement.
|
// Do the same as above, but accounting for two's complement.
|
||||||
for byte in buf.iter_mut().rev() {
|
for byte in buf.iter_mut().rev() {
|
||||||
let n = zero - (x % base); // Get the current place value.
|
let n = zero - (x % base); // Get the current place value.
|
||||||
x = x / base; // Deaccumulate the number.
|
x = x / base; // Deaccumulate the number.
|
||||||
*byte = self.digit(cast(n).unwrap()); // Store the digit in the buffer.
|
*byte = self.digit(n.to_u8()); // Store the digit in the buffer.
|
||||||
curr -= 1;
|
curr -= 1;
|
||||||
if x == zero { break }; // No more digits left to accumulate.
|
if x == zero { break }; // No more digits left to accumulate.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let buf = unsafe { str::from_utf8_unchecked(&buf[curr..]) };
|
let buf = unsafe { str::from_utf8_unchecked(&buf[curr..]) };
|
||||||
|
|
|
@ -62,7 +62,6 @@
|
||||||
|
|
||||||
use prelude::*;
|
use prelude::*;
|
||||||
|
|
||||||
use default::Default;
|
|
||||||
use mem;
|
use mem;
|
||||||
|
|
||||||
pub use self::sip::SipHasher;
|
pub use self::sip::SipHasher;
|
||||||
|
|
|
@ -13,7 +13,6 @@
|
||||||
#![allow(deprecated)] // until the next snapshot for inherent wrapping ops
|
#![allow(deprecated)] // until the next snapshot for inherent wrapping ops
|
||||||
|
|
||||||
use prelude::*;
|
use prelude::*;
|
||||||
use default::Default;
|
|
||||||
use super::Hasher;
|
use super::Hasher;
|
||||||
|
|
||||||
/// An implementation of SipHash 2-4.
|
/// An implementation of SipHash 2-4.
|
||||||
|
|
|
@ -64,7 +64,7 @@ use cmp::{Ord, PartialOrd, PartialEq};
|
||||||
use default::Default;
|
use default::Default;
|
||||||
use marker;
|
use marker;
|
||||||
use mem;
|
use mem;
|
||||||
use num::{Int, Zero, One};
|
use num::{Zero, One};
|
||||||
use ops::{self, Add, Sub, FnMut, Mul, RangeFrom};
|
use ops::{self, Add, Sub, FnMut, Mul, RangeFrom};
|
||||||
use option::Option::{self, Some, None};
|
use option::Option::{self, Some, None};
|
||||||
use marker::Sized;
|
use marker::Sized;
|
||||||
|
@ -2327,9 +2327,8 @@ impl<I: RandomAccessIterator, F> RandomAccessIterator for Inspect<I, F>
|
||||||
/// An iterator that yields sequential Fibonacci numbers, and stops on overflow.
|
/// An iterator that yields sequential Fibonacci numbers, and stops on overflow.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # #![feature(core)]
|
/// #![feature(core)]
|
||||||
/// use std::iter::Unfold;
|
/// use std::iter::Unfold;
|
||||||
/// use std::num::Int; // For `.checked_add()`
|
|
||||||
///
|
///
|
||||||
/// // This iterator will yield up to the last Fibonacci number before the max
|
/// // This iterator will yield up to the last Fibonacci number before the max
|
||||||
/// // value of `u32`. You can simply change `u32` to `u64` in this line if
|
/// // value of `u32`. You can simply change `u32` to `u64` in this line if
|
||||||
|
@ -2647,80 +2646,6 @@ impl<A: Step + Zero + Clone> Iterator for StepBy<A, ops::Range<A>> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An iterator over the range [start, stop] by `step`. It handles overflow by stopping.
|
|
||||||
#[derive(Clone)]
|
|
||||||
#[unstable(feature = "core",
|
|
||||||
reason = "likely to be replaced by range notation and adapters")]
|
|
||||||
pub struct RangeStepInclusive<A> {
|
|
||||||
state: A,
|
|
||||||
stop: A,
|
|
||||||
step: A,
|
|
||||||
rev: bool,
|
|
||||||
done: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns an iterator over the range [start, stop] by `step`.
|
|
||||||
///
|
|
||||||
/// It handles overflow by stopping.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// # #![feature(core)]
|
|
||||||
/// use std::iter::range_step_inclusive;
|
|
||||||
///
|
|
||||||
/// for i in range_step_inclusive(0, 10, 2) {
|
|
||||||
/// println!("{}", i);
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// This prints:
|
|
||||||
///
|
|
||||||
/// ```text
|
|
||||||
/// 0
|
|
||||||
/// 2
|
|
||||||
/// 4
|
|
||||||
/// 6
|
|
||||||
/// 8
|
|
||||||
/// 10
|
|
||||||
/// ```
|
|
||||||
#[inline]
|
|
||||||
#[unstable(feature = "core",
|
|
||||||
reason = "likely to be replaced by range notation and adapters")]
|
|
||||||
#[allow(deprecated)]
|
|
||||||
pub fn range_step_inclusive<A: Int>(start: A, stop: A, step: A) -> RangeStepInclusive<A> {
|
|
||||||
let rev = step < Int::zero();
|
|
||||||
RangeStepInclusive {
|
|
||||||
state: start,
|
|
||||||
stop: stop,
|
|
||||||
step: step,
|
|
||||||
rev: rev,
|
|
||||||
done: false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[unstable(feature = "core",
|
|
||||||
reason = "likely to be replaced by range notation and adapters")]
|
|
||||||
#[allow(deprecated)]
|
|
||||||
impl<A: Int> Iterator for RangeStepInclusive<A> {
|
|
||||||
type Item = A;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn next(&mut self) -> Option<A> {
|
|
||||||
if !self.done && ((self.rev && self.state >= self.stop) ||
|
|
||||||
(!self.rev && self.state <= self.stop)) {
|
|
||||||
let result = self.state;
|
|
||||||
match self.state.checked_add(self.step) {
|
|
||||||
Some(x) => self.state = x,
|
|
||||||
None => self.done = true
|
|
||||||
}
|
|
||||||
Some(result)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! range_exact_iter_impl {
|
macro_rules! range_exact_iter_impl {
|
||||||
($($t:ty)*) => ($(
|
($($t:ty)*) => ($(
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
|
|
|
@ -108,6 +108,7 @@ mod uint_macros;
|
||||||
#[path = "num/f32.rs"] pub mod f32;
|
#[path = "num/f32.rs"] pub mod f32;
|
||||||
#[path = "num/f64.rs"] pub mod f64;
|
#[path = "num/f64.rs"] pub mod f64;
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
pub mod num;
|
pub mod num;
|
||||||
|
|
||||||
/* The libcore prelude, not as all-encompassing as the libstd prelude */
|
/* The libcore prelude, not as all-encompassing as the libstd prelude */
|
||||||
|
|
|
@ -35,7 +35,16 @@ use hash::Hasher;
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
#[lang="send"]
|
#[lang="send"]
|
||||||
#[rustc_on_unimplemented = "`{Self}` cannot be sent between threads safely"]
|
#[rustc_on_unimplemented = "`{Self}` cannot be sent between threads safely"]
|
||||||
#[allow(deprecated)]
|
#[cfg(not(stage0))]
|
||||||
|
pub unsafe trait Send {
|
||||||
|
// empty.
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Types able to be transferred across thread boundaries.
|
||||||
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
|
#[lang="send"]
|
||||||
|
#[rustc_on_unimplemented = "`{Self}` cannot be sent between threads safely"]
|
||||||
|
#[cfg(stage0)]
|
||||||
pub unsafe trait Send : MarkerTrait {
|
pub unsafe trait Send : MarkerTrait {
|
||||||
// empty.
|
// empty.
|
||||||
}
|
}
|
||||||
|
@ -51,7 +60,17 @@ impl !Send for Managed { }
|
||||||
#[lang="sized"]
|
#[lang="sized"]
|
||||||
#[rustc_on_unimplemented = "`{Self}` does not have a constant size known at compile-time"]
|
#[rustc_on_unimplemented = "`{Self}` does not have a constant size known at compile-time"]
|
||||||
#[fundamental] // for Default, for example, which requires that `[T]: !Default` be evaluatable
|
#[fundamental] // for Default, for example, which requires that `[T]: !Default` be evaluatable
|
||||||
#[allow(deprecated)]
|
#[cfg(not(stage0))]
|
||||||
|
pub trait Sized {
|
||||||
|
// Empty.
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Types with a constant size known at compile-time.
|
||||||
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
|
#[lang="sized"]
|
||||||
|
#[rustc_on_unimplemented = "`{Self}` does not have a constant size known at compile-time"]
|
||||||
|
#[fundamental] // for Default, for example, which requires that `[T]: !Default` be evaluatable
|
||||||
|
#[cfg(stage0)]
|
||||||
pub trait Sized : MarkerTrait {
|
pub trait Sized : MarkerTrait {
|
||||||
// Empty.
|
// Empty.
|
||||||
}
|
}
|
||||||
|
@ -199,13 +218,23 @@ pub trait Copy : Clone {
|
||||||
/// the `sync` crate do ensure that any mutation cannot cause data
|
/// the `sync` crate do ensure that any mutation cannot cause data
|
||||||
/// races. Hence these types are `Sync`.
|
/// races. Hence these types are `Sync`.
|
||||||
///
|
///
|
||||||
/// Any types with interior mutability must also use the `std::cell::UnsafeCell` wrapper around the
|
/// Any types with interior mutability must also use the `std::cell::UnsafeCell`
|
||||||
/// value(s) which can be mutated when behind a `&` reference; not doing this is undefined
|
/// wrapper around the value(s) which can be mutated when behind a `&`
|
||||||
/// behaviour (for example, `transmute`-ing from `&T` to `&mut T` is illegal).
|
/// reference; not doing this is undefined behaviour (for example,
|
||||||
|
/// `transmute`-ing from `&T` to `&mut T` is illegal).
|
||||||
|
#[cfg(not(stage0))]
|
||||||
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
|
#[lang="sync"]
|
||||||
|
#[rustc_on_unimplemented = "`{Self}` cannot be shared between threads safely"]
|
||||||
|
pub unsafe trait Sync {
|
||||||
|
// Empty
|
||||||
|
}
|
||||||
|
|
||||||
|
/// dox
|
||||||
|
#[cfg(stage0)]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
#[lang="sync"]
|
#[lang="sync"]
|
||||||
#[rustc_on_unimplemented = "`{Self}` cannot be shared between threads safely"]
|
#[rustc_on_unimplemented = "`{Self}` cannot be shared between threads safely"]
|
||||||
#[allow(deprecated)]
|
|
||||||
pub unsafe trait Sync : MarkerTrait {
|
pub unsafe trait Sync : MarkerTrait {
|
||||||
// Empty
|
// Empty
|
||||||
}
|
}
|
||||||
|
@ -272,42 +301,20 @@ macro_rules! impls{
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `MarkerTrait` is deprecated and no longer needed.
|
/// dox
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
#[deprecated(since = "1.0.0", reason = "No longer needed")]
|
|
||||||
#[allow(deprecated)]
|
|
||||||
#[cfg(stage0)]
|
#[cfg(stage0)]
|
||||||
pub trait MarkerTrait : PhantomFn<Self,Self> { }
|
pub trait MarkerTrait : PhantomFn<Self,Self> { }
|
||||||
|
|
||||||
/// `MarkerTrait` is deprecated and no longer needed.
|
#[cfg(stage0)]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
impl<T: ?Sized> MarkerTrait for T {}
|
||||||
#[deprecated(since = "1.0.0", reason = "No longer needed")]
|
|
||||||
#[allow(deprecated)]
|
|
||||||
#[cfg(not(stage0))]
|
|
||||||
pub trait MarkerTrait { }
|
|
||||||
|
|
||||||
#[allow(deprecated)]
|
/// dox
|
||||||
impl<T:?Sized> MarkerTrait for T { }
|
|
||||||
|
|
||||||
/// `PhantomFn` is a deprecated marker trait that is no longer needed.
|
|
||||||
#[lang="phantom_fn"]
|
#[lang="phantom_fn"]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
|
||||||
#[deprecated(since = "1.0.0", reason = "No longer needed")]
|
|
||||||
#[cfg(stage0)]
|
#[cfg(stage0)]
|
||||||
pub trait PhantomFn<A:?Sized,R:?Sized=()> {
|
pub trait PhantomFn<A:?Sized,R:?Sized=()> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `PhantomFn` is a deprecated marker trait that is no longer needed.
|
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
|
||||||
#[deprecated(since = "1.0.0", reason = "No longer needed")]
|
|
||||||
#[cfg(not(stage0))]
|
|
||||||
pub trait PhantomFn<A:?Sized,R:?Sized=()> {
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(deprecated)]
|
|
||||||
#[cfg(not(stage0))]
|
|
||||||
impl<A:?Sized,R:?Sized,T:?Sized> PhantomFn<A,R> for T { }
|
|
||||||
|
|
||||||
/// `PhantomData<T>` allows you to describe that a type acts as if it stores a value of type `T`,
|
/// `PhantomData<T>` allows you to describe that a type acts as if it stores a value of type `T`,
|
||||||
/// even though it does not. This allows you to inform the compiler about certain safety properties
|
/// even though it does not. This allows you to inform the compiler about certain safety properties
|
||||||
/// of your code.
|
/// of your code.
|
||||||
|
@ -454,8 +461,14 @@ mod impls {
|
||||||
#[rustc_reflect_like]
|
#[rustc_reflect_like]
|
||||||
#[unstable(feature = "core", reason = "requires RFC and more experience")]
|
#[unstable(feature = "core", reason = "requires RFC and more experience")]
|
||||||
#[allow(deprecated)]
|
#[allow(deprecated)]
|
||||||
pub trait Reflect : MarkerTrait {
|
#[cfg(not(stage0))]
|
||||||
}
|
pub trait Reflect {}
|
||||||
|
|
||||||
|
/// dox
|
||||||
|
#[rustc_reflect_like]
|
||||||
|
#[unstable(feature = "core", reason = "requires RFC and more experience")]
|
||||||
|
#[cfg(stage0)]
|
||||||
|
pub trait Reflect: MarkerTrait {}
|
||||||
|
|
||||||
impl Reflect for .. { }
|
impl Reflect for .. { }
|
||||||
|
|
||||||
|
|
|
@ -10,12 +10,17 @@
|
||||||
|
|
||||||
//! Exposes the NonZero lang item which provides optimization hints.
|
//! Exposes the NonZero lang item which provides optimization hints.
|
||||||
|
|
||||||
use marker::{Sized, MarkerTrait};
|
use marker::Sized;
|
||||||
use ops::Deref;
|
use ops::Deref;
|
||||||
|
#[cfg(stage0)] use marker::MarkerTrait;
|
||||||
|
|
||||||
/// Unsafe trait to indicate what types are usable with the NonZero struct
|
/// Unsafe trait to indicate what types are usable with the NonZero struct
|
||||||
#[allow(deprecated)]
|
#[cfg(not(stage0))]
|
||||||
pub unsafe trait Zeroable : MarkerTrait {}
|
pub unsafe trait Zeroable {}
|
||||||
|
|
||||||
|
/// Unsafe trait to indicate what types are usable with the NonZero struct
|
||||||
|
#[cfg(stage0)]
|
||||||
|
pub unsafe trait Zeroable: MarkerTrait {}
|
||||||
|
|
||||||
unsafe impl<T:?Sized> Zeroable for *const T {}
|
unsafe impl<T:?Sized> Zeroable for *const T {}
|
||||||
unsafe impl<T:?Sized> Zeroable for *mut T {}
|
unsafe impl<T:?Sized> Zeroable for *mut T {}
|
||||||
|
|
|
@ -16,11 +16,12 @@
|
||||||
|
|
||||||
#![stable(feature = "rust1", since = "1.0.0")]
|
#![stable(feature = "rust1", since = "1.0.0")]
|
||||||
|
|
||||||
|
use prelude::*;
|
||||||
|
|
||||||
use intrinsics;
|
use intrinsics;
|
||||||
use mem;
|
use mem;
|
||||||
use num::Float;
|
use num::{Float, ParseFloatError};
|
||||||
use num::FpCategory as Fp;
|
use num::FpCategory as Fp;
|
||||||
use option::Option;
|
|
||||||
|
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub const RADIX: u32 = 2;
|
pub const RADIX: u32 = 2;
|
||||||
|
@ -33,19 +34,6 @@ pub const DIGITS: u32 = 6;
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub const EPSILON: f32 = 1.19209290e-07_f32;
|
pub const EPSILON: f32 = 1.19209290e-07_f32;
|
||||||
|
|
||||||
/// Smallest finite f32 value
|
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
|
||||||
#[deprecated(since = "1.0.0", reason = "use `std::f32::MIN`")]
|
|
||||||
pub const MIN_VALUE: f32 = -3.40282347e+38_f32;
|
|
||||||
/// Smallest positive, normalized f32 value
|
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
|
||||||
#[deprecated(since = "1.0.0", reason = "use `std::f32::MIN_POSITIVE`")]
|
|
||||||
pub const MIN_POS_VALUE: f32 = 1.17549435e-38_f32;
|
|
||||||
/// Largest finite f32 value
|
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
|
||||||
#[deprecated(since = "1.0.0", reason = "use `std::f32::MAX`")]
|
|
||||||
pub const MAX_VALUE: f32 = 3.40282347e+38_f32;
|
|
||||||
|
|
||||||
/// Smallest finite f32 value
|
/// Smallest finite f32 value
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub const MIN: f32 = -3.40282347e+38_f32;
|
pub const MIN: f32 = -3.40282347e+38_f32;
|
||||||
|
@ -118,26 +106,14 @@ pub mod consts {
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub const FRAC_2_SQRT_PI: f32 = 1.12837916709551257389615890312154517_f32;
|
pub const FRAC_2_SQRT_PI: f32 = 1.12837916709551257389615890312154517_f32;
|
||||||
|
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
|
||||||
#[deprecated(since = "1.0.0", reason = "renamed to FRAC_2_SQRT_PI")]
|
|
||||||
pub const FRAC_2_SQRTPI: f32 = 1.12837916709551257389615890312154517_f32;
|
|
||||||
|
|
||||||
/// sqrt(2.0)
|
/// sqrt(2.0)
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub const SQRT_2: f32 = 1.41421356237309504880168872420969808_f32;
|
pub const SQRT_2: f32 = 1.41421356237309504880168872420969808_f32;
|
||||||
|
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
|
||||||
#[deprecated(since = "1.0.0", reason = "renamed to SQRT_2")]
|
|
||||||
pub const SQRT2: f32 = 1.41421356237309504880168872420969808_f32;
|
|
||||||
|
|
||||||
/// 1.0/sqrt(2.0)
|
/// 1.0/sqrt(2.0)
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub const FRAC_1_SQRT_2: f32 = 0.707106781186547524400844362104849039_f32;
|
pub const FRAC_1_SQRT_2: f32 = 0.707106781186547524400844362104849039_f32;
|
||||||
|
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
|
||||||
#[deprecated(since = "1.0.0", reason = "renamed to FRAC_1_SQRT_2")]
|
|
||||||
pub const FRAC_1_SQRT2: f32 = 0.707106781186547524400844362104849039_f32;
|
|
||||||
|
|
||||||
/// Euler's number
|
/// Euler's number
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub const E: f32 = 2.71828182845904523536028747135266250_f32;
|
pub const E: f32 = 2.71828182845904523536028747135266250_f32;
|
||||||
|
@ -179,6 +155,8 @@ impl Float for f32 {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn one() -> f32 { 1.0 }
|
fn one() -> f32 { 1.0 }
|
||||||
|
|
||||||
|
from_str_radix_float_impl! { f32 }
|
||||||
|
|
||||||
/// Returns `true` if the number is NaN.
|
/// Returns `true` if the number is NaN.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn is_nan(self) -> bool { self != self }
|
fn is_nan(self) -> bool { self != self }
|
||||||
|
@ -218,56 +196,6 @@ impl Float for f32 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
#[unstable(feature = "core")]
|
|
||||||
#[deprecated(since = "1.0.0")]
|
|
||||||
fn mantissa_digits(_: Option<f32>) -> usize { MANTISSA_DIGITS as usize }
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
#[unstable(feature = "core")]
|
|
||||||
#[deprecated(since = "1.0.0")]
|
|
||||||
fn digits(_: Option<f32>) -> usize { DIGITS as usize }
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
#[unstable(feature = "core")]
|
|
||||||
#[deprecated(since = "1.0.0")]
|
|
||||||
fn epsilon() -> f32 { EPSILON }
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
#[unstable(feature = "core")]
|
|
||||||
#[deprecated(since = "1.0.0")]
|
|
||||||
fn min_exp(_: Option<f32>) -> isize { MIN_EXP as isize }
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
#[unstable(feature = "core")]
|
|
||||||
#[deprecated(since = "1.0.0")]
|
|
||||||
fn max_exp(_: Option<f32>) -> isize { MAX_EXP as isize }
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
#[unstable(feature = "core")]
|
|
||||||
#[deprecated(since = "1.0.0")]
|
|
||||||
fn min_10_exp(_: Option<f32>) -> isize { MIN_10_EXP as isize }
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
#[unstable(feature = "core")]
|
|
||||||
#[deprecated(since = "1.0.0")]
|
|
||||||
fn max_10_exp(_: Option<f32>) -> isize { MAX_10_EXP as isize }
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
#[unstable(feature = "core")]
|
|
||||||
#[deprecated(since = "1.0.0")]
|
|
||||||
fn min_value() -> f32 { MIN }
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
#[unstable(feature = "core")]
|
|
||||||
#[deprecated(since = "1.0.0")]
|
|
||||||
fn min_pos_value(_: Option<f32>) -> f32 { MIN_POSITIVE }
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
#[unstable(feature = "core")]
|
|
||||||
#[deprecated(since = "1.0.0")]
|
|
||||||
fn max_value() -> f32 { MAX }
|
|
||||||
|
|
||||||
/// Returns the mantissa, exponent and sign as integers.
|
/// Returns the mantissa, exponent and sign as integers.
|
||||||
fn integer_decode(self) -> (u64, i16, i8) {
|
fn integer_decode(self) -> (u64, i16, i8) {
|
||||||
let bits: u32 = unsafe { mem::transmute(self) };
|
let bits: u32 = unsafe { mem::transmute(self) };
|
||||||
|
@ -310,9 +238,6 @@ impl Float for f32 {
|
||||||
/// The fractional part of the number, satisfying:
|
/// The fractional part of the number, satisfying:
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # #![feature(core)]
|
|
||||||
/// use std::num::Float;
|
|
||||||
///
|
|
||||||
/// let x = 1.65f32;
|
/// let x = 1.65f32;
|
||||||
/// assert!(x == x.trunc() + x.fract())
|
/// assert!(x == x.trunc() + x.fract())
|
||||||
/// ```
|
/// ```
|
||||||
|
|
|
@ -16,11 +16,12 @@
|
||||||
|
|
||||||
#![stable(feature = "rust1", since = "1.0.0")]
|
#![stable(feature = "rust1", since = "1.0.0")]
|
||||||
|
|
||||||
|
use prelude::*;
|
||||||
|
|
||||||
use intrinsics;
|
use intrinsics;
|
||||||
use mem;
|
use mem;
|
||||||
use num::Float;
|
|
||||||
use num::FpCategory as Fp;
|
use num::FpCategory as Fp;
|
||||||
use option::Option;
|
use num::{Float, ParseFloatError};
|
||||||
|
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub const RADIX: u32 = 2;
|
pub const RADIX: u32 = 2;
|
||||||
|
@ -33,19 +34,6 @@ pub const DIGITS: u32 = 15;
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub const EPSILON: f64 = 2.2204460492503131e-16_f64;
|
pub const EPSILON: f64 = 2.2204460492503131e-16_f64;
|
||||||
|
|
||||||
/// Smallest finite f64 value
|
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
|
||||||
#[deprecated(since = "1.0.0", reason = "use `std::f64::MIN`")]
|
|
||||||
pub const MIN_VALUE: f64 = -1.7976931348623157e+308_f64;
|
|
||||||
/// Smallest positive, normalized f64 value
|
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
|
||||||
#[deprecated(since = "1.0.0", reason = "use `std::f64::MIN_POSITIVE`")]
|
|
||||||
pub const MIN_POS_VALUE: f64 = 2.2250738585072014e-308_f64;
|
|
||||||
/// Largest finite f64 value
|
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
|
||||||
#[deprecated(since = "1.0.0", reason = "use `std::f64::MAX`")]
|
|
||||||
pub const MAX_VALUE: f64 = 1.7976931348623157e+308_f64;
|
|
||||||
|
|
||||||
/// Smallest finite f64 value
|
/// Smallest finite f64 value
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub const MIN: f64 = -1.7976931348623157e+308_f64;
|
pub const MIN: f64 = -1.7976931348623157e+308_f64;
|
||||||
|
@ -118,26 +106,14 @@ pub mod consts {
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub const FRAC_2_SQRT_PI: f64 = 1.12837916709551257389615890312154517_f64;
|
pub const FRAC_2_SQRT_PI: f64 = 1.12837916709551257389615890312154517_f64;
|
||||||
|
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
|
||||||
#[deprecated(since = "1.0.0", reason = "renamed to FRAC_2_SQRT_PI")]
|
|
||||||
pub const FRAC_2_SQRTPI: f64 = 1.12837916709551257389615890312154517_f64;
|
|
||||||
|
|
||||||
/// sqrt(2.0)
|
/// sqrt(2.0)
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub const SQRT_2: f64 = 1.41421356237309504880168872420969808_f64;
|
pub const SQRT_2: f64 = 1.41421356237309504880168872420969808_f64;
|
||||||
|
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
|
||||||
#[deprecated(since = "1.0.0", reason = "renamed to SQRT_2")]
|
|
||||||
pub const SQRT2: f64 = 1.41421356237309504880168872420969808_f64;
|
|
||||||
|
|
||||||
/// 1.0/sqrt(2.0)
|
/// 1.0/sqrt(2.0)
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub const FRAC_1_SQRT_2: f64 = 0.707106781186547524400844362104849039_f64;
|
pub const FRAC_1_SQRT_2: f64 = 0.707106781186547524400844362104849039_f64;
|
||||||
|
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
|
||||||
#[deprecated(since = "1.0.0", reason = "renamed to FRAC_1_SQRT_2")]
|
|
||||||
pub const FRAC_1_SQRT2: f64 = 0.707106781186547524400844362104849039_f64;
|
|
||||||
|
|
||||||
/// Euler's number
|
/// Euler's number
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub const E: f64 = 2.71828182845904523536028747135266250_f64;
|
pub const E: f64 = 2.71828182845904523536028747135266250_f64;
|
||||||
|
@ -179,6 +155,8 @@ impl Float for f64 {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn one() -> f64 { 1.0 }
|
fn one() -> f64 { 1.0 }
|
||||||
|
|
||||||
|
from_str_radix_float_impl! { f64 }
|
||||||
|
|
||||||
/// Returns `true` if the number is NaN.
|
/// Returns `true` if the number is NaN.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn is_nan(self) -> bool { self != self }
|
fn is_nan(self) -> bool { self != self }
|
||||||
|
@ -218,56 +196,6 @@ impl Float for f64 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
#[unstable(feature = "core")]
|
|
||||||
#[deprecated(since = "1.0.0")]
|
|
||||||
fn mantissa_digits(_: Option<f64>) -> usize { MANTISSA_DIGITS as usize }
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
#[unstable(feature = "core")]
|
|
||||||
#[deprecated(since = "1.0.0")]
|
|
||||||
fn digits(_: Option<f64>) -> usize { DIGITS as usize }
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
#[unstable(feature = "core")]
|
|
||||||
#[deprecated(since = "1.0.0")]
|
|
||||||
fn epsilon() -> f64 { EPSILON }
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
#[unstable(feature = "core")]
|
|
||||||
#[deprecated(since = "1.0.0")]
|
|
||||||
fn min_exp(_: Option<f64>) -> isize { MIN_EXP as isize }
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
#[unstable(feature = "core")]
|
|
||||||
#[deprecated(since = "1.0.0")]
|
|
||||||
fn max_exp(_: Option<f64>) -> isize { MAX_EXP as isize }
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
#[unstable(feature = "core")]
|
|
||||||
#[deprecated(since = "1.0.0")]
|
|
||||||
fn min_10_exp(_: Option<f64>) -> isize { MIN_10_EXP as isize }
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
#[unstable(feature = "core")]
|
|
||||||
#[deprecated(since = "1.0.0")]
|
|
||||||
fn max_10_exp(_: Option<f64>) -> isize { MAX_10_EXP as isize }
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
#[unstable(feature = "core")]
|
|
||||||
#[deprecated(since = "1.0.0")]
|
|
||||||
fn min_value() -> f64 { MIN }
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
#[unstable(feature = "core")]
|
|
||||||
#[deprecated(since = "1.0.0")]
|
|
||||||
fn min_pos_value(_: Option<f64>) -> f64 { MIN_POSITIVE }
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
#[unstable(feature = "core")]
|
|
||||||
#[deprecated(since = "1.0.0")]
|
|
||||||
fn max_value() -> f64 { MAX }
|
|
||||||
|
|
||||||
/// Returns the mantissa, exponent and sign as integers.
|
/// Returns the mantissa, exponent and sign as integers.
|
||||||
fn integer_decode(self) -> (u64, i16, i8) {
|
fn integer_decode(self) -> (u64, i16, i8) {
|
||||||
let bits: u64 = unsafe { mem::transmute(self) };
|
let bits: u64 = unsafe { mem::transmute(self) };
|
||||||
|
@ -310,9 +238,6 @@ impl Float for f64 {
|
||||||
/// The fractional part of the number, satisfying:
|
/// The fractional part of the number, satisfying:
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # #![feature(core)]
|
|
||||||
/// use std::num::Float;
|
|
||||||
///
|
|
||||||
/// let x = 1.65f64;
|
/// let x = 1.65f64;
|
||||||
/// assert!(x == x.trunc() + x.fract())
|
/// assert!(x == x.trunc() + x.fract())
|
||||||
/// ```
|
/// ```
|
||||||
|
|
|
@ -18,3 +18,145 @@ macro_rules! assert_approx_eq {
|
||||||
"{} is not approximately equal to {}", *a, *b);
|
"{} is not approximately equal to {}", *a, *b);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
macro_rules! from_str_radix_float_impl {
|
||||||
|
($T:ty) => {
|
||||||
|
fn from_str_radix(src: &str, radix: u32)
|
||||||
|
-> Result<$T, ParseFloatError> {
|
||||||
|
use num::FloatErrorKind::*;
|
||||||
|
use num::ParseFloatError as PFE;
|
||||||
|
|
||||||
|
// Special values
|
||||||
|
match src {
|
||||||
|
"inf" => return Ok(Float::infinity()),
|
||||||
|
"-inf" => return Ok(Float::neg_infinity()),
|
||||||
|
"NaN" => return Ok(Float::nan()),
|
||||||
|
_ => {},
|
||||||
|
}
|
||||||
|
|
||||||
|
let (is_positive, src) = match src.slice_shift_char() {
|
||||||
|
None => return Err(PFE { kind: Empty }),
|
||||||
|
Some(('-', "")) => return Err(PFE { kind: Empty }),
|
||||||
|
Some(('-', src)) => (false, src),
|
||||||
|
Some((_, _)) => (true, src),
|
||||||
|
};
|
||||||
|
|
||||||
|
// The significand to accumulate
|
||||||
|
let mut sig = if is_positive { 0.0 } else { -0.0 };
|
||||||
|
// Necessary to detect overflow
|
||||||
|
let mut prev_sig = sig;
|
||||||
|
let mut cs = src.chars().enumerate();
|
||||||
|
// Exponent prefix and exponent index offset
|
||||||
|
let mut exp_info = None::<(char, usize)>;
|
||||||
|
|
||||||
|
// Parse the integer part of the significand
|
||||||
|
for (i, c) in cs.by_ref() {
|
||||||
|
match c.to_digit(radix) {
|
||||||
|
Some(digit) => {
|
||||||
|
// shift significand one digit left
|
||||||
|
sig = sig * (radix as $T);
|
||||||
|
|
||||||
|
// add/subtract current digit depending on sign
|
||||||
|
if is_positive {
|
||||||
|
sig = sig + ((digit as isize) as $T);
|
||||||
|
} else {
|
||||||
|
sig = sig - ((digit as isize) as $T);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Detect overflow by comparing to last value, except
|
||||||
|
// if we've not seen any non-zero digits.
|
||||||
|
if prev_sig != 0.0 {
|
||||||
|
if is_positive && sig <= prev_sig
|
||||||
|
{ return Ok(Float::infinity()); }
|
||||||
|
if !is_positive && sig >= prev_sig
|
||||||
|
{ return Ok(Float::neg_infinity()); }
|
||||||
|
|
||||||
|
// Detect overflow by reversing the shift-and-add process
|
||||||
|
if is_positive && (prev_sig != (sig - digit as $T) / radix as $T)
|
||||||
|
{ return Ok(Float::infinity()); }
|
||||||
|
if !is_positive && (prev_sig != (sig + digit as $T) / radix as $T)
|
||||||
|
{ return Ok(Float::neg_infinity()); }
|
||||||
|
}
|
||||||
|
prev_sig = sig;
|
||||||
|
},
|
||||||
|
None => match c {
|
||||||
|
'e' | 'E' | 'p' | 'P' => {
|
||||||
|
exp_info = Some((c, i + 1));
|
||||||
|
break; // start of exponent
|
||||||
|
},
|
||||||
|
'.' => {
|
||||||
|
break; // start of fractional part
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
return Err(PFE { kind: Invalid });
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we are not yet at the exponent parse the fractional
|
||||||
|
// part of the significand
|
||||||
|
if exp_info.is_none() {
|
||||||
|
let mut power = 1.0;
|
||||||
|
for (i, c) in cs.by_ref() {
|
||||||
|
match c.to_digit(radix) {
|
||||||
|
Some(digit) => {
|
||||||
|
// Decrease power one order of magnitude
|
||||||
|
power = power / (radix as $T);
|
||||||
|
// add/subtract current digit depending on sign
|
||||||
|
sig = if is_positive {
|
||||||
|
sig + (digit as $T) * power
|
||||||
|
} else {
|
||||||
|
sig - (digit as $T) * power
|
||||||
|
};
|
||||||
|
// Detect overflow by comparing to last value
|
||||||
|
if is_positive && sig < prev_sig
|
||||||
|
{ return Ok(Float::infinity()); }
|
||||||
|
if !is_positive && sig > prev_sig
|
||||||
|
{ return Ok(Float::neg_infinity()); }
|
||||||
|
prev_sig = sig;
|
||||||
|
},
|
||||||
|
None => match c {
|
||||||
|
'e' | 'E' | 'p' | 'P' => {
|
||||||
|
exp_info = Some((c, i + 1));
|
||||||
|
break; // start of exponent
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
return Err(PFE { kind: Invalid });
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse and calculate the exponent
|
||||||
|
let exp = match exp_info {
|
||||||
|
Some((c, offset)) => {
|
||||||
|
let base = match c {
|
||||||
|
'E' | 'e' if radix == 10 => 10.0,
|
||||||
|
'P' | 'p' if radix == 16 => 2.0,
|
||||||
|
_ => return Err(PFE { kind: Invalid }),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Parse the exponent as decimal integer
|
||||||
|
let src = &src[offset..];
|
||||||
|
let (is_positive, exp) = match src.slice_shift_char() {
|
||||||
|
Some(('-', src)) => (false, src.parse::<usize>()),
|
||||||
|
Some(('+', src)) => (true, src.parse::<usize>()),
|
||||||
|
Some((_, _)) => (true, src.parse::<usize>()),
|
||||||
|
None => return Err(PFE { kind: Invalid }),
|
||||||
|
};
|
||||||
|
|
||||||
|
match (is_positive, exp) {
|
||||||
|
(true, Ok(exp)) => base.powi(exp as i32),
|
||||||
|
(false, Ok(exp)) => 1.0 / base.powi(exp as i32),
|
||||||
|
(_, Err(_)) => return Err(PFE { kind: Invalid }),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
None => 1.0, // no exponent
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(sig * exp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -15,8 +15,6 @@ use super::Wrapping;
|
||||||
|
|
||||||
use ops::*;
|
use ops::*;
|
||||||
|
|
||||||
use intrinsics::{overflowing_add, overflowing_sub, overflowing_mul};
|
|
||||||
|
|
||||||
use intrinsics::{i8_add_with_overflow, u8_add_with_overflow};
|
use intrinsics::{i8_add_with_overflow, u8_add_with_overflow};
|
||||||
use intrinsics::{i16_add_with_overflow, u16_add_with_overflow};
|
use intrinsics::{i16_add_with_overflow, u16_add_with_overflow};
|
||||||
use intrinsics::{i32_add_with_overflow, u32_add_with_overflow};
|
use intrinsics::{i32_add_with_overflow, u32_add_with_overflow};
|
||||||
|
@ -32,14 +30,6 @@ use intrinsics::{i64_mul_with_overflow, u64_mul_with_overflow};
|
||||||
|
|
||||||
use ::{i8,i16,i32,i64};
|
use ::{i8,i16,i32,i64};
|
||||||
|
|
||||||
#[unstable(feature = "core", reason = "may be removed, renamed, or relocated")]
|
|
||||||
#[deprecated(since = "1.0.0", reason = "moved to inherent methods")]
|
|
||||||
pub trait WrappingOps {
|
|
||||||
fn wrapping_add(self, rhs: Self) -> Self;
|
|
||||||
fn wrapping_sub(self, rhs: Self) -> Self;
|
|
||||||
fn wrapping_mul(self, rhs: Self) -> Self;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[unstable(feature = "core", reason = "may be removed, renamed, or relocated")]
|
#[unstable(feature = "core", reason = "may be removed, renamed, or relocated")]
|
||||||
pub trait OverflowingOps {
|
pub trait OverflowingOps {
|
||||||
fn overflowing_add(self, rhs: Self) -> (Self, bool);
|
fn overflowing_add(self, rhs: Self) -> (Self, bool);
|
||||||
|
@ -99,27 +89,6 @@ sh_impl_all! { u8 u16 u32 u64 usize i8 i16 i32 i64 isize }
|
||||||
|
|
||||||
macro_rules! wrapping_impl {
|
macro_rules! wrapping_impl {
|
||||||
($($t:ty)*) => ($(
|
($($t:ty)*) => ($(
|
||||||
impl WrappingOps for $t {
|
|
||||||
#[inline(always)]
|
|
||||||
fn wrapping_add(self, rhs: $t) -> $t {
|
|
||||||
unsafe {
|
|
||||||
overflowing_add(self, rhs)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#[inline(always)]
|
|
||||||
fn wrapping_sub(self, rhs: $t) -> $t {
|
|
||||||
unsafe {
|
|
||||||
overflowing_sub(self, rhs)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#[inline(always)]
|
|
||||||
fn wrapping_mul(self, rhs: $t) -> $t {
|
|
||||||
unsafe {
|
|
||||||
overflowing_mul(self, rhs)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
impl Add for Wrapping<$t> {
|
impl Add for Wrapping<$t> {
|
||||||
type Output = Wrapping<$t>;
|
type Output = Wrapping<$t>;
|
||||||
|
|
|
@ -551,25 +551,6 @@ impl<T> Option<T> {
|
||||||
IterMut { inner: Item { opt: self.as_mut() } }
|
IterMut { inner: Item { opt: self.as_mut() } }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a consuming iterator over the possibly contained value.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// let x = Some("string");
|
|
||||||
/// let v: Vec<&str> = x.into_iter().collect();
|
|
||||||
/// assert_eq!(v, ["string"]);
|
|
||||||
///
|
|
||||||
/// let x = None;
|
|
||||||
/// let v: Vec<&str> = x.into_iter().collect();
|
|
||||||
/// assert!(v.is_empty());
|
|
||||||
/// ```
|
|
||||||
#[inline]
|
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
|
||||||
pub fn into_iter(self) -> IntoIter<T> {
|
|
||||||
IntoIter { inner: Item { opt: self } }
|
|
||||||
}
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////
|
||||||
// Boolean operations on the values, eager and lazy
|
// Boolean operations on the values, eager and lazy
|
||||||
/////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -770,6 +751,30 @@ impl<T> Default for Option<T> {
|
||||||
fn default() -> Option<T> { None }
|
fn default() -> Option<T> { None }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
|
impl<T> IntoIterator for Option<T> {
|
||||||
|
type Item = T;
|
||||||
|
type IntoIter = IntoIter<T>;
|
||||||
|
|
||||||
|
/// Returns a consuming iterator over the possibly contained value.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// let x = Some("string");
|
||||||
|
/// let v: Vec<&str> = x.into_iter().collect();
|
||||||
|
/// assert_eq!(v, ["string"]);
|
||||||
|
///
|
||||||
|
/// let x = None;
|
||||||
|
/// let v: Vec<&str> = x.into_iter().collect();
|
||||||
|
/// assert!(v.is_empty());
|
||||||
|
/// ```
|
||||||
|
#[inline]
|
||||||
|
fn into_iter(self) -> IntoIter<T> {
|
||||||
|
IntoIter { inner: Item { opt: self } }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
// The Option Iterators
|
// The Option Iterators
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -37,11 +37,10 @@ pub use char::CharExt;
|
||||||
pub use clone::Clone;
|
pub use clone::Clone;
|
||||||
pub use cmp::{PartialEq, PartialOrd, Eq, Ord};
|
pub use cmp::{PartialEq, PartialOrd, Eq, Ord};
|
||||||
pub use convert::{AsRef, AsMut, Into, From};
|
pub use convert::{AsRef, AsMut, Into, From};
|
||||||
|
pub use default::Default;
|
||||||
|
pub use iter::IntoIterator;
|
||||||
pub use iter::{Iterator, DoubleEndedIterator, Extend, ExactSizeIterator};
|
pub use iter::{Iterator, DoubleEndedIterator, Extend, ExactSizeIterator};
|
||||||
pub use option::Option::{self, Some, None};
|
pub use option::Option::{self, Some, None};
|
||||||
pub use result::Result::{self, Ok, Err};
|
pub use result::Result::{self, Ok, Err};
|
||||||
pub use slice::SliceExt;
|
pub use slice::SliceExt;
|
||||||
pub use str::StrExt;
|
pub use str::StrExt;
|
||||||
|
|
||||||
#[allow(deprecated)] pub use slice::AsSlice;
|
|
||||||
#[allow(deprecated)] pub use str::Str;
|
|
||||||
|
|
|
@ -234,8 +234,6 @@ use fmt;
|
||||||
use iter::{Iterator, DoubleEndedIterator, FromIterator, ExactSizeIterator, IntoIterator};
|
use iter::{Iterator, DoubleEndedIterator, FromIterator, ExactSizeIterator, IntoIterator};
|
||||||
use ops::{FnMut, FnOnce};
|
use ops::{FnMut, FnOnce};
|
||||||
use option::Option::{self, None, Some};
|
use option::Option::{self, None, Some};
|
||||||
#[allow(deprecated)]
|
|
||||||
use slice::AsSlice;
|
|
||||||
use slice;
|
use slice;
|
||||||
|
|
||||||
/// `Result` is a type that represents either success (`Ok`) or failure (`Err`).
|
/// `Result` is a type that represents either success (`Ok`) or failure (`Err`).
|
||||||
|
@ -547,25 +545,6 @@ impl<T, E> Result<T, E> {
|
||||||
IterMut { inner: self.as_mut().ok() }
|
IterMut { inner: self.as_mut().ok() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a consuming iterator over the possibly contained value.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// let x: Result<u32, &str> = Ok(5);
|
|
||||||
/// let v: Vec<u32> = x.into_iter().collect();
|
|
||||||
/// assert_eq!(v, [5]);
|
|
||||||
///
|
|
||||||
/// let x: Result<u32, &str> = Err("nothing!");
|
|
||||||
/// let v: Vec<u32> = x.into_iter().collect();
|
|
||||||
/// assert_eq!(v, []);
|
|
||||||
/// ```
|
|
||||||
#[inline]
|
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
|
||||||
pub fn into_iter(self) -> IntoIter<T> {
|
|
||||||
IntoIter { inner: self.ok() }
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////
|
||||||
// Boolean operations on the values, eager and lazy
|
// Boolean operations on the values, eager and lazy
|
||||||
/////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -787,23 +766,27 @@ impl<T: fmt::Debug, E> Result<T, E> {
|
||||||
// Trait implementations
|
// Trait implementations
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#[unstable(feature = "core",
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
reason = "waiting on the stability of the trait itself")]
|
impl<T, E> IntoIterator for Result<T, E> {
|
||||||
#[deprecated(since = "1.0.0",
|
type Item = T;
|
||||||
reason = "use inherent method instead")]
|
type IntoIter = IntoIter<T>;
|
||||||
#[allow(deprecated)]
|
|
||||||
impl<T, E> AsSlice<T> for Result<T, E> {
|
/// Returns a consuming iterator over the possibly contained value.
|
||||||
/// Converts from `Result<T, E>` to `&[T]` (without copying)
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// let x: Result<u32, &str> = Ok(5);
|
||||||
|
/// let v: Vec<u32> = x.into_iter().collect();
|
||||||
|
/// assert_eq!(v, [5]);
|
||||||
|
///
|
||||||
|
/// let x: Result<u32, &str> = Err("nothing!");
|
||||||
|
/// let v: Vec<u32> = x.into_iter().collect();
|
||||||
|
/// assert_eq!(v, []);
|
||||||
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
fn as_slice<'a>(&'a self) -> &'a [T] {
|
fn into_iter(self) -> IntoIter<T> {
|
||||||
match *self {
|
IntoIter { inner: self.ok() }
|
||||||
Ok(ref x) => slice::ref_slice(x),
|
|
||||||
Err(_) => {
|
|
||||||
// work around lack of implicit coercion from fixed-size array to slice
|
|
||||||
let emp: &[_] = &[];
|
|
||||||
emp
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -51,7 +51,7 @@ use result::Result::{Ok, Err};
|
||||||
use ptr;
|
use ptr;
|
||||||
use mem;
|
use mem;
|
||||||
use mem::size_of;
|
use mem::size_of;
|
||||||
use marker::{Send, Sized, Sync, self};
|
use marker::{Send, Sync, self};
|
||||||
use raw::Repr;
|
use raw::Repr;
|
||||||
// Avoid conflicts with *both* the Slice trait (buggy) and the `slice::raw` module.
|
// Avoid conflicts with *both* the Slice trait (buggy) and the `slice::raw` module.
|
||||||
use raw::Slice as RawSlice;
|
use raw::Slice as RawSlice;
|
||||||
|
@ -595,37 +595,6 @@ impl<T> ops::IndexMut<RangeFull> for [T] {
|
||||||
// Common traits
|
// Common traits
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
/// Data that is viewable as a slice.
|
|
||||||
#[unstable(feature = "core",
|
|
||||||
reason = "will be replaced by slice syntax")]
|
|
||||||
#[deprecated(since = "1.0.0",
|
|
||||||
reason = "use std::convert::AsRef<[T]> instead")]
|
|
||||||
pub trait AsSlice<T> {
|
|
||||||
/// Work with `self` as a slice.
|
|
||||||
fn as_slice<'a>(&'a self) -> &'a [T];
|
|
||||||
}
|
|
||||||
|
|
||||||
#[unstable(feature = "core", reason = "trait is experimental")]
|
|
||||||
#[allow(deprecated)]
|
|
||||||
impl<T> AsSlice<T> for [T] {
|
|
||||||
#[inline(always)]
|
|
||||||
fn as_slice<'a>(&'a self) -> &'a [T] { self }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[unstable(feature = "core", reason = "trait is experimental")]
|
|
||||||
#[allow(deprecated)]
|
|
||||||
impl<'a, T, U: ?Sized + AsSlice<T>> AsSlice<T> for &'a U {
|
|
||||||
#[inline(always)]
|
|
||||||
fn as_slice(&self) -> &[T] { AsSlice::as_slice(*self) }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[unstable(feature = "core", reason = "trait is experimental")]
|
|
||||||
#[allow(deprecated)]
|
|
||||||
impl<'a, T, U: ?Sized + AsSlice<T>> AsSlice<T> for &'a mut U {
|
|
||||||
#[inline(always)]
|
|
||||||
fn as_slice(&self) -> &[T] { AsSlice::as_slice(*self) }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
impl<'a, T> Default for &'a [T] {
|
impl<'a, T> Default for &'a [T] {
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
|
|
|
@ -25,7 +25,6 @@ use default::Default;
|
||||||
use fmt;
|
use fmt;
|
||||||
use iter::ExactSizeIterator;
|
use iter::ExactSizeIterator;
|
||||||
use iter::{Map, Iterator, DoubleEndedIterator};
|
use iter::{Map, Iterator, DoubleEndedIterator};
|
||||||
use marker::Sized;
|
|
||||||
use mem;
|
use mem;
|
||||||
use ops::{Fn, FnMut, FnOnce};
|
use ops::{Fn, FnMut, FnOnce};
|
||||||
use option::Option::{self, None, Some};
|
use option::Option::{self, None, Some};
|
||||||
|
@ -1463,30 +1462,6 @@ mod traits {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Any string that can be represented as a slice
|
|
||||||
#[unstable(feature = "core",
|
|
||||||
reason = "Instead of taking this bound generically, this trait will be \
|
|
||||||
replaced with one of slicing syntax (&foo[..]), deref coercions, or \
|
|
||||||
a more generic conversion trait")]
|
|
||||||
#[deprecated(since = "1.0.0",
|
|
||||||
reason = "use std::convert::AsRef<str> instead")]
|
|
||||||
pub trait Str {
|
|
||||||
/// Work with `self` as a slice.
|
|
||||||
fn as_slice<'a>(&'a self) -> &'a str;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(deprecated)]
|
|
||||||
impl Str for str {
|
|
||||||
#[inline]
|
|
||||||
fn as_slice<'a>(&'a self) -> &'a str { self }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(deprecated)]
|
|
||||||
impl<'a, S: ?Sized> Str for &'a S where S: Str {
|
|
||||||
#[inline]
|
|
||||||
fn as_slice(&self) -> &str { Str::as_slice(*self) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Methods for string slices
|
/// Methods for string slices
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
|
|
|
@ -110,8 +110,6 @@ fn test_partial_max() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_user_defined_eq() {
|
fn test_user_defined_eq() {
|
||||||
use core::num::SignedInt;
|
|
||||||
|
|
||||||
// Our type.
|
// Our type.
|
||||||
struct SketchyNum {
|
struct SketchyNum {
|
||||||
num : isize
|
num : isize
|
||||||
|
|
|
@ -11,7 +11,6 @@
|
||||||
use core::iter::*;
|
use core::iter::*;
|
||||||
use core::iter::order::*;
|
use core::iter::order::*;
|
||||||
use core::iter::MinMaxResult::*;
|
use core::iter::MinMaxResult::*;
|
||||||
use core::num::SignedInt;
|
|
||||||
use core::usize;
|
use core::usize;
|
||||||
use core::cmp;
|
use core::cmp;
|
||||||
|
|
||||||
|
@ -783,16 +782,6 @@ fn test_range_step() {
|
||||||
assert_eq!((200..200).step_by(1).collect::<Vec<isize>>(), []);
|
assert_eq!((200..200).step_by(1).collect::<Vec<isize>>(), []);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_range_step_inclusive() {
|
|
||||||
assert_eq!(range_step_inclusive(0, 20, 5).collect::<Vec<isize>>(), [0, 5, 10, 15, 20]);
|
|
||||||
assert_eq!(range_step_inclusive(20, 0, -5).collect::<Vec<isize>>(), [20, 15, 10, 5, 0]);
|
|
||||||
assert_eq!(range_step_inclusive(20, 0, -6).collect::<Vec<isize>>(), [20, 14, 8, 2]);
|
|
||||||
assert_eq!(range_step_inclusive(200, 255, 50).collect::<Vec<u8>>(), [200, 250]);
|
|
||||||
assert_eq!(range_step_inclusive(200, -5, 1).collect::<Vec<isize>>(), []);
|
|
||||||
assert_eq!(range_step_inclusive(200, 200, 1).collect::<Vec<isize>>(), [200]);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_reverse() {
|
fn test_reverse() {
|
||||||
let mut ys = [1, 2, 3, 4, 5];
|
let mut ys = [1, 2, 3, 4, 5];
|
||||||
|
|
|
@ -10,8 +10,8 @@
|
||||||
|
|
||||||
// Do not remove on snapshot creation. Needed for bootstrap. (Issue #22364)
|
// Do not remove on snapshot creation. Needed for bootstrap. (Issue #22364)
|
||||||
#![cfg_attr(stage0, feature(custom_attribute))]
|
#![cfg_attr(stage0, feature(custom_attribute))]
|
||||||
|
|
||||||
#![feature(box_syntax)]
|
#![feature(box_syntax)]
|
||||||
#![feature(int_uint)]
|
|
||||||
#![feature(unboxed_closures)]
|
#![feature(unboxed_closures)]
|
||||||
#![feature(unsafe_destructor)]
|
#![feature(unsafe_destructor)]
|
||||||
#![feature(core)]
|
#![feature(core)]
|
||||||
|
@ -21,13 +21,11 @@
|
||||||
#![feature(std_misc)]
|
#![feature(std_misc)]
|
||||||
#![feature(libc)]
|
#![feature(libc)]
|
||||||
#![feature(hash)]
|
#![feature(hash)]
|
||||||
#![feature(io)]
|
|
||||||
#![feature(collections)]
|
|
||||||
#![feature(debug_builders)]
|
#![feature(debug_builders)]
|
||||||
#![feature(unique)]
|
#![feature(unique)]
|
||||||
#![feature(step_by)]
|
#![feature(step_by)]
|
||||||
#![feature(slice_patterns)]
|
#![feature(slice_patterns)]
|
||||||
#![allow(deprecated)] // rand
|
#![feature(float_from_str_radix)]
|
||||||
|
|
||||||
extern crate core;
|
extern crate core;
|
||||||
extern crate test;
|
extern crate test;
|
||||||
|
|
|
@ -8,12 +8,11 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
macro_rules! int_module { ($T:ty, $T_i:ident) => (
|
macro_rules! int_module { ($T:ident, $T_i:ident) => (
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use core::$T_i::*;
|
use core::$T_i::*;
|
||||||
use core::isize;
|
use core::isize;
|
||||||
use core::num::{FromStrRadix, Int, SignedInt};
|
|
||||||
use core::ops::{Shl, Shr, Not, BitXor, BitAnd, BitOr};
|
use core::ops::{Shl, Shr, Not, BitXor, BitAnd, BitOr};
|
||||||
use num;
|
use num;
|
||||||
|
|
||||||
|
@ -129,30 +128,30 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_le() {
|
fn test_le() {
|
||||||
assert_eq!(Int::from_le(A.to_le()), A);
|
assert_eq!($T::from_le(A.to_le()), A);
|
||||||
assert_eq!(Int::from_le(B.to_le()), B);
|
assert_eq!($T::from_le(B.to_le()), B);
|
||||||
assert_eq!(Int::from_le(C.to_le()), C);
|
assert_eq!($T::from_le(C.to_le()), C);
|
||||||
assert_eq!(Int::from_le(_0), _0);
|
assert_eq!($T::from_le(_0), _0);
|
||||||
assert_eq!(Int::from_le(_1), _1);
|
assert_eq!($T::from_le(_1), _1);
|
||||||
assert_eq!(_0.to_le(), _0);
|
assert_eq!(_0.to_le(), _0);
|
||||||
assert_eq!(_1.to_le(), _1);
|
assert_eq!(_1.to_le(), _1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_be() {
|
fn test_be() {
|
||||||
assert_eq!(Int::from_be(A.to_be()), A);
|
assert_eq!($T::from_be(A.to_be()), A);
|
||||||
assert_eq!(Int::from_be(B.to_be()), B);
|
assert_eq!($T::from_be(B.to_be()), B);
|
||||||
assert_eq!(Int::from_be(C.to_be()), C);
|
assert_eq!($T::from_be(C.to_be()), C);
|
||||||
assert_eq!(Int::from_be(_0), _0);
|
assert_eq!($T::from_be(_0), _0);
|
||||||
assert_eq!(Int::from_be(_1), _1);
|
assert_eq!($T::from_be(_1), _1);
|
||||||
assert_eq!(_0.to_be(), _0);
|
assert_eq!(_0.to_be(), _0);
|
||||||
assert_eq!(_1.to_be(), _1);
|
assert_eq!(_1.to_be(), _1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_signed_checked_div() {
|
fn test_signed_checked_div() {
|
||||||
assert!(10.checked_div(2) == Some(5));
|
assert!((10 as $T).checked_div(2) == Some(5));
|
||||||
assert!(5.checked_div(0) == None);
|
assert!((5 as $T).checked_div(0) == None);
|
||||||
assert!(isize::MIN.checked_div(-1) == None);
|
assert!(isize::MIN.checked_div(-1) == None);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -180,26 +179,26 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_from_str_radix() {
|
fn test_from_str_radix() {
|
||||||
assert_eq!(FromStrRadix::from_str_radix("123", 10), Ok(123 as $T));
|
assert_eq!($T::from_str_radix("123", 10), Ok(123 as $T));
|
||||||
assert_eq!(FromStrRadix::from_str_radix("1001", 2), Ok(9 as $T));
|
assert_eq!($T::from_str_radix("1001", 2), Ok(9 as $T));
|
||||||
assert_eq!(FromStrRadix::from_str_radix("123", 8), Ok(83 as $T));
|
assert_eq!($T::from_str_radix("123", 8), Ok(83 as $T));
|
||||||
assert_eq!(FromStrRadix::from_str_radix("123", 16), Ok(291 as i32));
|
assert_eq!(i32::from_str_radix("123", 16), Ok(291 as i32));
|
||||||
assert_eq!(FromStrRadix::from_str_radix("ffff", 16), Ok(65535 as i32));
|
assert_eq!(i32::from_str_radix("ffff", 16), Ok(65535 as i32));
|
||||||
assert_eq!(FromStrRadix::from_str_radix("FFFF", 16), Ok(65535 as i32));
|
assert_eq!(i32::from_str_radix("FFFF", 16), Ok(65535 as i32));
|
||||||
assert_eq!(FromStrRadix::from_str_radix("z", 36), Ok(35 as $T));
|
assert_eq!($T::from_str_radix("z", 36), Ok(35 as $T));
|
||||||
assert_eq!(FromStrRadix::from_str_radix("Z", 36), Ok(35 as $T));
|
assert_eq!($T::from_str_radix("Z", 36), Ok(35 as $T));
|
||||||
|
|
||||||
assert_eq!(FromStrRadix::from_str_radix("-123", 10), Ok(-123 as $T));
|
assert_eq!($T::from_str_radix("-123", 10), Ok(-123 as $T));
|
||||||
assert_eq!(FromStrRadix::from_str_radix("-1001", 2), Ok(-9 as $T));
|
assert_eq!($T::from_str_radix("-1001", 2), Ok(-9 as $T));
|
||||||
assert_eq!(FromStrRadix::from_str_radix("-123", 8), Ok(-83 as $T));
|
assert_eq!($T::from_str_radix("-123", 8), Ok(-83 as $T));
|
||||||
assert_eq!(FromStrRadix::from_str_radix("-123", 16), Ok(-291 as i32));
|
assert_eq!(i32::from_str_radix("-123", 16), Ok(-291 as i32));
|
||||||
assert_eq!(FromStrRadix::from_str_radix("-ffff", 16), Ok(-65535 as i32));
|
assert_eq!(i32::from_str_radix("-ffff", 16), Ok(-65535 as i32));
|
||||||
assert_eq!(FromStrRadix::from_str_radix("-FFFF", 16), Ok(-65535 as i32));
|
assert_eq!(i32::from_str_radix("-FFFF", 16), Ok(-65535 as i32));
|
||||||
assert_eq!(FromStrRadix::from_str_radix("-z", 36), Ok(-35 as $T));
|
assert_eq!($T::from_str_radix("-z", 36), Ok(-35 as $T));
|
||||||
assert_eq!(FromStrRadix::from_str_radix("-Z", 36), Ok(-35 as $T));
|
assert_eq!($T::from_str_radix("-Z", 36), Ok(-35 as $T));
|
||||||
|
|
||||||
assert_eq!(FromStrRadix::from_str_radix("Z", 35).ok(), None::<$T>);
|
assert_eq!($T::from_str_radix("Z", 35).ok(), None::<$T>);
|
||||||
assert_eq!(FromStrRadix::from_str_radix("-9", 2).ok(), None::<$T>);
|
assert_eq!($T::from_str_radix("-9", 2).ok(), None::<$T>);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -10,7 +10,6 @@
|
||||||
|
|
||||||
use core::cmp::PartialEq;
|
use core::cmp::PartialEq;
|
||||||
use core::fmt::Debug;
|
use core::fmt::Debug;
|
||||||
use core::num::{NumCast, cast};
|
|
||||||
use core::ops::{Add, Sub, Mul, Div, Rem};
|
use core::ops::{Add, Sub, Mul, Div, Rem};
|
||||||
use core::marker::Copy;
|
use core::marker::Copy;
|
||||||
|
|
||||||
|
@ -32,18 +31,12 @@ mod u64;
|
||||||
|
|
||||||
/// Helper function for testing numeric operations
|
/// Helper function for testing numeric operations
|
||||||
pub fn test_num<T>(ten: T, two: T) where
|
pub fn test_num<T>(ten: T, two: T) where
|
||||||
T: PartialEq + NumCast
|
T: PartialEq
|
||||||
+ Add<Output=T> + Sub<Output=T>
|
+ Add<Output=T> + Sub<Output=T>
|
||||||
+ Mul<Output=T> + Div<Output=T>
|
+ Mul<Output=T> + Div<Output=T>
|
||||||
+ Rem<Output=T> + Debug
|
+ Rem<Output=T> + Debug
|
||||||
+ Copy
|
+ Copy
|
||||||
{
|
{
|
||||||
assert_eq!(ten.add(two), cast(12).unwrap());
|
|
||||||
assert_eq!(ten.sub(two), cast(8).unwrap());
|
|
||||||
assert_eq!(ten.mul(two), cast(20).unwrap());
|
|
||||||
assert_eq!(ten.div(two), cast(5).unwrap());
|
|
||||||
assert_eq!(ten.rem(two), cast(0).unwrap());
|
|
||||||
|
|
||||||
assert_eq!(ten.add(two), ten + two);
|
assert_eq!(ten.add(two), ten + two);
|
||||||
assert_eq!(ten.sub(two), ten - two);
|
assert_eq!(ten.sub(two), ten - two);
|
||||||
assert_eq!(ten.mul(two), ten * two);
|
assert_eq!(ten.mul(two), ten * two);
|
||||||
|
@ -56,33 +49,33 @@ mod test {
|
||||||
use core::option::Option;
|
use core::option::Option;
|
||||||
use core::option::Option::{Some, None};
|
use core::option::Option::{Some, None};
|
||||||
use core::num::Float;
|
use core::num::Float;
|
||||||
use core::num::from_str_radix;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn from_str_issue7588() {
|
fn from_str_issue7588() {
|
||||||
let u : Option<u8> = from_str_radix("1000", 10).ok();
|
let u : Option<u8> = u8::from_str_radix("1000", 10).ok();
|
||||||
assert_eq!(u, None);
|
assert_eq!(u, None);
|
||||||
let s : Option<i16> = from_str_radix("80000", 10).ok();
|
let s : Option<i16> = i16::from_str_radix("80000", 10).ok();
|
||||||
assert_eq!(s, None);
|
assert_eq!(s, None);
|
||||||
let f : Option<f32> = from_str_radix("10000000000000000000000000000000000000000", 10).ok();
|
let s = "10000000000000000000000000000000000000000";
|
||||||
|
let f : Option<f32> = f32::from_str_radix(s, 10).ok();
|
||||||
assert_eq!(f, Some(Float::infinity()));
|
assert_eq!(f, Some(Float::infinity()));
|
||||||
let fe : Option<f32> = from_str_radix("1e40", 10).ok();
|
let fe : Option<f32> = f32::from_str_radix("1e40", 10).ok();
|
||||||
assert_eq!(fe, Some(Float::infinity()));
|
assert_eq!(fe, Some(Float::infinity()));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_from_str_radix_float() {
|
fn test_from_str_radix_float() {
|
||||||
let x1 : Option<f64> = from_str_radix("-123.456", 10).ok();
|
let x1 : Option<f64> = f64::from_str_radix("-123.456", 10).ok();
|
||||||
assert_eq!(x1, Some(-123.456));
|
assert_eq!(x1, Some(-123.456));
|
||||||
let x2 : Option<f32> = from_str_radix("123.456", 10).ok();
|
let x2 : Option<f32> = f32::from_str_radix("123.456", 10).ok();
|
||||||
assert_eq!(x2, Some(123.456));
|
assert_eq!(x2, Some(123.456));
|
||||||
let x3 : Option<f32> = from_str_radix("-0.0", 10).ok();
|
let x3 : Option<f32> = f32::from_str_radix("-0.0", 10).ok();
|
||||||
assert_eq!(x3, Some(-0.0));
|
assert_eq!(x3, Some(-0.0));
|
||||||
let x4 : Option<f32> = from_str_radix("0.0", 10).ok();
|
let x4 : Option<f32> = f32::from_str_radix("0.0", 10).ok();
|
||||||
assert_eq!(x4, Some(0.0));
|
assert_eq!(x4, Some(0.0));
|
||||||
let x4 : Option<f32> = from_str_radix("1.0", 10).ok();
|
let x4 : Option<f32> = f32::from_str_radix("1.0", 10).ok();
|
||||||
assert_eq!(x4, Some(1.0));
|
assert_eq!(x4, Some(1.0));
|
||||||
let x5 : Option<f32> = from_str_radix("-1.0", 10).ok();
|
let x5 : Option<f32> = f32::from_str_radix("-1.0", 10).ok();
|
||||||
assert_eq!(x5, Some(-1.0));
|
assert_eq!(x5, Some(-1.0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,11 +8,10 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
macro_rules! uint_module { ($T:ty, $T_i:ident) => (
|
macro_rules! uint_module { ($T:ident, $T_i:ident) => (
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use core::$T_i::*;
|
use core::$T_i::*;
|
||||||
use core::num::Int;
|
|
||||||
use num;
|
use num;
|
||||||
use core::ops::{BitOr, BitAnd, BitXor, Shl, Shr, Not};
|
use core::ops::{BitOr, BitAnd, BitXor, Shl, Shr, Not};
|
||||||
|
|
||||||
|
@ -97,30 +96,30 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_le() {
|
fn test_le() {
|
||||||
assert_eq!(Int::from_le(A.to_le()), A);
|
assert_eq!($T::from_le(A.to_le()), A);
|
||||||
assert_eq!(Int::from_le(B.to_le()), B);
|
assert_eq!($T::from_le(B.to_le()), B);
|
||||||
assert_eq!(Int::from_le(C.to_le()), C);
|
assert_eq!($T::from_le(C.to_le()), C);
|
||||||
assert_eq!(Int::from_le(_0), _0);
|
assert_eq!($T::from_le(_0), _0);
|
||||||
assert_eq!(Int::from_le(_1), _1);
|
assert_eq!($T::from_le(_1), _1);
|
||||||
assert_eq!(_0.to_le(), _0);
|
assert_eq!(_0.to_le(), _0);
|
||||||
assert_eq!(_1.to_le(), _1);
|
assert_eq!(_1.to_le(), _1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_be() {
|
fn test_be() {
|
||||||
assert_eq!(Int::from_be(A.to_be()), A);
|
assert_eq!($T::from_be(A.to_be()), A);
|
||||||
assert_eq!(Int::from_be(B.to_be()), B);
|
assert_eq!($T::from_be(B.to_be()), B);
|
||||||
assert_eq!(Int::from_be(C.to_be()), C);
|
assert_eq!($T::from_be(C.to_be()), C);
|
||||||
assert_eq!(Int::from_be(_0), _0);
|
assert_eq!($T::from_be(_0), _0);
|
||||||
assert_eq!(Int::from_be(_1), _1);
|
assert_eq!($T::from_be(_1), _1);
|
||||||
assert_eq!(_0.to_be(), _0);
|
assert_eq!(_0.to_be(), _0);
|
||||||
assert_eq!(_1.to_be(), _1);
|
assert_eq!(_1.to_be(), _1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_unsigned_checked_div() {
|
fn test_unsigned_checked_div() {
|
||||||
assert!(10.checked_div(2) == Some(5));
|
assert!((10 as $T).checked_div(2) == Some(5));
|
||||||
assert!(5.checked_div(0) == None);
|
assert!((5 as $T).checked_div(0) == None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -91,7 +91,6 @@
|
||||||
|
|
||||||
#![deny(missing_docs)]
|
#![deny(missing_docs)]
|
||||||
#![feature(staged_api)]
|
#![feature(staged_api)]
|
||||||
#![feature(str_words)]
|
|
||||||
#![feature(str_char)]
|
#![feature(str_char)]
|
||||||
#![cfg_attr(test, feature(rustc_private))]
|
#![cfg_attr(test, feature(rustc_private))]
|
||||||
|
|
||||||
|
@ -771,7 +770,7 @@ pub fn usage(brief: &str, opts: &[OptGroup]) -> String {
|
||||||
|
|
||||||
// Normalize desc to contain words separated by one space character
|
// Normalize desc to contain words separated by one space character
|
||||||
let mut desc_normalized_whitespace = String::new();
|
let mut desc_normalized_whitespace = String::new();
|
||||||
for word in desc.words() {
|
for word in desc.split_whitespace() {
|
||||||
desc_normalized_whitespace.push_str(word);
|
desc_normalized_whitespace.push_str(word);
|
||||||
desc_normalized_whitespace.push(' ');
|
desc_normalized_whitespace.push(' ');
|
||||||
}
|
}
|
||||||
|
|
|
@ -3536,6 +3536,30 @@ pub mod consts {
|
||||||
pub const IPV6_DROP_MEMBERSHIP: c_int = 21;
|
pub const IPV6_DROP_MEMBERSHIP: c_int = 21;
|
||||||
|
|
||||||
pub const TCP_NODELAY: c_int = 1;
|
pub const TCP_NODELAY: c_int = 1;
|
||||||
|
pub const TCP_MAXSEG: c_int = 2;
|
||||||
|
pub const TCP_CORK: c_int = 3;
|
||||||
|
pub const TCP_KEEPIDLE: c_int = 4;
|
||||||
|
pub const TCP_KEEPINTVL: c_int = 5;
|
||||||
|
pub const TCP_KEEPCNT: c_int = 6;
|
||||||
|
pub const TCP_SYNCNT: c_int = 7;
|
||||||
|
pub const TCP_LINGER2: c_int = 8;
|
||||||
|
pub const TCP_DEFER_ACCEPT: c_int = 9;
|
||||||
|
pub const TCP_WINDOW_CLAMP: c_int = 10;
|
||||||
|
pub const TCP_INFO: c_int = 11;
|
||||||
|
pub const TCP_QUICKACK: c_int = 12;
|
||||||
|
pub const TCP_CONGESTION: c_int = 13;
|
||||||
|
pub const TCP_MD5SIG: c_int = 14;
|
||||||
|
pub const TCP_COOKIE_TRANSACTIONS: c_int = 15;
|
||||||
|
pub const TCP_THIN_LINEAR_TIMEOUTS: c_int = 16;
|
||||||
|
pub const TCP_THIN_DUPACK: c_int = 17;
|
||||||
|
pub const TCP_USER_TIMEOUT: c_int = 18;
|
||||||
|
pub const TCP_REPAIR: c_int = 19;
|
||||||
|
pub const TCP_REPAIR_QUEUE: c_int = 20;
|
||||||
|
pub const TCP_QUEUE_SEQ: c_int = 21;
|
||||||
|
pub const TCP_REPAIR_OPTIONS: c_int = 22;
|
||||||
|
pub const TCP_FASTOPEN: c_int = 23;
|
||||||
|
pub const TCP_TIMESTAMP: c_int = 24;
|
||||||
|
|
||||||
pub const SOL_SOCKET: c_int = 1;
|
pub const SOL_SOCKET: c_int = 1;
|
||||||
|
|
||||||
pub const SO_DEBUG: c_int = 1;
|
pub const SO_DEBUG: c_int = 1;
|
||||||
|
|
|
@ -11,8 +11,6 @@
|
||||||
//! The ChaCha random number generator.
|
//! The ChaCha random number generator.
|
||||||
|
|
||||||
use core::prelude::*;
|
use core::prelude::*;
|
||||||
use core::num::Int;
|
|
||||||
use core::num::wrapping::WrappingOps;
|
|
||||||
use {Rng, SeedableRng, Rand};
|
use {Rng, SeedableRng, Rand};
|
||||||
|
|
||||||
const KEY_WORDS : usize = 8; // 8 words for the 256-bit key
|
const KEY_WORDS : usize = 8; // 8 words for the 256-bit key
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
//! that do not need to record state.
|
//! that do not need to record state.
|
||||||
|
|
||||||
use core::prelude::*;
|
use core::prelude::*;
|
||||||
use core::num::{Float, Int};
|
use core::num::Float;
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
|
|
||||||
use {Rng, Rand};
|
use {Rng, Rand};
|
||||||
|
|
|
@ -13,8 +13,6 @@
|
||||||
// this is surprisingly complicated to be both generic & correct
|
// this is surprisingly complicated to be both generic & correct
|
||||||
|
|
||||||
use core::prelude::PartialOrd;
|
use core::prelude::PartialOrd;
|
||||||
use core::num::Int;
|
|
||||||
use core::num::wrapping::WrappingOps;
|
|
||||||
|
|
||||||
use Rng;
|
use Rng;
|
||||||
use distributions::{Sample, IndependentSample};
|
use distributions::{Sample, IndependentSample};
|
||||||
|
@ -73,7 +71,7 @@ pub trait SampleRange {
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! integer_impl {
|
macro_rules! integer_impl {
|
||||||
($ty:ty, $unsigned:ty) => {
|
($ty:ident, $unsigned:ident) => {
|
||||||
impl SampleRange for $ty {
|
impl SampleRange for $ty {
|
||||||
// we play free and fast with unsigned vs signed here
|
// we play free and fast with unsigned vs signed here
|
||||||
// (when $ty is signed), but that's fine, since the
|
// (when $ty is signed), but that's fine, since the
|
||||||
|
@ -83,7 +81,7 @@ macro_rules! integer_impl {
|
||||||
|
|
||||||
fn construct_range(low: $ty, high: $ty) -> Range<$ty> {
|
fn construct_range(low: $ty, high: $ty) -> Range<$ty> {
|
||||||
let range = (high as $unsigned).wrapping_sub(low as $unsigned);
|
let range = (high as $unsigned).wrapping_sub(low as $unsigned);
|
||||||
let unsigned_max: $unsigned = Int::max_value();
|
let unsigned_max: $unsigned = $unsigned::max_value();
|
||||||
|
|
||||||
// this is the largest number that fits into $unsigned
|
// this is the largest number that fits into $unsigned
|
||||||
// that `range` divides evenly, so, if we've sampled
|
// that `range` divides evenly, so, if we've sampled
|
||||||
|
@ -148,7 +146,6 @@ float_impl! { f64 }
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use std::num::Int;
|
|
||||||
use std::prelude::v1::*;
|
use std::prelude::v1::*;
|
||||||
use distributions::{Sample, IndependentSample};
|
use distributions::{Sample, IndependentSample};
|
||||||
use super::Range as Range;
|
use super::Range as Range;
|
||||||
|
@ -168,11 +165,11 @@ mod tests {
|
||||||
fn test_integers() {
|
fn test_integers() {
|
||||||
let mut rng = ::test::rng();
|
let mut rng = ::test::rng();
|
||||||
macro_rules! t {
|
macro_rules! t {
|
||||||
($($ty:ty),*) => {{
|
($($ty:ident),*) => {{
|
||||||
$(
|
$(
|
||||||
let v: &[($ty, $ty)] = &[(0, 10),
|
let v: &[($ty, $ty)] = &[(0, 10),
|
||||||
(10, 127),
|
(10, 127),
|
||||||
(Int::min_value(), Int::max_value())];
|
($ty::min_value(), $ty::max_value())];
|
||||||
for &(low, high) in v {
|
for &(low, high) in v {
|
||||||
let mut sampler: Range<$ty> = Range::new(low, high);
|
let mut sampler: Range<$ty> = Range::new(low, high);
|
||||||
for _ in 0..1000 {
|
for _ in 0..1000 {
|
||||||
|
|
|
@ -14,7 +14,6 @@
|
||||||
use core::prelude::*;
|
use core::prelude::*;
|
||||||
|
|
||||||
use {Rng, SeedableRng};
|
use {Rng, SeedableRng};
|
||||||
use core::default::Default;
|
|
||||||
|
|
||||||
/// How many bytes of entropy the underling RNG is allowed to generate
|
/// How many bytes of entropy the underling RNG is allowed to generate
|
||||||
/// before it is reseeded.
|
/// before it is reseeded.
|
||||||
|
@ -126,7 +125,6 @@ mod test {
|
||||||
|
|
||||||
use core::iter::{order, repeat};
|
use core::iter::{order, repeat};
|
||||||
use super::{ReseedingRng, ReseedWithDefault};
|
use super::{ReseedingRng, ReseedWithDefault};
|
||||||
use std::default::Default;
|
|
||||||
use {SeedableRng, Rng};
|
use {SeedableRng, Rng};
|
||||||
|
|
||||||
struct Counter {
|
struct Counter {
|
||||||
|
|
|
@ -836,7 +836,6 @@ pub mod writer {
|
||||||
use std::io::prelude::*;
|
use std::io::prelude::*;
|
||||||
use std::io::{self, SeekFrom, Cursor};
|
use std::io::{self, SeekFrom, Cursor};
|
||||||
use std::slice::bytes;
|
use std::slice::bytes;
|
||||||
use std::num::ToPrimitive;
|
|
||||||
|
|
||||||
use super::{ EsVec, EsMap, EsEnum, EsSub8, EsSub32, EsVecElt, EsMapKey,
|
use super::{ EsVec, EsMap, EsEnum, EsSub8, EsSub32, EsVecElt, EsMapKey,
|
||||||
EsU64, EsU32, EsU16, EsU8, EsI64, EsI32, EsI16, EsI8,
|
EsU64, EsU32, EsU16, EsU8, EsI64, EsI32, EsI16, EsI8,
|
||||||
|
@ -1070,10 +1069,10 @@ pub mod writer {
|
||||||
impl<'a> Encoder<'a> {
|
impl<'a> Encoder<'a> {
|
||||||
// used internally to emit things like the vector length and so on
|
// used internally to emit things like the vector length and so on
|
||||||
fn _emit_tagged_sub(&mut self, v: usize) -> EncodeResult {
|
fn _emit_tagged_sub(&mut self, v: usize) -> EncodeResult {
|
||||||
if let Some(v) = v.to_u8() {
|
if v as u8 as usize == v {
|
||||||
self.wr_tagged_raw_u8(EsSub8 as usize, v)
|
self.wr_tagged_raw_u8(EsSub8 as usize, v as u8)
|
||||||
} else if let Some(v) = v.to_u32() {
|
} else if v as u32 as usize == v {
|
||||||
self.wr_tagged_raw_u32(EsSub32 as usize, v)
|
self.wr_tagged_raw_u32(EsSub32 as usize, v as u32)
|
||||||
} else {
|
} else {
|
||||||
Err(io::Error::new(io::ErrorKind::Other,
|
Err(io::Error::new(io::ErrorKind::Other,
|
||||||
&format!("length or variant id too big: {}",
|
&format!("length or variant id too big: {}",
|
||||||
|
@ -1101,21 +1100,24 @@ pub mod writer {
|
||||||
self.emit_u64(v as u64)
|
self.emit_u64(v as u64)
|
||||||
}
|
}
|
||||||
fn emit_u64(&mut self, v: u64) -> EncodeResult {
|
fn emit_u64(&mut self, v: u64) -> EncodeResult {
|
||||||
match v.to_u32() {
|
if v as u32 as u64 == v {
|
||||||
Some(v) => self.emit_u32(v),
|
self.emit_u32(v as u32)
|
||||||
None => self.wr_tagged_raw_u64(EsU64 as usize, v)
|
} else {
|
||||||
|
self.wr_tagged_raw_u64(EsU64 as usize, v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn emit_u32(&mut self, v: u32) -> EncodeResult {
|
fn emit_u32(&mut self, v: u32) -> EncodeResult {
|
||||||
match v.to_u16() {
|
if v as u16 as u32 == v {
|
||||||
Some(v) => self.emit_u16(v),
|
self.emit_u16(v as u16)
|
||||||
None => self.wr_tagged_raw_u32(EsU32 as usize, v)
|
} else {
|
||||||
|
self.wr_tagged_raw_u32(EsU32 as usize, v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn emit_u16(&mut self, v: u16) -> EncodeResult {
|
fn emit_u16(&mut self, v: u16) -> EncodeResult {
|
||||||
match v.to_u8() {
|
if v as u8 as u16 == v {
|
||||||
Some(v) => self.emit_u8(v),
|
self.emit_u8(v as u8)
|
||||||
None => self.wr_tagged_raw_u16(EsU16 as usize, v)
|
} else {
|
||||||
|
self.wr_tagged_raw_u16(EsU16 as usize, v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn emit_u8(&mut self, v: u8) -> EncodeResult {
|
fn emit_u8(&mut self, v: u8) -> EncodeResult {
|
||||||
|
@ -1126,21 +1128,24 @@ pub mod writer {
|
||||||
self.emit_i64(v as i64)
|
self.emit_i64(v as i64)
|
||||||
}
|
}
|
||||||
fn emit_i64(&mut self, v: i64) -> EncodeResult {
|
fn emit_i64(&mut self, v: i64) -> EncodeResult {
|
||||||
match v.to_i32() {
|
if v as i32 as i64 == v {
|
||||||
Some(v) => self.emit_i32(v),
|
self.emit_i32(v as i32)
|
||||||
None => self.wr_tagged_raw_i64(EsI64 as usize, v)
|
} else {
|
||||||
|
self.wr_tagged_raw_i64(EsI64 as usize, v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn emit_i32(&mut self, v: i32) -> EncodeResult {
|
fn emit_i32(&mut self, v: i32) -> EncodeResult {
|
||||||
match v.to_i16() {
|
if v as i16 as i32 == v {
|
||||||
Some(v) => self.emit_i16(v),
|
self.emit_i16(v as i16)
|
||||||
None => self.wr_tagged_raw_i32(EsI32 as usize, v)
|
} else {
|
||||||
|
self.wr_tagged_raw_i32(EsI32 as usize, v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn emit_i16(&mut self, v: i16) -> EncodeResult {
|
fn emit_i16(&mut self, v: i16) -> EncodeResult {
|
||||||
match v.to_i8() {
|
if v as i8 as i16 == v {
|
||||||
Some(v) => self.emit_i8(v),
|
self.emit_i8(v as i8)
|
||||||
None => self.wr_tagged_raw_i16(EsI16 as usize, v)
|
} else {
|
||||||
|
self.wr_tagged_raw_i16(EsI16 as usize, v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn emit_i8(&mut self, v: i8) -> EncodeResult {
|
fn emit_i8(&mut self, v: i8) -> EncodeResult {
|
||||||
|
|
|
@ -208,7 +208,7 @@ fn main() {
|
||||||
unsafe { f(); }
|
unsafe { f(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
See also http://doc.rust-lang.org/book/unsafe-code.html
|
See also http://doc.rust-lang.org/book/unsafe.html
|
||||||
"##,
|
"##,
|
||||||
|
|
||||||
E0152: r##"
|
E0152: r##"
|
||||||
|
|
|
@ -38,7 +38,6 @@
|
||||||
#![feature(staged_api)]
|
#![feature(staged_api)]
|
||||||
#![feature(std_misc)]
|
#![feature(std_misc)]
|
||||||
#![feature(path_ext)]
|
#![feature(path_ext)]
|
||||||
#![feature(str_words)]
|
|
||||||
#![feature(str_char)]
|
#![feature(str_char)]
|
||||||
#![feature(into_cow)]
|
#![feature(into_cow)]
|
||||||
#![feature(slice_patterns)]
|
#![feature(slice_patterns)]
|
||||||
|
@ -69,6 +68,9 @@ extern crate test;
|
||||||
|
|
||||||
pub use rustc_llvm as llvm;
|
pub use rustc_llvm as llvm;
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
mod macros;
|
||||||
|
|
||||||
// NB: This module needs to be declared first so diagnostics are
|
// NB: This module needs to be declared first so diagnostics are
|
||||||
// registered before they are used.
|
// registered before they are used.
|
||||||
pub mod diagnostics;
|
pub mod diagnostics;
|
||||||
|
@ -142,6 +144,7 @@ pub mod util {
|
||||||
pub mod ppaux;
|
pub mod ppaux;
|
||||||
pub mod nodemap;
|
pub mod nodemap;
|
||||||
pub mod lev_distance;
|
pub mod lev_distance;
|
||||||
|
pub mod num;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod lib {
|
pub mod lib {
|
||||||
|
|
46
src/librustc/macros.rs
Normal file
46
src/librustc/macros.rs
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
macro_rules! enum_from_u32 {
|
||||||
|
($(#[$attr:meta])* pub enum $name:ident {
|
||||||
|
$($variant:ident = $e:expr,)*
|
||||||
|
}) => {
|
||||||
|
$(#[$attr])*
|
||||||
|
pub enum $name {
|
||||||
|
$($variant = $e),*
|
||||||
|
}
|
||||||
|
|
||||||
|
impl $name {
|
||||||
|
pub fn from_u32(u: u32) -> Option<$name> {
|
||||||
|
$(if u == $name::$variant as u32 {
|
||||||
|
return Some($name::$variant)
|
||||||
|
})*
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
($(#[$attr:meta])* pub enum $name:ident {
|
||||||
|
$($variant:ident,)*
|
||||||
|
}) => {
|
||||||
|
$(#[$attr])*
|
||||||
|
pub enum $name {
|
||||||
|
$($variant,)*
|
||||||
|
}
|
||||||
|
|
||||||
|
impl $name {
|
||||||
|
pub fn from_u32(u: u32) -> Option<$name> {
|
||||||
|
$(if u == $name::$variant as u32 {
|
||||||
|
return Some($name::$variant)
|
||||||
|
})*
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -116,37 +116,39 @@ pub const tag_items_data_item_reexport_def_id: usize = 0x47;
|
||||||
pub const tag_items_data_item_reexport_name: usize = 0x48;
|
pub const tag_items_data_item_reexport_name: usize = 0x48;
|
||||||
|
|
||||||
// used to encode crate_ctxt side tables
|
// used to encode crate_ctxt side tables
|
||||||
#[derive(Copy, Clone, PartialEq, FromPrimitive)]
|
enum_from_u32! {
|
||||||
#[repr(usize)]
|
#[derive(Copy, Clone, PartialEq)]
|
||||||
pub enum astencode_tag { // Reserves 0x50 -- 0x6f
|
#[repr(usize)]
|
||||||
tag_ast = 0x50,
|
pub enum astencode_tag { // Reserves 0x50 -- 0x6f
|
||||||
|
tag_ast = 0x50,
|
||||||
|
|
||||||
tag_tree = 0x51,
|
tag_tree = 0x51,
|
||||||
|
|
||||||
tag_id_range = 0x52,
|
tag_id_range = 0x52,
|
||||||
|
|
||||||
tag_table = 0x53,
|
tag_table = 0x53,
|
||||||
// GAP 0x54, 0x55
|
// GAP 0x54, 0x55
|
||||||
tag_table_def = 0x56,
|
tag_table_def = 0x56,
|
||||||
tag_table_node_type = 0x57,
|
tag_table_node_type = 0x57,
|
||||||
tag_table_item_subst = 0x58,
|
tag_table_item_subst = 0x58,
|
||||||
tag_table_freevars = 0x59,
|
tag_table_freevars = 0x59,
|
||||||
tag_table_tcache = 0x5a,
|
tag_table_tcache = 0x5a,
|
||||||
tag_table_param_defs = 0x5b,
|
tag_table_param_defs = 0x5b,
|
||||||
tag_table_mutbl = 0x5c,
|
tag_table_mutbl = 0x5c,
|
||||||
tag_table_last_use = 0x5d,
|
tag_table_last_use = 0x5d,
|
||||||
tag_table_spill = 0x5e,
|
tag_table_spill = 0x5e,
|
||||||
tag_table_method_map = 0x5f,
|
tag_table_method_map = 0x5f,
|
||||||
tag_table_vtable_map = 0x60,
|
tag_table_vtable_map = 0x60,
|
||||||
tag_table_adjustments = 0x61,
|
tag_table_adjustments = 0x61,
|
||||||
tag_table_moves_map = 0x62,
|
tag_table_moves_map = 0x62,
|
||||||
tag_table_capture_map = 0x63,
|
tag_table_capture_map = 0x63,
|
||||||
tag_table_closure_tys = 0x64,
|
tag_table_closure_tys = 0x64,
|
||||||
tag_table_closure_kinds = 0x65,
|
tag_table_closure_kinds = 0x65,
|
||||||
tag_table_upvar_capture_map = 0x66,
|
tag_table_upvar_capture_map = 0x66,
|
||||||
tag_table_capture_modes = 0x67,
|
tag_table_capture_modes = 0x67,
|
||||||
tag_table_object_cast_map = 0x68,
|
tag_table_object_cast_map = 0x68,
|
||||||
tag_table_const_qualif = 0x69,
|
tag_table_const_qualif = 0x69,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const tag_item_trait_item_sort: usize = 0x70;
|
pub const tag_item_trait_item_sort: usize = 0x70;
|
||||||
|
|
|
@ -68,11 +68,13 @@ pub enum LinkagePreference {
|
||||||
RequireStatic,
|
RequireStatic,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, FromPrimitive)]
|
enum_from_u32! {
|
||||||
pub enum NativeLibraryKind {
|
#[derive(Copy, Clone, PartialEq)]
|
||||||
NativeStatic, // native static library (.a archive)
|
pub enum NativeLibraryKind {
|
||||||
NativeFramework, // OSX-specific
|
NativeStatic, // native static library (.a archive)
|
||||||
NativeUnknown, // default way to specify a dynamic library
|
NativeFramework, // OSX-specific
|
||||||
|
NativeUnknown, // default way to specify a dynamic library
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Where a crate came from on the local filesystem. One of these two options
|
// Where a crate came from on the local filesystem. One of these two options
|
||||||
|
|
|
@ -35,7 +35,6 @@ use std::collections::HashMap;
|
||||||
use std::hash::{self, Hash, SipHasher};
|
use std::hash::{self, Hash, SipHasher};
|
||||||
use std::io::prelude::*;
|
use std::io::prelude::*;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::num::FromPrimitive;
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::slice::bytes;
|
use std::slice::bytes;
|
||||||
use std::str;
|
use std::str;
|
||||||
|
@ -1349,7 +1348,7 @@ pub fn get_native_libraries(cdata: Cmd)
|
||||||
let kind_doc = reader::get_doc(lib_doc, tag_native_libraries_kind);
|
let kind_doc = reader::get_doc(lib_doc, tag_native_libraries_kind);
|
||||||
let name_doc = reader::get_doc(lib_doc, tag_native_libraries_name);
|
let name_doc = reader::get_doc(lib_doc, tag_native_libraries_name);
|
||||||
let kind: cstore::NativeLibraryKind =
|
let kind: cstore::NativeLibraryKind =
|
||||||
FromPrimitive::from_u32(reader::doc_as_u32(kind_doc)).unwrap();
|
cstore::NativeLibraryKind::from_u32(reader::doc_as_u32(kind_doc)).unwrap();
|
||||||
let name = name_doc.as_str().to_string();
|
let name = name_doc.as_str().to_string();
|
||||||
result.push((kind, name));
|
result.push((kind, name));
|
||||||
true
|
true
|
||||||
|
@ -1359,7 +1358,7 @@ pub fn get_native_libraries(cdata: Cmd)
|
||||||
|
|
||||||
pub fn get_plugin_registrar_fn(data: &[u8]) -> Option<ast::NodeId> {
|
pub fn get_plugin_registrar_fn(data: &[u8]) -> Option<ast::NodeId> {
|
||||||
reader::maybe_get_doc(rbml::Doc::new(data), tag_plugin_registrar_fn)
|
reader::maybe_get_doc(rbml::Doc::new(data), tag_plugin_registrar_fn)
|
||||||
.map(|doc| FromPrimitive::from_u32(reader::doc_as_u32(doc)).unwrap())
|
.map(|doc| reader::doc_as_u32(doc))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn each_exported_macro<F>(data: &[u8], intr: &IdentInterner, mut f: F) where
|
pub fn each_exported_macro<F>(data: &[u8], intr: &IdentInterner, mut f: F) where
|
||||||
|
@ -1407,7 +1406,7 @@ pub fn get_missing_lang_items(cdata: Cmd)
|
||||||
let mut result = Vec::new();
|
let mut result = Vec::new();
|
||||||
reader::tagged_docs(items, tag_lang_items_missing, |missing_docs| {
|
reader::tagged_docs(items, tag_lang_items_missing, |missing_docs| {
|
||||||
let item: lang_items::LangItem =
|
let item: lang_items::LangItem =
|
||||||
FromPrimitive::from_u32(reader::doc_as_u32(missing_docs)).unwrap();
|
lang_items::LangItem::from_u32(reader::doc_as_u32(missing_docs)).unwrap();
|
||||||
result.push(item);
|
result.push(item);
|
||||||
true
|
true
|
||||||
});
|
});
|
||||||
|
|
|
@ -692,11 +692,16 @@ pub fn note_crate_name(diag: &SpanHandler, name: &str) {
|
||||||
|
|
||||||
impl ArchiveMetadata {
|
impl ArchiveMetadata {
|
||||||
fn new(ar: ArchiveRO) -> Option<ArchiveMetadata> {
|
fn new(ar: ArchiveRO) -> Option<ArchiveMetadata> {
|
||||||
let data = match ar.read(METADATA_FILENAME) {
|
let data = {
|
||||||
Some(data) => data as *const [u8],
|
let section = ar.iter().find(|sect| {
|
||||||
None => {
|
sect.name() == Some(METADATA_FILENAME)
|
||||||
debug!("didn't find '{}' in the archive", METADATA_FILENAME);
|
});
|
||||||
return None;
|
match section {
|
||||||
|
Some(s) => s.data() as *const [u8],
|
||||||
|
None => {
|
||||||
|
debug!("didn't find '{}' in the archive", METADATA_FILENAME);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -41,7 +41,6 @@ use syntax;
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use std::io::SeekFrom;
|
use std::io::SeekFrom;
|
||||||
use std::io::prelude::*;
|
use std::io::prelude::*;
|
||||||
use std::num::FromPrimitive;
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
|
||||||
|
@ -1713,7 +1712,8 @@ fn decode_side_tables(dcx: &DecodeContext,
|
||||||
debug!(">> Side table document with tag 0x{:x} \
|
debug!(">> Side table document with tag 0x{:x} \
|
||||||
found for id {} (orig {})",
|
found for id {} (orig {})",
|
||||||
tag, id, id0);
|
tag, id, id0);
|
||||||
let decoded_tag: Option<c::astencode_tag> = FromPrimitive::from_usize(tag);
|
let tag = tag as u32;
|
||||||
|
let decoded_tag: Option<c::astencode_tag> = c::astencode_tag::from_u32(tag);
|
||||||
match decoded_tag {
|
match decoded_tag {
|
||||||
None => {
|
None => {
|
||||||
dcx.tcx.sess.bug(
|
dcx.tcx.sess.bug(
|
||||||
|
|
|
@ -20,6 +20,7 @@ use middle::{astencode, def};
|
||||||
use middle::pat_util::def_to_path;
|
use middle::pat_util::def_to_path;
|
||||||
use middle::ty::{self, Ty};
|
use middle::ty::{self, Ty};
|
||||||
use middle::astconv_util::ast_ty_to_prim_ty;
|
use middle::astconv_util::ast_ty_to_prim_ty;
|
||||||
|
use util::num::ToPrimitive;
|
||||||
|
|
||||||
use syntax::ast::{self, Expr};
|
use syntax::ast::{self, Expr};
|
||||||
use syntax::codemap::Span;
|
use syntax::codemap::Span;
|
||||||
|
@ -30,7 +31,6 @@ use syntax::{ast_map, ast_util, codemap};
|
||||||
|
|
||||||
use std::borrow::{Cow, IntoCow};
|
use std::borrow::{Cow, IntoCow};
|
||||||
use std::num::wrapping::OverflowingOps;
|
use std::num::wrapping::OverflowingOps;
|
||||||
use std::num::ToPrimitive;
|
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::collections::hash_map::Entry::Vacant;
|
use std::collections::hash_map::Entry::Vacant;
|
||||||
use std::{i8, i16, i32, i64};
|
use std::{i8, i16, i32, i64};
|
||||||
|
|
|
@ -36,7 +36,6 @@ use syntax::visit::Visitor;
|
||||||
use syntax::visit;
|
use syntax::visit;
|
||||||
|
|
||||||
use std::iter::Enumerate;
|
use std::iter::Enumerate;
|
||||||
use std::num::FromPrimitive;
|
|
||||||
use std::slice;
|
use std::slice;
|
||||||
|
|
||||||
// The actual lang items defined come at the end of this file in one handy table.
|
// The actual lang items defined come at the end of this file in one handy table.
|
||||||
|
@ -46,9 +45,12 @@ macro_rules! lets_do_this {
|
||||||
$( $variant:ident, $name:expr, $method:ident; )*
|
$( $variant:ident, $name:expr, $method:ident; )*
|
||||||
) => {
|
) => {
|
||||||
|
|
||||||
#[derive(Copy, Clone, FromPrimitive, PartialEq, Eq, Hash)]
|
|
||||||
pub enum LangItem {
|
enum_from_u32! {
|
||||||
$($variant),*
|
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub enum LangItem {
|
||||||
|
$($variant,)*
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct LanguageItems {
|
pub struct LanguageItems {
|
||||||
|
@ -71,7 +73,7 @@ impl LanguageItems {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn item_name(index: usize) -> &'static str {
|
pub fn item_name(index: usize) -> &'static str {
|
||||||
let item: Option<LangItem> = FromPrimitive::from_usize(index);
|
let item: Option<LangItem> = LangItem::from_u32(index as u32);
|
||||||
match item {
|
match item {
|
||||||
$( Some($variant) => $name, )*
|
$( Some($variant) => $name, )*
|
||||||
None => "???"
|
None => "???"
|
||||||
|
|
|
@ -63,6 +63,7 @@ use util::ppaux::{Repr, UserString};
|
||||||
use util::common::{memoized, ErrorReported};
|
use util::common::{memoized, ErrorReported};
|
||||||
use util::nodemap::{NodeMap, NodeSet, DefIdMap, DefIdSet};
|
use util::nodemap::{NodeMap, NodeSet, DefIdMap, DefIdSet};
|
||||||
use util::nodemap::FnvHashMap;
|
use util::nodemap::FnvHashMap;
|
||||||
|
use util::num::ToPrimitive;
|
||||||
|
|
||||||
use arena::TypedArena;
|
use arena::TypedArena;
|
||||||
use std::borrow::{Borrow, Cow};
|
use std::borrow::{Borrow, Cow};
|
||||||
|
@ -71,7 +72,6 @@ use std::cmp;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::hash::{Hash, SipHasher, Hasher};
|
use std::hash::{Hash, SipHasher, Hasher};
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::num::ToPrimitive;
|
|
||||||
use std::ops;
|
use std::ops;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::vec::IntoIter;
|
use std::vec::IntoIter;
|
||||||
|
|
|
@ -418,7 +418,7 @@ macro_rules! options {
|
||||||
-> bool {
|
-> bool {
|
||||||
match v {
|
match v {
|
||||||
Some(s) => {
|
Some(s) => {
|
||||||
for s in s.words() {
|
for s in s.split_whitespace() {
|
||||||
slot.push(s.to_string());
|
slot.push(s.to_string());
|
||||||
}
|
}
|
||||||
true
|
true
|
||||||
|
@ -431,7 +431,7 @@ macro_rules! options {
|
||||||
-> bool {
|
-> bool {
|
||||||
match v {
|
match v {
|
||||||
Some(s) => {
|
Some(s) => {
|
||||||
let v = s.words().map(|s| s.to_string()).collect();
|
let v = s.split_whitespace().map(|s| s.to_string()).collect();
|
||||||
*slot = Some(v);
|
*slot = Some(v);
|
||||||
true
|
true
|
||||||
},
|
},
|
||||||
|
|
98
src/librustc/util/num.rs
Normal file
98
src/librustc/util/num.rs
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
pub trait ToPrimitive {
|
||||||
|
fn to_i8(&self) -> Option<i8>;
|
||||||
|
fn to_i16(&self) -> Option<i16>;
|
||||||
|
fn to_i32(&self) -> Option<i32>;
|
||||||
|
fn to_i64(&self) -> Option<i64>;
|
||||||
|
fn to_u8(&self) -> Option<u8>;
|
||||||
|
fn to_u16(&self) -> Option<u16>;
|
||||||
|
fn to_u32(&self) -> Option<u32>;
|
||||||
|
fn to_u64(&self) -> Option<u64>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToPrimitive for i64 {
|
||||||
|
fn to_i8(&self) -> Option<i8> {
|
||||||
|
if *self < i8::min_value() as i64 || *self > i8::max_value() as i64 {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(*self as i8)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn to_i16(&self) -> Option<i16> {
|
||||||
|
if *self < i16::min_value() as i64 || *self > i16::max_value() as i64 {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(*self as i16)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn to_i32(&self) -> Option<i32> {
|
||||||
|
if *self < i32::min_value() as i64 || *self > i32::max_value() as i64 {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(*self as i32)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn to_i64(&self) -> Option<i64> {
|
||||||
|
Some(*self)
|
||||||
|
}
|
||||||
|
fn to_u8(&self) -> Option<u8> {
|
||||||
|
if *self < 0 || *self > u8::max_value() as i64 {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(*self as u8)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn to_u16(&self) -> Option<u16> {
|
||||||
|
if *self < 0 || *self > u16::max_value() as i64 {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(*self as u16)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn to_u32(&self) -> Option<u32> {
|
||||||
|
if *self < 0 || *self > u32::max_value() as i64 {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(*self as u32)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn to_u64(&self) -> Option<u64> {
|
||||||
|
if *self < 0 {None} else {Some(*self as u64)}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToPrimitive for u64 {
|
||||||
|
fn to_i8(&self) -> Option<i8> {
|
||||||
|
if *self > i8::max_value() as u64 {None} else {Some(*self as i8)}
|
||||||
|
}
|
||||||
|
fn to_i16(&self) -> Option<i16> {
|
||||||
|
if *self > i16::max_value() as u64 {None} else {Some(*self as i16)}
|
||||||
|
}
|
||||||
|
fn to_i32(&self) -> Option<i32> {
|
||||||
|
if *self > i32::max_value() as u64 {None} else {Some(*self as i32)}
|
||||||
|
}
|
||||||
|
fn to_i64(&self) -> Option<i64> {
|
||||||
|
if *self > i64::max_value() as u64 {None} else {Some(*self as i64)}
|
||||||
|
}
|
||||||
|
fn to_u8(&self) -> Option<u8> {
|
||||||
|
if *self > u8::max_value() as u64 {None} else {Some(*self as u8)}
|
||||||
|
}
|
||||||
|
fn to_u16(&self) -> Option<u16> {
|
||||||
|
if *self > u16::max_value() as u64 {None} else {Some(*self as u16)}
|
||||||
|
}
|
||||||
|
fn to_u32(&self) -> Option<u32> {
|
||||||
|
if *self > u32::max_value() as u64 {None} else {Some(*self as u32)}
|
||||||
|
}
|
||||||
|
fn to_u64(&self) -> Option<u64> {
|
||||||
|
Some(*self)
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,13 +11,14 @@
|
||||||
//! A helper class for dealing with static archives
|
//! A helper class for dealing with static archives
|
||||||
|
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::fs;
|
use std::fs::{self, File};
|
||||||
use std::io::prelude::*;
|
use std::io::prelude::*;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::process::{Command, Output, Stdio};
|
use std::process::{Command, Output, Stdio};
|
||||||
use std::str;
|
use std::str;
|
||||||
use syntax::diagnostic::Handler as ErrorHandler;
|
use syntax::diagnostic::Handler as ErrorHandler;
|
||||||
|
use rustc_llvm::archive_ro::ArchiveRO;
|
||||||
|
|
||||||
use tempdir::TempDir;
|
use tempdir::TempDir;
|
||||||
|
|
||||||
|
@ -282,17 +283,14 @@ impl<'a> ArchiveBuilder<'a> {
|
||||||
mut skip: F) -> io::Result<()>
|
mut skip: F) -> io::Result<()>
|
||||||
where F: FnMut(&str) -> bool,
|
where F: FnMut(&str) -> bool,
|
||||||
{
|
{
|
||||||
let loc = TempDir::new("rsar").unwrap();
|
let archive = match ArchiveRO::open(archive) {
|
||||||
|
Some(ar) => ar,
|
||||||
// First, extract the contents of the archive to a temporary directory.
|
None => return Err(io::Error::new(io::ErrorKind::Other,
|
||||||
// We don't unpack directly into `self.work_dir` due to the possibility
|
"failed to open archive")),
|
||||||
// of filename collisions.
|
};
|
||||||
let archive = env::current_dir().unwrap().join(archive);
|
|
||||||
run_ar(self.archive.handler, &self.archive.maybe_ar_prog,
|
|
||||||
"x", Some(loc.path()), &[&archive]);
|
|
||||||
|
|
||||||
// Next, we must rename all of the inputs to "guaranteed unique names".
|
// Next, we must rename all of the inputs to "guaranteed unique names".
|
||||||
// We move each file into `self.work_dir` under its new unique name.
|
// We write each file into `self.work_dir` under its new unique name.
|
||||||
// The reason for this renaming is that archives are keyed off the name
|
// The reason for this renaming is that archives are keyed off the name
|
||||||
// of the files, so if two files have the same name they will override
|
// of the files, so if two files have the same name they will override
|
||||||
// one another in the archive (bad).
|
// one another in the archive (bad).
|
||||||
|
@ -300,27 +298,46 @@ impl<'a> ArchiveBuilder<'a> {
|
||||||
// We skip any files explicitly desired for skipping, and we also skip
|
// We skip any files explicitly desired for skipping, and we also skip
|
||||||
// all SYMDEF files as these are just magical placeholders which get
|
// all SYMDEF files as these are just magical placeholders which get
|
||||||
// re-created when we make a new archive anyway.
|
// re-created when we make a new archive anyway.
|
||||||
let files = try!(fs::read_dir(loc.path()));
|
for file in archive.iter() {
|
||||||
for file in files {
|
let filename = match file.name() {
|
||||||
let file = try!(file).path();
|
Some(s) => s,
|
||||||
let filename = file.file_name().unwrap().to_str().unwrap();
|
None => continue,
|
||||||
if skip(filename) { continue }
|
|
||||||
if filename.contains(".SYMDEF") { continue }
|
|
||||||
|
|
||||||
let filename = format!("r-{}-{}", name, filename);
|
|
||||||
// LLDB (as mentioned in back::link) crashes on filenames of exactly
|
|
||||||
// 16 bytes in length. If we're including an object file with
|
|
||||||
// exactly 16-bytes of characters, give it some prefix so that it's
|
|
||||||
// not 16 bytes.
|
|
||||||
let filename = if filename.len() == 16 {
|
|
||||||
format!("lldb-fix-{}", filename)
|
|
||||||
} else {
|
|
||||||
filename
|
|
||||||
};
|
};
|
||||||
let new_filename = self.work_dir.path().join(&filename[..]);
|
if filename.contains(".SYMDEF") { continue }
|
||||||
try!(fs::rename(&file, &new_filename));
|
if skip(filename) { continue }
|
||||||
self.members.push(PathBuf::from(filename));
|
|
||||||
|
// An archive can contain files of the same name multiple times, so
|
||||||
|
// we need to be sure to not have them overwrite one another when we
|
||||||
|
// extract them. Consequently we need to find a truly unique file
|
||||||
|
// name for us!
|
||||||
|
let mut new_filename = String::new();
|
||||||
|
for n in 0.. {
|
||||||
|
let n = if n == 0 {String::new()} else {format!("-{}", n)};
|
||||||
|
new_filename = format!("r{}-{}-{}", n, name, filename);
|
||||||
|
|
||||||
|
// LLDB (as mentioned in back::link) crashes on filenames of
|
||||||
|
// exactly
|
||||||
|
// 16 bytes in length. If we're including an object file with
|
||||||
|
// exactly 16-bytes of characters, give it some prefix so
|
||||||
|
// that it's not 16 bytes.
|
||||||
|
new_filename = if new_filename.len() == 16 {
|
||||||
|
format!("lldb-fix-{}", new_filename)
|
||||||
|
} else {
|
||||||
|
new_filename
|
||||||
|
};
|
||||||
|
|
||||||
|
let present = self.members.iter().filter_map(|p| {
|
||||||
|
p.file_name().and_then(|f| f.to_str())
|
||||||
|
}).any(|s| s == new_filename);
|
||||||
|
if !present {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let dst = self.work_dir.path().join(&new_filename);
|
||||||
|
try!(try!(File::create(&dst)).write_all(file.data()));
|
||||||
|
self.members.push(PathBuf::from(new_filename));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,6 +46,7 @@
|
||||||
extern crate syntax;
|
extern crate syntax;
|
||||||
extern crate libc;
|
extern crate libc;
|
||||||
extern crate serialize;
|
extern crate serialize;
|
||||||
|
extern crate rustc_llvm;
|
||||||
#[macro_use] extern crate log;
|
#[macro_use] extern crate log;
|
||||||
|
|
||||||
pub mod abi;
|
pub mod abi;
|
||||||
|
|
|
@ -12,10 +12,7 @@
|
||||||
//! use. This implementation is not intended for external use or for any use where security is
|
//! use. This implementation is not intended for external use or for any use where security is
|
||||||
//! important.
|
//! important.
|
||||||
|
|
||||||
#![allow(deprecated)] // to_be32
|
|
||||||
|
|
||||||
use std::iter::repeat;
|
use std::iter::repeat;
|
||||||
use std::num::Int;
|
|
||||||
use std::slice::bytes::{MutableByteVector, copy_memory};
|
use std::slice::bytes::{MutableByteVector, copy_memory};
|
||||||
use serialize::hex::ToHex;
|
use serialize::hex::ToHex;
|
||||||
|
|
||||||
|
@ -61,10 +58,10 @@ impl ToBits for u64 {
|
||||||
|
|
||||||
/// Adds the specified number of bytes to the bit count. panic!() if this would cause numeric
|
/// Adds the specified number of bytes to the bit count. panic!() if this would cause numeric
|
||||||
/// overflow.
|
/// overflow.
|
||||||
fn add_bytes_to_bits<T: Int + ToBits>(bits: T, bytes: T) -> T {
|
fn add_bytes_to_bits(bits: u64, bytes: u64) -> u64 {
|
||||||
let (new_high_bits, new_low_bits) = bytes.to_bits();
|
let (new_high_bits, new_low_bits) = bytes.to_bits();
|
||||||
|
|
||||||
if new_high_bits > T::zero() {
|
if new_high_bits > 0 {
|
||||||
panic!("numeric overflow occurred.")
|
panic!("numeric overflow occurred.")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -543,14 +540,14 @@ mod tests {
|
||||||
// A normal addition - no overflow occurs
|
// A normal addition - no overflow occurs
|
||||||
#[test]
|
#[test]
|
||||||
fn test_add_bytes_to_bits_ok() {
|
fn test_add_bytes_to_bits_ok() {
|
||||||
assert!(super::add_bytes_to_bits::<u64>(100, 10) == 180);
|
assert!(super::add_bytes_to_bits(100, 10) == 180);
|
||||||
}
|
}
|
||||||
|
|
||||||
// A simple failure case - adding 1 to the max value
|
// A simple failure case - adding 1 to the max value
|
||||||
#[test]
|
#[test]
|
||||||
#[should_panic]
|
#[should_panic]
|
||||||
fn test_add_bytes_to_bits_overflow() {
|
fn test_add_bytes_to_bits_overflow() {
|
||||||
super::add_bytes_to_bits::<u64>(u64::MAX, 1);
|
super::add_bytes_to_bits(u64::MAX, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Test {
|
struct Test {
|
||||||
|
|
|
@ -10,15 +10,23 @@
|
||||||
|
|
||||||
//! A wrapper around LLVM's archive (.a) code
|
//! A wrapper around LLVM's archive (.a) code
|
||||||
|
|
||||||
use libc;
|
|
||||||
use ArchiveRef;
|
use ArchiveRef;
|
||||||
|
|
||||||
use std::ffi::CString;
|
use std::ffi::CString;
|
||||||
use std::slice;
|
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
use std::slice;
|
||||||
|
use std::str;
|
||||||
|
|
||||||
pub struct ArchiveRO {
|
pub struct ArchiveRO { ptr: ArchiveRef }
|
||||||
ptr: ArchiveRef,
|
|
||||||
|
pub struct Iter<'a> {
|
||||||
|
archive: &'a ArchiveRO,
|
||||||
|
ptr: ::ArchiveIteratorRef,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Child<'a> {
|
||||||
|
name: Option<&'a str>,
|
||||||
|
data: &'a [u8],
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ArchiveRO {
|
impl ArchiveRO {
|
||||||
|
@ -52,18 +60,9 @@ impl ArchiveRO {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reads a file in the archive
|
pub fn iter(&self) -> Iter {
|
||||||
pub fn read<'a>(&'a self, file: &str) -> Option<&'a [u8]> {
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut size = 0 as libc::size_t;
|
Iter { ptr: ::LLVMRustArchiveIteratorNew(self.ptr), archive: self }
|
||||||
let file = CString::new(file).unwrap();
|
|
||||||
let ptr = ::LLVMRustArchiveReadSection(self.ptr, file.as_ptr(),
|
|
||||||
&mut size);
|
|
||||||
if ptr.is_null() {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
Some(slice::from_raw_parts(ptr as *const u8, size as usize))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -75,3 +74,47 @@ impl Drop for ArchiveRO {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a> Iterator for Iter<'a> {
|
||||||
|
type Item = Child<'a>;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Child<'a>> {
|
||||||
|
unsafe {
|
||||||
|
let ptr = ::LLVMRustArchiveIteratorCurrent(self.ptr);
|
||||||
|
if ptr.is_null() {
|
||||||
|
return None
|
||||||
|
}
|
||||||
|
let mut name_len = 0;
|
||||||
|
let name_ptr = ::LLVMRustArchiveChildName(ptr, &mut name_len);
|
||||||
|
let mut data_len = 0;
|
||||||
|
let data_ptr = ::LLVMRustArchiveChildData(ptr, &mut data_len);
|
||||||
|
let child = Child {
|
||||||
|
name: if name_ptr.is_null() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
let name = slice::from_raw_parts(name_ptr as *const u8,
|
||||||
|
name_len as usize);
|
||||||
|
str::from_utf8(name).ok().map(|s| s.trim())
|
||||||
|
},
|
||||||
|
data: slice::from_raw_parts(data_ptr as *const u8,
|
||||||
|
data_len as usize),
|
||||||
|
};
|
||||||
|
::LLVMRustArchiveIteratorNext(self.ptr);
|
||||||
|
Some(child)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unsafe_destructor]
|
||||||
|
impl<'a> Drop for Iter<'a> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe {
|
||||||
|
::LLVMRustArchiveIteratorFree(self.ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Child<'a> {
|
||||||
|
pub fn name(&self) -> Option<&'a str> { self.name }
|
||||||
|
pub fn data(&self) -> &'a [u8] { self.data }
|
||||||
|
}
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
#![feature(libc)]
|
#![feature(libc)]
|
||||||
#![feature(link_args)]
|
#![feature(link_args)]
|
||||||
#![feature(staged_api)]
|
#![feature(staged_api)]
|
||||||
|
#![feature(unsafe_destructor)]
|
||||||
|
|
||||||
extern crate libc;
|
extern crate libc;
|
||||||
#[macro_use] #[no_link] extern crate rustc_bitflags;
|
#[macro_use] #[no_link] extern crate rustc_bitflags;
|
||||||
|
@ -488,9 +489,12 @@ pub type PassRef = *mut Pass_opaque;
|
||||||
#[allow(missing_copy_implementations)]
|
#[allow(missing_copy_implementations)]
|
||||||
pub enum TargetMachine_opaque {}
|
pub enum TargetMachine_opaque {}
|
||||||
pub type TargetMachineRef = *mut TargetMachine_opaque;
|
pub type TargetMachineRef = *mut TargetMachine_opaque;
|
||||||
#[allow(missing_copy_implementations)]
|
|
||||||
pub enum Archive_opaque {}
|
pub enum Archive_opaque {}
|
||||||
pub type ArchiveRef = *mut Archive_opaque;
|
pub type ArchiveRef = *mut Archive_opaque;
|
||||||
|
pub enum ArchiveIterator_opaque {}
|
||||||
|
pub type ArchiveIteratorRef = *mut ArchiveIterator_opaque;
|
||||||
|
pub enum ArchiveChild_opaque {}
|
||||||
|
pub type ArchiveChildRef = *mut ArchiveChild_opaque;
|
||||||
#[allow(missing_copy_implementations)]
|
#[allow(missing_copy_implementations)]
|
||||||
pub enum Twine_opaque {}
|
pub enum Twine_opaque {}
|
||||||
pub type TwineRef = *mut Twine_opaque;
|
pub type TwineRef = *mut Twine_opaque;
|
||||||
|
@ -2051,13 +2055,17 @@ extern {
|
||||||
pub fn LLVMRustMarkAllFunctionsNounwind(M: ModuleRef);
|
pub fn LLVMRustMarkAllFunctionsNounwind(M: ModuleRef);
|
||||||
|
|
||||||
pub fn LLVMRustOpenArchive(path: *const c_char) -> ArchiveRef;
|
pub fn LLVMRustOpenArchive(path: *const c_char) -> ArchiveRef;
|
||||||
pub fn LLVMRustArchiveReadSection(AR: ArchiveRef, name: *const c_char,
|
pub fn LLVMRustArchiveIteratorNew(AR: ArchiveRef) -> ArchiveIteratorRef;
|
||||||
out_len: *mut size_t) -> *const c_char;
|
pub fn LLVMRustArchiveIteratorNext(AIR: ArchiveIteratorRef);
|
||||||
|
pub fn LLVMRustArchiveIteratorCurrent(AIR: ArchiveIteratorRef) -> ArchiveChildRef;
|
||||||
|
pub fn LLVMRustArchiveChildName(ACR: ArchiveChildRef,
|
||||||
|
size: *mut size_t) -> *const c_char;
|
||||||
|
pub fn LLVMRustArchiveChildData(ACR: ArchiveChildRef,
|
||||||
|
size: *mut size_t) -> *const c_char;
|
||||||
|
pub fn LLVMRustArchiveIteratorFree(AIR: ArchiveIteratorRef);
|
||||||
pub fn LLVMRustDestroyArchive(AR: ArchiveRef);
|
pub fn LLVMRustDestroyArchive(AR: ArchiveRef);
|
||||||
|
|
||||||
pub fn LLVMRustSetDLLExportStorageClass(V: ValueRef);
|
pub fn LLVMRustSetDLLExportStorageClass(V: ValueRef);
|
||||||
pub fn LLVMVersionMajor() -> c_int;
|
|
||||||
pub fn LLVMVersionMinor() -> c_int;
|
|
||||||
|
|
||||||
pub fn LLVMRustGetSectionName(SI: SectionIteratorRef,
|
pub fn LLVMRustGetSectionName(SI: SectionIteratorRef,
|
||||||
data: *mut *const c_char) -> c_int;
|
data: *mut *const c_char) -> c_int;
|
||||||
|
|
|
@ -21,9 +21,6 @@ use libc;
|
||||||
use flate;
|
use flate;
|
||||||
|
|
||||||
use std::ffi::CString;
|
use std::ffi::CString;
|
||||||
use std::mem;
|
|
||||||
#[allow(deprecated)]
|
|
||||||
use std::num::Int;
|
|
||||||
|
|
||||||
pub fn run(sess: &session::Session, llmod: ModuleRef,
|
pub fn run(sess: &session::Session, llmod: ModuleRef,
|
||||||
tm: TargetMachineRef, reachable: &[String]) {
|
tm: TargetMachineRef, reachable: &[String]) {
|
||||||
|
@ -63,13 +60,13 @@ pub fn run(sess: &session::Session, llmod: ModuleRef,
|
||||||
let file = &file[3..file.len() - 5]; // chop off lib/.rlib
|
let file = &file[3..file.len() - 5]; // chop off lib/.rlib
|
||||||
debug!("reading {}", file);
|
debug!("reading {}", file);
|
||||||
for i in 0.. {
|
for i in 0.. {
|
||||||
let bc_encoded = time(sess.time_passes(),
|
let filename = format!("{}.{}.bytecode.deflate", file, i);
|
||||||
&format!("check for {}.{}.bytecode.deflate", name, i),
|
let msg = format!("check for {}", filename);
|
||||||
(),
|
let bc_encoded = time(sess.time_passes(), &msg, (), |_| {
|
||||||
|_| {
|
archive.iter().find(|section| {
|
||||||
archive.read(&format!("{}.{}.bytecode.deflate",
|
section.name() == Some(&filename[..])
|
||||||
file, i))
|
})
|
||||||
});
|
});
|
||||||
let bc_encoded = match bc_encoded {
|
let bc_encoded = match bc_encoded {
|
||||||
Some(data) => data,
|
Some(data) => data,
|
||||||
None => {
|
None => {
|
||||||
|
@ -79,9 +76,10 @@ pub fn run(sess: &session::Session, llmod: ModuleRef,
|
||||||
path.display()));
|
path.display()));
|
||||||
}
|
}
|
||||||
// No more bitcode files to read.
|
// No more bitcode files to read.
|
||||||
break;
|
break
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
|
let bc_encoded = bc_encoded.data();
|
||||||
|
|
||||||
let bc_decoded = if is_versioned_bytecode_format(bc_encoded) {
|
let bc_decoded = if is_versioned_bytecode_format(bc_encoded) {
|
||||||
time(sess.time_passes(), &format!("decode {}.{}.bc", file, i), (), |_| {
|
time(sess.time_passes(), &format!("decode {}.{}.bc", file, i), (), |_| {
|
||||||
|
@ -198,19 +196,15 @@ fn is_versioned_bytecode_format(bc: &[u8]) -> bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn extract_bytecode_format_version(bc: &[u8]) -> u32 {
|
fn extract_bytecode_format_version(bc: &[u8]) -> u32 {
|
||||||
return read_from_le_bytes::<u32>(bc, link::RLIB_BYTECODE_OBJECT_VERSION_OFFSET);
|
let pos = link::RLIB_BYTECODE_OBJECT_VERSION_OFFSET;
|
||||||
|
let byte_data = &bc[pos..pos + 4];
|
||||||
|
let data = unsafe { *(byte_data.as_ptr() as *const u32) };
|
||||||
|
u32::from_le(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn extract_compressed_bytecode_size_v1(bc: &[u8]) -> u64 {
|
fn extract_compressed_bytecode_size_v1(bc: &[u8]) -> u64 {
|
||||||
return read_from_le_bytes::<u64>(bc, link::RLIB_BYTECODE_OBJECT_V1_DATASIZE_OFFSET);
|
let pos = link::RLIB_BYTECODE_OBJECT_V1_DATASIZE_OFFSET;
|
||||||
}
|
let byte_data = &bc[pos..pos + 8];
|
||||||
|
let data = unsafe { *(byte_data.as_ptr() as *const u64) };
|
||||||
#[allow(deprecated)]
|
u64::from_le(data)
|
||||||
fn read_from_le_bytes<T: Int>(bytes: &[u8], position_in_bytes: usize) -> T {
|
|
||||||
let byte_data = &bytes[position_in_bytes..position_in_bytes + mem::size_of::<T>()];
|
|
||||||
let data = unsafe {
|
|
||||||
*(byte_data.as_ptr() as *const T)
|
|
||||||
};
|
|
||||||
|
|
||||||
Int::from_le(data)
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -348,7 +348,7 @@ unsafe extern "C" fn report_inline_asm<'a, 'b>(cgcx: &'a CodegenContext<'a>,
|
||||||
|
|
||||||
match cgcx.lto_ctxt {
|
match cgcx.lto_ctxt {
|
||||||
Some((sess, _)) => {
|
Some((sess, _)) => {
|
||||||
sess.codemap().with_expn_info(ExpnId::from_llvm_cookie(cookie), |info| match info {
|
sess.codemap().with_expn_info(ExpnId::from_u32(cookie), |info| match info {
|
||||||
Some(ei) => sess.span_err(ei.call_site, msg),
|
Some(ei) => sess.span_err(ei.call_site, msg),
|
||||||
None => sess.err(msg),
|
None => sess.err(msg),
|
||||||
});
|
});
|
||||||
|
|
|
@ -45,8 +45,6 @@
|
||||||
|
|
||||||
pub use self::Repr::*;
|
pub use self::Repr::*;
|
||||||
|
|
||||||
#[allow(deprecated)]
|
|
||||||
use std::num::Int;
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use llvm::{ValueRef, True, IntEQ, IntNE};
|
use llvm::{ValueRef, True, IntEQ, IntNE};
|
||||||
|
|
|
@ -138,7 +138,7 @@ pub fn trans_inline_asm<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ia: &ast::InlineAsm)
|
||||||
let kind = llvm::LLVMGetMDKindIDInContext(bcx.ccx().llcx(),
|
let kind = llvm::LLVMGetMDKindIDInContext(bcx.ccx().llcx(),
|
||||||
key.as_ptr() as *const c_char, key.len() as c_uint);
|
key.as_ptr() as *const c_char, key.len() as c_uint);
|
||||||
|
|
||||||
let val: llvm::ValueRef = C_i32(bcx.ccx(), ia.expn_id.to_llvm_cookie());
|
let val: llvm::ValueRef = C_i32(bcx.ccx(), ia.expn_id.into_u32() as i32);
|
||||||
|
|
||||||
llvm::LLVMSetMetadata(r, kind,
|
llvm::LLVMSetMetadata(r, kind,
|
||||||
llvm::LLVMMDNodeInContext(bcx.ccx().llcx(), &val, 1));
|
llvm::LLVMMDNodeInContext(bcx.ccx().llcx(), &val, 1));
|
||||||
|
|
|
@ -878,16 +878,7 @@ fn declare_intrinsic(ccx: &CrateContext, key: & &'static str) -> Option<ValueRef
|
||||||
// were introduced in LLVM 3.4, so we case on that.
|
// were introduced in LLVM 3.4, so we case on that.
|
||||||
macro_rules! compatible_ifn {
|
macro_rules! compatible_ifn {
|
||||||
($name:expr, $cname:ident ($($arg:expr),*) -> $ret:expr) => (
|
($name:expr, $cname:ident ($($arg:expr),*) -> $ret:expr) => (
|
||||||
if unsafe { llvm::LLVMVersionMinor() >= 4 } {
|
ifn!($name, fn($($arg),*) -> $ret);
|
||||||
// The `if key == $name` is already in ifn!
|
|
||||||
ifn!($name, fn($($arg),*) -> $ret);
|
|
||||||
} else if *key == $name {
|
|
||||||
let f = declare::declare_cfn(ccx, stringify!($cname),
|
|
||||||
Type::func(&[$($arg),*], &$ret),
|
|
||||||
ty::mk_nil(ccx.tcx()));
|
|
||||||
ccx.intrinsics().borrow_mut().insert($name, f.clone());
|
|
||||||
return Some(f);
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2653,26 +2653,8 @@ fn set_members_of_composite_type(cx: &CrateContext,
|
||||||
let mut composite_types_completed =
|
let mut composite_types_completed =
|
||||||
debug_context(cx).composite_types_completed.borrow_mut();
|
debug_context(cx).composite_types_completed.borrow_mut();
|
||||||
if composite_types_completed.contains(&composite_type_metadata) {
|
if composite_types_completed.contains(&composite_type_metadata) {
|
||||||
let (llvm_version_major, llvm_version_minor) = unsafe {
|
cx.sess().bug("debuginfo::set_members_of_composite_type() - \
|
||||||
(llvm::LLVMVersionMajor(), llvm::LLVMVersionMinor())
|
Already completed forward declaration re-encountered.");
|
||||||
};
|
|
||||||
|
|
||||||
let actual_llvm_version = llvm_version_major * 1000000 + llvm_version_minor * 1000;
|
|
||||||
let min_supported_llvm_version = 3 * 1000000 + 4 * 1000;
|
|
||||||
|
|
||||||
if actual_llvm_version < min_supported_llvm_version {
|
|
||||||
cx.sess().warn(&format!("This version of rustc was built with LLVM \
|
|
||||||
{}.{}. Rustc just ran into a known \
|
|
||||||
debuginfo corruption problem thatoften \
|
|
||||||
occurs with LLVM versions below 3.4. \
|
|
||||||
Please use a rustc built with anewer \
|
|
||||||
version of LLVM.",
|
|
||||||
llvm_version_major,
|
|
||||||
llvm_version_minor));
|
|
||||||
} else {
|
|
||||||
cx.sess().bug("debuginfo::set_members_of_composite_type() - \
|
|
||||||
Already completed forward declaration re-encountered.");
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
composite_types_completed.insert(composite_type_metadata);
|
composite_types_completed.insert(composite_type_metadata);
|
||||||
}
|
}
|
||||||
|
|
|
@ -746,11 +746,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
|
||||||
let src = to_arg_ty(bcx, llargs[2], tp_ty);
|
let src = to_arg_ty(bcx, llargs[2], tp_ty);
|
||||||
let res = AtomicCmpXchg(bcx, ptr, cmp, src, order,
|
let res = AtomicCmpXchg(bcx, ptr, cmp, src, order,
|
||||||
strongest_failure_ordering);
|
strongest_failure_ordering);
|
||||||
if unsafe { llvm::LLVMVersionMinor() >= 5 } {
|
ExtractValue(bcx, res, 0)
|
||||||
ExtractValue(bcx, res, 0)
|
|
||||||
} else {
|
|
||||||
res
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
"load" => {
|
"load" => {
|
||||||
|
|
|
@ -21,8 +21,6 @@ use util::ppaux::Repr;
|
||||||
|
|
||||||
use trans::type_::Type;
|
use trans::type_::Type;
|
||||||
|
|
||||||
#[allow(deprecated)]
|
|
||||||
use std::num::Int;
|
|
||||||
use syntax::abi;
|
use syntax::abi;
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
|
|
||||||
|
|
|
@ -45,7 +45,7 @@ mod u_str;
|
||||||
pub mod char;
|
pub mod char;
|
||||||
|
|
||||||
pub mod str {
|
pub mod str {
|
||||||
pub use u_str::{UnicodeStr, Words, Graphemes, GraphemeIndices};
|
pub use u_str::{UnicodeStr, SplitWhitespace, Words, Graphemes, GraphemeIndices};
|
||||||
pub use u_str::{utf8_char_width, is_utf16, Utf16Items, Utf16Item};
|
pub use u_str::{utf8_char_width, is_utf16, Utf16Items, Utf16Item};
|
||||||
pub use u_str::{utf16_items, Utf16Encoder};
|
pub use u_str::{utf16_items, Utf16Encoder};
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,9 +25,16 @@ use core::str::Split;
|
||||||
|
|
||||||
use tables::grapheme::GraphemeCat;
|
use tables::grapheme::GraphemeCat;
|
||||||
|
|
||||||
/// An iterator over the words of a string, separated by a sequence of whitespace
|
#[deprecated(reason = "struct Words is being replaced by struct SplitWhitespace",
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
since = "1.1.0")]
|
||||||
pub struct Words<'a> {
|
#[unstable(feature = "str_words",
|
||||||
|
reason = "words() will be replaced by split_whitespace() in 1.1.0")]
|
||||||
|
pub type Words<'a> = SplitWhitespace<'a>;
|
||||||
|
|
||||||
|
/// An iterator over the non-whitespace substrings of a string,
|
||||||
|
/// separated by any amount of whitespace.
|
||||||
|
#[stable(feature = "split_whitespace", since = "1.1.0")]
|
||||||
|
pub struct SplitWhitespace<'a> {
|
||||||
inner: Filter<Split<'a, fn(char) -> bool>, fn(&&str) -> bool>,
|
inner: Filter<Split<'a, fn(char) -> bool>, fn(&&str) -> bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,7 +43,9 @@ pub struct Words<'a> {
|
||||||
pub trait UnicodeStr {
|
pub trait UnicodeStr {
|
||||||
fn graphemes<'a>(&'a self, is_extended: bool) -> Graphemes<'a>;
|
fn graphemes<'a>(&'a self, is_extended: bool) -> Graphemes<'a>;
|
||||||
fn grapheme_indices<'a>(&'a self, is_extended: bool) -> GraphemeIndices<'a>;
|
fn grapheme_indices<'a>(&'a self, is_extended: bool) -> GraphemeIndices<'a>;
|
||||||
|
#[allow(deprecated)]
|
||||||
fn words<'a>(&'a self) -> Words<'a>;
|
fn words<'a>(&'a self) -> Words<'a>;
|
||||||
|
fn split_whitespace<'a>(&'a self) -> SplitWhitespace<'a>;
|
||||||
fn is_whitespace(&self) -> bool;
|
fn is_whitespace(&self) -> bool;
|
||||||
fn is_alphanumeric(&self) -> bool;
|
fn is_alphanumeric(&self) -> bool;
|
||||||
fn width(&self, is_cjk: bool) -> usize;
|
fn width(&self, is_cjk: bool) -> usize;
|
||||||
|
@ -56,15 +65,21 @@ impl UnicodeStr for str {
|
||||||
GraphemeIndices { start_offset: self.as_ptr() as usize, iter: self.graphemes(is_extended) }
|
GraphemeIndices { start_offset: self.as_ptr() as usize, iter: self.graphemes(is_extended) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(deprecated)]
|
||||||
#[inline]
|
#[inline]
|
||||||
fn words(&self) -> Words {
|
fn words(&self) -> Words {
|
||||||
|
self.split_whitespace()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn split_whitespace(&self) -> SplitWhitespace {
|
||||||
fn is_not_empty(s: &&str) -> bool { !s.is_empty() }
|
fn is_not_empty(s: &&str) -> bool { !s.is_empty() }
|
||||||
let is_not_empty: fn(&&str) -> bool = is_not_empty; // coerce to fn pointer
|
let is_not_empty: fn(&&str) -> bool = is_not_empty; // coerce to fn pointer
|
||||||
|
|
||||||
fn is_whitespace(c: char) -> bool { c.is_whitespace() }
|
fn is_whitespace(c: char) -> bool { c.is_whitespace() }
|
||||||
let is_whitespace: fn(char) -> bool = is_whitespace; // coerce to fn pointer
|
let is_whitespace: fn(char) -> bool = is_whitespace; // coerce to fn pointer
|
||||||
|
|
||||||
Words { inner: self.split(is_whitespace).filter(is_not_empty) }
|
SplitWhitespace { inner: self.split(is_whitespace).filter(is_not_empty) }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -545,11 +560,11 @@ impl<I> Iterator for Utf16Encoder<I> where I: Iterator<Item=char> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Iterator for Words<'a> {
|
impl<'a> Iterator for SplitWhitespace<'a> {
|
||||||
type Item = &'a str;
|
type Item = &'a str;
|
||||||
|
|
||||||
fn next(&mut self) -> Option<&'a str> { self.inner.next() }
|
fn next(&mut self) -> Option<&'a str> { self.inner.next() }
|
||||||
}
|
}
|
||||||
impl<'a> DoubleEndedIterator for Words<'a> {
|
impl<'a> DoubleEndedIterator for SplitWhitespace<'a> {
|
||||||
fn next_back(&mut self) -> Option<&'a str> { self.inner.next_back() }
|
fn next_back(&mut self) -> Option<&'a str> { self.inner.next_back() }
|
||||||
}
|
}
|
||||||
|
|
|
@ -274,7 +274,7 @@ pub fn render(w: &mut fmt::Formatter, s: &str, print_toc: bool) -> fmt::Result {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Transform the contents of the header into a hyphenated string
|
// Transform the contents of the header into a hyphenated string
|
||||||
let id = s.words().map(|s| s.to_ascii_lowercase())
|
let id = s.split_whitespace().map(|s| s.to_ascii_lowercase())
|
||||||
.collect::<Vec<String>>().connect("-");
|
.collect::<Vec<String>>().connect("-");
|
||||||
|
|
||||||
// This is a terrible hack working around how hoedown gives us rendered
|
// This is a terrible hack working around how hoedown gives us rendered
|
||||||
|
|
|
@ -31,7 +31,6 @@
|
||||||
#![feature(std_misc)]
|
#![feature(std_misc)]
|
||||||
#![feature(test)]
|
#![feature(test)]
|
||||||
#![feature(unicode)]
|
#![feature(unicode)]
|
||||||
#![feature(str_words)]
|
|
||||||
#![feature(path_ext)]
|
#![feature(path_ext)]
|
||||||
#![feature(path_relative_from)]
|
#![feature(path_relative_from)]
|
||||||
#![feature(slice_patterns)]
|
#![feature(slice_patterns)]
|
||||||
|
@ -240,7 +239,7 @@ pub fn main_args(args: &[String]) -> isize {
|
||||||
|
|
||||||
let test_args = matches.opt_strs("test-args");
|
let test_args = matches.opt_strs("test-args");
|
||||||
let test_args: Vec<String> = test_args.iter()
|
let test_args: Vec<String> = test_args.iter()
|
||||||
.flat_map(|s| s.words())
|
.flat_map(|s| s.split_whitespace())
|
||||||
.map(|s| s.to_string())
|
.map(|s| s.to_string())
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
@ -404,13 +403,13 @@ fn rust_input(cratefile: &str, externs: core::Externs, matches: &getopts::Matche
|
||||||
}
|
}
|
||||||
clean::NameValue(ref x, ref value)
|
clean::NameValue(ref x, ref value)
|
||||||
if "passes" == *x => {
|
if "passes" == *x => {
|
||||||
for pass in value.words() {
|
for pass in value.split_whitespace() {
|
||||||
passes.push(pass.to_string());
|
passes.push(pass.to_string());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
clean::NameValue(ref x, ref value)
|
clean::NameValue(ref x, ref value)
|
||||||
if "plugins" == *x => {
|
if "plugins" == *x => {
|
||||||
for p in value.words() {
|
for p in value.split_whitespace() {
|
||||||
plugins.push(p.to_string());
|
plugins.push(p.to_string());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -204,12 +204,10 @@ use std::io::prelude::*;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::mem::swap;
|
use std::mem::swap;
|
||||||
use std::num::FpCategory as Fp;
|
use std::num::FpCategory as Fp;
|
||||||
#[allow(deprecated)]
|
|
||||||
use std::num::wrapping::WrappingOps;
|
|
||||||
use std::ops::Index;
|
use std::ops::Index;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::string;
|
use std::string;
|
||||||
use std::{char, f64, fmt, num, str};
|
use std::{char, f64, fmt, str};
|
||||||
use std;
|
use std;
|
||||||
use rustc_unicode::str as unicode_str;
|
use rustc_unicode::str as unicode_str;
|
||||||
use rustc_unicode::str::Utf16Item;
|
use rustc_unicode::str::Utf16Item;
|
||||||
|
@ -460,8 +458,8 @@ fn spaces(wr: &mut fmt::Write, mut n: usize) -> EncodeResult {
|
||||||
fn fmt_number_or_null(v: f64) -> string::String {
|
fn fmt_number_or_null(v: f64) -> string::String {
|
||||||
match v.classify() {
|
match v.classify() {
|
||||||
Fp::Nan | Fp::Infinite => string::String::from_str("null"),
|
Fp::Nan | Fp::Infinite => string::String::from_str("null"),
|
||||||
_ if v.fract() != 0f64 => f64::to_str_digits(v, 6),
|
_ if v.fract() != 0f64 => v.to_string(),
|
||||||
_ => f64::to_str_digits(v, 6) + ".0",
|
_ => v.to_string() + ".0",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1165,7 +1163,7 @@ impl Json {
|
||||||
pub fn as_i64(&self) -> Option<i64> {
|
pub fn as_i64(&self) -> Option<i64> {
|
||||||
match *self {
|
match *self {
|
||||||
Json::I64(n) => Some(n),
|
Json::I64(n) => Some(n),
|
||||||
Json::U64(n) => num::cast(n),
|
Json::U64(n) => Some(n as i64),
|
||||||
_ => None
|
_ => None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1174,7 +1172,7 @@ impl Json {
|
||||||
/// Returns None otherwise.
|
/// Returns None otherwise.
|
||||||
pub fn as_u64(&self) -> Option<u64> {
|
pub fn as_u64(&self) -> Option<u64> {
|
||||||
match *self {
|
match *self {
|
||||||
Json::I64(n) => num::cast(n),
|
Json::I64(n) => Some(n as u64),
|
||||||
Json::U64(n) => Some(n),
|
Json::U64(n) => Some(n),
|
||||||
_ => None
|
_ => None
|
||||||
}
|
}
|
||||||
|
@ -1184,8 +1182,8 @@ impl Json {
|
||||||
/// Returns None otherwise.
|
/// Returns None otherwise.
|
||||||
pub fn as_f64(&self) -> Option<f64> {
|
pub fn as_f64(&self) -> Option<f64> {
|
||||||
match *self {
|
match *self {
|
||||||
Json::I64(n) => num::cast(n),
|
Json::I64(n) => Some(n as f64),
|
||||||
Json::U64(n) => num::cast(n),
|
Json::U64(n) => Some(n as f64),
|
||||||
Json::F64(n) => Some(n),
|
Json::F64(n) => Some(n),
|
||||||
_ => None
|
_ => None
|
||||||
}
|
}
|
||||||
|
@ -1556,7 +1554,7 @@ impl<T: Iterator<Item=char>> Parser<T> {
|
||||||
|
|
||||||
#[allow(deprecated)] // possible resolve bug is mapping these to traits
|
#[allow(deprecated)] // possible resolve bug is mapping these to traits
|
||||||
fn parse_u64(&mut self) -> Result<u64, ParserError> {
|
fn parse_u64(&mut self) -> Result<u64, ParserError> {
|
||||||
let mut accum = 0;
|
let mut accum = 0u64;
|
||||||
let last_accum = 0; // necessary to detect overflow.
|
let last_accum = 0; // necessary to detect overflow.
|
||||||
|
|
||||||
match self.ch_or_null() {
|
match self.ch_or_null() {
|
||||||
|
@ -2059,7 +2057,7 @@ impl<T: Iterator<Item=char>> Builder<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Decodes a json value from an `&mut old_io::Reader`
|
/// Decodes a json value from an `&mut io::Read`
|
||||||
pub fn from_reader(rdr: &mut Read) -> Result<Json, BuilderError> {
|
pub fn from_reader(rdr: &mut Read) -> Result<Json, BuilderError> {
|
||||||
let mut contents = Vec::new();
|
let mut contents = Vec::new();
|
||||||
match rdr.read_to_end(&mut contents) {
|
match rdr.read_to_end(&mut contents) {
|
||||||
|
@ -2121,14 +2119,8 @@ macro_rules! read_primitive {
|
||||||
($name:ident, $ty:ty) => {
|
($name:ident, $ty:ty) => {
|
||||||
fn $name(&mut self) -> DecodeResult<$ty> {
|
fn $name(&mut self) -> DecodeResult<$ty> {
|
||||||
match self.pop() {
|
match self.pop() {
|
||||||
Json::I64(f) => match num::cast(f) {
|
Json::I64(f) => Ok(f as $ty),
|
||||||
Some(f) => Ok(f),
|
Json::U64(f) => Ok(f as $ty),
|
||||||
None => Err(ExpectedError("Number".to_string(), format!("{}", f))),
|
|
||||||
},
|
|
||||||
Json::U64(f) => match num::cast(f) {
|
|
||||||
Some(f) => Ok(f),
|
|
||||||
None => Err(ExpectedError("Number".to_string(), format!("{}", f))),
|
|
||||||
},
|
|
||||||
Json::F64(f) => Err(ExpectedError("Integer".to_string(), format!("{}", f))),
|
Json::F64(f) => Err(ExpectedError("Integer".to_string(), format!("{}", f))),
|
||||||
// re: #12967.. a type w/ numeric keys (ie HashMap<usize, V> etc)
|
// re: #12967.. a type w/ numeric keys (ie HashMap<usize, V> etc)
|
||||||
// is going to have a string here, as per JSON spec.
|
// is going to have a string here, as per JSON spec.
|
||||||
|
|
|
@ -914,33 +914,6 @@ impl<K, V, S> HashMap<K, V, S>
|
||||||
IterMut { inner: self.table.iter_mut() }
|
IterMut { inner: self.table.iter_mut() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a consuming iterator, that is, one that moves each key-value
|
|
||||||
/// pair out of the map in arbitrary order. The map cannot be used after
|
|
||||||
/// calling this.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use std::collections::HashMap;
|
|
||||||
///
|
|
||||||
/// let mut map = HashMap::new();
|
|
||||||
/// map.insert("a", 1);
|
|
||||||
/// map.insert("b", 2);
|
|
||||||
/// map.insert("c", 3);
|
|
||||||
///
|
|
||||||
/// // Not possible with .iter()
|
|
||||||
/// let vec: Vec<(&str, isize)> = map.into_iter().collect();
|
|
||||||
/// ```
|
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
|
||||||
pub fn into_iter(self) -> IntoIter<K, V> {
|
|
||||||
fn last_two<A, B, C>((_, b, c): (A, B, C)) -> (B, C) { (b, c) }
|
|
||||||
let last_two: fn((SafeHash, K, V)) -> (K, V) = last_two;
|
|
||||||
|
|
||||||
IntoIter {
|
|
||||||
inner: self.table.into_iter().map(last_two)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Gets the given key's corresponding entry in the map for in-place manipulation.
|
/// Gets the given key's corresponding entry in the map for in-place manipulation.
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub fn entry(&mut self, key: K) -> Entry<K, V> {
|
pub fn entry(&mut self, key: K) -> Entry<K, V> {
|
||||||
|
@ -1388,8 +1361,30 @@ impl<K, V, S> IntoIterator for HashMap<K, V, S>
|
||||||
type Item = (K, V);
|
type Item = (K, V);
|
||||||
type IntoIter = IntoIter<K, V>;
|
type IntoIter = IntoIter<K, V>;
|
||||||
|
|
||||||
|
/// Creates a consuming iterator, that is, one that moves each key-value
|
||||||
|
/// pair out of the map in arbitrary order. The map cannot be used after
|
||||||
|
/// calling this.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use std::collections::HashMap;
|
||||||
|
///
|
||||||
|
/// let mut map = HashMap::new();
|
||||||
|
/// map.insert("a", 1);
|
||||||
|
/// map.insert("b", 2);
|
||||||
|
/// map.insert("c", 3);
|
||||||
|
///
|
||||||
|
/// // Not possible with .iter()
|
||||||
|
/// let vec: Vec<(&str, isize)> = map.into_iter().collect();
|
||||||
|
/// ```
|
||||||
fn into_iter(self) -> IntoIter<K, V> {
|
fn into_iter(self) -> IntoIter<K, V> {
|
||||||
self.into_iter()
|
fn last_two<A, B, C>((_, b, c): (A, B, C)) -> (B, C) { (b, c) }
|
||||||
|
let last_two: fn((SafeHash, K, V)) -> (K, V) = last_two;
|
||||||
|
|
||||||
|
IntoIter {
|
||||||
|
inner: self.table.into_iter().map(last_two)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1625,7 +1620,7 @@ mod test_map {
|
||||||
|
|
||||||
use super::HashMap;
|
use super::HashMap;
|
||||||
use super::Entry::{Occupied, Vacant};
|
use super::Entry::{Occupied, Vacant};
|
||||||
use iter::{range_inclusive, range_step_inclusive, repeat};
|
use iter::{range_inclusive, repeat};
|
||||||
use cell::RefCell;
|
use cell::RefCell;
|
||||||
use rand::{thread_rng, Rng};
|
use rand::{thread_rng, Rng};
|
||||||
|
|
||||||
|
@ -1861,7 +1856,7 @@ mod test_map {
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove backwards
|
// remove backwards
|
||||||
for i in range_step_inclusive(1000, 1, -1) {
|
for i in (1..1001).rev() {
|
||||||
assert!(m.remove(&i).is_some());
|
assert!(m.remove(&i).is_some());
|
||||||
|
|
||||||
for j in range_inclusive(i, 1000) {
|
for j in range_inclusive(i, 1000) {
|
||||||
|
|
|
@ -269,34 +269,6 @@ impl<T, S> HashSet<T, S>
|
||||||
Iter { iter: self.map.keys() }
|
Iter { iter: self.map.keys() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a consuming iterator, that is, one that moves each value out
|
|
||||||
/// of the set in arbitrary order. The set cannot be used after calling
|
|
||||||
/// this.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use std::collections::HashSet;
|
|
||||||
/// let mut set = HashSet::new();
|
|
||||||
/// set.insert("a".to_string());
|
|
||||||
/// set.insert("b".to_string());
|
|
||||||
///
|
|
||||||
/// // Not possible to collect to a Vec<String> with a regular `.iter()`.
|
|
||||||
/// let v: Vec<String> = set.into_iter().collect();
|
|
||||||
///
|
|
||||||
/// // Will print in an arbitrary order.
|
|
||||||
/// for x in v.iter() {
|
|
||||||
/// println!("{}", x);
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
|
||||||
pub fn into_iter(self) -> IntoIter<T> {
|
|
||||||
fn first<A, B>((a, _): (A, B)) -> A { a }
|
|
||||||
let first: fn((T, ())) -> T = first;
|
|
||||||
|
|
||||||
IntoIter { iter: self.map.into_iter().map(first) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Visit the values representing the difference.
|
/// Visit the values representing the difference.
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
|
@ -848,8 +820,31 @@ impl<T, S> IntoIterator for HashSet<T, S>
|
||||||
type Item = T;
|
type Item = T;
|
||||||
type IntoIter = IntoIter<T>;
|
type IntoIter = IntoIter<T>;
|
||||||
|
|
||||||
|
/// Creates a consuming iterator, that is, one that moves each value out
|
||||||
|
/// of the set in arbitrary order. The set cannot be used after calling
|
||||||
|
/// this.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use std::collections::HashSet;
|
||||||
|
/// let mut set = HashSet::new();
|
||||||
|
/// set.insert("a".to_string());
|
||||||
|
/// set.insert("b".to_string());
|
||||||
|
///
|
||||||
|
/// // Not possible to collect to a Vec<String> with a regular `.iter()`.
|
||||||
|
/// let v: Vec<String> = set.into_iter().collect();
|
||||||
|
///
|
||||||
|
/// // Will print in an arbitrary order.
|
||||||
|
/// for x in v.iter() {
|
||||||
|
/// println!("{}", x);
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
fn into_iter(self) -> IntoIter<T> {
|
fn into_iter(self) -> IntoIter<T> {
|
||||||
self.into_iter()
|
fn first<A, B>((a, _): (A, B)) -> A { a }
|
||||||
|
let first: fn((T, ())) -> T = first;
|
||||||
|
|
||||||
|
IntoIter { iter: self.map.into_iter().map(first) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ use iter::{Iterator, ExactSizeIterator};
|
||||||
use marker::{Copy, Send, Sync, Sized, self};
|
use marker::{Copy, Send, Sync, Sized, self};
|
||||||
use mem::{min_align_of, size_of};
|
use mem::{min_align_of, size_of};
|
||||||
use mem;
|
use mem;
|
||||||
use num::wrapping::{OverflowingOps, WrappingOps};
|
use num::wrapping::OverflowingOps;
|
||||||
use ops::{Deref, DerefMut, Drop};
|
use ops::{Deref, DerefMut, Drop};
|
||||||
use option::Option;
|
use option::Option;
|
||||||
use option::Option::{Some, None};
|
use option::Option::{Some, None};
|
||||||
|
|
|
@ -259,19 +259,14 @@ mod dl {
|
||||||
|
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
mod dl {
|
mod dl {
|
||||||
|
use prelude::v1::*;
|
||||||
|
|
||||||
use ffi::OsStr;
|
use ffi::OsStr;
|
||||||
use iter::Iterator;
|
|
||||||
use libc;
|
use libc;
|
||||||
use libc::consts::os::extra::ERROR_CALL_NOT_IMPLEMENTED;
|
use libc::consts::os::extra::ERROR_CALL_NOT_IMPLEMENTED;
|
||||||
use ops::FnOnce;
|
|
||||||
use sys::os;
|
use sys::os;
|
||||||
use os::windows::prelude::*;
|
use os::windows::prelude::*;
|
||||||
use option::Option::{self, Some, None};
|
|
||||||
use ptr;
|
use ptr;
|
||||||
use result::Result;
|
|
||||||
use result::Result::{Ok, Err};
|
|
||||||
use string::String;
|
|
||||||
use vec::Vec;
|
|
||||||
use sys::c::compat::kernel32::SetThreadErrorMode;
|
use sys::c::compat::kernel32::SetThreadErrorMode;
|
||||||
|
|
||||||
pub fn open(filename: Option<&OsStr>) -> Result<*mut u8, String> {
|
pub fn open(filename: Option<&OsStr>) -> Result<*mut u8, String> {
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue