auto merge of #19665 : alexcrichton/rust/rollup, r=alexcrichton
This commit is contained in:
commit
b25e100173
@ -123,7 +123,8 @@ PKG_EXE = dist/$(PKG_NAME)-$(CFG_BUILD).exe
|
||||
$(PKG_EXE): rust.iss modpath.iss upgrade.iss LICENSE.txt rust-logo.ico \
|
||||
$(CSREQ3_T_$(CFG_BUILD)_H_$(CFG_BUILD)) \
|
||||
dist-prepare-win
|
||||
$(CFG_PYTHON) $(S)src/etc/make-win-dist.py tmp/dist/win $(CFG_BUILD)
|
||||
$(Q)rm -rf tmp/dist/win/gcc
|
||||
$(CFG_PYTHON) $(S)src/etc/make-win-dist.py tmp/dist/win/rust tmp/dist/win/gcc $(CFG_BUILD)
|
||||
@$(call E, ISCC: $@)
|
||||
$(Q)$(CFG_ISCC) $<
|
||||
|
||||
@ -131,7 +132,7 @@ $(eval $(call DEF_PREPARE,win))
|
||||
|
||||
dist-prepare-win: PREPARE_HOST=$(CFG_BUILD)
|
||||
dist-prepare-win: PREPARE_TARGETS=$(CFG_BUILD)
|
||||
dist-prepare-win: PREPARE_DEST_DIR=tmp/dist/win
|
||||
dist-prepare-win: PREPARE_DEST_DIR=tmp/dist/win/rust
|
||||
dist-prepare-win: PREPARE_DIR_CMD=$(DEFAULT_PREPARE_DIR_CMD)
|
||||
dist-prepare-win: PREPARE_BIN_CMD=$(DEFAULT_PREPARE_BIN_CMD)
|
||||
dist-prepare-win: PREPARE_LIB_CMD=$(DEFAULT_PREPARE_LIB_CMD)
|
||||
|
@ -32,7 +32,7 @@ two languages for those phrases to be in. We'll use this module layout:
|
||||
+---------+ | +-----------+
|
||||
| +---| farewells |
|
||||
+---------+ | +-----------+
|
||||
| phrases |---+
|
||||
| phrases |---+
|
||||
+---------+ | +-----------+
|
||||
| +---| greetings |
|
||||
+----------+ | +-----------+
|
||||
@ -219,7 +219,7 @@ Put this in `src/english/greetings.rs`:
|
||||
|
||||
fn hello() -> String {
|
||||
"Hello!".to_string()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Put this in `src/english/farewells.rs`:
|
||||
@ -229,7 +229,7 @@ Put this in `src/english/farewells.rs`:
|
||||
|
||||
fn goodbye() -> String {
|
||||
"Goodbye.".to_string()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Put this in `src/japanese/greetings.rs`:
|
||||
@ -239,7 +239,7 @@ Put this in `src/japanese/greetings.rs`:
|
||||
|
||||
fn hello() -> String {
|
||||
"こんにちは".to_string()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Of course, you can copy and paste this from this web page, or just type
|
||||
@ -253,7 +253,7 @@ Put this in `src/japanese/farewells.rs`:
|
||||
|
||||
fn goodbye() -> String {
|
||||
"さようなら".to_string()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
(This is "Sayoonara", if you're curious.)
|
||||
@ -381,11 +381,11 @@ $ cargo run
|
||||
/home/you/projects/phrases/src/japanese/greetings.rs:1:1: 3:2 warning: code is never used: `hello`, #[warn(dead_code)] on by default
|
||||
/home/you/projects/phrases/src/japanese/greetings.rs:1 fn hello() -> String {
|
||||
/home/you/projects/phrases/src/japanese/greetings.rs:2 "こんにちは".to_string()
|
||||
/home/you/projects/phrases/src/japanese/greetings.rs:3 }
|
||||
/home/you/projects/phrases/src/japanese/greetings.rs:3 }
|
||||
/home/you/projects/phrases/src/japanese/farewells.rs:1:1: 3:2 warning: code is never used: `goodbye`, #[warn(dead_code)] on by default
|
||||
/home/you/projects/phrases/src/japanese/farewells.rs:1 fn goodbye() -> String {
|
||||
/home/you/projects/phrases/src/japanese/farewells.rs:2 "さようなら".to_string()
|
||||
/home/you/projects/phrases/src/japanese/farewells.rs:3 }
|
||||
/home/you/projects/phrases/src/japanese/farewells.rs:3 }
|
||||
Running `target/phrases`
|
||||
Hello in English: Hello!
|
||||
Goodbye in English: Goodbye.
|
||||
@ -452,7 +452,7 @@ fn main() {
|
||||
|
||||
Rust will give us a compile-time error:
|
||||
|
||||
```{notrust,ignore}
|
||||
```{notrust}
|
||||
Compiling phrases v0.0.1 (file:///home/you/projects/phrases)
|
||||
/home/you/projects/phrases/src/main.rs:4:5: 4:40 error: a value named `hello` has already been imported in this module
|
||||
/home/you/projects/phrases/src/main.rs:4 use phrases::japanese::greetings::hello;
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
> The best-laid plans of mice and men
|
||||
> Often go awry
|
||||
>
|
||||
>
|
||||
> "Tae a Moose", Robert Burns
|
||||
|
||||
Sometimes, things just go wrong. It's important to have a plan for when the
|
||||
@ -76,7 +76,7 @@ fn main() {
|
||||
|
||||
This will give us an error:
|
||||
|
||||
```{notrust,ignore}
|
||||
```{notrust}
|
||||
error: non-exhaustive patterns: `_` not covered [E0004]
|
||||
```
|
||||
|
||||
@ -189,7 +189,7 @@ panic!("boom");
|
||||
|
||||
gives
|
||||
|
||||
```{notrust,ignore}
|
||||
```{notrust}
|
||||
task '<main>' panicked at 'boom', hello.rs:2
|
||||
```
|
||||
|
||||
|
@ -93,7 +93,7 @@ must have a deallocation for each allocation. Rust handles this for you. It
|
||||
knows that our handle, `x`, is the owning reference to our box. Rust knows that
|
||||
`x` will go out of scope at the end of the block, and so it inserts a call to
|
||||
deallocate the memory at the end of the scope. Because the compiler does this
|
||||
for us, it's impossible to forget. We always exaclty one deallocations paired
|
||||
for us, it's impossible to forget. We always have exactly one deallocation paired
|
||||
with each of our allocations.
|
||||
|
||||
This is pretty straightforward, but what happens when we want to pass our box
|
||||
@ -130,7 +130,7 @@ fn add_one(mut num: Box<int>) {
|
||||
|
||||
This does not compile, and gives us an error:
|
||||
|
||||
```{notrust,ignore}
|
||||
```{notrust}
|
||||
error: use of moved value: `x`
|
||||
println!("{}", x);
|
||||
^
|
||||
@ -186,11 +186,11 @@ This function takes ownership, because it takes a `Box`, which owns its
|
||||
contents. But then we give ownership right back.
|
||||
|
||||
In the physical world, you can give one of your possessions to someone for a
|
||||
short period of time. You still own your posession, you're just letting someone
|
||||
short period of time. You still own your possession, you're just letting someone
|
||||
else use it for a while. We call that 'lending' something to someone, and that
|
||||
person is said to be 'borrowing' that something from you.
|
||||
|
||||
Rust's ownershp system also allows an owner to lend out a handle for a limited
|
||||
Rust's ownership system also allows an owner to lend out a handle for a limited
|
||||
period. This is also called 'borrowing.' Here's a version of `add_one` which
|
||||
borrows its argument rather than taking ownership:
|
||||
|
||||
@ -231,7 +231,7 @@ fn add_one(num: &int) -> int {
|
||||
|
||||
Rust has a feature called 'lifetime elision,' which allows you to not write
|
||||
lifetime annotations in certain circumstances. This is one of them. Without
|
||||
eliding the liftimes, `add_one` looks like this:
|
||||
eliding the lifetimes, `add_one` looks like this:
|
||||
|
||||
```rust
|
||||
fn add_one<'a>(num: &'a int) -> int {
|
||||
@ -254,7 +254,7 @@ This part _declares_ our lifetimes. This says that `add_one` has one lifetime,
|
||||
fn add_two<'a, 'b>(...)
|
||||
```
|
||||
|
||||
Then in our parameter list, we use the liftimes we've named:
|
||||
Then in our parameter list, we use the lifetimes we've named:
|
||||
|
||||
```{rust,ignore}
|
||||
...(num: &'a int) -> ...
|
||||
@ -279,7 +279,7 @@ fn main() {
|
||||
}
|
||||
```
|
||||
|
||||
As you can see, `struct`s can also have liftimes. In a similar way to functions,
|
||||
As you can see, `struct`s can also have lifetimes. In a similar way to functions,
|
||||
|
||||
```{rust}
|
||||
struct Foo<'a> {
|
||||
@ -295,7 +295,7 @@ x: &'a int,
|
||||
# }
|
||||
```
|
||||
|
||||
uses it. So why do we need a liftime here? We need to ensure that any reference
|
||||
uses it. So why do we need a lifetime here? We need to ensure that any reference
|
||||
to a `Foo` cannot outlive the reference to an `int` it contains.
|
||||
|
||||
## Thinking in scopes
|
||||
@ -406,7 +406,7 @@ fn main() {
|
||||
We try to make four `Wheel`s, each with a `Car` that it's attached to. But the
|
||||
compiler knows that on the second iteration of the loop, there's a problem:
|
||||
|
||||
```{notrust,ignore}
|
||||
```{notrust}
|
||||
error: use of moved value: `car`
|
||||
Wheel { size: 360, owner: car };
|
||||
^~~
|
||||
|
@ -84,7 +84,7 @@ println!("{}", x + z);
|
||||
|
||||
This gives us an error:
|
||||
|
||||
```{notrust,ignore}
|
||||
```{notrust}
|
||||
hello.rs:6:24: 6:25 error: mismatched types: expected `int` but found `&int` (expected int but found &-ptr)
|
||||
hello.rs:6 println!("{}", x + z);
|
||||
^
|
||||
@ -132,7 +132,7 @@ Pointers are useful in languages that are pass-by-value, rather than
|
||||
pass-by-reference. Basically, languages can make two choices (this is made
|
||||
up syntax, it's not Rust):
|
||||
|
||||
```{notrust,ignore}
|
||||
```{ignore}
|
||||
func foo(x) {
|
||||
x = 5
|
||||
}
|
||||
@ -152,7 +152,7 @@ and therefore, can change its value. At the comment, `i` will be `5`.
|
||||
So what do pointers have to do with this? Well, since pointers point to a
|
||||
location in memory...
|
||||
|
||||
```{notrust,ignore}
|
||||
```{ignore}
|
||||
func foo(&int x) {
|
||||
*x = 5
|
||||
}
|
||||
@ -179,7 +179,7 @@ but here are problems with pointers in other languages:
|
||||
Uninitialized pointers can cause a problem. For example, what does this program
|
||||
do?
|
||||
|
||||
```{notrust,ignore}
|
||||
```{ignore}
|
||||
&int x;
|
||||
*x = 5; // whoops!
|
||||
```
|
||||
@ -191,7 +191,7 @@ knows. This might be harmless, and it might be catastrophic.
|
||||
When you combine pointers and functions, it's easy to accidentally invalidate
|
||||
the memory the pointer is pointing to. For example:
|
||||
|
||||
```{notrust,ignore}
|
||||
```{ignore}
|
||||
func make_pointer(): &int {
|
||||
x = 5;
|
||||
|
||||
@ -213,7 +213,7 @@ As one last example of a big problem with pointers, **aliasing** can be an
|
||||
issue. Two pointers are said to alias when they point at the same location
|
||||
in memory. Like this:
|
||||
|
||||
```{notrust,ignore}
|
||||
```{ignore}
|
||||
func mutate(&int i, int j) {
|
||||
*i = j;
|
||||
}
|
||||
@ -398,7 +398,7 @@ fn main() {
|
||||
|
||||
It gives this error:
|
||||
|
||||
```{notrust,ignore}
|
||||
```{notrust}
|
||||
test.rs:5:8: 5:10 error: cannot assign to `*x` because it is borrowed
|
||||
test.rs:5 *x -= 1;
|
||||
^~
|
||||
@ -522,7 +522,7 @@ boxes, though. As a rough approximation, you can treat this Rust code:
|
||||
|
||||
As being similar to this C code:
|
||||
|
||||
```{notrust,ignore}
|
||||
```{ignore}
|
||||
{
|
||||
int *x;
|
||||
x = (int *)malloc(sizeof(int));
|
||||
@ -626,7 +626,7 @@ fn main() {
|
||||
|
||||
This prints:
|
||||
|
||||
```{notrust,ignore}
|
||||
```{ignore}
|
||||
Cons(1, box Cons(2, box Cons(3, box Nil)))
|
||||
```
|
||||
|
||||
|
@ -181,7 +181,7 @@ for l in s.graphemes(true) {
|
||||
|
||||
This prints:
|
||||
|
||||
```{notrust,ignore}
|
||||
```{text}
|
||||
u͔
|
||||
n͈̰̎
|
||||
i̙̮͚̦
|
||||
@ -207,7 +207,7 @@ for l in s.chars() {
|
||||
|
||||
This prints:
|
||||
|
||||
```{notrust,ignore}
|
||||
```{text}
|
||||
u
|
||||
͔
|
||||
n
|
||||
@ -252,7 +252,7 @@ for l in s.bytes() {
|
||||
|
||||
This will print:
|
||||
|
||||
```{notrust,ignore}
|
||||
```{text}
|
||||
117
|
||||
205
|
||||
148
|
||||
|
155
src/doc/guide.md
155
src/doc/guide.md
@ -355,7 +355,7 @@ just `cargo build` and it'll work the right way.
|
||||
|
||||
You'll also notice that Cargo has created a new file: `Cargo.lock`.
|
||||
|
||||
```{ignore,notrust}
|
||||
```{ignore}
|
||||
[root]
|
||||
name = "hello_world"
|
||||
version = "0.0.1"
|
||||
@ -426,7 +426,7 @@ x = 10i;
|
||||
|
||||
It will give you this error:
|
||||
|
||||
```{ignore,notrust}
|
||||
```{notrust}
|
||||
error: re-assignment of immutable variable `x`
|
||||
x = 10i;
|
||||
^~~~~~~
|
||||
@ -486,7 +486,7 @@ fn main() {
|
||||
You can use `cargo build` on the command line to build it. You'll get a warning,
|
||||
but it will still print "Hello, world!":
|
||||
|
||||
```{ignore,notrust}
|
||||
```{notrust}
|
||||
Compiling hello_world v0.0.1 (file:///home/you/projects/hello_world)
|
||||
src/main.rs:2:9: 2:10 warning: unused variable: `x`, #[warn(unused_variable)] on by default
|
||||
src/main.rs:2 let x: int;
|
||||
@ -664,7 +664,7 @@ let y: int = if x == 5i { 10i; } else { 15i; };
|
||||
|
||||
Note the semicolons after the 10 and 15. Rust will give us the following error:
|
||||
|
||||
```{ignore,notrust}
|
||||
```{notrust}
|
||||
error: mismatched types: expected `int` but found `()` (expected int but found ())
|
||||
```
|
||||
|
||||
@ -747,7 +747,7 @@ fn print_number(x, y) {
|
||||
|
||||
You get this error:
|
||||
|
||||
```{ignore,notrust}
|
||||
```{notrust}
|
||||
hello.rs:5:18: 5:19 error: expected `:` but found `,`
|
||||
hello.rs:5 fn print_number(x, y) {
|
||||
```
|
||||
@ -779,7 +779,7 @@ fn add_one(x: int) -> int {
|
||||
|
||||
We would get an error:
|
||||
|
||||
```{ignore,notrust}
|
||||
```{ignore}
|
||||
error: not all control paths return a value
|
||||
fn add_one(x: int) -> int {
|
||||
x + 1;
|
||||
@ -1160,6 +1160,55 @@ Where a `StringResult` is either an `StringOK`, with the result of a computation
|
||||
`ErrorReason` with a `String` explaining what caused the computation to fail. These kinds of
|
||||
`enum`s are actually very useful and are even part of the standard library.
|
||||
|
||||
Enum variants are namespaced under the enum names. For example, here is an example of using
|
||||
our `StringResult`:
|
||||
|
||||
```rust
|
||||
# enum StringResult {
|
||||
# StringOK(String),
|
||||
# ErrorReason(String),
|
||||
# }
|
||||
fn respond(greeting: &str) -> StringResult {
|
||||
if greeting == "Hello" {
|
||||
StringResult::StringOK("Good morning!".to_string())
|
||||
} else {
|
||||
StringResult::ErrorReason("I didn't understand you!".to_string())
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Notice that we need both the enum name and the variant name: `StringResult::StringOK`, but
|
||||
we didn't need to with `Ordering`, we just said `Greater` rather than `Ordering::Greater`.
|
||||
There's a reason: the Rust prelude imports the variants of `Ordering` as well as the enum
|
||||
itself. We can use the `use` keyword to do something similar with `StringResult`:
|
||||
|
||||
```rust
|
||||
use StringResult::StringOK;
|
||||
use StringResult::ErrorReason;
|
||||
|
||||
enum StringResult {
|
||||
StringOK(String),
|
||||
ErrorReason(String),
|
||||
}
|
||||
|
||||
# fn main() {}
|
||||
|
||||
fn respond(greeting: &str) -> StringResult {
|
||||
if greeting == "Hello" {
|
||||
StringOK("Good morning!".to_string())
|
||||
} else {
|
||||
ErrorReason("I didn't understand you!".to_string())
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
We'll learn more about `use` later, but it's used to bring names into scope. `use` declarations
|
||||
must come before anything else, which looks a little strange in this example, since we `use`
|
||||
the variants before we define them. Anyway, in the body of `respond`, we can just say `StringOK`
|
||||
now, rather than the full `StringResult::StringOK`. Importing variants can be convenient, but can
|
||||
also cause name conflicts, so do this with caution. It's considered good style to rarely import
|
||||
variants for this reason.
|
||||
|
||||
As you can see `enum`s with values are quite a powerful tool for data representation,
|
||||
and can be even more useful when they're generic across types. But before we get to
|
||||
generics, let's talk about how to use them with pattern matching, a tool that will
|
||||
@ -1197,7 +1246,7 @@ So what's the big advantage here? Well, there are a few. First of all, `match`
|
||||
enforces 'exhaustiveness checking.' Do you see that last arm, the one with the
|
||||
underscore (`_`)? If we remove that arm, Rust will give us an error:
|
||||
|
||||
```{ignore,notrust}
|
||||
```{notrust}
|
||||
error: non-exhaustive patterns: `_` not covered
|
||||
```
|
||||
|
||||
@ -1344,7 +1393,7 @@ for x in range(0i, 10i) {
|
||||
|
||||
In slightly more abstract terms,
|
||||
|
||||
```{ignore,notrust}
|
||||
```{ignore}
|
||||
for var in expression {
|
||||
code
|
||||
}
|
||||
@ -1849,7 +1898,7 @@ Before we move on, let me show you one more Cargo command: `run`. `cargo run`
|
||||
is kind of like `cargo build`, but it also then runs the produced executable.
|
||||
Try it out:
|
||||
|
||||
```{notrust,ignore}
|
||||
```{notrust}
|
||||
$ cargo run
|
||||
Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game)
|
||||
Running `target/guessing_game`
|
||||
@ -1947,7 +1996,7 @@ for this example, it is not important.
|
||||
|
||||
Let's try to compile this using `cargo build`:
|
||||
|
||||
```{notrust,no_run}
|
||||
```{notrust}
|
||||
$ cargo build
|
||||
Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game)
|
||||
src/main.rs:7:26: 7:34 error: the type of this value must be known in this context
|
||||
@ -1995,7 +2044,7 @@ fn main() {
|
||||
|
||||
Try running our new program a few times:
|
||||
|
||||
```{notrust,ignore}
|
||||
```{notrust}
|
||||
$ cargo run
|
||||
Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game)
|
||||
Running `target/guessing_game`
|
||||
@ -2048,7 +2097,7 @@ fn main() {
|
||||
|
||||
And trying it out:
|
||||
|
||||
```{notrust,ignore}
|
||||
```{notrust}
|
||||
$ cargo run
|
||||
Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game)
|
||||
Running `target/guessing_game`
|
||||
@ -2103,7 +2152,7 @@ fn cmp(a: int, b: int) -> Ordering {
|
||||
|
||||
If we try to compile, we'll get some errors:
|
||||
|
||||
```{notrust,ignore}
|
||||
```{notrust}
|
||||
$ cargo build
|
||||
Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game)
|
||||
src/main.rs:20:15: 20:20 error: mismatched types: expected `int` but found `collections::string::String` (expected int but found struct collections::string::String)
|
||||
@ -2157,7 +2206,7 @@ fn cmp(a: uint, b: uint) -> Ordering {
|
||||
|
||||
And try compiling again:
|
||||
|
||||
```{notrust,ignore}
|
||||
```{notrust}
|
||||
$ cargo build
|
||||
Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game)
|
||||
src/main.rs:20:15: 20:20 error: mismatched types: expected `uint` but found `collections::string::String` (expected uint but found struct collections::string::String)
|
||||
@ -2170,7 +2219,7 @@ This error is similar to the last one: we expected to get a `uint`, but we got
|
||||
a `String` instead! That's because our `input` variable is coming from the
|
||||
standard input, and you can guess anything. Try it:
|
||||
|
||||
```{notrust,ignore}
|
||||
```{notrust}
|
||||
$ ./target/guessing_game
|
||||
Guess the number!
|
||||
The secret number is: 73
|
||||
@ -2254,7 +2303,7 @@ fn cmp(a: uint, b: uint) -> Ordering {
|
||||
|
||||
Let's try it out!
|
||||
|
||||
```{notrust,ignore}
|
||||
```{notrust}
|
||||
$ cargo build
|
||||
Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game)
|
||||
src/main.rs:22:15: 22:24 error: mismatched types: expected `uint` but found `core::option::Option<uint>` (expected uint but found enum core::option::Option)
|
||||
@ -2313,7 +2362,7 @@ fn cmp(a: uint, b: uint) -> Ordering {
|
||||
We use a `match` to either give us the `uint` inside of the `Option`, or we
|
||||
print an error message and return. Let's give this a shot:
|
||||
|
||||
```{notrust,ignore}
|
||||
```{notrust}
|
||||
$ cargo run
|
||||
Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game)
|
||||
Running `target/guessing_game`
|
||||
@ -2378,7 +2427,7 @@ fn cmp(a: uint, b: uint) -> Ordering {
|
||||
|
||||
Let's try it!
|
||||
|
||||
```{notrust,ignore}
|
||||
```{notrust}
|
||||
$ cargo run
|
||||
Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game)
|
||||
Running `target/guessing_game`
|
||||
@ -2455,7 +2504,7 @@ fn cmp(a: uint, b: uint) -> Ordering {
|
||||
And try it out. But wait, didn't we just add an infinite loop? Yup. Remember
|
||||
that `return`? If we give a non-number answer, we'll `return` and quit. Observe:
|
||||
|
||||
```{notrust,ignore}
|
||||
```{notrust}
|
||||
$ cargo run
|
||||
Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game)
|
||||
Running `target/guessing_game`
|
||||
@ -2587,7 +2636,7 @@ fn cmp(a: uint, b: uint) -> Ordering {
|
||||
|
||||
Now we should be good! Let's try:
|
||||
|
||||
```{notrust,ignore}
|
||||
```{notrust}
|
||||
$ cargo run
|
||||
Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game)
|
||||
Running `target/guessing_game`
|
||||
@ -2703,7 +2752,7 @@ $ cd modules
|
||||
|
||||
Let's double check our work by compiling:
|
||||
|
||||
```{bash,notrust}
|
||||
```{bash}
|
||||
$ cargo run
|
||||
Compiling modules v0.0.1 (file:///home/you/projects/modules)
|
||||
Running `target/modules`
|
||||
@ -2765,7 +2814,7 @@ mod hello {
|
||||
|
||||
It gives an error:
|
||||
|
||||
```{notrust,ignore}
|
||||
```{notrust}
|
||||
Compiling modules v0.0.1 (file:///home/you/projects/modules)
|
||||
src/main.rs:2:5: 2:23 error: function `print_hello` is private
|
||||
src/main.rs:2 hello::print_hello();
|
||||
@ -2789,7 +2838,7 @@ mod hello {
|
||||
Usage of the `pub` keyword is sometimes called 'exporting', because
|
||||
we're making the function available for other modules. This will work:
|
||||
|
||||
```{notrust,ignore}
|
||||
```{notrust}
|
||||
$ cargo run
|
||||
Compiling modules v0.0.1 (file:///home/you/projects/modules)
|
||||
Running `target/modules`
|
||||
@ -2923,7 +2972,7 @@ $ cd testing
|
||||
|
||||
And try it out:
|
||||
|
||||
```{notrust,ignore}
|
||||
```{notrust}
|
||||
$ cargo run
|
||||
Compiling testing v0.0.1 (file:///home/you/projects/testing)
|
||||
Running `target/testing`
|
||||
@ -2955,7 +3004,7 @@ you give them descriptive names. You'll see why in a moment. We then use a
|
||||
macro, `assert!`, to assert that something is true. In this case, we're giving
|
||||
it `false`, so this test should fail. Let's try it!
|
||||
|
||||
```{notrust,ignore}
|
||||
```{notrust}
|
||||
$ cargo test
|
||||
Compiling testing v0.0.1 (file:///home/you/projects/testing)
|
||||
/home/you/projects/testing/src/main.rs:1:1: 3:2 warning: function is never used: `main`, #[warn(dead_code)] on by default
|
||||
@ -2984,7 +3033,7 @@ task '<main>' failed at 'Some tests failed', /home/you/src/rust/src/libtest/lib.
|
||||
|
||||
Lots of output! Let's break this down:
|
||||
|
||||
```{notrust,ignore}
|
||||
```{ignore}
|
||||
$ cargo test
|
||||
Compiling testing v0.0.1 (file:///home/you/projects/testing)
|
||||
```
|
||||
@ -2992,7 +3041,7 @@ $ cargo test
|
||||
You can run all of your tests with `cargo test`. This runs both your tests in
|
||||
`tests`, as well as the tests you put inside of your crate.
|
||||
|
||||
```{notrust,ignore}
|
||||
```{notrust}
|
||||
/home/you/projects/testing/src/main.rs:1:1: 3:2 warning: function is never used: `main`, #[warn(dead_code)] on by default
|
||||
/home/you/projects/testing/src/main.rs:1 fn main() {
|
||||
/home/you/projects/testing/src/main.rs:2 println!("Hello, world!")
|
||||
@ -3006,7 +3055,7 @@ case, Rust is warning us that we've written some code that's never used: our
|
||||
We'll turn this lint off for just this function soon. For now, just ignore this
|
||||
output.
|
||||
|
||||
```{notrust,ignore}
|
||||
```{ignore}
|
||||
Running target/lib-654ce120f310a3a5
|
||||
|
||||
running 1 test
|
||||
@ -3018,7 +3067,7 @@ with good names? This is why. Here, it says 'test foo' because we called our
|
||||
test 'foo.' If we had given it a good name, it'd be more clear which test
|
||||
failed, especially as we accumulate more tests.
|
||||
|
||||
```{notrust,ignore}
|
||||
```{notrust}
|
||||
failures:
|
||||
|
||||
---- foo stdout ----
|
||||
@ -3049,7 +3098,7 @@ fn foo() {
|
||||
|
||||
And then try to run our tests again:
|
||||
|
||||
```{notrust,ignore}
|
||||
```{ignore}
|
||||
$ cargo test
|
||||
Compiling testing v0.0.1 (file:///home/you/projects/testing)
|
||||
Running target/lib-654ce120f310a3a5
|
||||
@ -3089,7 +3138,7 @@ include `main` when it's _not_ true. So we use `not` to negate things:
|
||||
With this attribute we won't get the warning (even
|
||||
though `src/main.rs` gets recompiled this time):
|
||||
|
||||
```{notrust,ignore}
|
||||
```{ignore}
|
||||
$ cargo test
|
||||
Compiling testing v0.0.1 (file:///home/you/projects/testing)
|
||||
Running target/lib-654ce120f310a3a5
|
||||
@ -3120,7 +3169,7 @@ fn math_checks_out() {
|
||||
|
||||
And try to run the test:
|
||||
|
||||
```{notrust,ignore}
|
||||
```{notrust}
|
||||
$ cargo test
|
||||
Compiling testing v0.0.1 (file:///home/you/projects/testing)
|
||||
/home/you/projects/testing/tests/lib.rs:3:18: 3:38 error: unresolved name `add_three_times_four`.
|
||||
@ -3180,7 +3229,7 @@ fn math_checks_out() {
|
||||
|
||||
Let's give it a run:
|
||||
|
||||
```{ignore,notrust}
|
||||
```{ignore}
|
||||
$ cargo test
|
||||
Compiling testing v0.0.1 (file:///home/you/projects/testing)
|
||||
Running target/lib-654ce120f310a3a5
|
||||
@ -3229,7 +3278,7 @@ fn times_four(x: int) -> int { x * 4 }
|
||||
|
||||
If you run `cargo test`, you should get the same output:
|
||||
|
||||
```{ignore,notrust}
|
||||
```{ignore}
|
||||
$ cargo test
|
||||
Compiling testing v0.0.1 (file:///home/you/projects/testing)
|
||||
Running target/lib-654ce120f310a3a5
|
||||
@ -3283,7 +3332,7 @@ fn test_add_three() {
|
||||
|
||||
We'd get this error:
|
||||
|
||||
```{notrust,ignore}
|
||||
```{notrust}
|
||||
Compiling testing v0.0.1 (file:///home/you/projects/testing)
|
||||
/home/you/projects/testing/tests/lib.rs:3:5: 3:24 error: function `add_three` is private
|
||||
/home/you/projects/testing/tests/lib.rs:3 use testing::add_three;
|
||||
@ -3325,7 +3374,7 @@ mod test {
|
||||
|
||||
Let's give it a shot:
|
||||
|
||||
```{ignore,notrust}
|
||||
```{ignore}
|
||||
$ cargo test
|
||||
Compiling testing v0.0.1 (file:///home/you/projects/testing)
|
||||
Running target/lib-654ce120f310a3a5
|
||||
@ -3455,7 +3504,7 @@ let y = &mut x;
|
||||
|
||||
Rust will complain:
|
||||
|
||||
```{ignore,notrust}
|
||||
```{notrust}
|
||||
error: cannot borrow immutable local variable `x` as mutable
|
||||
let y = &mut x;
|
||||
^
|
||||
@ -3482,7 +3531,7 @@ let z = &mut x;
|
||||
|
||||
It gives us this error:
|
||||
|
||||
```{notrust,ignore}
|
||||
```{notrust}
|
||||
error: cannot borrow `x` as mutable more than once at a time
|
||||
let z = &mut x;
|
||||
^
|
||||
@ -3628,7 +3677,7 @@ let z = &mut x;
|
||||
|
||||
The error:
|
||||
|
||||
```{notrust,ignore}
|
||||
```{notrust}
|
||||
error: cannot borrow `x` as mutable more than once at a time
|
||||
let z = &mut x;
|
||||
^
|
||||
@ -3646,7 +3695,7 @@ note: previous borrow ends here
|
||||
|
||||
This error comes in three parts. Let's go over each in turn.
|
||||
|
||||
```{notrust,ignore}
|
||||
```{notrust}
|
||||
error: cannot borrow `x` as mutable more than once at a time
|
||||
let z = &mut x;
|
||||
^
|
||||
@ -3655,7 +3704,7 @@ error: cannot borrow `x` as mutable more than once at a time
|
||||
This error states the restriction: you cannot lend out something mutable more
|
||||
than once at the same time. The borrow checker knows the rules!
|
||||
|
||||
```{notrust,ignore}
|
||||
```{notrust}
|
||||
note: previous borrow of `x` occurs here; the mutable borrow prevents subsequent moves, borrows, or modification of `x` until the borrow ends
|
||||
let y = &mut x;
|
||||
^
|
||||
@ -3667,7 +3716,7 @@ the first mutable borrow occurred. The error showed us the second. So now we
|
||||
see both parts of the problem. It also alludes to rule #3, by reminding us that
|
||||
we can't change `x` until the borrow is over.
|
||||
|
||||
```{notrust,ignore}
|
||||
```{ignore}
|
||||
note: previous borrow ends here
|
||||
fn main() {
|
||||
let mut x = 5i;
|
||||
@ -3681,8 +3730,8 @@ Here's the second note, which lets us know where the first borrow would be over.
|
||||
This is useful, because if we wait to try to borrow `x` after this borrow is
|
||||
over, then everything will work.
|
||||
|
||||
For more advanced patterns, please consult the [Lifetime
|
||||
Guide](guide-lifetimes.html). You'll also learn what this type signature with
|
||||
For more advanced patterns, please consult the [Ownership
|
||||
Guide](guide-ownership.html). You'll also learn what this type signature with
|
||||
the `'a` syntax is:
|
||||
|
||||
```{rust,ignore}
|
||||
@ -3770,7 +3819,7 @@ let y = &mut x;
|
||||
|
||||
This gives us this error:
|
||||
|
||||
```{notrust,ignore}
|
||||
```{notrust}
|
||||
error: cannot use `*x` because it was mutably borrowed
|
||||
*x;
|
||||
^~
|
||||
@ -4595,7 +4644,7 @@ element reference has the closure it's been given as an argument called on it.
|
||||
So this would give us the numbers from `2-100`. Well, almost! If you
|
||||
compile the example, you'll get a warning:
|
||||
|
||||
```{notrust,ignore}
|
||||
```{ignore}
|
||||
warning: unused result which must be used: iterator adaptors are lazy and
|
||||
do nothing unless consumed, #[warn(unused_must_use)] on by default
|
||||
range(1i, 100i).map(|x| x + 1i);
|
||||
@ -4625,7 +4674,7 @@ for i in std::iter::count(1i, 5i).take(5) {
|
||||
|
||||
This will print
|
||||
|
||||
```{notrust,ignore}
|
||||
```{ignore}
|
||||
1
|
||||
6
|
||||
11
|
||||
@ -4838,7 +4887,7 @@ We can then use `T` inside the rest of the signature: `x` has type `T`, and half
|
||||
of the `Result` has type `T`. However, if we try to compile that example, we'll get
|
||||
an error:
|
||||
|
||||
```{notrust,ignore}
|
||||
```{notrust}
|
||||
error: binary operation `==` cannot be applied to type `T`
|
||||
```
|
||||
|
||||
@ -4894,7 +4943,7 @@ we use `impl Trait for Item`, rather than just `impl Item`.
|
||||
So what's the big deal? Remember the error we were getting with our generic
|
||||
`inverse` function?
|
||||
|
||||
```{notrust,ignore}
|
||||
```{notrust}
|
||||
error: binary operation `==` cannot be applied to type `T`
|
||||
```
|
||||
|
||||
@ -4909,7 +4958,7 @@ fn print_area<T>(shape: T) {
|
||||
|
||||
Rust complains:
|
||||
|
||||
```{notrust,ignore}
|
||||
```{notrust}
|
||||
error: type `T` does not implement any method in scope named `area`
|
||||
```
|
||||
|
||||
@ -4985,7 +5034,7 @@ fn main() {
|
||||
|
||||
This program outputs:
|
||||
|
||||
```{notrust,ignore}
|
||||
```{ignore}
|
||||
This shape has an area of 3.141593
|
||||
This shape has an area of 1
|
||||
```
|
||||
@ -4999,7 +5048,7 @@ print_area(5i);
|
||||
|
||||
We get a compile-time error:
|
||||
|
||||
```{notrust,ignore}
|
||||
```{ignore}
|
||||
error: failed to find an implementation of trait main::HasArea for int
|
||||
```
|
||||
|
||||
@ -5066,7 +5115,7 @@ fn main() {
|
||||
Now that we've moved the structs and traits into their own module, we get an
|
||||
error:
|
||||
|
||||
```{notrust,ignore}
|
||||
```{notrust}
|
||||
error: type `shapes::Circle` does not implement any method in scope named `area`
|
||||
```
|
||||
|
||||
|
@ -58,13 +58,13 @@ authors = ["Your Name <you@example.com>"]
|
||||
```
|
||||
|
||||
This is called a **manifest**, and it contains all of the metadata that Cargo
|
||||
needs to compile your project.
|
||||
needs to compile your project.
|
||||
|
||||
Here's what's in `src/main.rs`:
|
||||
|
||||
```{rust}
|
||||
fn main() {
|
||||
println!("Hello, world!")
|
||||
println!("Hello, world!");
|
||||
}
|
||||
```
|
||||
|
||||
@ -207,7 +207,7 @@ and two...
|
||||
|
||||
```{bash}
|
||||
$ g++ hello.cpp -Wall -Werror
|
||||
$ ./a.out
|
||||
$ ./a.out
|
||||
Segmentation fault (core dumped)
|
||||
```
|
||||
|
||||
@ -313,7 +313,7 @@ print `"Hello"`, or does Rust crash?
|
||||
|
||||
Neither. It refuses to compile:
|
||||
|
||||
```{notrust,ignore}
|
||||
```{notrust}
|
||||
$ cargo run
|
||||
Compiling hello_world v0.0.1 (file:///Users/you/src/hello_world)
|
||||
main.rs:8:5: 8:6 error: cannot borrow `v` as mutable because it is also borrowed as immutable
|
||||
@ -428,7 +428,7 @@ fn main() {
|
||||
|
||||
It gives us this error:
|
||||
|
||||
```{notrust,ignore}
|
||||
```{notrust}
|
||||
6:71 error: capture of moved value: `numbers`
|
||||
for j in range(0, 3) { numbers[j] += 1 }
|
||||
^~~~~~~
|
||||
|
@ -496,9 +496,8 @@ Examples of integer literals of various forms:
|
||||
|
||||
A _floating-point literal_ has one of two forms:
|
||||
|
||||
* Two _decimal literals_ separated by a period
|
||||
character `U+002E` (`.`), with an optional _exponent_ trailing after the
|
||||
second decimal literal.
|
||||
* A _decimal literal_ followed by a period character `U+002E` (`.`). This is
|
||||
optionally followed by another decimal literal, with an optional _exponent_.
|
||||
* A single _decimal literal_ followed by an _exponent_.
|
||||
|
||||
By default, a floating-point literal has a generic type, and, like integer
|
||||
@ -509,12 +508,17 @@ types), which explicitly determine the type of the literal.
|
||||
Examples of floating-point literals of various forms:
|
||||
|
||||
```
|
||||
123.0f64; // type f64
|
||||
0.1f64; // type f64
|
||||
0.1f32; // type f32
|
||||
12E+99_f64; // type f64
|
||||
123.0f64; // type f64
|
||||
0.1f64; // type f64
|
||||
0.1f32; // type f32
|
||||
12E+99_f64; // type f64
|
||||
let x: f64 = 2.; // type f64
|
||||
```
|
||||
|
||||
This last example is different because it is not possible to use the suffix
|
||||
syntax with a floating point literal ending in a period. `2.f64` would attempt
|
||||
to call a method named `f64` on `2`.
|
||||
|
||||
##### Boolean literals
|
||||
|
||||
The two values of the boolean type are written `true` and `false`.
|
||||
|
@ -8,6 +8,12 @@
|
||||
# option. This file may not be copied, modified, or distributed
|
||||
# except according to those terms.
|
||||
|
||||
# Script parameters:
|
||||
# argv[1] = rust component root,
|
||||
# argv[2] = gcc component root,
|
||||
# argv[3] = target triple
|
||||
# The first two correspond to the two installable components defined in the setup script.
|
||||
|
||||
import sys, os, shutil, subprocess
|
||||
|
||||
def find_files(files, path):
|
||||
@ -22,7 +28,7 @@ def find_files(files, path):
|
||||
raise Exception("Could not find '%s' in %s" % (fname, path))
|
||||
return found
|
||||
|
||||
def make_win_dist(dist_root, target_triple):
|
||||
def make_win_dist(rust_root, gcc_root, target_triple):
|
||||
# Ask gcc where it keeps its stuff
|
||||
gcc_out = subprocess.check_output(["gcc.exe", "-print-search-dirs"])
|
||||
bin_path = os.environ["PATH"].split(os.pathsep)
|
||||
@ -90,29 +96,29 @@ def make_win_dist(dist_root, target_triple):
|
||||
target_libs = find_files(target_libs, lib_path)
|
||||
|
||||
# Copy runtime dlls next to rustc.exe
|
||||
dist_bin_dir = os.path.join(dist_root, "bin")
|
||||
dist_bin_dir = os.path.join(rust_root, "bin")
|
||||
for src in rustc_dlls:
|
||||
shutil.copy(src, dist_bin_dir)
|
||||
|
||||
# Copy platform tools to platform-specific bin directory
|
||||
target_bin_dir = os.path.join(dist_root, "bin", "rustlib", target_triple, "bin")
|
||||
target_bin_dir = os.path.join(gcc_root, "bin", "rustlib", target_triple, "bin")
|
||||
if not os.path.exists(target_bin_dir):
|
||||
os.makedirs(target_bin_dir)
|
||||
for src in target_tools:
|
||||
shutil.copy(src, target_bin_dir)
|
||||
|
||||
# Copy platform libs to platform-spcific lib directory
|
||||
target_lib_dir = os.path.join(dist_root, "bin", "rustlib", target_triple, "lib")
|
||||
target_lib_dir = os.path.join(gcc_root, "bin", "rustlib", target_triple, "lib")
|
||||
if not os.path.exists(target_lib_dir):
|
||||
os.makedirs(target_lib_dir)
|
||||
for src in target_libs:
|
||||
shutil.copy(src, target_lib_dir)
|
||||
|
||||
# Copy license files
|
||||
lic_dir = os.path.join(dist_root, "bin", "third-party")
|
||||
lic_dir = os.path.join(rust_root, "bin", "third-party")
|
||||
if os.path.exists(lic_dir):
|
||||
shutil.rmtree(lic_dir) # copytree() won't overwrite existing files
|
||||
shutil.copytree(os.path.join(os.path.dirname(__file__), "third-party"), lic_dir)
|
||||
|
||||
if __name__=="__main__":
|
||||
make_win_dist(sys.argv[1], sys.argv[2])
|
||||
make_win_dist(sys.argv[1], sys.argv[2], sys.argv[3])
|
||||
|
@ -14,6 +14,7 @@ AppPublisherURL=http://www.rust-lang.org
|
||||
VersionInfoVersion={#CFG_VERSION_WIN}
|
||||
LicenseFile=LICENSE.txt
|
||||
|
||||
PrivilegesRequired=lowest
|
||||
DisableWelcomePage=true
|
||||
DisableProgramGroupPage=true
|
||||
DisableReadyPage=true
|
||||
@ -37,8 +38,13 @@ Uninstallable=yes
|
||||
[Tasks]
|
||||
Name: modifypath; Description: &Add {app}\bin to your PATH (recommended)
|
||||
|
||||
[Components]
|
||||
Name: rust; Description: "Rust compiler and standard crates"; Types: full compact custom; Flags: fixed
|
||||
Name: gcc; Description: "Linker and platform libraries"; Types: full
|
||||
|
||||
[Files]
|
||||
Source: "tmp/dist/win/*.*" ; DestDir: "{app}"; Flags: ignoreversion recursesubdirs
|
||||
Source: "tmp/dist/win/rust/*.*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs; Components: rust
|
||||
Source: "tmp/dist/win/gcc/*.*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs; Components: gcc
|
||||
|
||||
[Code]
|
||||
const
|
||||
|
@ -141,6 +141,7 @@
|
||||
|
||||
#![stable]
|
||||
|
||||
use core::borrow::BorrowFrom;
|
||||
use core::cell::Cell;
|
||||
use core::clone::Clone;
|
||||
use core::cmp::{PartialEq, PartialOrd, Eq, Ord, Ordering};
|
||||
@ -349,6 +350,12 @@ impl<T: Clone> Rc<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> BorrowFrom<Rc<T>> for T {
|
||||
fn borrow_from(owned: &Rc<T>) -> &T {
|
||||
&**owned
|
||||
}
|
||||
}
|
||||
|
||||
#[experimental = "Deref is experimental."]
|
||||
impl<T> Deref<T> for Rc<T> {
|
||||
#[inline(always)]
|
||||
|
@ -1026,6 +1026,24 @@ impl<'a, K: Ord, V> OccupiedEntry<'a, K, V> {
|
||||
|
||||
impl<K, V> BTreeMap<K, V> {
|
||||
/// Gets an iterator over the entries of the map.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::BTreeMap;
|
||||
///
|
||||
/// let mut map = BTreeMap::new();
|
||||
/// map.insert(1u, "a");
|
||||
/// map.insert(2u, "b");
|
||||
/// map.insert(3u, "c");
|
||||
///
|
||||
/// for (key, value) in map.iter() {
|
||||
/// println!("{}: {}", key, value);
|
||||
/// }
|
||||
///
|
||||
/// let (first_key, first_value) = map.iter().next().unwrap();
|
||||
/// assert_eq!((*first_key, *first_value), (1u, "a"));
|
||||
/// ```
|
||||
#[unstable = "matches collection reform specification, waiting for dust to settle"]
|
||||
pub fn iter<'a>(&'a self) -> Entries<'a, K, V> {
|
||||
let len = self.len();
|
||||
|
@ -11,9 +11,6 @@
|
||||
//! A doubly-linked list with owned nodes.
|
||||
//!
|
||||
//! The `DList` allows pushing and popping elements at either end.
|
||||
//!
|
||||
//! `DList` implements the trait `Deque`. It should be imported with
|
||||
//! `use collections::Deque`.
|
||||
|
||||
// DList is constructed like a singly-linked list over the field `next`.
|
||||
// including the last link being None; each Node owns its `next` field.
|
||||
|
@ -11,7 +11,6 @@
|
||||
//! This crate implements a double-ended queue with `O(1)` amortized inserts and removals from both
|
||||
//! ends of the container. It also has `O(1)` indexing like a vector. The contained elements are
|
||||
//! not required to be copyable, and the queue will be sendable if the contained type is sendable.
|
||||
//! Its interface `Deque` is defined in `collections`.
|
||||
|
||||
use core::prelude::*;
|
||||
|
||||
@ -35,7 +34,7 @@ static MINIMUM_CAPACITY: uint = 2u;
|
||||
// FIXME(conventions): implement shrink_to_fit. Awkward with the current design, but it should
|
||||
// be scrapped anyway. Defer to rewrite?
|
||||
|
||||
/// `RingBuf` is a circular buffer that implements `Deque`.
|
||||
/// `RingBuf` is a circular buffer.
|
||||
pub struct RingBuf<T> {
|
||||
// tail and head are pointers into the buffer. Tail always points
|
||||
// to the first element that could be read, Head always points
|
||||
|
@ -729,15 +729,38 @@ impl FromIterator<char> for String {
|
||||
}
|
||||
}
|
||||
|
||||
#[experimental = "waiting on FromIterator stabilization"]
|
||||
impl<'a> FromIterator<&'a str> for String {
|
||||
fn from_iter<I:Iterator<&'a str>>(iterator: I) -> String {
|
||||
let mut buf = String::new();
|
||||
buf.extend(iterator);
|
||||
buf
|
||||
}
|
||||
}
|
||||
|
||||
#[experimental = "waiting on Extend stabilization"]
|
||||
impl Extend<char> for String {
|
||||
fn extend<I:Iterator<char>>(&mut self, mut iterator: I) {
|
||||
let (lower_bound, _) = iterator.size_hint();
|
||||
self.reserve(lower_bound);
|
||||
for ch in iterator {
|
||||
self.push(ch)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[experimental = "waiting on Extend stabilization"]
|
||||
impl<'a> Extend<&'a str> for String {
|
||||
fn extend<I: Iterator<&'a str>>(&mut self, mut iterator: I) {
|
||||
// A guess that at least one byte per iterator element will be needed.
|
||||
let (lower_bound, _) = iterator.size_hint();
|
||||
self.reserve(lower_bound);
|
||||
for s in iterator {
|
||||
self.push_str(s)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for String {
|
||||
#[inline]
|
||||
fn eq(&self, other: &String) -> bool { PartialEq::eq(&**self, &**other) }
|
||||
@ -1307,6 +1330,27 @@ mod tests {
|
||||
"[[], [1], [1, 1]]");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_iterator() {
|
||||
let s = "ศไทย中华Việt Nam".to_string();
|
||||
let t = "ศไทย中华";
|
||||
let u = "Việt Nam";
|
||||
|
||||
let a: String = s.chars().collect();
|
||||
assert_eq!(s, a);
|
||||
|
||||
let mut b = t.to_string();
|
||||
b.extend(u.chars());
|
||||
assert_eq!(s, b);
|
||||
|
||||
let c: String = vec![t, u].into_iter().collect();
|
||||
assert_eq!(s, c);
|
||||
|
||||
let mut d = t.to_string();
|
||||
d.extend(vec![u].into_iter());
|
||||
assert_eq!(s, d);
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_with_capacity(b: &mut Bencher) {
|
||||
b.iter(|| {
|
||||
|
@ -44,7 +44,7 @@
|
||||
pub use self::Ordering::*;
|
||||
|
||||
use kinds::{Copy, Sized};
|
||||
use option::{Option, Some, None};
|
||||
use option::Option::{mod, Some, None};
|
||||
|
||||
/// Trait for values that can be compared for equality and inequality.
|
||||
///
|
||||
|
@ -59,7 +59,7 @@
|
||||
#![allow(unknown_features, raw_pointer_deriving)]
|
||||
#![feature(globs, intrinsics, lang_items, macro_rules, phase)]
|
||||
#![feature(simd, unsafe_destructor, slicing_syntax)]
|
||||
#![feature(default_type_params)]
|
||||
#![feature(default_type_params, unboxed_closures)]
|
||||
#![deny(missing_docs)]
|
||||
|
||||
mod macros;
|
||||
|
@ -143,7 +143,10 @@
|
||||
|
||||
#![stable]
|
||||
|
||||
#[cfg(stage0)]
|
||||
pub use self::Option::*;
|
||||
#[cfg(not(stage0))]
|
||||
use self::Option::*;
|
||||
|
||||
use cmp::{Eq, Ord};
|
||||
use default::Default;
|
||||
|
@ -230,7 +230,7 @@
|
||||
|
||||
#![stable]
|
||||
|
||||
pub use self::Result::*;
|
||||
use self::Result::*;
|
||||
|
||||
use kinds::Copy;
|
||||
use std::fmt::Show;
|
||||
|
@ -76,7 +76,7 @@ impl FromStr for bool {
|
||||
Section: Creating a string
|
||||
*/
|
||||
|
||||
/// Converts a vector to a string slice without performing any allocations.
|
||||
/// Converts a slice of bytes to a string slice without performing any allocations.
|
||||
///
|
||||
/// Once the slice has been validated as utf-8, it is transmuted in-place and
|
||||
/// returned as a '&str' instead of a '&[u8]'
|
||||
|
@ -117,7 +117,7 @@ impl ChaChaRng {
|
||||
/// security proof for a more involved example of this.
|
||||
///
|
||||
/// The modified word layout is:
|
||||
/// ```notrust
|
||||
/// ```ignore
|
||||
/// constant constant constant constant
|
||||
/// key key key key
|
||||
/// key key key key
|
||||
|
@ -120,7 +120,7 @@
|
||||
//!
|
||||
//! The compiler accepts a flag of this form a number of times:
|
||||
//!
|
||||
//! ```notrust
|
||||
//! ```ignore
|
||||
//! --extern crate-name=path/to/the/crate.rlib
|
||||
//! ```
|
||||
//!
|
||||
@ -152,7 +152,7 @@
|
||||
//!
|
||||
//! and the compiler would be invoked as:
|
||||
//!
|
||||
//! ```notrust
|
||||
//! ```ignore
|
||||
//! rustc a.rs --extern b1=path/to/libb1.rlib --extern b2=path/to/libb2.rlib
|
||||
//! ```
|
||||
//!
|
||||
@ -178,7 +178,7 @@
|
||||
//! dependencies, not the upstream transitive dependencies. Consider this
|
||||
//! dependency graph:
|
||||
//!
|
||||
//! ```notrust
|
||||
//! ```ignore
|
||||
//! A.1 A.2
|
||||
//! | |
|
||||
//! | |
|
||||
|
@ -288,7 +288,6 @@ fn load_environment<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
debuginfo::create_captured_var_metadata(
|
||||
bcx,
|
||||
def_id.node,
|
||||
cdata_ty,
|
||||
env_pointer_alloca,
|
||||
i,
|
||||
captured_by_ref,
|
||||
@ -328,7 +327,7 @@ fn load_unboxed_closure_environment<'blk, 'tcx>(
|
||||
// Store the pointer to closure data in an alloca for debug info because that's what the
|
||||
// llvm.dbg.declare intrinsic expects
|
||||
let env_pointer_alloca = if bcx.sess().opts.debuginfo == FullDebugInfo {
|
||||
let alloc = alloc_ty(bcx, ty::mk_mut_ptr(bcx.tcx(), self_type), "__debuginfo_env_ptr");
|
||||
let alloc = alloca(bcx, val_ty(llenv), "__debuginfo_env_ptr");
|
||||
Store(bcx, llenv, alloc);
|
||||
Some(alloc)
|
||||
} else {
|
||||
@ -357,7 +356,6 @@ fn load_unboxed_closure_environment<'blk, 'tcx>(
|
||||
debuginfo::create_captured_var_metadata(
|
||||
bcx,
|
||||
def_id.node,
|
||||
self_type,
|
||||
env_pointer_alloca,
|
||||
i,
|
||||
captured_by_ref,
|
||||
|
@ -884,7 +884,6 @@ pub fn create_local_var_metadata(bcx: Block, local: &ast::Local) {
|
||||
/// Adds the created metadata nodes directly to the crate's IR.
|
||||
pub fn create_captured_var_metadata<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
node_id: ast::NodeId,
|
||||
env_data_type: Ty<'tcx>,
|
||||
env_pointer: ValueRef,
|
||||
env_index: uint,
|
||||
captured_by_ref: bool,
|
||||
@ -930,7 +929,10 @@ pub fn create_captured_var_metadata<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
let variable_type = node_id_type(bcx, node_id);
|
||||
let scope_metadata = bcx.fcx.debug_context.get_ref(cx, span).fn_metadata;
|
||||
|
||||
let llvm_env_data_type = type_of::type_of(cx, env_data_type);
|
||||
// env_pointer is the alloca containing the pointer to the environment,
|
||||
// so it's type is **EnvironmentType. In order to find out the type of
|
||||
// the environment we have to "dereference" two times.
|
||||
let llvm_env_data_type = val_ty(env_pointer).element_type().element_type();
|
||||
let byte_offset_of_var_in_env = machine::llelement_offset(cx,
|
||||
llvm_env_data_type,
|
||||
env_index);
|
||||
|
@ -386,20 +386,81 @@ fn convert_angle_bracketed_parameters<'tcx, AC, RS>(this: &AC,
|
||||
(regions, types)
|
||||
}
|
||||
|
||||
/// Returns the appropriate lifetime to use for any output lifetimes
|
||||
/// (if one exists) and a vector of the (pattern, number of lifetimes)
|
||||
/// corresponding to each input type/pattern.
|
||||
fn find_implied_output_region(input_tys: &[Ty], input_pats: Vec<String>)
|
||||
-> (Option<ty::Region>, Vec<(String, uint)>)
|
||||
{
|
||||
let mut lifetimes_for_params: Vec<(String, uint)> = Vec::new();
|
||||
let mut possible_implied_output_region = None;
|
||||
|
||||
for (input_type, input_pat) in input_tys.iter().zip(input_pats.into_iter()) {
|
||||
let mut accumulator = Vec::new();
|
||||
ty::accumulate_lifetimes_in_type(&mut accumulator, *input_type);
|
||||
|
||||
if accumulator.len() == 1 {
|
||||
// there's a chance that the unique lifetime of this
|
||||
// iteration will be the appropriate lifetime for output
|
||||
// parameters, so lets store it.
|
||||
possible_implied_output_region = Some(accumulator[0])
|
||||
}
|
||||
|
||||
lifetimes_for_params.push((input_pat, accumulator.len()));
|
||||
}
|
||||
|
||||
let implied_output_region = if lifetimes_for_params.iter().map(|&(_, n)| n).sum() == 1 {
|
||||
assert!(possible_implied_output_region.is_some());
|
||||
possible_implied_output_region
|
||||
} else {
|
||||
None
|
||||
};
|
||||
(implied_output_region, lifetimes_for_params)
|
||||
}
|
||||
|
||||
fn convert_ty_with_lifetime_elision<'tcx,AC>(this: &AC,
|
||||
implied_output_region: Option<ty::Region>,
|
||||
param_lifetimes: Vec<(String, uint)>,
|
||||
ty: &ast::Ty)
|
||||
-> Ty<'tcx>
|
||||
where AC: AstConv<'tcx>
|
||||
{
|
||||
match implied_output_region {
|
||||
Some(implied_output_region) => {
|
||||
let rb = SpecificRscope::new(implied_output_region);
|
||||
ast_ty_to_ty(this, &rb, ty)
|
||||
}
|
||||
None => {
|
||||
// All regions must be explicitly specified in the output
|
||||
// if the lifetime elision rules do not apply. This saves
|
||||
// the user from potentially-confusing errors.
|
||||
let rb = UnelidableRscope::new(param_lifetimes);
|
||||
ast_ty_to_ty(this, &rb, ty)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn convert_parenthesized_parameters<'tcx,AC>(this: &AC,
|
||||
data: &ast::ParenthesizedParameterData)
|
||||
-> Vec<Ty<'tcx>>
|
||||
where AC: AstConv<'tcx>
|
||||
{
|
||||
let binding_rscope = BindingRscope::new();
|
||||
|
||||
let inputs = data.inputs.iter()
|
||||
.map(|a_t| ast_ty_to_ty(this, &binding_rscope, &**a_t))
|
||||
.collect();
|
||||
.collect::<Vec<Ty<'tcx>>>();
|
||||
|
||||
let input_params = Vec::from_elem(inputs.len(), String::new());
|
||||
let (implied_output_region,
|
||||
params_lifetimes) = find_implied_output_region(&*inputs, input_params);
|
||||
|
||||
let input_ty = ty::mk_tup(this.tcx(), inputs);
|
||||
|
||||
let output = match data.output {
|
||||
Some(ref output_ty) => ast_ty_to_ty(this, &binding_rscope, &**output_ty),
|
||||
Some(ref output_ty) => convert_ty_with_lifetime_elision(this,
|
||||
implied_output_region,
|
||||
params_lifetimes,
|
||||
&**output_ty),
|
||||
None => ty::mk_nil(this.tcx()),
|
||||
};
|
||||
|
||||
@ -1059,55 +1120,33 @@ fn ty_of_method_or_bare_fn<'a, 'tcx, AC: AstConv<'tcx>>(
|
||||
let self_and_input_tys: Vec<Ty> =
|
||||
self_ty.into_iter().chain(input_tys).collect();
|
||||
|
||||
let mut lifetimes_for_params: Vec<(String, Vec<ty::Region>)> = Vec::new();
|
||||
|
||||
// Second, if there was exactly one lifetime (either a substitution or a
|
||||
// reference) in the arguments, then any anonymous regions in the output
|
||||
// have that lifetime.
|
||||
if implied_output_region.is_none() {
|
||||
let mut self_and_input_tys_iter = self_and_input_tys.iter();
|
||||
if self_ty.is_some() {
|
||||
let lifetimes_for_params = if implied_output_region.is_none() {
|
||||
let input_tys = if self_ty.is_some() {
|
||||
// Skip the first argument if `self` is present.
|
||||
drop(self_and_input_tys_iter.next())
|
||||
}
|
||||
self_and_input_tys.slice_from(1)
|
||||
} else {
|
||||
self_and_input_tys.slice_from(0)
|
||||
};
|
||||
|
||||
for (input_type, input_pat) in self_and_input_tys_iter.zip(input_pats.into_iter()) {
|
||||
let mut accumulator = Vec::new();
|
||||
ty::accumulate_lifetimes_in_type(&mut accumulator, *input_type);
|
||||
lifetimes_for_params.push((input_pat, accumulator));
|
||||
}
|
||||
|
||||
if lifetimes_for_params.iter().map(|&(_, ref x)| x.len()).sum() == 1 {
|
||||
implied_output_region =
|
||||
Some(lifetimes_for_params.iter()
|
||||
.filter_map(|&(_, ref x)|
|
||||
if x.len() == 1 { Some(x[0]) } else { None })
|
||||
.next().unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
let param_lifetimes: Vec<(String, uint)> = lifetimes_for_params.into_iter()
|
||||
.map(|(n, v)| (n, v.len()))
|
||||
.filter(|&(_, l)| l != 0)
|
||||
.collect();
|
||||
let (ior, lfp) = find_implied_output_region(input_tys, input_pats);
|
||||
implied_output_region = ior;
|
||||
lfp
|
||||
} else {
|
||||
vec![]
|
||||
};
|
||||
|
||||
let output_ty = match decl.output {
|
||||
ast::Return(ref output) if output.node == ast::TyInfer =>
|
||||
ty::FnConverging(this.ty_infer(output.span)),
|
||||
ast::Return(ref output) =>
|
||||
ty::FnConverging(match implied_output_region {
|
||||
Some(implied_output_region) => {
|
||||
let rb = SpecificRscope::new(implied_output_region);
|
||||
ast_ty_to_ty(this, &rb, &**output)
|
||||
}
|
||||
None => {
|
||||
// All regions must be explicitly specified in the output
|
||||
// if the lifetime elision rules do not apply. This saves
|
||||
// the user from potentially-confusing errors.
|
||||
let rb = UnelidableRscope::new(param_lifetimes);
|
||||
ast_ty_to_ty(this, &rb, &**output)
|
||||
}
|
||||
}),
|
||||
ty::FnConverging(convert_ty_with_lifetime_elision(this,
|
||||
implied_output_region,
|
||||
lifetimes_for_params,
|
||||
&**output)),
|
||||
ast::NoReturn(_) => ty::FnDiverging
|
||||
};
|
||||
|
||||
|
46
src/librustc_typeck/check/callee.rs
Normal file
46
src/librustc_typeck/check/callee.rs
Normal file
@ -0,0 +1,46 @@
|
||||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use syntax::ast;
|
||||
use syntax::codemap::Span;
|
||||
use CrateCtxt;
|
||||
|
||||
/// Check that it is legal to call methods of the trait corresponding
|
||||
/// to `trait_id` (this only cares about the trait, not the specific
|
||||
/// method that is called)
|
||||
pub fn check_legal_trait_for_method_call(ccx: &CrateCtxt, span: Span, trait_id: ast::DefId) {
|
||||
let tcx = ccx.tcx;
|
||||
let did = Some(trait_id);
|
||||
let li = &tcx.lang_items;
|
||||
|
||||
if did == li.drop_trait() {
|
||||
span_err!(tcx.sess, span, E0040, "explicit use of destructor method");
|
||||
} else if !tcx.sess.features.borrow().unboxed_closures {
|
||||
// the #[feature(unboxed_closures)] feature isn't
|
||||
// activated so we need to enforce the closure
|
||||
// restrictions.
|
||||
|
||||
let method = if did == li.fn_trait() {
|
||||
"call"
|
||||
} else if did == li.fn_mut_trait() {
|
||||
"call_mut"
|
||||
} else if did == li.fn_once_trait() {
|
||||
"call_once"
|
||||
} else {
|
||||
return // not a closure method, everything is OK.
|
||||
};
|
||||
|
||||
span_err!(tcx.sess, span, E0174,
|
||||
"explicit use of unboxed closure method `{}` is experimental",
|
||||
method);
|
||||
span_help!(tcx.sess, span,
|
||||
"add `#![feature(unboxed_closures)]` to the crate attributes to enable");
|
||||
}
|
||||
}
|
@ -10,7 +10,7 @@
|
||||
|
||||
use super::probe;
|
||||
|
||||
use check::{mod, FnCtxt, NoPreference, PreferMutLvalue};
|
||||
use check::{mod, FnCtxt, NoPreference, PreferMutLvalue, callee};
|
||||
use middle::subst::{mod, Subst};
|
||||
use middle::traits;
|
||||
use middle::ty::{mod, Ty};
|
||||
@ -90,7 +90,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
|
||||
let self_ty = self.adjust_self_ty(unadjusted_self_ty, &pick.adjustment);
|
||||
|
||||
// Make sure nobody calls `drop()` explicitly.
|
||||
self.enforce_drop_trait_limitations(&pick);
|
||||
self.enforce_illegal_method_limitations(&pick);
|
||||
|
||||
// Create substitutions for the method's type parameters.
|
||||
let (rcvr_substs, method_origin) =
|
||||
@ -624,14 +624,11 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
|
||||
self.fcx.infcx()
|
||||
}
|
||||
|
||||
fn enforce_drop_trait_limitations(&self, pick: &probe::Pick) {
|
||||
fn enforce_illegal_method_limitations(&self, pick: &probe::Pick) {
|
||||
// Disallow calls to the method `drop` defined in the `Drop` trait.
|
||||
match pick.method_ty.container {
|
||||
ty::TraitContainer(trait_def_id) => {
|
||||
if Some(trait_def_id) == self.tcx().lang_items.drop_trait() {
|
||||
span_err!(self.tcx().sess, self.span, E0040,
|
||||
"explicit call to destructor");
|
||||
}
|
||||
callee::check_legal_trait_for_method_call(self.fcx.ccx, self.span, trait_def_id)
|
||||
}
|
||||
ty::ImplContainer(..) => {
|
||||
// Since `drop` is a trait method, we expect that any
|
||||
|
@ -130,6 +130,7 @@ pub mod demand;
|
||||
pub mod method;
|
||||
pub mod wf;
|
||||
mod closure;
|
||||
mod callee;
|
||||
|
||||
/// Fields that are part of a `FnCtxt` which are inherited by
|
||||
/// closures defined within the function. For example:
|
||||
@ -5095,8 +5096,17 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
}
|
||||
|
||||
// Case 3. Reference to a method.
|
||||
def::DefStaticMethod(..) => {
|
||||
def::DefStaticMethod(_, providence) |
|
||||
def::DefMethod(_, _, providence) => {
|
||||
assert!(path.segments.len() >= 2);
|
||||
|
||||
match providence {
|
||||
def::FromTrait(trait_did) => {
|
||||
callee::check_legal_trait_for_method_call(fcx.ccx, span, trait_did)
|
||||
}
|
||||
def::FromImpl(_) => {}
|
||||
}
|
||||
|
||||
segment_spaces = Vec::from_elem(path.segments.len() - 2, None);
|
||||
segment_spaces.push(Some(subst::TypeSpace));
|
||||
segment_spaces.push(Some(subst::FnSpace));
|
||||
@ -5108,7 +5118,6 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
def::DefMod(..) |
|
||||
def::DefForeignMod(..) |
|
||||
def::DefLocal(..) |
|
||||
def::DefMethod(..) |
|
||||
def::DefUse(..) |
|
||||
def::DefRegion(..) |
|
||||
def::DefLabel(..) |
|
||||
|
@ -212,6 +212,9 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> {
|
||||
trait_ref.repr(self.crate_context.tcx),
|
||||
token::get_ident(item.ident));
|
||||
|
||||
enforce_trait_manually_implementable(self.crate_context.tcx,
|
||||
item.span,
|
||||
trait_ref.def_id);
|
||||
self.add_trait_impl(trait_ref.def_id, impl_did);
|
||||
}
|
||||
|
||||
@ -542,6 +545,28 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn enforce_trait_manually_implementable(tcx: &ty::ctxt, sp: Span, trait_def_id: ast::DefId) {
|
||||
if tcx.sess.features.borrow().unboxed_closures {
|
||||
// the feature gate allows all of them
|
||||
return
|
||||
}
|
||||
let did = Some(trait_def_id);
|
||||
let li = &tcx.lang_items;
|
||||
|
||||
let trait_name = if did == li.fn_trait() {
|
||||
"Fn"
|
||||
} else if did == li.fn_mut_trait() {
|
||||
"FnMut"
|
||||
} else if did == li.fn_once_trait() {
|
||||
"FnOnce"
|
||||
} else {
|
||||
return // everything OK
|
||||
};
|
||||
span_err!(tcx.sess, sp, E0173, "manual implementations of `{}` are experimental", trait_name);
|
||||
span_help!(tcx.sess, sp,
|
||||
"add `#![feature(unboxed_closures)]` to the crate attributes to enable");
|
||||
}
|
||||
|
||||
fn subst_receiver_types_in_method_ty<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||
impl_id: ast::DefId,
|
||||
impl_poly_type: &ty::Polytype<'tcx>,
|
||||
|
@ -53,7 +53,7 @@ register_diagnostics!(
|
||||
E0035,
|
||||
E0036,
|
||||
E0038,
|
||||
E0040,
|
||||
E0040, // explicit use of destructor method
|
||||
E0044,
|
||||
E0045,
|
||||
E0046,
|
||||
@ -147,5 +147,7 @@ register_diagnostics!(
|
||||
E0168,
|
||||
E0169,
|
||||
E0171,
|
||||
E0172
|
||||
E0172,
|
||||
E0173, // manual implementations of unboxed closure traits are experimental
|
||||
E0174 // explicit use of unboxed closure methods are experimental
|
||||
)
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
@ -28,10 +28,22 @@ pub enum CharacterSet {
|
||||
|
||||
impl Copy for CharacterSet {}
|
||||
|
||||
/// Available newline types
|
||||
pub enum Newline {
|
||||
/// A linefeed (i.e. Unix-style newline)
|
||||
LF,
|
||||
/// A carriage return and a linefeed (i.e. Windows-style newline)
|
||||
CRLF
|
||||
}
|
||||
|
||||
impl Copy for Newline {}
|
||||
|
||||
/// Contains configuration parameters for `to_base64`.
|
||||
pub struct Config {
|
||||
/// Character set to use
|
||||
pub char_set: CharacterSet,
|
||||
/// Newline to use
|
||||
pub newline: Newline,
|
||||
/// True to pad output with `=` characters
|
||||
pub pad: bool,
|
||||
/// `Some(len)` to wrap lines at `len`, `None` to disable line wrapping
|
||||
@ -42,15 +54,15 @@ impl Copy for Config {}
|
||||
|
||||
/// Configuration for RFC 4648 standard base64 encoding
|
||||
pub static STANDARD: Config =
|
||||
Config {char_set: Standard, pad: true, line_length: None};
|
||||
Config {char_set: Standard, newline: Newline::CRLF, pad: true, line_length: None};
|
||||
|
||||
/// Configuration for RFC 4648 base64url encoding
|
||||
pub static URL_SAFE: Config =
|
||||
Config {char_set: UrlSafe, pad: false, line_length: None};
|
||||
Config {char_set: UrlSafe, newline: Newline::CRLF, pad: false, line_length: None};
|
||||
|
||||
/// Configuration for RFC 2045 MIME base64 encoding
|
||||
pub static MIME: Config =
|
||||
Config {char_set: Standard, pad: true, line_length: Some(76)};
|
||||
Config {char_set: Standard, newline: Newline::CRLF, pad: true, line_length: Some(76)};
|
||||
|
||||
static STANDARD_CHARS: &'static[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ\
|
||||
abcdefghijklmnopqrstuvwxyz\
|
||||
@ -87,24 +99,30 @@ impl ToBase64 for [u8] {
|
||||
UrlSafe => URLSAFE_CHARS
|
||||
};
|
||||
|
||||
let mut v = Vec::new();
|
||||
// In general, this Vec only needs (4/3) * self.len() memory, but
|
||||
// addition is faster than multiplication and division.
|
||||
let mut v = Vec::with_capacity(self.len() + self.len());
|
||||
let mut i = 0;
|
||||
let mut cur_length = 0;
|
||||
let len = self.len();
|
||||
while i < len - (len % 3) {
|
||||
match config.line_length {
|
||||
Some(line_length) =>
|
||||
if cur_length >= line_length {
|
||||
v.push(b'\r');
|
||||
v.push(b'\n');
|
||||
cur_length = 0;
|
||||
},
|
||||
None => ()
|
||||
let mod_len = len % 3;
|
||||
let cond_len = len - mod_len;
|
||||
let newline = match config.newline {
|
||||
Newline::LF => b"\n",
|
||||
Newline::CRLF => b"\r\n"
|
||||
};
|
||||
while i < cond_len {
|
||||
let (first, second, third) = (self[i], self[i + 1], self[i + 2]);
|
||||
if let Some(line_length) = config.line_length {
|
||||
if cur_length >= line_length {
|
||||
v.push_all(newline);
|
||||
cur_length = 0;
|
||||
}
|
||||
}
|
||||
|
||||
let n = (self[i] as u32) << 16 |
|
||||
(self[i + 1] as u32) << 8 |
|
||||
(self[i + 2] as u32);
|
||||
let n = (first as u32) << 16 |
|
||||
(second as u32) << 8 |
|
||||
(third as u32);
|
||||
|
||||
// This 24-bit number gets separated into four 6-bit numbers.
|
||||
v.push(bytes[((n >> 18) & 63) as uint]);
|
||||
@ -116,20 +134,17 @@ impl ToBase64 for [u8] {
|
||||
i += 3;
|
||||
}
|
||||
|
||||
if len % 3 != 0 {
|
||||
match config.line_length {
|
||||
Some(line_length) =>
|
||||
if cur_length >= line_length {
|
||||
v.push(b'\r');
|
||||
v.push(b'\n');
|
||||
},
|
||||
None => ()
|
||||
if mod_len != 0 {
|
||||
if let Some(line_length) = config.line_length {
|
||||
if cur_length >= line_length {
|
||||
v.push_all(newline);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Heh, would be cool if we knew this was exhaustive
|
||||
// (the dream of bounded integer types)
|
||||
match len % 3 {
|
||||
match mod_len {
|
||||
0 => (),
|
||||
1 => {
|
||||
let n = (self[i] as u32) << 16;
|
||||
@ -232,7 +247,7 @@ impl FromBase64 for str {
|
||||
|
||||
impl FromBase64 for [u8] {
|
||||
fn from_base64(&self) -> Result<Vec<u8>, FromBase64Error> {
|
||||
let mut r = Vec::new();
|
||||
let mut r = Vec::with_capacity(self.len());
|
||||
let mut buf: u32 = 0;
|
||||
let mut modulus = 0i;
|
||||
|
||||
@ -288,7 +303,7 @@ impl FromBase64 for [u8] {
|
||||
mod tests {
|
||||
extern crate test;
|
||||
use self::test::Bencher;
|
||||
use base64::{Config, FromBase64, ToBase64, STANDARD, URL_SAFE};
|
||||
use base64::{Config, Newline, FromBase64, ToBase64, STANDARD, URL_SAFE};
|
||||
|
||||
#[test]
|
||||
fn test_to_base64_basic() {
|
||||
@ -302,14 +317,27 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_to_base64_line_break() {
|
||||
fn test_to_base64_crlf_line_break() {
|
||||
assert!(![0u8, ..1000].to_base64(Config {line_length: None, ..STANDARD})
|
||||
.contains("\r\n"));
|
||||
assert_eq!("foobar".as_bytes().to_base64(Config {line_length: Some(4),
|
||||
..STANDARD}),
|
||||
assert_eq!(b"foobar".to_base64(Config {line_length: Some(4),
|
||||
..STANDARD}),
|
||||
"Zm9v\r\nYmFy");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_to_base64_lf_line_break() {
|
||||
assert!(![0u8, ..1000].to_base64(Config {line_length: None,
|
||||
newline: Newline::LF,
|
||||
..STANDARD})
|
||||
.as_slice()
|
||||
.contains("\n"));
|
||||
assert_eq!(b"foobar".to_base64(Config {line_length: Some(4),
|
||||
newline: Newline::LF,
|
||||
..STANDARD}),
|
||||
"Zm9v\nYmFy");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_to_base64_padding() {
|
||||
assert_eq!("f".as_bytes().to_base64(Config {pad: false, ..STANDARD}), "Zg");
|
||||
@ -344,6 +372,10 @@ mod tests {
|
||||
b"foobar");
|
||||
assert_eq!("Zm9vYg==\r\n".from_base64().unwrap(),
|
||||
b"foob");
|
||||
assert_eq!("Zm9v\nYmFy".from_base64().unwrap(),
|
||||
b"foobar");
|
||||
assert_eq!("Zm9vYg==\n".from_base64().unwrap(),
|
||||
b"foob");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -23,7 +23,7 @@ Core encoding and decoding interfaces.
|
||||
html_root_url = "http://doc.rust-lang.org/nightly/",
|
||||
html_playground_url = "http://play.rust-lang.org/")]
|
||||
#![allow(unknown_features)]
|
||||
#![feature(macro_rules, default_type_params, phase, slicing_syntax, globs)]
|
||||
#![feature(macro_rules, default_type_params, phase, slicing_syntax, globs, if_let)]
|
||||
|
||||
// test harness access
|
||||
#[cfg(test)]
|
||||
|
@ -21,9 +21,11 @@ use iter::IteratorExt;
|
||||
use mem;
|
||||
use ops::*;
|
||||
use option::*;
|
||||
use option::Option::{None, Some};
|
||||
use os;
|
||||
use path::{Path,GenericPath};
|
||||
use result::*;
|
||||
use result::Result::{Err, Ok};
|
||||
use slice::{AsSlice,SlicePrelude};
|
||||
use str;
|
||||
use string::String;
|
||||
@ -216,6 +218,7 @@ pub mod dl {
|
||||
use kinds::Copy;
|
||||
use ptr;
|
||||
use result::*;
|
||||
use result::Result::{Err, Ok};
|
||||
use string::String;
|
||||
|
||||
pub unsafe fn open_external<T: ToCStr>(filename: T) -> *mut u8 {
|
||||
|
@ -160,7 +160,7 @@ pub fn getcwd() -> IoResult<Path> {
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
pub mod windows {
|
||||
pub mod windoze {
|
||||
use libc::types::os::arch::extra::DWORD;
|
||||
use libc;
|
||||
use option::Option;
|
||||
@ -386,7 +386,7 @@ pub fn getenv_as_bytes(n: &str) -> Option<Vec<u8>> {
|
||||
pub fn getenv(n: &str) -> Option<String> {
|
||||
unsafe {
|
||||
with_env_lock(|| {
|
||||
use os::windows::{fill_utf16_buf_and_decode};
|
||||
use os::windoze::{fill_utf16_buf_and_decode};
|
||||
let mut n: Vec<u16> = n.utf16_units().collect();
|
||||
n.push(0);
|
||||
fill_utf16_buf_and_decode(|buf, sz| {
|
||||
@ -715,7 +715,7 @@ pub fn self_exe_name() -> Option<Path> {
|
||||
#[cfg(windows)]
|
||||
fn load_self() -> Option<Vec<u8>> {
|
||||
unsafe {
|
||||
use os::windows::fill_utf16_buf_and_decode;
|
||||
use os::windoze::fill_utf16_buf_and_decode;
|
||||
fill_utf16_buf_and_decode(|buf, sz| {
|
||||
libc::GetModuleFileNameW(0u as libc::DWORD, buf, sz)
|
||||
}).map(|s| s.into_string().into_bytes())
|
||||
@ -1215,7 +1215,11 @@ pub enum MapOption {
|
||||
/// Create a map for a specific address range. Corresponds to `MAP_FIXED` on
|
||||
/// POSIX.
|
||||
MapAddr(*const u8),
|
||||
/// Create a memory mapping for a file with a given HANDLE.
|
||||
#[cfg(windows)]
|
||||
MapFd(libc::HANDLE),
|
||||
/// Create a memory mapping for a file with a given fd.
|
||||
#[cfg(not(windows))]
|
||||
MapFd(c_int),
|
||||
/// When using `MapFd`, the start of the map is `uint` bytes from the start
|
||||
/// of the file.
|
||||
@ -1413,7 +1417,7 @@ impl MemoryMap {
|
||||
let mut readable = false;
|
||||
let mut writable = false;
|
||||
let mut executable = false;
|
||||
let mut fd: c_int = -1;
|
||||
let mut handle: HANDLE = libc::INVALID_HANDLE_VALUE;
|
||||
let mut offset: uint = 0;
|
||||
let len = round_up(min_len, page_size());
|
||||
|
||||
@ -1423,23 +1427,23 @@ impl MemoryMap {
|
||||
MapWritable => { writable = true; },
|
||||
MapExecutable => { executable = true; }
|
||||
MapAddr(addr_) => { lpAddress = addr_ as LPVOID; },
|
||||
MapFd(fd_) => { fd = fd_; },
|
||||
MapFd(handle_) => { handle = handle_; },
|
||||
MapOffset(offset_) => { offset = offset_; },
|
||||
MapNonStandardFlags(..) => {}
|
||||
}
|
||||
}
|
||||
|
||||
let flProtect = match (executable, readable, writable) {
|
||||
(false, false, false) if fd == -1 => libc::PAGE_NOACCESS,
|
||||
(false, false, false) if handle == libc::INVALID_HANDLE_VALUE => libc::PAGE_NOACCESS,
|
||||
(false, true, false) => libc::PAGE_READONLY,
|
||||
(false, true, true) => libc::PAGE_READWRITE,
|
||||
(true, false, false) if fd == -1 => libc::PAGE_EXECUTE,
|
||||
(true, false, false) if handle == libc::INVALID_HANDLE_VALUE => libc::PAGE_EXECUTE,
|
||||
(true, true, false) => libc::PAGE_EXECUTE_READ,
|
||||
(true, true, true) => libc::PAGE_EXECUTE_READWRITE,
|
||||
_ => return Err(ErrUnsupProt)
|
||||
};
|
||||
|
||||
if fd == -1 {
|
||||
if handle == libc::INVALID_HANDLE_VALUE {
|
||||
if offset != 0 {
|
||||
return Err(ErrUnsupOffset);
|
||||
}
|
||||
@ -1467,7 +1471,7 @@ impl MemoryMap {
|
||||
// we should never get here.
|
||||
};
|
||||
unsafe {
|
||||
let hFile = libc::get_osfhandle(fd) as HANDLE;
|
||||
let hFile = handle;
|
||||
let mapping = libc::CreateFileMappingW(hFile,
|
||||
ptr::null_mut(),
|
||||
flProtect,
|
||||
@ -1991,55 +1995,47 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn memory_map_file() {
|
||||
use result::Result::{Ok, Err};
|
||||
use libc;
|
||||
use os::*;
|
||||
use libc::*;
|
||||
use io::fs;
|
||||
use io::fs::{File, unlink};
|
||||
use io::SeekStyle::SeekSet;
|
||||
use io::FileMode::Open;
|
||||
use io::FileAccess::ReadWrite;
|
||||
|
||||
#[cfg(unix)]
|
||||
fn lseek_(fd: c_int, size: uint) {
|
||||
unsafe {
|
||||
assert!(lseek(fd, size as off_t, SEEK_SET) == size as off_t);
|
||||
}
|
||||
#[cfg(not(windows))]
|
||||
fn get_fd(file: &File) -> libc::c_int {
|
||||
use os::unix::AsRawFd;
|
||||
file.as_raw_fd()
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
fn lseek_(fd: c_int, size: uint) {
|
||||
unsafe {
|
||||
assert!(lseek(fd, size as c_long, SEEK_SET) == size as c_long);
|
||||
}
|
||||
fn get_fd(file: &File) -> libc::HANDLE {
|
||||
use os::windows::AsRawHandle;
|
||||
file.as_raw_handle()
|
||||
}
|
||||
|
||||
let mut path = tmpdir();
|
||||
path.push("mmap_file.tmp");
|
||||
let size = MemoryMap::granularity() * 2;
|
||||
let mut file = File::open_mode(&path, Open, ReadWrite).unwrap();
|
||||
file.seek(size as i64, SeekSet);
|
||||
file.write_u8(0);
|
||||
|
||||
let fd = unsafe {
|
||||
let fd = path.with_c_str(|path| {
|
||||
open(path, O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR)
|
||||
});
|
||||
lseek_(fd, size);
|
||||
"x".with_c_str(|x| assert!(write(fd, x as *const c_void, 1) == 1));
|
||||
fd
|
||||
};
|
||||
let chunk = match MemoryMap::new(size / 2, &[
|
||||
let chunk = MemoryMap::new(size / 2, &[
|
||||
MapReadable,
|
||||
MapWritable,
|
||||
MapFd(fd),
|
||||
MapFd(get_fd(&file)),
|
||||
MapOffset(size / 2)
|
||||
]) {
|
||||
Ok(chunk) => chunk,
|
||||
Err(msg) => panic!("{}", msg)
|
||||
};
|
||||
]).unwrap();
|
||||
assert!(chunk.len > 0);
|
||||
|
||||
unsafe {
|
||||
*chunk.data = 0xbe;
|
||||
assert!(*chunk.data == 0xbe);
|
||||
close(fd);
|
||||
}
|
||||
drop(chunk);
|
||||
|
||||
fs::unlink(&path).unwrap();
|
||||
unlink(&path).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -80,7 +80,7 @@
|
||||
//! circle, both centered at the origin. Since the area of a unit circle is π,
|
||||
//! we have:
|
||||
//!
|
||||
//! ```notrust
|
||||
//! ```text
|
||||
//! (area of unit circle) / (area of square) = π / 4
|
||||
//! ```
|
||||
//!
|
||||
|
@ -8,7 +8,7 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use option::None;
|
||||
use option::Option::None;
|
||||
use rustrt::task::Task;
|
||||
use rustrt::local::Local;
|
||||
|
||||
|
@ -185,7 +185,23 @@ impl StaticKey {
|
||||
}
|
||||
|
||||
unsafe fn lazy_init(&self) -> uint {
|
||||
let key = imp::create(self.dtor);
|
||||
// POSIX allows the key created here to be 0, but the compare_and_swap
|
||||
// below relies on using 0 as a sentinel value to check who won the
|
||||
// race to set the shared TLS key. As far as I know, there is no
|
||||
// guaranteed value that cannot be returned as a posix_key_create key,
|
||||
// so there is no value we can initialize the inner key with to
|
||||
// prove that it has not yet been set. As such, we'll continue using a
|
||||
// value of 0, but with some gyrations to make sure we have a non-0
|
||||
// value returned from the creation routine.
|
||||
// FIXME: this is clearly a hack, and should be cleaned up.
|
||||
let key1 = imp::create(self.dtor);
|
||||
let key = if key1 != 0 {
|
||||
key1
|
||||
} else {
|
||||
let key2 = imp::create(self.dtor);
|
||||
imp::destroy(key1);
|
||||
key2
|
||||
};
|
||||
assert!(key != 0);
|
||||
match self.inner.key.compare_and_swap(0, key as uint, atomic::SeqCst) {
|
||||
// The CAS succeeded, so we've created the actual key
|
||||
|
@ -15,7 +15,7 @@ use libc::{mod, c_int};
|
||||
|
||||
use c_str::CString;
|
||||
use mem;
|
||||
use os::windows::fill_utf16_buf_and_decode;
|
||||
use os::windoze::fill_utf16_buf_and_decode;
|
||||
use path;
|
||||
use ptr;
|
||||
use str;
|
||||
|
@ -66,12 +66,19 @@ pub fn cs_cmp(cx: &mut ExtCtxt, span: Span,
|
||||
cx.ident_of("cmp"),
|
||||
cx.ident_of("Equal")));
|
||||
|
||||
let cmp_path = vec![
|
||||
cx.ident_of("std"),
|
||||
cx.ident_of("cmp"),
|
||||
cx.ident_of("Ord"),
|
||||
cx.ident_of("cmp"),
|
||||
];
|
||||
|
||||
/*
|
||||
Builds:
|
||||
|
||||
let __test = self_field1.cmp(&other_field2);
|
||||
let __test = ::std::cmp::Ord::cmp(&self_field1, &other_field1);
|
||||
if other == ::std::cmp::Ordering::Equal {
|
||||
let __test = self_field2.cmp(&other_field2);
|
||||
let __test = ::std::cmp::Ord::cmp(&self_field2, &other_field2);
|
||||
if __test == ::std::cmp::Ordering::Equal {
|
||||
...
|
||||
} else {
|
||||
@ -83,11 +90,11 @@ pub fn cs_cmp(cx: &mut ExtCtxt, span: Span,
|
||||
|
||||
FIXME #6449: These `if`s could/should be `match`es.
|
||||
*/
|
||||
cs_same_method_fold(
|
||||
cs_fold(
|
||||
// foldr nests the if-elses correctly, leaving the first field
|
||||
// as the outermost one, and the last as the innermost.
|
||||
false,
|
||||
|cx, span, old, new| {
|
||||
|cx, span, old, self_f, other_fs| {
|
||||
// let __test = new;
|
||||
// if __test == ::std::cmp::Ordering::Equal {
|
||||
// old
|
||||
@ -95,6 +102,20 @@ pub fn cs_cmp(cx: &mut ExtCtxt, span: Span,
|
||||
// __test
|
||||
// }
|
||||
|
||||
let new = {
|
||||
let other_f = match other_fs {
|
||||
[ref o_f] => o_f,
|
||||
_ => cx.span_bug(span, "not exactly 2 arguments in `deriving(PartialOrd)`"),
|
||||
};
|
||||
|
||||
let args = vec![
|
||||
cx.expr_addr_of(span, self_f),
|
||||
cx.expr_addr_of(span, other_f.clone()),
|
||||
];
|
||||
|
||||
cx.expr_call_global(span, cmp_path.clone(), args)
|
||||
};
|
||||
|
||||
let assign = cx.stmt_let(span, false, test_id, new);
|
||||
|
||||
let cond = cx.expr_binary(span, ast::BiEq,
|
||||
|
@ -20,5 +20,5 @@ impl Drop for Foo {
|
||||
|
||||
fn main() {
|
||||
let x = Foo { x: 3 };
|
||||
x.drop(); //~ ERROR explicit call to destructor
|
||||
x.drop(); //~ ERROR explicit use of destructor method
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ impl Drop for Foo {
|
||||
|
||||
impl Bar for Foo {
|
||||
fn blah(&self) {
|
||||
self.drop(); //~ ERROR explicit call to destructor
|
||||
self.drop(); //~ ERROR explicit use of destructor method
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,26 @@
|
||||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![allow(dead_code)]
|
||||
|
||||
struct Foo;
|
||||
impl Fn<(), ()> for Foo { //~ ERROR manual implementations of `Fn` are experimental
|
||||
extern "rust-call" fn call(&self, args: ()) -> () {}
|
||||
}
|
||||
struct Bar;
|
||||
impl FnMut<(), ()> for Bar { //~ ERROR manual implementations of `FnMut` are experimental
|
||||
extern "rust-call" fn call_mut(&self, args: ()) -> () {}
|
||||
}
|
||||
struct Baz;
|
||||
impl FnOnce<(), ()> for Baz { //~ ERROR manual implementations of `FnOnce` are experimental
|
||||
extern "rust-call" fn call_once(&self, args: ()) -> () {}
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,19 @@
|
||||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![allow(dead_code)]
|
||||
|
||||
fn foo<F: Fn<(), ()>>(mut f: F) {
|
||||
f.call(()); //~ ERROR explicit use of unboxed closure method `call`
|
||||
f.call_mut(()); //~ ERROR explicit use of unboxed closure method `call_mut`
|
||||
f.call_once(()); //~ ERROR explicit use of unboxed closure method `call_once`
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,19 @@
|
||||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![allow(dead_code)]
|
||||
|
||||
fn foo<F: Fn<(), ()>>(mut f: F, mut g: F) {
|
||||
Fn::call(&g, ()); //~ ERROR explicit use of unboxed closure method `call`
|
||||
FnMut::call_mut(&mut g, ()); //~ ERROR explicit use of unboxed closure method `call_mut`
|
||||
FnOnce::call_once(g, ()); //~ ERROR explicit use of unboxed closure method `call_once`
|
||||
}
|
||||
|
||||
fn main() {}
|
20
src/test/compile-fail/illegal-ufcs-drop.rs
Normal file
20
src/test/compile-fail/illegal-ufcs-drop.rs
Normal file
@ -0,0 +1,20 @@
|
||||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
struct Foo;
|
||||
|
||||
impl Drop for Foo {
|
||||
fn drop(&mut self) {}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
Drop::drop(&mut Foo) //~ ERROR explicit use of destructor method
|
||||
}
|
@ -33,7 +33,6 @@ fn h(_x: &Foo) -> &int { //~ ERROR missing lifetime specifier
|
||||
|
||||
fn i(_x: int) -> &int { //~ ERROR missing lifetime specifier
|
||||
//~^ HELP this function's return type contains a borrowed value
|
||||
//~^^ HELP consider giving it a 'static lifetime
|
||||
panic!()
|
||||
}
|
||||
|
||||
|
@ -44,9 +44,9 @@ fn test<'a,'b>() {
|
||||
eq::< for<'a,'b> Foo<(&'a int,&'b uint),uint>,
|
||||
Foo(&int,&uint) -> uint >();
|
||||
|
||||
// FIXME(#18992) Test lifetime elision in `()` form:
|
||||
// eq::< for<'a,'b> Foo<(&'a int,), &'a int>,
|
||||
// Foo(&int) -> &int >();
|
||||
// lifetime elision
|
||||
eq::< for<'a,'b> Foo<(&'a int,), &'a int>,
|
||||
Foo(&int) -> &int >();
|
||||
|
||||
// Errors expected:
|
||||
eq::< Foo<(),()>, Foo(char) >();
|
||||
|
@ -0,0 +1,34 @@
|
||||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Test that the unboxed closure sugar can be used with an arbitrary
|
||||
// struct type and that it is equivalent to the same syntax using
|
||||
// angle brackets. This test covers only simple types and in
|
||||
// particular doesn't test bound regions.
|
||||
|
||||
#![feature(unboxed_closures)]
|
||||
#![allow(dead_code)]
|
||||
|
||||
trait Foo<T,U> {
|
||||
fn dummy(&self, t: T, u: U);
|
||||
}
|
||||
|
||||
trait Eq<Sized? X> for Sized? { }
|
||||
impl<Sized? X> Eq<X> for X { }
|
||||
fn eq<Sized? A,Sized? B:Eq<A>>() { }
|
||||
|
||||
fn main() {
|
||||
eq::< for<'a> Foo<(&'a int,), &'a int>,
|
||||
Foo(&int) -> &int >();
|
||||
eq::< for<'a> Foo<(&'a int,), (&'a int, &'a int)>,
|
||||
Foo(&int) -> (&int, &int) >();
|
||||
|
||||
let _: Foo(&int, &uint) -> &uint; //~ ERROR missing lifetime specifier
|
||||
}
|
@ -28,6 +28,19 @@
|
||||
// gdb-command:print *owned
|
||||
// gdb-check:$5 = 6
|
||||
|
||||
// gdb-command:continue
|
||||
|
||||
// gdb-command:print variable
|
||||
// gdb-check:$6 = 2
|
||||
// gdb-command:print constant
|
||||
// gdb-check:$7 = 2
|
||||
// gdb-command:print a_struct
|
||||
// gdb-check:$8 = {a = -3, b = 4.5, c = 5}
|
||||
// gdb-command:print *struct_ref
|
||||
// gdb-check:$9 = {a = -3, b = 4.5, c = 5}
|
||||
// gdb-command:print *owned
|
||||
// gdb-check:$10 = 6
|
||||
|
||||
|
||||
// === LLDB TESTS ==================================================================================
|
||||
|
||||
@ -44,6 +57,20 @@
|
||||
// lldb-command:print *owned
|
||||
// lldb-check:[...]$4 = 6
|
||||
|
||||
// lldb-command:continue
|
||||
|
||||
// lldb-command:print variable
|
||||
// lldb-check:[...]$5 = 2
|
||||
// lldb-command:print constant
|
||||
// lldb-check:[...]$6 = 2
|
||||
// lldb-command:print a_struct
|
||||
// lldb-check:[...]$7 = Struct { a: -3, b: 4.5, c: 5 }
|
||||
// lldb-command:print *struct_ref
|
||||
// lldb-check:[...]$8 = Struct { a: -3, b: 4.5, c: 5 }
|
||||
// lldb-command:print *owned
|
||||
// lldb-check:[...]$9 = 6
|
||||
|
||||
#![feature(unboxed_closures)]
|
||||
#![allow(unused_variables)]
|
||||
|
||||
struct Struct {
|
||||
@ -65,12 +92,22 @@ fn main() {
|
||||
let struct_ref = &a_struct;
|
||||
let owned = box 6;
|
||||
|
||||
let closure = || {
|
||||
zzz(); // #break
|
||||
variable = constant + a_struct.a + struct_ref.a + *owned;
|
||||
};
|
||||
{
|
||||
let closure = || {
|
||||
zzz(); // #break
|
||||
variable = constant + a_struct.a + struct_ref.a + *owned;
|
||||
};
|
||||
|
||||
closure();
|
||||
closure();
|
||||
}
|
||||
|
||||
{
|
||||
let mut unboxed_closure = |&mut:| {
|
||||
zzz(); // #break
|
||||
variable = constant + a_struct.a + struct_ref.a + *owned;
|
||||
};
|
||||
unboxed_closure();
|
||||
}
|
||||
}
|
||||
|
||||
fn zzz() {()}
|
||||
|
@ -8,18 +8,18 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#[deriving(PartialEq, PartialOrd)]
|
||||
#[deriving(Eq, PartialEq, PartialOrd, Ord)]
|
||||
enum Test<'a> {
|
||||
Int(&'a int),
|
||||
Slice(&'a [u8]),
|
||||
}
|
||||
|
||||
#[deriving(PartialEq, PartialOrd)]
|
||||
#[deriving(Eq, PartialEq, PartialOrd, Ord)]
|
||||
struct Version {
|
||||
vendor_info: &'static str
|
||||
}
|
||||
|
||||
#[deriving(PartialEq, PartialOrd)]
|
||||
#[deriving(Eq, PartialEq, PartialOrd, Ord)]
|
||||
struct Foo(&'static str);
|
||||
|
||||
fn main() {}
|
||||
|
22
src/test/run-pass/ufcs-type-params.rs
Normal file
22
src/test/run-pass/ufcs-type-params.rs
Normal file
@ -0,0 +1,22 @@
|
||||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
trait Foo<T> {
|
||||
fn get(&self) -> T;
|
||||
}
|
||||
|
||||
impl Foo<i32> for i32 {
|
||||
fn get(&self) -> i32 { *self }
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x: i32 = 1;
|
||||
Foo::<i32>::get(&x);
|
||||
}
|
@ -8,8 +8,6 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// ignore-test
|
||||
|
||||
extern crate libc;
|
||||
|
||||
use std::io::process::Command;
|
||||
@ -18,51 +16,38 @@ use std::iter::IteratorExt;
|
||||
use libc::funcs::posix88::unistd;
|
||||
|
||||
|
||||
// "ps -A -o pid,sid,command" with GNU ps should output something like this:
|
||||
// PID SID COMMAND
|
||||
// 1 1 /sbin/init
|
||||
// The output from "ps -A -o pid,ppid,args" should look like this:
|
||||
// PID PPID COMMAND
|
||||
// 1 0 /sbin/init
|
||||
// 2 0 [kthreadd]
|
||||
// 3 0 [ksoftirqd/0]
|
||||
// ...
|
||||
// 12562 9237 ./spawn-failure
|
||||
// 12563 9237 [spawn-failure] <defunct>
|
||||
// 12564 9237 [spawn-failure] <defunct>
|
||||
// 6076 9064 /bin/zsh
|
||||
// ...
|
||||
// 12592 9237 [spawn-failure] <defunct>
|
||||
// 12593 9237 ps -A -o pid,sid,command
|
||||
// 12884 12884 /bin/zsh
|
||||
// 12922 12922 /bin/zsh
|
||||
// 7164 6076 ./spawn-failure
|
||||
// 7165 7164 [spawn-failure] <defunct>
|
||||
// 7166 7164 [spawn-failure] <defunct>
|
||||
// ...
|
||||
// 7197 7164 [spawn-failure] <defunct>
|
||||
// 7198 7164 ps -A -o pid,ppid,command
|
||||
// ...
|
||||
|
||||
#[cfg(unix)]
|
||||
fn find_zombies() {
|
||||
// http://man.freebsd.org/ps(1)
|
||||
// http://man7.org/linux/man-pages/man1/ps.1.html
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
const FIELDS: &'static str = "pid,sid,command";
|
||||
let my_pid = unsafe { unistd::getpid() };
|
||||
|
||||
// https://developer.apple.com/library/mac/documentation/Darwin/
|
||||
// Reference/ManPages/man1/ps.1.html
|
||||
#[cfg(target_os = "macos")]
|
||||
const FIELDS: &'static str = "pid,sess,command";
|
||||
|
||||
let my_sid = unsafe { unistd::getsid(0) };
|
||||
|
||||
let ps_cmd_output = Command::new("ps").args(&["-A", "-o", FIELDS]).output().unwrap();
|
||||
// http://pubs.opengroup.org/onlinepubs/9699919799/utilities/ps.html
|
||||
let ps_cmd_output = Command::new("ps").args(&["-A", "-o", "pid,ppid,args"]).output().unwrap();
|
||||
let ps_output = String::from_utf8_lossy(ps_cmd_output.output.as_slice());
|
||||
|
||||
let found = ps_output.split('\n').enumerate().any(|(line_no, line)|
|
||||
0 < line_no && 0 < line.len() &&
|
||||
my_sid == from_str(line.split(' ').filter(|w| 0 < w.len()).nth(1)
|
||||
.expect("1st column should be Session ID")
|
||||
).expect("Session ID string into integer") &&
|
||||
line.contains("defunct") && {
|
||||
println!("Zombie child {}", line);
|
||||
true
|
||||
for (line_no, line) in ps_output.split('\n').enumerate() {
|
||||
if 0 < line_no && 0 < line.len() &&
|
||||
my_pid == from_str(line.split(' ').filter(|w| 0 < w.len()).nth(1)
|
||||
.expect("1st column should be PPID")
|
||||
).expect("PPID string into integer") &&
|
||||
line.contains("defunct") {
|
||||
panic!("Zombie child {}", line);
|
||||
}
|
||||
);
|
||||
|
||||
assert!( ! found, "Found at least one zombie child");
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
@ -71,10 +56,13 @@ fn find_zombies() { }
|
||||
fn main() {
|
||||
let too_long = format!("/NoSuchCommand{:0300}", 0u8);
|
||||
|
||||
for _ in range(0u32, 100) {
|
||||
let invalid = Command::new(too_long.as_slice()).spawn();
|
||||
assert!(invalid.is_err());
|
||||
}
|
||||
let _failures = Vec::from_fn(100, |_i| {
|
||||
let cmd = Command::new(too_long.as_slice());
|
||||
let failed = cmd.spawn();
|
||||
assert!(failed.is_err(), "Make sure the command fails to spawn(): {}", cmd);
|
||||
failed
|
||||
});
|
||||
|
||||
find_zombies();
|
||||
// then _failures goes out of scope
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user