diff --git a/mk/docs.mk b/mk/docs.mk index 933a0bdc717ca..b81851e93c0b3 100644 --- a/mk/docs.mk +++ b/mk/docs.mk @@ -112,8 +112,8 @@ HTML_DEPS += doc/version_info.html doc/version_info.html: $(D)/version_info.html.template $(MKFILE_DEPS) \ $(wildcard $(D)/*.*) | doc/ @$(call E, version-info: $@) - $(Q)sed -e "s/VERSION/$(CFG_RELEASE)/; s/SHORT_HASH/$(shell echo \ - $(CFG_VER_HASH) | head -c 8)/;\ + $(Q)sed -e "s/VERSION/$(CFG_RELEASE)/; s/SHORT_HASH/$(\ + CFG_SHORT_VER_HASH)/;\ s/STAMP/$(CFG_VER_HASH)/;" $< >$@ GENERATED += doc/version.tex doc/version_info.html diff --git a/mk/main.mk b/mk/main.mk index 15e9897d47dbd..98b83530c8de0 100644 --- a/mk/main.mk +++ b/mk/main.mk @@ -46,7 +46,8 @@ ifneq ($(wildcard $(subst $(SPACE),\$(SPACE),$(CFG_GIT))),) ifneq ($(wildcard $(subst $(SPACE),\$(SPACE),$(CFG_GIT_DIR))),) CFG_VER_DATE = $(shell git --git-dir='$(CFG_GIT_DIR)' log -1 --pretty=format:'%ci') CFG_VER_HASH = $(shell git --git-dir='$(CFG_GIT_DIR)' rev-parse HEAD) - CFG_VERSION += ($(CFG_VER_HASH) $(CFG_VER_DATE)) + CFG_SHORT_VER_HASH = $(shell git --git-dir='$(CFG_GIT_DIR)' rev-parse --short=9 HEAD) + CFG_VERSION += ($(CFG_SHORT_VER_HASH) $(CFG_VER_DATE)) endif endif diff --git a/src/doc/guide.md b/src/doc/guide.md index 0175817e66a7e..e3acb0575d226 100644 --- a/src/doc/guide.md +++ b/src/doc/guide.md @@ -18,8 +18,9 @@ something special, and we hope you do too. To show you how to get going with Rust, we're going to write the traditional "Hello, World!" program. Next, we'll introduce you to a tool that's useful for -writing real-world Rust programs and libraries: "Cargo." Then, we'll show off -Rust's features by writing a little program together. +writing real-world Rust programs and libraries: "Cargo." After that, we'll talk +about the basics of Rust, write a little program to try them out, and then learn +more advanced things. Sound good? Let's go! @@ -357,70 +358,9 @@ That's it! We've successfully built `hello_world` with Cargo. Even though our program is simple, it's using much of the real tooling that you'll use for the rest of your Rust career. -Next, we'll learn more about Rust itself, by starting to write a more complicated -program. We hope you want to do more with Rust than just print "Hello, world!" - -## Guessing Game - -Let's write a bigger program in Rust. We could just go through a laundry list -of Rust features, but that's boring. Instead, we'll learn more about how to -code in Rust by writing a few example projects. - -For our first project, we'll implement a classic beginner programming problem: -the guessing game. Here's how it works: Our program will generate a random -integer between one and a hundred. It will then prompt us to enter a guess. -Upon entering our guess, it will tell us if we're too low or too high. Once we -guess correctly, it will congratulate us, and print the number of guesses we've -taken to the screen. Sound good? It sounds easy, but it'll end up showing off a -number of basic features of Rust. - -### Set up - -Let's set up a new project. Go to your projects directory, and make a new -directory for the project, as well as a `src` directory for our code: - -```{bash} -$ cd ~/projects -$ mkdir guessing_game -$ cd guessing_game -$ mkdir src -``` - -Great. Next, let's make a `Cargo.toml` file so Cargo knows how to build our -project: - -```{ignore} -[package] - -name = "guessing_game" -version = "0.1.0" -authors = [ "someone@example.com" ] - -[[bin]] - -name = "guessing_game" -``` - -Finally, we need our source file. Let's just make it hello world for now, so we -can check that our setup works. In `src/guessing_game.rs`: - -```{rust} -fn main() { - println!("Hello world!"); -} -``` - -Let's make sure that worked: - -```{bash} -$ cargo build - Compiling guessing_game v0.1.0 (file:/home/you/projects/guessing_game) -$ -``` - -Excellent! Open up your `src/guessing_game.rs` again. We'll be writing all of -our code in this file. The next section of the tutorial will show you how to -build multiple-file projects. +Now that you've got the tools down, let's actually learn more about the Rust +language itself. These are the basics that will serve you well through the rest +of your time with Rust. ## Variable bindings @@ -1143,25 +1083,31 @@ can only be _one_ of `Less`, `Equal`, or `Greater` at any given time. Here's an example: ```rust -let x = 5i; -let y = 10i; +fn cmp(a: int, b: int) -> Ordering { + if a < b { Less } + else if a > b { Greater } + else { Equal } +} -let ordering = x.cmp(&y); +fn main() { + let x = 5i; + let y = 10i; -if ordering == Less { - println!("less"); -} else if ordering == Greater { - println!("greater"); -} else if ordering == Equal { - println!("equal"); + let ordering = cmp(x, y); + + if ordering == Less { + println!("less"); + } else if ordering == Greater { + println!("greater"); + } else if ordering == Equal { + println!("equal"); + } } ``` -`cmp` is a function that compares two things, and returns an `Ordering`. The -call looks a little bit strange: rather than `cmp(x, y)`, we say `x.cmp(&y)`. -We haven't covered methods and references yet, so it should look a little bit -foreign. Right now, just pretend it says `cmp(x, y)`, and we'll get to those -details soon. +`cmp` is a function that compares two things, and returns an `Ordering`. We +return either `Less`, `Greater`, or `Equal`, depending on if the two values +are greater, less, or equal. The `ordering` variable has the type `Ordering`, and so contains one of the three values. We can then do a bunch of `if`/`else` comparisons to check @@ -1172,12 +1118,12 @@ that not only makes them nicer to read, but also makes sure that you never miss a case. Before we get to that, though, let's talk about another kind of enum: one with values. -This enum has two variants, one of which has a value.: +This enum has two variants, one of which has a value: -``` +```{rust} enum OptionalInt { Value(int), - Missing + Missing, } fn main() { @@ -1261,30 +1207,46 @@ for every possible value of `x`, and so our program will now compile. section on enums? ```{rust} -let x = 5i; -let y = 10i; +fn cmp(a: int, b: int) -> Ordering { + if a < b { Less } + else if a > b { Greater } + else { Equal } +} -let ordering = x.cmp(&y); +fn main() { + let x = 5i; + let y = 10i; + + let ordering = cmp(x, y); -if ordering == Less { - println!("less"); -} else if ordering == Greater { - println!("greater"); -} else if ordering == Equal { - println!("equal"); + if ordering == Less { + println!("less"); + } else if ordering == Greater { + println!("greater"); + } else if ordering == Equal { + println!("equal"); + } } ``` We can re-write this as a `match`: ```{rust} -let x = 5i; -let y = 10i; +fn cmp(a: int, b: int) -> Ordering { + if a < b { Less } + else if a > b { Greater } + else { Equal } +} + +fn main() { + let x = 5i; + let y = 10i; -match x.cmp(&y) { - Less => println!("less"), - Greater => println!("greater"), - Equal => println!("equal"), + match cmp(x, y) { + Less => println!("less"), + Greater => println!("greater"), + Equal => println!("equal"), + } } ``` @@ -1297,17 +1259,25 @@ make sure to cover all of our bases. `match` is also an expression, which means we can use it on the right hand side of a `let` binding. We could also implement the previous line like this: -``` -let x = 5i; -let y = 10i; +```{rust} +fn cmp(a: int, b: int) -> Ordering { + if a < b { Less } + else if a > b { Greater } + else { Equal } +} -let result = match x.cmp(&y) { - Less => "less", - Greater => "greater", - Equal => "equal", -}; +fn main() { + let x = 5i; + let y = 10i; + + let result = match cmp(x, y) { + Less => "less", + Greater => "greater", + Equal => "equal", + }; -println!("{}", result); + println!("{}", result); +} ``` In this case, it doesn't make a lot of sense, as we are just making a temporary @@ -1463,6 +1433,8 @@ we haven't seen before. Here's a simple program that reads some input, and then prints it back out: ```{rust,ignore} +use std::io; + fn main() { println!("Type something!"); @@ -1474,7 +1446,7 @@ fn main() { Let's go over these chunks, one by one: -```{rust} +```{rust,ignore} std::io::stdin(); ``` @@ -1527,16 +1499,68 @@ a full line of input. Nice and easy. .ok().expect("Failed to read line"); ``` -Here's the thing: reading a line from standard input could fail. For example, -if this program isn't running in a terminal, but is running as part of a cron -job, or some other context where there's no standard input. So Rust expects us -to handle this case. Given that we plan on always running this program in a -terminal, we use the `ok()` method to tell Rust that we're expecting everything -to be just peachy, and the `expect()` method on that result to give an error -message if our expectation goes wrong. +Do you remember this code? + +``` +enum OptionalInt { + Value(int), + Missing, +} + +fn main() { + let x = Value(5); + let y = Missing; + + match x { + Value(n) => println!("x is {:d}", n), + Missing => println!("x is missing!"), + } + + match y { + Value(n) => println!("y is {:d}", n), + Missing => println!("y is missing!"), + } +} +``` + +We had to match each time, to see if we had a value or not. In this case, +though, we _know_ that `x` has a `Value`. But `match` forces us to handle +the `missing` case. This is what we want 99% of the time, but sometimes, we +know better than the compiler. + +Likewise, `read_line()` does not return a line of input. It _might_ return a +line of input. It might also fail to do so. This could happen if our program +isn't running in a terminal, but as part of a cron job, or some other context +where there's no standard input. Because of this, `read_line` returns a type +very similar to our `OptionalInt`: an `IoResult`. We haven't talked about +`IoResult` yet because it is the **generic** form of our `OptionalInt`. +Until then, you can think of it as being the same thing, just for any type, not +just `int`s. + +Rust provides a method on these `IoResult`s called `ok()`, which does the +same thing as our `match` statement, but assuming that we have a valid value. +If we don't, it will terminate our program. In this case, if we can't get +input, our program doesn't work, so we're okay with that. In most cases, we +would want to handle the error case explicitly. The result of `ok()` has a +method, `expect()`, which allows us to give an error message if this crash +happens. We will cover the exact details of how all of this works later in the Guide. -For now, this is all you need. +For now, this gives you enough of a basic understanding to work with. + +Back to the code we were working on! Here's a refresher: + +```{rust,ignore} +use std::io; + +fn main() { + println!("Type something!"); + + let input = io::stdin().read_line().ok().expect("Failed to read line"); + + println!("{}", input); +} +``` With long lines like this, Rust gives you some flexibility with the whitespace. We _could_ write the example like this: @@ -1562,11 +1586,878 @@ here. That's all you need to get basic input from the standard input! It's not too complicated, but there are a number of small parts. -## Guessing Game: complete +## Guessing Game + +Okay! We've got the basics of Rust down. Let's write a bigger program. + +For our first project, we'll implement a classic beginner programming problem: +the guessing game. Here's how it works: Our program will generate a random +integer between one and a hundred. It will then prompt us to enter a guess. +Upon entering our guess, it will tell us if we're too low or too high. Once we +guess correctly, it will congratulate us, and print the number of guesses we've +taken to the screen. Sound good? + +### Set up + +Let's set up a new project. Go to your projects directory, and make a new +directory for the project, as well as a `src` directory for our code: + +```{bash} +$ cd ~/projects +$ mkdir guessing_game +$ cd guessing_game +$ mkdir src +``` + +Great. Next, let's make a `Cargo.toml` file so Cargo knows how to build our +project: + +```{ignore} +[package] + +name = "guessing_game" +version = "0.1.0" +authors = [ "someone@example.com" ] + +[[bin]] + +name = "guessing_game" +``` + +Finally, we need our source file. Let's just make it hello world for now, so we +can check that our setup works. In `src/guessing_game.rs`: + +```{rust} +fn main() { + println!("Hello world!"); +} +``` + +Let's make sure that worked: + +```{bash} +$ cargo build + Compiling guessing_game v0.1.0 (file:/home/you/projects/guessing_game) +$ +``` + +Excellent! Open up your `src/guessing_game.rs` again. We'll be writing all of +our code in this file. We'll talk about multiple-file projects later on in the +guide. + +### Processing a Guess + +Let's get to it! The first thing we need to do for our guessing game is +allow our player to input a guess. Put this in your `src/guessing_game.rs`: + +```{rust,no_run} +use std::io; + +fn main() { + println!("Guess the number!"); + + println!("Please input your guess."); + + let input = io::stdin().read_line() + .ok() + .expect("Failed to read line"); + + println!("You guessed: {}", input); +} +``` + +You've seen this code before, when we talked about standard input. We +import the `std::io` module with `use`, and then our `main` function contains +our program's logic. We print a little message announcing the game, ask the +user to input a guess, get their input, and then print it out. + +Because we talked about this in the section on standard I/O, I won't go into +more details here. If you need a refresher, go re-read that section. + +### Generating a secret number + +Next, we need to generate a secret number. To do that, we need to use Rust's +random number generation, which we haven't talked about yet. Rust includes a +bunch of interesting functions in its standard library. If you need a bit of +code, it's possible that it's already been written for you! In this case, +we do know that Rust has random number generation, but we don't know how to +use it. + +Enter the docs. Rust has a page specifically to document the standard library. +You can find that page [here](std/index.html). There's a lot of information on +that page, but the best part is the search bar. Right up at the top, there's +a box that you can enter in a search term. The search is pretty primitive +right now, but is getting better all the time. If you type 'random' in that +box, the page will update to [this +one](http://doc.rust-lang.org/std/index.html?search=random). The very first +result is a link to +[std::rand::random](http://doc.rust-lang.org/std/rand/fn.random.html). If we +click on that result, we'll be taken to its documentation page. + +This page shows us a few things: the type signature of the function, some +explanatory text, and then an example. Let's modify our code to add in the +`random` function: + +```{rust,ignore} +use std::io; +use std::rand; + +fn main() { + println!("Guess the number!"); + + let secret_number = (rand::random() % 100i) + 1i; + + println!("The secret number is: {}", secret_number); + + println!("Please input your guess."); + + let input = io::stdin().read_line() + .ok() + .expect("Failed to read line"); + + + println!("You guessed: {}", input); +} +``` + +The first thing we changed was to `use std::rand`, as the docs +explained. We then added in a `let` expression to create a variable binding +named `secret_number`, and we printed out its result. Let's try to compile +this using `cargo build`: + +```{notrust,no_run} +$ cargo build + Compiling guessing_game v0.1.0 (file:/home/you/projects/guessing_game) +src/guessing_game.rs:7:26: 7:34 error: the type of this value must be known in this context +src/guessing_game.rs:7 let secret_number = (rand::random() % 100i) + 1i; + ^~~~~~~~ +error: aborting due to previous error +``` + +It didn't work! Rust says "the type of this value must be known in this +context." What's up with that? Well, as it turns out, `rand::random()` can +generate many kinds of random values, not just integers. And in this case, Rust +isn't sure what kind of value `random()` should generate. So we have to help +it. With number literals, we just add an `i` onto the end to tell Rust they're +integers, but that does not work with functions. There's a different syntax, +and it looks like this: + +```{rust,ignore} +rand::random::(); +``` + +This says "please give me a random `int` value." We can change our code to use +this hint... + +```{rust,no_run} +use std::io; +use std::rand; + +fn main() { + println!("Guess the number!"); + + let secret_number = (rand::random::() % 100i) + 1i; + + println!("The secret number is: {}", secret_number); + + println!("Please input your guess."); + + let input = io::stdin().read_line() + .ok() + .expect("Failed to read line"); + + + println!("You guessed: {}", input); +} +``` + +... and then recompile: + +```{notrust,ignore} +$ cargo build + Compiling guessing_game v0.1.0 (file:/home/steve/tmp/guessing_game) +$ +``` + +Excellent! Try running our new program a few times: + +```{notrust,ignore} +$ ./target/guessing_game +Guess the number! +The secret number is: 7 +Please input your guess. +4 +You guessed: 4 +$ ./target/guessing_game +Guess the number! +The secret number is: 83 +Please input your guess. +5 +You guessed: 5 +$ ./target/guessing_game +Guess the number! +The secret number is: -29 +Please input your guess. +42 +You guessed: 42 +``` + +Wait. Negative 29? We wanted a number between one and a hundred! We have two +options here: we can either ask `random()` to generate an unsigned integer, which +can only be positive, or we can use the `abs()` function. Let's go with the +unsigned integer approach. If we want a random positive number, we should ask for +a random positive number. Our code looks like this now: + +```{rust,no_run} +use std::io; +use std::rand; + +fn main() { + println!("Guess the number!"); + + let secret_number = (rand::random::() % 100u) + 1u; + + println!("The secret number is: {}", secret_number); + + println!("Please input your guess."); + + let input = io::stdin().read_line() + .ok() + .expect("Failed to read line"); + + + println!("You guessed: {}", input); +} +``` + +And trying it out: + +```{notrust,ignore} +$ cargo build + Compiling guessing_game v0.1.0 (file:/home/you/projects/guessing_game) +$ ./target/guessing_game +Guess the number! +The secret number is: 57 +Please input your guess. +3 +You guessed: 3 +``` + +Great! Next up: let's compare our guess to the secret guess. + +### Comparing guesses + +If you remember, earlier in the tutorial, we made a `cmp` function that compared +two numbers. Let's add that in, along with a `match` statement to compare the +guess to the secret guess: + +```{rust,ignore} +use std::io; +use std::rand; + +fn main() { + println!("Guess the number!"); + + let secret_number = (rand::random::() % 100u) + 1u; + + println!("The secret number is: {}", secret_number); + + println!("Please input your guess."); + + let input = io::stdin().read_line() + .ok() + .expect("Failed to read line"); + + + println!("You guessed: {}", input); + + match cmp(input, secret_number) { + Less => println!("Too small!"), + Greater => println!("Too big!"), + Equal => { println!("You win!"); }, + } +} + +fn cmp(a: int, b: int) -> Ordering { + if a < b { Less } + else if a > b { Greater } + else { Equal } +} +``` + +If we try to compile, we'll get some errors: + +```{notrust,ignore} +$ cargo build +$ cargo build + Compiling guessing_game v0.1.0 (file:/home/you/projects/guessing_game) +src/guessing_game.rs:20:15: 20:20 error: mismatched types: expected `int` but found `collections::string::String` (expected int but found struct collections::string::String) +src/guessing_game.rs:20 match cmp(input, secret_number) { + ^~~~~ +src/guessing_game.rs:20:22: 20:35 error: mismatched types: expected `int` but found `uint` (expected int but found uint) +src/guessing_game.rs:20 match cmp(input, secret_number) { + ^~~~~~~~~~~~~ +error: aborting due to 2 previous errors +``` + +This often happens when writing Rust programs, and is one of Rust's greatest +strengths. You try out some code, see if it compiles, and Rust tells you that +you've done something wrong. In this case, our `cmp` function works on integers, +but we've given it unsigned integers. In this case, the fix is easy, because +we wrote the `cmp` function! Let's change it to take `uint`s: + +```{rust,ignore} +use std::io; +use std::rand; + +fn main() { + println!("Guess the number!"); + + let secret_number = (rand::random::() % 100u) + 1u; + + println!("The secret number is: {}", secret_number); + + println!("Please input your guess."); + + let input = io::stdin().read_line() + .ok() + .expect("Failed to read line"); + + + println!("You guessed: {}", input); + + match cmp(input, secret_number) { + Less => println!("Too small!"), + Greater => println!("Too big!"), + Equal => { println!("You win!"); }, + } +} + +fn cmp(a: uint, b: uint) -> Ordering { + if a < b { Less } + else if a > b { Greater } + else { Equal } +} +``` + +And try compiling again: + +```{notrust,ignore} +$ cargo build + Compiling guessing_game v0.1.0 (file:/home/you/projects/guessing_game) +src/guessing_game.rs:20:15: 20:20 error: mismatched types: expected `uint` but found `collections::string::String` (expected uint but found struct collections::string::String) +src/guessing_game.rs:20 match cmp(input, secret_number) { + ^~~~~ +error: aborting due to previous error +``` + +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} +$ ./target/guessing_game +Guess the number! +The secret number is: 73 +Please input your guess. +hello +You guessed: hello +``` + +Oops! Also, you'll note that we just ran our program even though it didn't compile. +This works because the older version we did successfully compile was still lying +around. Gotta be careful! + +Anyway, we have a `String`, but we need a `uint`. What to do? Well, there's +a function for that: + +```{rust,ignore} +let input = io::stdin().read_line() + .ok() + .expect("Failed to read line"); +let guess: Option = from_str(input.as_slice()); +``` + +The `from_str` function takes in a `&str` value and converts it into something. +We tell it what kind of something with a type hint. Remember our type hint with +`random()`? It looked like this: + +```{rust,ignore} +rand::random::(); +``` + +There's an alternate way of providing a hint too, and that's declaring the type +in a `let`: + +```{rust,ignore} +let x: uint = rand::random(); +``` + +In this case, we say `x` is a `uint` explicitly, so Rust is able to properly +tell `random()` what to generate. In a similar fashion, both of these work: + +```{rust,ignore} +let guess = from_str::>("5"); +let guess: Option = from_str("5"); +``` + +In this case, I happen to prefer the latter, and in the `random()` case, I prefer +the former. I think the nested `<>`s make the first option especially ugly and +a bit harder to read. + +Anyway, with us now convering our input to a number, our code looks like this: + +```{rust,ignore} +use std::io; +use std::rand; + +fn main() { + println!("Guess the number!"); + + let secret_number = (rand::random::() % 100u) + 1u; + + println!("The secret number is: {}", secret_number); + + println!("Please input your guess."); + + let input = io::stdin().read_line() + .ok() + .expect("Failed to read line"); + let input_num: Option = from_str(input.as_slice()); + + + + println!("You guessed: {}", input_num); + + match cmp(input_num, secret_number) { + Less => println!("Too small!"), + Greater => println!("Too big!"), + Equal => { println!("You win!"); }, + } +} + +fn cmp(a: uint, b: uint) -> Ordering { + if a < b { Less } + else if a > b { Greater } + else { Equal } +} +``` + +Let's try it out! + +```{notrust,ignore} +$ cargo build + Compiling guessing_game v0.1.0 (file:/home/steve/tmp/guessing_game) +src/guessing_game.rs:22:15: 22:24 error: mismatched types: expected `uint` but found `core::option::Option` (expected uint but found enum core::option::Option) +src/guessing_game.rs:22 match cmp(input_num, secret_number) { + ^~~~~~~~~ +error: aborting due to previous error +``` + +Oh yeah! Our `input_num` has the type `Option`, rather than `uint`. We +need to unwrap the Option. If you remember from before, `match` is a great way +to do that. Try this code: + +```{rust,no_run} +use std::io; +use std::rand; + +fn main() { + println!("Guess the number!"); + + let secret_number = (rand::random::() % 100u) + 1u; + + println!("The secret number is: {}", secret_number); + + println!("Please input your guess."); + + let input = io::stdin().read_line() + .ok() + .expect("Failed to read line"); + let input_num: Option = from_str(input.as_slice()); + + let num = match input_num { + Some(num) => num, + None => { + println!("Please input a number!"); + return; + } + }; + + + println!("You guessed: {}", num); + + match cmp(num, secret_number) { + Less => println!("Too small!"), + Greater => println!("Too big!"), + Equal => { println!("You win!"); }, + } +} + +fn cmp(a: uint, b: uint) -> Ordering { + if a < b { Less } + else if a > b { Greater } + else { Equal } +} +``` + +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} +$ cargo build + Compiling guessing_game v0.1.0 (file:/home/you/projects/guessing_game) +$ ./target/guessing_game +Guess the number! +The secret number is: 17 +Please input your guess. +5 +Please input a number! +$ +``` + +Uh, what? But we did! + +... actually, we didn't. See, when you get a line of input from `stdin()`, +you get all the input. Including the `\n` character from you pressing Enter. +So, `from_str()` sees the string `"5\n"` and says "nope, that's not a number, +there's non-number stuff in there!" Luckily for us, `&str`s have an easy +method we can use defined on them: `trim()`. One small modification, and our +code looks like this: + +```{rust,no_run} +use std::io; +use std::rand; + +fn main() { + println!("Guess the number!"); + + let secret_number = (rand::random::() % 100u) + 1u; + + println!("The secret number is: {}", secret_number); + + println!("Please input your guess."); + + let input = io::stdin().read_line() + .ok() + .expect("Failed to read line"); + let input_num: Option = from_str(input.as_slice().trim()); + + let num = match input_num { + Some(num) => num, + None => { + println!("Please input a number!"); + return; + } + }; + + + println!("You guessed: {}", num); + + match cmp(num, secret_number) { + Less => println!("Too small!"), + Greater => println!("Too big!"), + Equal => { println!("You win!"); }, + } +} + +fn cmp(a: uint, b: uint) -> Ordering { + if a < b { Less } + else if a > b { Greater } + else { Equal } +} +``` + +Let's try it! + +```{notrust,ignore} +$ cargo build + Compiling guessing_game v0.1.0 (file:/home/you/projects/guessing_game) +$ ./target/guessing_game +Guess the number! +The secret number is: 58 +Please input your guess. + 76 +You guessed: 76 +Too big! +$ +``` + +Nice! You can see I even added spaces before my guess, and it still figured +out that I guessed 76. Run the program a few times, and verify that guessing +the number works, as well as guessing a number too small. + +The Rust compiler helped us out quite a bit there! This technique is called +"lean on the compiler," and it's often useful when working on some code. Let +the error messages help guide you towards the correct types. + +Now we've got most of the game working, but we can only make one guess. Let's +change that by adding loops! + +### Looping + +As we already discussed, the `loop` key word gives us an infinite loop. So +let's add that in: + +```{rust,no_run} +use std::io; +use std::rand; + +fn main() { + println!("Guess the number!"); + + let secret_number = (rand::random::() % 100u) + 1u; + + println!("The secret number is: {}", secret_number); + + loop { + + println!("Please input your guess."); + + let input = io::stdin().read_line() + .ok() + .expect("Failed to read line"); + let input_num: Option = from_str(input.as_slice().trim()); + + let num = match input_num { + Some(num) => num, + None => { + println!("Please input a number!"); + return; + } + }; + + + println!("You guessed: {}", num); + + match cmp(num, secret_number) { + Less => println!("Too small!"), + Greater => println!("Too big!"), + Equal => { println!("You win!"); }, + } + } +} + +fn cmp(a: uint, b: uint) -> Ordering { + if a < b { Less } + else if a > b { Greater } + else { Equal } +} +``` + +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} +$ cargo build + Compiling guessing_game v0.1.0 (file:/home/you/projects/guessing_game) +steve@computer:~/tmp/guessing_game$ ./target/guessing_game +Guess the number! +The secret number is: 59 +Please input your guess. +45 +You guessed: 45 +Too small! +Please input your guess. +60 +You guessed: 60 +Too big! +Please input your guess. +59 +You guessed: 59 +You win! +Please input your guess. +quit +Please input a number! +$ +``` + +Ha! `quit` actually quits. As does any other non-number input. Well, this is +suboptimal to say the least. First, let's actually quit when you win the game: + +```{rust,no_run} +use std::io; +use std::rand; + +fn main() { + println!("Guess the number!"); + + let secret_number = (rand::random::() % 100u) + 1u; + + println!("The secret number is: {}", secret_number); + + loop { + + println!("Please input your guess."); + + let input = io::stdin().read_line() + .ok() + .expect("Failed to read line"); + let input_num: Option = from_str(input.as_slice().trim()); + + let num = match input_num { + Some(num) => num, + None => { + println!("Please input a number!"); + return; + } + }; + + + println!("You guessed: {}", num); + + match cmp(num, secret_number) { + Less => println!("Too small!"), + Greater => println!("Too big!"), + Equal => { + println!("You win!"); + return; + }, + } + } +} + +fn cmp(a: uint, b: uint) -> Ordering { + if a < b { Less } + else if a > b { Greater } + else { Equal } +} +``` + +By adding the `return` line after the `You win!`, we'll exit the program when +we win. We have just one more tweak to make: when someone inputs a non-number, +we don't want to quit, we just want to ignore it. Change that `return` to +`continue`: + + +```{rust,no_run} +use std::io; +use std::rand; + +fn main() { + println!("Guess the number!"); + + let secret_number = (rand::random::() % 100u) + 1u; + + println!("The secret number is: {}", secret_number); + + loop { + + println!("Please input your guess."); + + let input = io::stdin().read_line() + .ok() + .expect("Failed to read line"); + let input_num: Option = from_str(input.as_slice().trim()); + + let num = match input_num { + Some(num) => num, + None => { + println!("Please input a number!"); + continue; + } + }; + + + println!("You guessed: {}", num); + + match cmp(num, secret_number) { + Less => println!("Too small!"), + Greater => println!("Too big!"), + Equal => { + println!("You win!"); + return; + }, + } + } +} + +fn cmp(a: uint, b: uint) -> Ordering { + if a < b { Less } + else if a > b { Greater } + else { Equal } +} +``` + +Now we should be good! Let's try: + +```{rust,ignore} +$ cargo build + Compiling guessing_game v0.1.0 (file:/home/you/projects/guessing_game) +$ ./target/guessing_game +Guess the number! +The secret number is: 61 +Please input your guess. +10 +You guessed: 10 +Too small! +Please input your guess. +99 +You guessed: 99 +Too big! +Please input your guess. +foo +Please input a number! +Please input your guess. +61 +You guessed: 61 +You win! +``` + +Awesome! With one tiny last tweak, we have finished the guessing game. Can you +think of what it is? That's right, we don't want to print out the secret number. +It was good for testing, but it kind of ruins the game. Here's our final source: + +```{rust,no_run} +use std::io; +use std::rand; + +fn main() { + println!("Guess the number!"); + + let secret_number = (rand::random::() % 100u) + 1u; + + loop { + + println!("Please input your guess."); + + let input = io::stdin().read_line() + .ok() + .expect("Failed to read line"); + let input_num: Option = from_str(input.as_slice().trim()); + + let num = match input_num { + Some(num) => num, + None => { + println!("Please input a number!"); + continue; + } + }; + + + println!("You guessed: {}", num); + + match cmp(num, secret_number) { + Less => println!("Too small!"), + Greater => println!("Too big!"), + Equal => { + println!("You win!"); + return; + }, + } + } +} + +fn cmp(a: uint, b: uint) -> Ordering { + if a < b { Less } + else if a > b { Greater } + else { Equal } +} +``` + +### Complete! At this point, you have successfully built the Guessing Game! Congratulations! -For reference, [We've placed the sample code on -GitHub](https://github.com/steveklabnik/guessing_game). You've now learned the basic syntax of Rust. All of this is relatively close to various other programming languages you have used in the past. These diff --git a/src/libcollections/bitv.rs b/src/libcollections/bitv.rs index 226da13f9e228..f1e9eabe8d1ed 100644 --- a/src/libcollections/bitv.rs +++ b/src/libcollections/bitv.rs @@ -8,6 +8,57 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +//! Collections implemented with bit vectors. +//! +//! # Example +//! +//! This is a simple example of the [Sieve of Eratosthenes][sieve] +//! which calculates prime numbers up to a given limit. +//! +//! [sieve]: http://en.wikipedia.org/wiki/Sieve_of_Eratosthenes +//! +//! ``` +//! use std::collections::{BitvSet, Bitv}; +//! use std::iter; +//! +//! let max_prime = 10000; +//! +//! // Store the primes as a BitvSet +//! let primes = { +//! // Assume all numbers are prime to begin, and then we +//! // cross off non-primes progressively +//! let mut bv = Bitv::with_capacity(max_prime, true); +//! +//! // Neither 0 nor 1 are prime +//! bv.set(0, false); +//! bv.set(1, false); +//! +//! for i in range(2, max_prime) { +//! // if i is a prime +//! if bv[i] { +//! // Mark all multiples of i as non-prime (any multiples below i * i +//! // will have been marked as non-prime previously) +//! for j in iter::range_step(i * i, max_prime, i) { bv.set(j, false) } +//! } +//! } +//! BitvSet::from_bitv(bv) +//! }; +//! +//! // Simple primality tests below our max bound +//! let print_primes = 20; +//! print!("The primes below {} are: ", print_primes); +//! for x in range(0, print_primes) { +//! if primes.contains(&x) { +//! print!("{} ", x); +//! } +//! } +//! println!(""); +//! +//! // We can manipulate the internal Bitv +//! let num_primes = primes.get_ref().iter().filter(|x| *x).count(); +//! println!("There are {} primes below {}", num_primes, max_prime); +//! ``` + #![allow(missing_doc)] use core::prelude::*; @@ -47,7 +98,7 @@ enum BitvVariant { Big(BigBitv), Small(SmallBitv) } /// # Example /// /// ```rust -/// use collections::bitv::Bitv; +/// use collections::Bitv; /// /// let mut bv = Bitv::with_capacity(10, false); /// @@ -155,13 +206,32 @@ impl Bitv { } } - /// Creates an empty Bitv + /// Create an empty Bitv. + /// + /// # Example + /// + /// ``` + /// use std::collections::Bitv; + /// let mut bv = Bitv::new(); + /// ``` pub fn new() -> Bitv { Bitv { storage: Vec::new(), nbits: 0 } } - /// Creates a Bitv that holds `nbits` elements, setting each element + /// Create a Bitv that holds `nbits` elements, setting each element /// to `init`. + /// + /// # Example + /// + /// ``` + /// use std::collections::Bitv; + /// + /// let mut bv = Bitv::with_capacity(10u, false); + /// assert_eq!(bv.len(), 10u); + /// for x in bv.iter() { + /// assert_eq!(x, false); + /// } + /// ``` pub fn with_capacity(nbits: uint, init: bool) -> Bitv { Bitv { storage: Vec::from_elem((nbits + uint::BITS - 1) / uint::BITS, @@ -170,29 +240,24 @@ impl Bitv { } } - /** - * Calculates the union of two bitvectors - * - * Sets `self` to the union of `self` and `v1`. Both bitvectors must be - * the same length. Returns `true` if `self` changed. - */ - #[inline] - pub fn union(&mut self, other: &Bitv) -> bool { - self.process(other, |w1, w2| w1 | w2) - } - - /** - * Calculates the intersection of two bitvectors - * - * Sets `self` to the intersection of `self` and `v1`. Both bitvectors - * must be the same length. Returns `true` if `self` changed. - */ - #[inline] - pub fn intersect(&mut self, other: &Bitv) -> bool { - self.process(other, |w1, w2| w1 & w2) - } - - /// Retrieve the value at index `i` + /// Retrieve the value at index `i`. + /// + /// # Failure + /// + /// Assert if `i` out of bounds. + /// + /// # Example + /// + /// ``` + /// use std::collections::bitv; + /// + /// let bv = bitv::from_bytes([0b01100000]); + /// assert_eq!(bv.get(0), false); + /// assert_eq!(bv.get(1), true); + /// + /// // Can also use array indexing + /// assert_eq!(bv[1], true); + /// ``` #[inline] pub fn get(&self, i: uint) -> bool { assert!(i < self.nbits); @@ -202,11 +267,21 @@ impl Bitv { x != 0 } - /** - * Set the value of a bit at a given index - * - * `i` must be less than the length of the bitvector. - */ + /// Set the value of a bit at a index `i`. + /// + /// # Failure + /// + /// Assert if `i` out of bounds. + /// + /// # Example + /// + /// ``` + /// use std::collections::Bitv; + /// + /// let mut bv = Bitv::with_capacity(5, false); + /// bv.set(3, true); + /// assert_eq!(bv[3], true); + /// ``` #[inline] pub fn set(&mut self, i: uint, x: bool) { assert!(i < self.nbits); @@ -217,33 +292,152 @@ impl Bitv { else { *self.storage.get(w) & !flag }; } - /// Set all bits to 1 + /// Set all bits to 1. + /// + /// # Example + /// + /// ``` + /// use std::collections::bitv; + /// + /// let before = 0b01100000; + /// let after = 0b11111111; + /// + /// let mut bv = bitv::from_bytes([before]); + /// bv.set_all(); + /// assert_eq!(bv, bitv::from_bytes([after])); + /// ``` #[inline] pub fn set_all(&mut self) { for w in self.storage.mut_iter() { *w = !0u; } } - /// Flip all bits + /// Flip all bits. + /// + /// # Example + /// + /// ``` + /// use std::collections::bitv; + /// + /// let before = 0b01100000; + /// let after = 0b10011111; + /// + /// let mut bv = bitv::from_bytes([before]); + /// bv.negate(); + /// assert_eq!(bv, bitv::from_bytes([after])); + /// ``` #[inline] pub fn negate(&mut self) { for w in self.storage.mut_iter() { *w = !*w; } } - /** - * Calculate the difference between two bitvectors - * - * Sets each element of `v0` to the value of that element minus the - * element of `v1` at the same index. Both bitvectors must be the same - * length. - * - * Returns `true` if `v0` was changed. - */ + /// Calculate the union of two bitvectors, acts like bitwise or. + /// + /// Set `self` to the union of `self` and `other`. Both bitvectors must be + /// the same length. Return `true` if `self` changed. + /// + /// # Failure + /// + /// Assert if the bitvectors are of different length. + /// + /// # Example + /// + /// ``` + /// use std::collections::bitv; + /// + /// let a = 0b01100100; + /// let b = 0b01011010; + /// let res = 0b01111110; + /// + /// let mut a = bitv::from_bytes([a]); + /// let b = bitv::from_bytes([b]); + /// + /// assert!(a.union(&b)); + /// assert_eq!(a, bitv::from_bytes([res])); + /// ``` + #[inline] + pub fn union(&mut self, other: &Bitv) -> bool { + self.process(other, |w1, w2| w1 | w2) + } + + /// Calculate the intersection of two bitvectors, acts like bitwise and. + /// + /// Set `self` to the intersection of `self` and `other`. Both bitvectors + /// must be the same length. Return `true` if `self` changed. + /// + /// # Failure + /// + /// Assert if the bitvectors are of different length. + /// + /// # Example + /// + /// ``` + /// use std::collections::bitv; + /// + /// let a = 0b01100100; + /// let b = 0b01011010; + /// let res = 0b01000000; + /// + /// let mut a = bitv::from_bytes([a]); + /// let b = bitv::from_bytes([b]); + /// + /// assert!(a.intersect(&b)); + /// assert_eq!(a, bitv::from_bytes([res])); + /// ``` + #[inline] + pub fn intersect(&mut self, other: &Bitv) -> bool { + self.process(other, |w1, w2| w1 & w2) + } + + /// Calculate the difference between two bitvectors. + /// + /// Set each element of `self` to the value of that element minus the + /// element of `other` at the same index. Both bitvectors must be the same + /// length. Return `true` if `self` changed. + /// + /// # Failure + /// + /// Assert if the bitvectors are of different length. + /// + /// # Example + /// + /// ``` + /// use std::collections::bitv; + /// + /// let a = 0b01100100; + /// let b = 0b01011010; + /// let a_b = 0b00100100; // a - b + /// let b_a = 0b00011010; // b - a + /// + /// let mut bva = bitv::from_bytes([a]); + /// let bvb = bitv::from_bytes([b]); + /// + /// assert!(bva.difference(&bvb)); + /// assert_eq!(bva, bitv::from_bytes([a_b])); + /// + /// let bva = bitv::from_bytes([a]); + /// let mut bvb = bitv::from_bytes([b]); + /// + /// assert!(bvb.difference(&bva)); + /// assert_eq!(bvb, bitv::from_bytes([b_a])); + /// ``` #[inline] pub fn difference(&mut self, other: &Bitv) -> bool { self.process(other, |w1, w2| w1 & !w2) } - /// Returns `true` if all bits are 1 + /// Returns `true` if all bits are 1. + /// + /// # Example + /// + /// ``` + /// use std::collections::Bitv; + /// + /// let mut bv = Bitv::with_capacity(5, true); + /// assert_eq!(bv.all(), true); + /// + /// bv.set(1, false); + /// assert_eq!(bv.all(), false); + /// ``` #[inline] pub fn all(&self) -> bool { let mut last_word = !0u; @@ -254,43 +448,77 @@ impl Bitv { (last_word == ((1 << self.nbits % uint::BITS) - 1) || last_word == !0u) } - /// Returns an iterator over the elements of the vector in order. + /// Return an iterator over the elements of the vector in order. /// /// # Example /// - /// ```rust - /// use collections::bitv::Bitv; - /// let mut bv = Bitv::with_capacity(10, false); - /// bv.set(1, true); - /// bv.set(2, true); - /// bv.set(3, true); - /// bv.set(5, true); - /// bv.set(8, true); - /// // Count bits set to 1; result should be 5 - /// println!("{}", bv.iter().filter(|x| *x).count()); + /// ``` + /// use std::collections::bitv; + /// + /// let bv = bitv::from_bytes([0b01110100, 0b10010010]); + /// assert_eq!(bv.iter().filter(|x| *x).count(), 7); /// ``` #[inline] pub fn iter<'a>(&'a self) -> Bits<'a> { Bits {bitv: self, next_idx: 0, end_idx: self.nbits} } - /// Returns `true` if all bits are 0 + /// Return `true` if all bits are 0. + /// + /// # Example + /// + /// ``` + /// use std::collections::Bitv; + /// + /// let mut bv = Bitv::with_capacity(10, false); + /// assert_eq!(bv.none(), true); + /// + /// bv.set(3, true); + /// assert_eq!(bv.none(), false); + /// ``` pub fn none(&self) -> bool { self.mask_words(0).all(|(_, w)| w == 0) } + /// Return `true` if any bit is 1. + /// + /// # Example + /// + /// ``` + /// use std::collections::Bitv; + /// + /// let mut bv = Bitv::with_capacity(10, false); + /// assert_eq!(bv.any(), false); + /// + /// bv.set(3, true); + /// assert_eq!(bv.any(), true); + /// ``` #[inline] - /// Returns `true` if any bit is 1 pub fn any(&self) -> bool { !self.none() } - /** - * Organise the bits into bytes, such that the first bit in the - * `Bitv` becomes the high-order bit of the first byte. If the - * size of the `Bitv` is not a multiple of 8 then trailing bits - * will be filled-in with false/0 - */ + /// Organise the bits into bytes, such that the first bit in the + /// `Bitv` becomes the high-order bit of the first byte. If the + /// size of the `Bitv` is not a multiple of 8 then trailing bits + /// will be filled-in with `false`. + /// + /// # Example + /// + /// ``` + /// use std::collections::Bitv; + /// + /// let mut bv = Bitv::with_capacity(3, true); + /// bv.set(1, false); + /// + /// assert_eq!(bv.to_bytes(), vec!(0b10100000)); + /// + /// let mut bv = Bitv::with_capacity(9, false); + /// bv.set(2, true); + /// bv.set(8, true); + /// + /// assert_eq!(bv.to_bytes(), vec!(0b00100000, 0b10000000)); + /// ``` pub fn to_bytes(&self) -> Vec { fn bit (bitv: &Bitv, byte: uint, bit: uint) -> u8 { let offset = byte * 8 + bit; @@ -315,18 +543,37 @@ impl Bitv { ) } - /** - * Transform `self` into a `Vec` by turning each bit into a `bool`. - */ + /// Transform `self` into a `Vec` by turning each bit into a `bool`. + /// + /// # Example + /// + /// ``` + /// use std::collections::bitv; + /// + /// let bv = bitv::from_bytes([0b10100000]); + /// assert_eq!(bv.to_bools(), vec!(true, false, true, false, + /// false, false, false, false)); + /// ``` pub fn to_bools(&self) -> Vec { Vec::from_fn(self.nbits, |i| self.get(i)) } - /** - * Compare a bitvector to a vector of `bool`. - * - * Both the bitvector and vector must have the same length. - */ + /// Compare a bitvector to a vector of `bool`. + /// Both the bitvector and vector must have the same length. + /// # Failure + /// + /// Assert if the bitvectors are of different length. + /// + /// # Example + /// + /// ``` + /// use std::collections::bitv; + /// + /// let bv = bitv::from_bytes([0b10100000]); + /// + /// assert!(bv.eq_vec([true, false, true, false, + /// false, false, false, false])); + /// ``` pub fn eq_vec(&self, v: &[bool]) -> bool { assert_eq!(self.nbits, v.len()); let mut i = 0; @@ -344,12 +591,12 @@ impl Bitv { /// /// # Example /// - /// ```rust - /// use collections::bitv::Bitv; - /// let mut bvec: Bitv = vec![false, true, true, false].iter().map(|n| *n).collect(); - /// let expected: Bitv = vec![false, true].iter().map(|n| *n).collect(); - /// bvec.truncate(2); - /// assert_eq!(bvec, expected); + /// ``` + /// use std::collections::bitv; + /// + /// let mut bv = bitv::from_bytes([0b01001011]); + /// bv.truncate(2); + /// assert!(bv.eq_vec([false, true])); /// ``` pub fn truncate(&mut self, len: uint) { if len < self.len() { @@ -363,7 +610,18 @@ impl Bitv { } } - /// Grows the vector to be able to store `size` bits without resizing + /// Grow the vector to be able to store `size` bits without resizing. + /// + /// # Example + /// + /// ``` + /// use std::collections::Bitv; + /// + /// let mut bv = Bitv::with_capacity(3, false); + /// bv.reserve(10); + /// assert_eq!(bv.len(), 3); + /// assert!(bv.capacity() >= 10); + /// ``` pub fn reserve(&mut self, size: uint) { let old_size = self.storage.len(); let size = (size + uint::BITS - 1) / uint::BITS; @@ -372,24 +630,34 @@ impl Bitv { } } - /// Returns the capacity in bits for this bit vector. Inserting any + /// Return the capacity in bits for this bit vector. Inserting any /// element less than this amount will not trigger a resizing. + /// + /// # Example + /// + /// ``` + /// use std::collections::Bitv; + /// + /// let mut bv = Bitv::new(); + /// bv.reserve(10); + /// assert!(bv.capacity() >= 10); + /// ``` #[inline] pub fn capacity(&self) -> uint { self.storage.len() * uint::BITS } - /// Grows the `Bitv` in-place. - /// - /// Adds `n` copies of `value` to the `Bitv`. + /// Grow the `Bitv` in-place. Add `n` copies of `value` to the `Bitv`. /// /// # Example /// - /// ```rust - /// use collections::bitv::Bitv; - /// let mut bvec: Bitv = vec![false, true, true, false].iter().map(|n| *n).collect(); - /// bvec.grow(2, true); - /// assert_eq!(bvec, vec![false, true, true, false, true, true].iter().map(|n| *n).collect()); + /// ``` + /// use std::collections::bitv; + /// + /// let mut bv = bitv::from_bytes([0b01001011]); + /// bv.grow(2, true); + /// assert_eq!(bv.len(), 10); + /// assert_eq!(bv.to_bytes(), vec!(0b01001011, 0b11000000)); /// ``` pub fn grow(&mut self, n: uint, value: bool) { let new_nbits = self.nbits + n; @@ -420,17 +688,22 @@ impl Bitv { self.nbits = new_nbits; } - /// Shorten a `Bitv` by one, returning the removed element + /// Shorten by one and return the removed element. + /// + /// # Failure + /// + /// Assert if empty. /// /// # Example /// - /// ```rust - /// use collections::bitv::Bitv; - /// let mut bvec: Bitv = vec![false, true, true, false].iter().map(|n| *n).collect(); - /// let expected: Bitv = vec![false, true, true].iter().map(|n| *n).collect(); - /// let popped = bvec.pop(); - /// assert_eq!(popped, false); - /// assert_eq!(bvec, expected); + /// ``` + /// use std::collections::bitv; + /// + /// let mut bv = bitv::from_bytes([0b01001001]); + /// assert_eq!(bv.pop(), true); + /// assert_eq!(bv.pop(), false); + /// assert_eq!(bv.len(), 6); + /// assert_eq!(bv.to_bytes(), vec!(0b01001000)); /// ``` pub fn pop(&mut self) -> bool { let ret = self.get(self.nbits - 1); @@ -442,17 +715,17 @@ impl Bitv { ret } - /// Pushes a `bool` onto the `Bitv` + /// Push a `bool` onto the end. /// /// # Example /// - /// ```rust - /// use collections::bitv::Bitv; - /// let prototype: Bitv = vec![false, true, true, false].iter().map(|n| *n).collect(); - /// let mut bvec: Bitv = vec![false, true].iter().map(|n| *n).collect(); - /// bvec.push(true); - /// bvec.push(false); - /// assert_eq!(prototype, bvec); + /// ``` + /// use std::collections::Bitv; + /// + /// let mut bv = Bitv::new(); + /// bv.push(true); + /// bv.push(false); + /// assert!(bv.eq_vec([true, false])); /// ``` pub fn push(&mut self, elem: bool) { let insert_pos = self.nbits; @@ -464,11 +737,21 @@ impl Bitv { } } -/** - * Transform a byte-vector into a `Bitv`. Each byte becomes 8 bits, - * with the most significant bits of each byte coming first. Each - * bit becomes `true` if equal to 1 or `false` if equal to 0. - */ +/// Transform a byte-vector into a `Bitv`. Each byte becomes 8 bits, +/// with the most significant bits of each byte coming first. Each +/// bit becomes `true` if equal to 1 or `false` if equal to 0. +/// +/// # Example +/// +/// ``` +/// use std::collections::bitv; +/// +/// let bv = bitv::from_bytes([0b10100000, 0b00010010]); +/// assert!(bv.eq_vec([true, false, true, false, +/// false, false, false, false, +/// false, false, false, true, +/// false, false, true, false])); +/// ``` pub fn from_bytes(bytes: &[u8]) -> Bitv { from_fn(bytes.len() * 8, |i| { let b = bytes[i / 8] as uint; @@ -477,10 +760,17 @@ pub fn from_bytes(bytes: &[u8]) -> Bitv { }) } -/** - * Create a `Bitv` of the specified length where the value at each - * index is `f(index)`. - */ +/// Create a `Bitv` of the specified length where the value at each +/// index is `f(index)`. +/// +/// # Example +/// +/// ``` +/// use std::collections::bitv::from_fn; +/// +/// let bv = from_fn(5, |i| { i % 2 == 0 }); +/// assert!(bv.eq_vec([true, false, true, false, true])); +/// ``` pub fn from_fn(len: uint, f: |index: uint| -> bool) -> Bitv { let mut bitv = Bitv::with_capacity(len, false); for i in range(0u, len) { @@ -626,11 +916,45 @@ impl<'a> RandomAccessIterator for Bits<'a> { } /// An implementation of a set using a bit vector as an underlying -/// representation for holding numerical elements. +/// representation for holding unsigned numerical elements. /// /// It should also be noted that the amount of storage necessary for holding a /// set of objects is proportional to the maximum of the objects when viewed /// as a `uint`. +/// +/// # Example +/// +/// ``` +/// use std::collections::{BitvSet, Bitv}; +/// use std::collections::bitv; +/// +/// // It's a regular set +/// let mut s = BitvSet::new(); +/// s.insert(0); +/// s.insert(3); +/// s.insert(7); +/// +/// s.remove(&7); +/// +/// if !s.contains(&7) { +/// println!("There is no 7"); +/// } +/// +/// // Can initialize from a `Bitv` +/// let other = BitvSet::from_bitv(bitv::from_bytes([0b11010000])); +/// +/// s.union_with(&other); +/// +/// // Print 0, 1, 3 in some order +/// for x in s.iter() { +/// println!("{}", x); +/// } +/// +/// // Can convert back to a `Bitv` +/// let bv: Bitv = s.unwrap(); +/// assert!(bv.eq_vec([true, true, false, true, +/// false, false, false, false])); +/// ``` #[deriving(Clone, PartialEq, Eq)] pub struct BitvSet(Bitv); @@ -640,20 +964,49 @@ impl Default for BitvSet { } impl BitvSet { - /// Creates a new bit vector set with initially no contents + /// Create a new bit vector set with initially no contents. + /// + /// # Example + /// + /// ``` + /// use std::collections::BitvSet; + /// let mut s = BitvSet::new(); + /// ``` #[inline] pub fn new() -> BitvSet { BitvSet(Bitv::new()) } - /// Creates a new bit vector set with initially no contents, able to - /// hold `nbits` elements without resizing + /// Create a new bit vector set with initially no contents, able to + /// hold `nbits` elements without resizing. + /// + /// # Example + /// + /// ``` + /// use std::collections::BitvSet; + /// let mut s = BitvSet::with_capacity(100); + /// assert!(s.capacity() >= 100); + /// ``` #[inline] pub fn with_capacity(nbits: uint) -> BitvSet { BitvSet(Bitv::with_capacity(nbits, false)) } - /// Creates a new bit vector set from the given bit vector + /// Create a new bit vector set from the given bit vector. + /// + /// # Example + /// + /// ``` + /// use std::collections::{bitv, BitvSet}; + /// + /// let bv = bitv::from_bytes([0b01100000]); + /// let s = BitvSet::from_bitv(bv); + /// + /// // Print 1, 2 in arbitrary order + /// for x in s.iter() { + /// println!("{}", x); + /// } + /// ``` #[inline] pub fn from_bitv(bitv: Bitv) -> BitvSet { BitvSet(bitv) @@ -661,33 +1014,93 @@ impl BitvSet { /// Returns the capacity in bits for this bit vector. Inserting any /// element less than this amount will not trigger a resizing. + /// + /// # Example + /// + /// ``` + /// use std::collections::BitvSet; + /// + /// let mut s = BitvSet::with_capacity(100); + /// assert!(s.capacity() >= 100); + /// ``` #[inline] pub fn capacity(&self) -> uint { let &BitvSet(ref bitv) = self; bitv.capacity() } - /// Grows the underlying vector to be able to store `size` bits + /// Grows the underlying vector to be able to store `size` bits. + /// + /// # Example + /// + /// ``` + /// use std::collections::BitvSet; + /// + /// let mut s = BitvSet::new(); + /// s.reserve(10); + /// assert!(s.capacity() >= 10); + /// ``` pub fn reserve(&mut self, size: uint) { let &BitvSet(ref mut bitv) = self; bitv.reserve(size) } - /// Consumes this set to return the underlying bit vector + /// Consume this set to return the underlying bit vector. + /// + /// # Example + /// + /// ``` + /// use std::collections::BitvSet; + /// + /// let mut s = BitvSet::new(); + /// s.insert(0); + /// s.insert(3); + /// + /// let bv = s.unwrap(); + /// assert!(bv.eq_vec([true, false, false, true])); + /// ``` #[inline] pub fn unwrap(self) -> Bitv { let BitvSet(bitv) = self; bitv } - /// Returns a reference to the underlying bit vector + /// Return a reference to the underlying bit vector. + /// + /// # Example + /// + /// ``` + /// use std::collections::BitvSet; + /// + /// let mut s = BitvSet::new(); + /// s.insert(0); + /// + /// let bv = s.get_ref(); + /// assert_eq!(bv[0], true); + /// ``` #[inline] pub fn get_ref<'a>(&'a self) -> &'a Bitv { let &BitvSet(ref bitv) = self; bitv } - /// Returns a mutable reference to the underlying bit vector + /// Return a mutable reference to the underlying bit vector. + /// + /// # Example + /// + /// ``` + /// use std::collections::BitvSet; + /// + /// let mut s = BitvSet::new(); + /// s.insert(0); + /// assert_eq!(s.contains(&0), true); + /// { + /// // Will free the set during bv's lifetime + /// let bv = s.get_mut_ref(); + /// bv.set(0, false); + /// } + /// assert_eq!(s.contains(&0), false); + /// ``` #[inline] pub fn get_mut_ref<'a>(&'a mut self) -> &'a mut Bitv { let &BitvSet(ref mut bitv) = self; @@ -709,8 +1122,25 @@ impl BitvSet { } } + /// Truncate the underlying vector to the least length required. + /// + /// # Example + /// + /// ``` + /// use std::collections::BitvSet; + /// + /// let mut s = BitvSet::new(); + /// s.insert(32183231); + /// s.remove(&32183231); + /// + /// // Internal storage will probably be bigger than necessary + /// println!("old capacity: {}", s.capacity()); + /// + /// // Now should be smaller + /// s.shrink_to_fit(); + /// println!("new capacity: {}", s.capacity()); + /// ``` #[inline] - /// Truncate the underlying vector to the least length required pub fn shrink_to_fit(&mut self) { let &BitvSet(ref mut bitv) = self; // Obtain original length @@ -723,84 +1153,245 @@ impl BitvSet { bitv.nbits = trunc_len * uint::BITS; } - /// Union in-place with the specified other bit vector - #[inline] - pub fn union_with(&mut self, other: &BitvSet) { - self.other_op(other, |w1, w2| w1 | w2); - } - - /// Intersect in-place with the specified other bit vector - #[inline] - pub fn intersect_with(&mut self, other: &BitvSet) { - self.other_op(other, |w1, w2| w1 & w2); - } - - /// Difference in-place with the specified other bit vector - #[inline] - pub fn difference_with(&mut self, other: &BitvSet) { - self.other_op(other, |w1, w2| w1 & !w2); - } - - /// Symmetric difference in-place with the specified other bit vector - #[inline] - pub fn symmetric_difference_with(&mut self, other: &BitvSet) { - self.other_op(other, |w1, w2| w1 ^ w2); - } - - /// Iterator over each uint stored in the BitvSet + /// Iterator over each uint stored in the BitvSet. + /// + /// # Example + /// + /// ``` + /// use std::collections::BitvSet; + /// use std::collections::bitv; + /// + /// let s = BitvSet::from_bitv(bitv::from_bytes([0b01001010])); + /// + /// // Print 1, 4, 6 in arbitrary order + /// for x in s.iter() { + /// println!("{}", x); + /// } + /// ``` #[inline] pub fn iter<'a>(&'a self) -> BitPositions<'a> { BitPositions {set: self, next_idx: 0} } - /// Iterator over each uint stored in the `self` setminus `other` + /// Iterator over each uint stored in `self` union `other`. + /// See [union_with](#method.union_with) for an efficient in-place version. + /// + /// # Example + /// + /// ``` + /// use std::collections::BitvSet; + /// use std::collections::bitv; + /// + /// let a = BitvSet::from_bitv(bitv::from_bytes([0b01101000])); + /// let b = BitvSet::from_bitv(bitv::from_bytes([0b10100000])); + /// + /// // Print 0, 1, 2, 4 in arbitrary order + /// for x in a.union(&b) { + /// println!("{}", x); + /// } + /// ``` #[inline] - pub fn difference<'a>(&'a self, other: &'a BitvSet) -> TwoBitPositions<'a> { + pub fn union<'a>(&'a self, other: &'a BitvSet) -> TwoBitPositions<'a> { TwoBitPositions { set: self, other: other, - merge: |w1, w2| w1 & !w2, + merge: |w1, w2| w1 | w2, current_word: 0, next_idx: 0 } } - /// Iterator over each uint stored in the symmetric difference of `self` and `other` + /// Iterator over each uint stored in `self` intersect `other`. + /// See [intersect_with](#method.intersect_with) for an efficient in-place version. + /// + /// # Example + /// + /// ``` + /// use std::collections::BitvSet; + /// use std::collections::bitv; + /// + /// let a = BitvSet::from_bitv(bitv::from_bytes([0b01101000])); + /// let b = BitvSet::from_bitv(bitv::from_bytes([0b10100000])); + /// + /// // Print 2 + /// for x in a.intersection(&b) { + /// println!("{}", x); + /// } + /// ``` #[inline] - pub fn symmetric_difference<'a>(&'a self, other: &'a BitvSet) -> TwoBitPositions<'a> { + pub fn intersection<'a>(&'a self, other: &'a BitvSet) -> Take> { + let min = cmp::min(self.capacity(), other.capacity()); TwoBitPositions { set: self, other: other, - merge: |w1, w2| w1 ^ w2, + merge: |w1, w2| w1 & w2, current_word: 0, next_idx: 0 - } + }.take(min) } - /// Iterator over each uint stored in `self` intersect `other` + /// Iterator over each uint stored in the `self` setminus `other`. + /// See [difference_with](#method.difference_with) for an efficient in-place version. + /// + /// # Example + /// + /// ``` + /// use std::collections::BitvSet; + /// use std::collections::bitv; + /// + /// let a = BitvSet::from_bitv(bitv::from_bytes([0b01101000])); + /// let b = BitvSet::from_bitv(bitv::from_bytes([0b10100000])); + /// + /// // Print 2, 4 in arbitrary order + /// for x in a.difference(&b) { + /// println!("{}", x); + /// } + /// + /// // Note that difference is not symmetric, + /// // and `b - a` means something else. + /// // This prints 0 + /// for x in b.difference(&a) { + /// println!("{}", x); + /// } + /// ``` #[inline] - pub fn intersection<'a>(&'a self, other: &'a BitvSet) -> Take> { - let min = cmp::min(self.capacity(), other.capacity()); + pub fn difference<'a>(&'a self, other: &'a BitvSet) -> TwoBitPositions<'a> { TwoBitPositions { set: self, other: other, - merge: |w1, w2| w1 & w2, + merge: |w1, w2| w1 & !w2, current_word: 0, next_idx: 0 - }.take(min) + } } - /// Iterator over each uint stored in `self` union `other` + /// Iterator over each uint stored in the symmetric difference of `self` and `other`. + /// See [symmetric_difference_with](#method.symmetric_difference_with) for + /// an efficient in-place version. + /// + /// # Example + /// + /// ``` + /// use std::collections::BitvSet; + /// use std::collections::bitv; + /// + /// let a = BitvSet::from_bitv(bitv::from_bytes([0b01101000])); + /// let b = BitvSet::from_bitv(bitv::from_bytes([0b10100000])); + /// + /// // Print 0, 1, 4 in arbitrary order + /// for x in a.symmetric_difference(&b) { + /// println!("{}", x); + /// } + /// ``` #[inline] - pub fn union<'a>(&'a self, other: &'a BitvSet) -> TwoBitPositions<'a> { + pub fn symmetric_difference<'a>(&'a self, other: &'a BitvSet) -> TwoBitPositions<'a> { TwoBitPositions { set: self, other: other, - merge: |w1, w2| w1 | w2, + merge: |w1, w2| w1 ^ w2, current_word: 0, next_idx: 0 } } + + /// Union in-place with the specified other bit vector. + /// + /// # Example + /// + /// ``` + /// use std::collections::BitvSet; + /// use std::collections::bitv; + /// + /// let a = 0b01101000; + /// let b = 0b10100000; + /// let res = 0b11101000; + /// + /// let mut a = BitvSet::from_bitv(bitv::from_bytes([a])); + /// let b = BitvSet::from_bitv(bitv::from_bytes([b])); + /// + /// a.union_with(&b); + /// assert_eq!(a.unwrap(), bitv::from_bytes([res])); + /// ``` + #[inline] + pub fn union_with(&mut self, other: &BitvSet) { + self.other_op(other, |w1, w2| w1 | w2); + } + + /// Intersect in-place with the specified other bit vector. + /// + /// # Example + /// + /// ``` + /// use std::collections::BitvSet; + /// use std::collections::bitv; + /// + /// let a = 0b01101000; + /// let b = 0b10100000; + /// let res = 0b00100000; + /// + /// let mut a = BitvSet::from_bitv(bitv::from_bytes([a])); + /// let b = BitvSet::from_bitv(bitv::from_bytes([b])); + /// + /// a.intersect_with(&b); + /// assert_eq!(a.unwrap(), bitv::from_bytes([res])); + /// ``` + #[inline] + pub fn intersect_with(&mut self, other: &BitvSet) { + self.other_op(other, |w1, w2| w1 & w2); + } + + /// Difference in-place with the specified other bit vector. + /// + /// # Example + /// + /// ``` + /// use std::collections::BitvSet; + /// use std::collections::bitv; + /// + /// let a = 0b01101000; + /// let b = 0b10100000; + /// let a_b = 0b01001000; // a - b + /// let b_a = 0b10000000; // b - a + /// + /// let mut bva = BitvSet::from_bitv(bitv::from_bytes([a])); + /// let bvb = BitvSet::from_bitv(bitv::from_bytes([b])); + /// + /// bva.difference_with(&bvb); + /// assert_eq!(bva.unwrap(), bitv::from_bytes([a_b])); + /// + /// let bva = BitvSet::from_bitv(bitv::from_bytes([a])); + /// let mut bvb = BitvSet::from_bitv(bitv::from_bytes([b])); + /// + /// bvb.difference_with(&bva); + /// assert_eq!(bvb.unwrap(), bitv::from_bytes([b_a])); + /// ``` + #[inline] + pub fn difference_with(&mut self, other: &BitvSet) { + self.other_op(other, |w1, w2| w1 & !w2); + } + + /// Symmetric difference in-place with the specified other bit vector. + /// + /// # Example + /// + /// ``` + /// use std::collections::BitvSet; + /// use std::collections::bitv; + /// + /// let a = 0b01101000; + /// let b = 0b10100000; + /// let res = 0b11001000; + /// + /// let mut a = BitvSet::from_bitv(bitv::from_bytes([a])); + /// let b = BitvSet::from_bitv(bitv::from_bytes([b])); + /// + /// a.symmetric_difference_with(&b); + /// assert_eq!(a.unwrap(), bitv::from_bytes([res])); + /// ``` + #[inline] + pub fn symmetric_difference_with(&mut self, other: &BitvSet) { + self.other_op(other, |w1, w2| w1 ^ w2); + } } impl fmt::Show for BitvSet { @@ -905,11 +1496,13 @@ impl MutableSet for BitvSet { } } +/// An iterator for `BitvSet`. pub struct BitPositions<'a> { set: &'a BitvSet, next_idx: uint } +/// An iterator combining wo `BitvSet` iterators. pub struct TwoBitPositions<'a> { set: &'a BitvSet, other: &'a BitvSet, diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs index d3c0c8856bd47..fba89df1bbc6b 100644 --- a/src/libcollections/lib.rs +++ b/src/libcollections/lib.rs @@ -327,33 +327,200 @@ pub trait MutableSet: Set + Mutable { /// A double-ended sequence that allows querying, insertion and deletion at both /// ends. +/// +/// # Example +/// +/// With a `Deque` we can simulate a queue efficiently: +/// +/// ``` +/// use std::collections::{RingBuf, Deque}; +/// +/// let mut queue = RingBuf::new(); +/// queue.push_back(1i); +/// queue.push_back(2i); +/// queue.push_back(3i); +/// +/// // Will print 1, 2, 3 +/// while !queue.is_empty() { +/// let x = queue.pop_front().unwrap(); +/// println!("{}", x); +/// } +/// ``` +/// +/// We can also simulate a stack: +/// +/// ``` +/// use std::collections::{RingBuf, Deque}; +/// +/// let mut stack = RingBuf::new(); +/// stack.push_front(1i); +/// stack.push_front(2i); +/// stack.push_front(3i); +/// +/// // Will print 3, 2, 1 +/// while !stack.is_empty() { +/// let x = stack.pop_front().unwrap(); +/// println!("{}", x); +/// } +/// ``` +/// +/// And of course we can mix and match: +/// +/// ``` +/// use std::collections::{DList, Deque}; +/// +/// let mut deque = DList::new(); +/// +/// // Init deque with 1, 2, 3, 4 +/// deque.push_front(2i); +/// deque.push_front(1i); +/// deque.push_back(3i); +/// deque.push_back(4i); +/// +/// // Will print (1, 4) and (2, 3) +/// while !deque.is_empty() { +/// let f = deque.pop_front().unwrap(); +/// let b = deque.pop_back().unwrap(); +/// println!("{}", (f, b)); +/// } +/// ``` pub trait Deque : Mutable { - /// Provide a reference to the front element, or None if the sequence is - /// empty + /// Provide a reference to the front element, or `None` if the sequence is + /// empty. + /// + /// # Example + /// + /// ``` + /// use std::collections::{RingBuf, Deque}; + /// + /// let mut d = RingBuf::new(); + /// assert_eq!(d.front(), None); + /// + /// d.push_back(1i); + /// d.push_back(2i); + /// assert_eq!(d.front(), Some(&1i)); + /// ``` fn front<'a>(&'a self) -> Option<&'a T>; - /// Provide a mutable reference to the front element, or None if the - /// sequence is empty + /// Provide a mutable reference to the front element, or `None` if the + /// sequence is empty. + /// + /// # Example + /// + /// ``` + /// use std::collections::{RingBuf, Deque}; + /// + /// let mut d = RingBuf::new(); + /// assert_eq!(d.front_mut(), None); + /// + /// d.push_back(1i); + /// d.push_back(2i); + /// match d.front_mut() { + /// Some(x) => *x = 9i, + /// None => (), + /// } + /// assert_eq!(d.front(), Some(&9i)); + /// ``` fn front_mut<'a>(&'a mut self) -> Option<&'a mut T>; - /// Provide a reference to the back element, or None if the sequence is - /// empty + /// Provide a reference to the back element, or `None` if the sequence is + /// empty. + /// + /// # Example + /// + /// ``` + /// use std::collections::{DList, Deque}; + /// + /// let mut d = DList::new(); + /// assert_eq!(d.back(), None); + /// + /// d.push_back(1i); + /// d.push_back(2i); + /// assert_eq!(d.back(), Some(&2i)); + /// ``` fn back<'a>(&'a self) -> Option<&'a T>; - /// Provide a mutable reference to the back element, or None if the sequence - /// is empty + /// Provide a mutable reference to the back element, or `None` if the sequence + /// is empty. + /// + /// # Example + /// + /// ``` + /// use std::collections::{DList, Deque}; + /// + /// let mut d = DList::new(); + /// assert_eq!(d.back(), None); + /// + /// d.push_back(1i); + /// d.push_back(2i); + /// match d.back_mut() { + /// Some(x) => *x = 9i, + /// None => (), + /// } + /// assert_eq!(d.back(), Some(&9i)); + /// ``` fn back_mut<'a>(&'a mut self) -> Option<&'a mut T>; - /// Insert an element first in the sequence + /// Insert an element first in the sequence. + /// + /// # Example + /// + /// ``` + /// use std::collections::{DList, Deque}; + /// + /// let mut d = DList::new(); + /// d.push_front(1i); + /// d.push_front(2i); + /// assert_eq!(d.front(), Some(&2i)); + /// ``` fn push_front(&mut self, elt: T); - /// Insert an element last in the sequence + /// Insert an element last in the sequence. + /// + /// # Example + /// + /// ``` + /// use std::collections::{DList, Deque}; + /// + /// let mut d = DList::new(); + /// d.push_back(1i); + /// d.push_back(2i); + /// assert_eq!(d.front(), Some(&1i)); + /// ``` fn push_back(&mut self, elt: T); - /// Remove the last element and return it, or None if the sequence is empty + /// Remove the last element and return it, or `None` if the sequence is empty. + /// + /// # Example + /// + /// ``` + /// use std::collections::{RingBuf, Deque}; + /// + /// let mut d = RingBuf::new(); + /// d.push_back(1i); + /// d.push_back(2i); + /// + /// assert_eq!(d.pop_back(), Some(2i)); + /// assert_eq!(d.pop_back(), Some(1i)); + /// assert_eq!(d.pop_back(), None); + /// ``` fn pop_back(&mut self) -> Option; - /// Remove the first element and return it, or None if the sequence is empty + /// Remove the first element and return it, or `None` if the sequence is empty. + /// + /// # Example + /// + /// ``` + /// use std::collections::{RingBuf, Deque}; + /// + /// let mut d = RingBuf::new(); + /// d.push_back(1i); + /// d.push_back(2i); + /// + /// assert_eq!(d.pop_front(), Some(1i)); + /// assert_eq!(d.pop_front(), Some(2i)); + /// assert_eq!(d.pop_front(), None); + /// ``` fn pop_front(&mut self) -> Option; } diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index 5450f2d7c31a3..d33bd4d04bdfc 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -856,8 +856,7 @@ mod tests { #[bench] fn from_utf8_lossy_100_multibyte(b: &mut Bencher) { - let s = "𐌀𐌖𐌋𐌄𐌑𐌉ปรدولة\ - الكويتทศไทย中华𐍅𐌿𐌻𐍆𐌹𐌻𐌰".as_bytes(); + let s = "𐌀𐌖𐌋𐌄𐌑𐌉ปรدولة الكويتทศไทย中华𐍅𐌿𐌻𐍆𐌹𐌻𐌰".as_bytes(); assert_eq!(100, s.len()); b.iter(|| { let _ = String::from_utf8_lossy(s); diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index 96228531ae54f..751775888b759 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -51,10 +51,27 @@ pub static PTR_MARKER: u8 = 0; /// The `vec!` macro is provided to make initialization more convenient: /// /// ```rust -/// let mut vec = vec!(1i, 2i, 3i); +/// let mut vec = vec![1i, 2i, 3i]; /// vec.push(4); -/// assert_eq!(vec, vec!(1, 2, 3, 4)); +/// assert_eq!(vec, vec![1, 2, 3, 4]); /// ``` +/// +/// # Capacity and reallocation +/// +/// The capacity of a vector is the amount of space allocated for any future +/// elements that will be added onto the vector. This is not to be confused +/// with the *length* of a vector, which specifies the number of actual +/// elements within the vector. If a vector's length exceeds its capacity, +/// its capacity will automatically be increased, but its elements will +/// have to be reallocated. +/// +/// For example, a vector with capacity 10 and length 0 would be an empty +/// vector with space for 10 more elements. Pushing 10 or fewer elements onto +/// the vector will not change its capacity or cause reallocation to occur. +/// However, if the vector's length is increased to 11, it will have to +/// reallocate, which can be slow. For this reason, it is recommended +/// to use `Vec::with_capacity` whenever possible to specify how big the vector +/// is expected to get. #[unsafe_no_drop_flag] pub struct Vec { len: uint, @@ -87,11 +104,28 @@ impl Vec { /// The vector will be able to hold exactly `capacity` elements without /// reallocating. If `capacity` is 0, the vector will not allocate. /// + /// It is important to note that this function does not specify the + /// *length* of the returned vector, but only the *capacity*. (For an + /// explanation of the difference between length and capacity, see + /// the main `Vec` docs above, 'Capacity and reallocation'.) To create + /// a vector of a given length, use `Vec::from_elem` or `Vec::from_fn`. + /// /// # Example /// /// ```rust /// # use std::vec::Vec; - /// let vec: Vec = Vec::with_capacity(10); + /// let mut vec: Vec = Vec::with_capacity(10); + /// + /// // The vector contains no items, even though it has capacity for more + /// assert_eq!(vec.len(), 0); + /// + /// // These are all done without reallocating... + /// for i in range(0i, 10) { + /// vec.push(i); + /// } + /// + /// // ...but this may make the vector reallocate + /// vec.push(11); /// ``` #[inline] pub fn with_capacity(capacity: uint) -> Vec { diff --git a/src/libgraphviz/lib.rs b/src/libgraphviz/lib.rs index 3c93a795071a6..f55a1ca62f72f 100644 --- a/src/libgraphviz/lib.rs +++ b/src/libgraphviz/lib.rs @@ -548,7 +548,7 @@ mod tests { from: uint, to: uint, label: &'static str } - fn Edge(from: uint, to: uint, label: &'static str) -> Edge { + fn edge(from: uint, to: uint, label: &'static str) -> Edge { Edge { from: from, to: to, label: label } } @@ -723,7 +723,7 @@ r#"digraph single_node { fn single_edge() { let labels : Trivial = UnlabelledNodes(2); let result = test_input(LabelledGraph::new("single_edge", labels, - vec!(Edge(0, 1, "E")))); + vec!(edge(0, 1, "E")))); assert_eq!(result.unwrap().as_slice(), r#"digraph single_edge { N0[label="N0"]; @@ -737,7 +737,7 @@ r#"digraph single_edge { fn single_cyclic_node() { let labels : Trivial = UnlabelledNodes(1); let r = test_input(LabelledGraph::new("single_cyclic_node", labels, - vec!(Edge(0, 0, "E")))); + vec!(edge(0, 0, "E")))); assert_eq!(r.unwrap().as_slice(), r#"digraph single_cyclic_node { N0[label="N0"]; @@ -751,8 +751,8 @@ r#"digraph single_cyclic_node { let labels = AllNodesLabelled(vec!("{x,y}", "{x}", "{y}", "{}")); let r = test_input(LabelledGraph::new( "hasse_diagram", labels, - vec!(Edge(0, 1, ""), Edge(0, 2, ""), - Edge(1, 3, ""), Edge(2, 3, "")))); + vec!(edge(0, 1, ""), edge(0, 2, ""), + edge(1, 3, ""), edge(2, 3, "")))); assert_eq!(r.unwrap().as_slice(), r#"digraph hasse_diagram { N0[label="{x,y}"]; @@ -785,8 +785,8 @@ r#"digraph hasse_diagram { let g = LabelledGraphWithEscStrs::new( "syntax_tree", labels, - vec!(Edge(0, 1, "then"), Edge(0, 2, "else"), - Edge(1, 3, ";"), Edge(2, 3, ";" ))); + vec!(edge(0, 1, "then"), edge(0, 2, "else"), + edge(1, 3, ";"), edge(2, 3, ";" ))); render(&g, &mut writer).unwrap(); let mut r = BufReader::new(writer.get_ref()); diff --git a/src/librlibc/lib.rs b/src/librlibc/lib.rs index cb27596c98c6b..c7295125f42f7 100644 --- a/src/librlibc/lib.rs +++ b/src/librlibc/lib.rs @@ -21,22 +21,26 @@ //! the system libc library. #![crate_name = "rlibc"] +#![experimental] #![license = "MIT/ASL2"] #![crate_type = "rlib"] #![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "http://www.rust-lang.org/favicon.ico", html_root_url = "http://doc.rust-lang.org/master/")] -#![feature(intrinsics)] +#![feature(intrinsics, phase)] #![no_std] -#![experimental] // This library defines the builtin functions, so it would be a shame for // LLVM to optimize these function calls to themselves! #![no_builtins] -#[cfg(test)] extern crate std; #[cfg(test)] extern crate native; +#[cfg(test)] extern crate test; +#[cfg(test)] extern crate debug; + +#[cfg(test)] #[phase(plugin, link)] extern crate std; +#[cfg(test)] #[phase(plugin, link)] extern crate core; // Require the offset intrinsics for LLVM to properly optimize the // implementations below. If pointer arithmetic is done through integers the @@ -95,11 +99,107 @@ pub unsafe extern "C" fn memcmp(s1: *const u8, s2: *const u8, n: uint) -> i32 { let a = *offset(s1, i as int); let b = *offset(s2, i as int); if a != b { - return (a - b) as i32 + return a as i32 - b as i32 } i += 1; } return 0; } -#[test] fn work_on_windows() { } // FIXME #10872 needed for a happy windows +#[cfg(test)] +mod test { + use core::option::{Some, None}; + use core::iter::Iterator; + use core::collections::Collection; + use core::str::StrSlice; + use core::slice::{MutableVector, ImmutableVector}; + + use super::{memcmp, memset, memcpy, memmove}; + + #[test] + fn memcmp_single_byte_pointers() { + unsafe { + assert_eq!(memcmp(&0xFAu8, &0xFAu8, 1), 0x00); + assert!(memcmp(&0xEFu8, &0xFEu8, 1) < 0x00); + } + } + + #[test] + fn memcmp_strings() { + { + let (x, z) = ("Hello!", "Good Bye."); + let l = x.len(); + unsafe { + assert_eq!(memcmp(x.as_ptr(), x.as_ptr(), l), 0); + assert!(memcmp(x.as_ptr(), z.as_ptr(), l) > 0); + assert!(memcmp(z.as_ptr(), x.as_ptr(), l) < 0); + } + } + { + let (x, z) = ("hey!", "hey."); + let l = x.len(); + unsafe { + assert!(memcmp(x.as_ptr(), z.as_ptr(), l) < 0); + } + } + } + + #[test] + fn memset_single_byte_pointers() { + let mut x: u8 = 0xFF; + unsafe { + memset(&mut x, 0xAA, 1); + assert_eq!(x, 0xAA); + memset(&mut x, 0x00, 1); + assert_eq!(x, 0x00); + x = 0x01; + memset(&mut x, 0x12, 0); + assert_eq!(x, 0x01); + } + } + + #[test] + fn memset_array() { + let mut buffer = [b'X', .. 100]; + unsafe { + memset(buffer.as_mut_ptr(), b'#' as i32, buffer.len()); + } + for byte in buffer.iter() { assert_eq!(*byte, b'#'); } + } + + #[test] + fn memcpy_and_memcmp_arrays() { + let (src, mut dst) = ([b'X', .. 100], [b'Y', .. 100]); + unsafe { + assert!(memcmp(src.as_ptr(), dst.as_ptr(), 100) != 0); + let _ = memcpy(dst.as_mut_ptr(), src.as_ptr(), 100); + assert_eq!(memcmp(src.as_ptr(), dst.as_ptr(), 100), 0); + } + } + + #[test] + fn memmove_overlapping() { + { + let mut buffer = [ b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9' ]; + unsafe { + memmove(&mut buffer[4], &buffer[0], 6); + let mut i = 0; + for byte in b"0123012345".iter() { + assert_eq!(buffer[i], *byte); + i += 1; + } + } + } + { + let mut buffer = [ b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9' ]; + unsafe { + memmove(&mut buffer[0], &buffer[4], 6); + let mut i = 0; + for byte in b"4567896789".iter() { + assert_eq!(buffer[i], *byte); + i += 1; + } + } + } + } +} diff --git a/src/librustc/driver/config.rs b/src/librustc/driver/config.rs index ee611293475f9..dd951d963e0d7 100644 --- a/src/librustc/driver/config.rs +++ b/src/librustc/driver/config.rs @@ -97,6 +97,10 @@ pub struct Options { pub color: ColorConfig, pub externs: HashMap>, pub crate_name: Option, + /// An optional name to use as the crate for std during std injection, + /// written `extern crate std = "name"`. Default to "std". Used by + /// out-of-tree drivers. + pub alt_std_name: Option } /// Some reasonable defaults @@ -124,6 +128,7 @@ pub fn basic_options() -> Options { color: Auto, externs: HashMap::new(), crate_name: None, + alt_std_name: None, } } @@ -577,7 +582,7 @@ pub fn optgroups() -> Vec { always = always colorize output; never = never colorize output", "auto|always|never"), optmulti("", "extern", "Specify where an external rust library is located", - "PATH"), + "NAME=PATH"), ) } @@ -593,24 +598,10 @@ fn parse_cfgspecs(cfgspecs: Vec ) -> ast::CrateConfig { } pub fn build_session_options(matches: &getopts::Matches) -> Options { - let mut crate_types: Vec = Vec::new(); + let unparsed_crate_types = matches.opt_strs("crate-type"); - for unparsed_crate_type in unparsed_crate_types.iter() { - for part in unparsed_crate_type.as_slice().split(',') { - let new_part = match part { - "lib" => default_lib_output(), - "rlib" => CrateTypeRlib, - "staticlib" => CrateTypeStaticlib, - "dylib" => CrateTypeDylib, - "bin" => CrateTypeExecutable, - _ => { - early_error(format!("unknown crate type: `{}`", - part).as_slice()) - } - }; - crate_types.push(new_part) - } - } + let crate_types = parse_crate_types_from_list(unparsed_crate_types) + .unwrap_or_else(|e| early_error(e.as_slice())); let parse_only = matches.opt_present("parse-only"); let no_trans = matches.opt_present("no-trans"); @@ -801,9 +792,33 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { color: color, externs: externs, crate_name: crate_name, + alt_std_name: None } } +pub fn parse_crate_types_from_list(list_list: Vec) -> Result, String> { + + let mut crate_types: Vec = Vec::new(); + for unparsed_crate_type in list_list.iter() { + for part in unparsed_crate_type.as_slice().split(',') { + let new_part = match part { + "lib" => default_lib_output(), + "rlib" => CrateTypeRlib, + "staticlib" => CrateTypeStaticlib, + "dylib" => CrateTypeDylib, + "bin" => CrateTypeExecutable, + _ => { + return Err(format!("unknown crate type: `{}`", + part)); + } + }; + crate_types.push(new_part) + } + } + + return Ok(crate_types); +} + impl fmt::Show for CrateType { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { diff --git a/src/librustc/driver/driver.rs b/src/librustc/driver/driver.rs index 81ace4d015c85..9796aab51fb6b 100644 --- a/src/librustc/driver/driver.rs +++ b/src/librustc/driver/driver.rs @@ -69,7 +69,8 @@ pub fn compile_input(sess: Session, cfg: ast::CrateConfig, input: &Input, outdir: &Option, - output: &Option) { + output: &Option, + addl_plugins: Option) { // We need nested scopes here, because the intermediate results can keep // large chunks of memory alive and we want to free them as soon as // possible to keep the peak memory usage low @@ -85,7 +86,8 @@ pub fn compile_input(sess: Session, let id = link::find_crate_name(Some(&sess), krate.attrs.as_slice(), input); let (expanded_crate, ast_map) - = match phase_2_configure_and_expand(&sess, krate, id.as_slice()) { + = match phase_2_configure_and_expand(&sess, krate, id.as_slice(), + addl_plugins) { None => return, Some(p) => p, }; @@ -179,6 +181,7 @@ pub fn phase_1_parse_input(sess: &Session, cfg: ast::CrateConfig, input: &Input) // modified /// Run the "early phases" of the compiler: initial `cfg` processing, +/// loading compiler plugins (including those from `addl_plugins`), /// syntax expansion, secondary `cfg` expansion, synthesis of a test /// harness if one is to be provided and injection of a dependency on the /// standard library and prelude. @@ -186,7 +189,8 @@ pub fn phase_1_parse_input(sess: &Session, cfg: ast::CrateConfig, input: &Input) /// Returns `None` if we're aborting after handling -W help. pub fn phase_2_configure_and_expand(sess: &Session, mut krate: ast::Crate, - crate_name: &str) + crate_name: &str, + addl_plugins: Option) -> Option<(ast::Crate, syntax::ast_map::Map)> { let time_passes = sess.time_passes(); @@ -212,9 +216,10 @@ pub fn phase_2_configure_and_expand(sess: &Session, krate = time(time_passes, "configuration 1", krate, |krate| front::config::strip_unconfigured_items(krate)); + let mut addl_plugins = Some(addl_plugins); let Plugins { macros, registrars } = time(time_passes, "plugin loading", (), |_| - plugin::load::load_plugins(sess, &krate)); + plugin::load::load_plugins(sess, &krate, addl_plugins.take_unwrap())); let mut registry = Registry::new(&krate); @@ -697,7 +702,7 @@ pub fn pretty_print_input(sess: Session, PpmExpanded | PpmExpandedIdentified | PpmTyped | PpmFlowGraph(_) => { let (krate, ast_map) = match phase_2_configure_and_expand(&sess, krate, - id.as_slice()) { + id.as_slice(), None) { None => return, Some(p) => p, }; diff --git a/src/librustc/driver/mod.rs b/src/librustc/driver/mod.rs index e433c3df8644c..a5df63a9e23fa 100644 --- a/src/librustc/driver/mod.rs +++ b/src/librustc/driver/mod.rs @@ -124,7 +124,7 @@ fn run_compiler(args: &[String]) { return; } - driver::compile_input(sess, cfg, &input, &odir, &ofile); + driver::compile_input(sess, cfg, &input, &odir, &ofile, None); } /// Prints version information and returns None on success or an error @@ -418,7 +418,7 @@ pub fn list_metadata(sess: &Session, path: &Path, /// /// The diagnostic emitter yielded to the procedure should be used for reporting /// errors of the compiler. -fn monitor(f: proc():Send) { +pub fn monitor(f: proc():Send) { // FIXME: This is a hack for newsched since it doesn't support split stacks. // rustc needs a lot of stack! When optimizations are disabled, it needs // even *more* stack than usual as well. diff --git a/src/librustc/front/std_inject.rs b/src/librustc/front/std_inject.rs index 351c9a6b77167..940112325fdf4 100644 --- a/src/librustc/front/std_inject.rs +++ b/src/librustc/front/std_inject.rs @@ -60,9 +60,16 @@ struct StandardLibraryInjector<'a> { impl<'a> fold::Folder for StandardLibraryInjector<'a> { fn fold_crate(&mut self, mut krate: ast::Crate) -> ast::Crate { + + // The name to use in `extern crate std = "name";` + let actual_crate_name = match self.sess.opts.alt_std_name { + Some(ref s) => token::intern_and_get_ident(s.as_slice()), + None => token::intern_and_get_ident("std"), + }; + let mut vis = vec!(ast::ViewItem { node: ast::ViewItemExternCrate(token::str_to_ident("std"), - None, + Some((actual_crate_name, ast::CookedStr)), ast::DUMMY_NODE_ID), attrs: vec!( attr::mk_attr_outer(attr::mk_attr_id(), attr::mk_list_item( diff --git a/src/librustc/front/test.rs b/src/librustc/front/test.rs index 0860d111a9ef0..08907f6c0ed5d 100644 --- a/src/librustc/front/test.rs +++ b/src/librustc/front/test.rs @@ -16,9 +16,9 @@ use driver::session::Session; use front::config; -use std::cell::RefCell; use std::gc::{Gc, GC}; use std::slice; +use std::mem; use std::vec; use syntax::ast_util::*; use syntax::attr::AttrMetaMethods; @@ -26,6 +26,7 @@ use syntax::attr; use syntax::codemap::{DUMMY_SP, Span, ExpnInfo, NameAndSpan, MacroAttribute}; use syntax::codemap; use syntax::ext::base::ExtCtxt; +use syntax::ext::build::AstBuilder; use syntax::ext::expand::ExpansionConfig; use syntax::fold::Folder; use syntax::fold; @@ -46,9 +47,11 @@ struct Test { struct TestCtxt<'a> { sess: &'a Session, - path: RefCell>, + path: Vec, + reexports: Vec>, ext_cx: ExtCtxt<'a>, - testfns: RefCell >, + testfns: Vec, + reexport_mod_ident: ast::Ident, is_test_crate: bool, config: ast::CrateConfig, } @@ -86,9 +89,9 @@ impl<'a> fold::Folder for TestHarnessGenerator<'a> { } fn fold_item(&mut self, i: Gc) -> SmallVector> { - self.cx.path.borrow_mut().push(i.ident); + self.cx.path.push(i.ident); debug!("current path: {}", - ast_util::path_name_i(self.cx.path.borrow().as_slice())); + ast_util::path_name_i(self.cx.path.as_slice())); if is_test_fn(&self.cx, i) || is_bench_fn(&self.cx, i) { match i.node { @@ -102,31 +105,41 @@ impl<'a> fold::Folder for TestHarnessGenerator<'a> { debug!("this is a test function"); let test = Test { span: i.span, - path: self.cx.path.borrow().clone(), + path: self.cx.path.clone(), bench: is_bench_fn(&self.cx, i), ignore: is_ignored(&self.cx, i), should_fail: should_fail(i) }; - self.cx.testfns.borrow_mut().push(test); + self.cx.testfns.push(test); + self.cx.reexports.push(self.cx.path.clone()); // debug!("have {} test/bench functions", // cx.testfns.len()); } } } - let res = fold::noop_fold_item(&*i, self); - self.cx.path.borrow_mut().pop(); + // We don't want to recurse into anything other than mods, since + // mods or tests inside of functions will break things + let res = match i.node { + ast::ItemMod(..) => fold::noop_fold_item(&*i, self), + _ => SmallVector::one(i), + }; + self.cx.path.pop(); res } fn fold_mod(&mut self, m: &ast::Mod) -> ast::Mod { + let reexports = mem::replace(&mut self.cx.reexports, Vec::new()); + let mut mod_folded = fold::noop_fold_mod(m, self); + let reexports = mem::replace(&mut self.cx.reexports, reexports); + // Remove any #[main] from the AST so it doesn't clash with // the one we're going to add. Only if compiling an executable. fn nomain(item: Gc) -> Gc { box(GC) ast::Item { attrs: item.attrs.iter().filter_map(|attr| { - if !attr.name().equiv(&("main")) { + if !attr.check_name("main") { Some(*attr) } else { None @@ -136,18 +149,39 @@ impl<'a> fold::Folder for TestHarnessGenerator<'a> { } } - let mod_nomain = ast::Mod { - inner: m.inner, - view_items: m.view_items.clone(), - items: m.items.iter().map(|i| nomain(*i)).collect(), - }; + for i in mod_folded.items.mut_iter() { + *i = nomain(*i); + } + if !reexports.is_empty() { + mod_folded.items.push(mk_reexport_mod(&mut self.cx, reexports)); + self.cx.reexports.push(self.cx.path.clone()); + } + + mod_folded + } +} - fold::noop_fold_mod(&mod_nomain, self) +fn mk_reexport_mod(cx: &mut TestCtxt, reexports: Vec>) + -> Gc { + let view_items = reexports.move_iter().map(|r| { + cx.ext_cx.view_use_simple(DUMMY_SP, ast::Public, cx.ext_cx.path(DUMMY_SP, r)) + }).collect(); + let reexport_mod = ast::Mod { + inner: DUMMY_SP, + view_items: view_items, + items: Vec::new(), + }; + box(GC) ast::Item { + ident: cx.reexport_mod_ident.clone(), + attrs: Vec::new(), + id: ast::DUMMY_NODE_ID, + node: ast::ItemMod(reexport_mod), + vis: ast::Public, + span: DUMMY_SP, } } -fn generate_test_harness(sess: &Session, krate: ast::Crate) - -> ast::Crate { +fn generate_test_harness(sess: &Session, krate: ast::Crate) -> ast::Crate { let mut cx: TestCtxt = TestCtxt { sess: sess, ext_cx: ExtCtxt::new(&sess.parse_sess, sess.opts.cfg.clone(), @@ -155,8 +189,10 @@ fn generate_test_harness(sess: &Session, krate: ast::Crate) deriving_hash_type_parameter: false, crate_name: "test".to_string(), }), - path: RefCell::new(Vec::new()), - testfns: RefCell::new(Vec::new()), + path: Vec::new(), + reexports: Vec::new(), + testfns: Vec::new(), + reexport_mod_ident: token::str_to_ident("__test_reexports"), is_test_crate: is_test_crate(&krate), config: krate.config.clone(), }; @@ -171,7 +207,7 @@ fn generate_test_harness(sess: &Session, krate: ast::Crate) }); let mut fold = TestHarnessGenerator { - cx: cx + cx: cx, }; let res = fold.fold_crate(krate); fold.cx.ext_cx.bt_pop(); @@ -275,7 +311,6 @@ fn add_test_module(cx: &TestCtxt, m: &ast::Mod) -> ast::Mod { We're going to be building a module that looks more or less like: mod __test { - #![!resolve_unexported] extern crate test (name = "test", vers = "..."); fn main() { test::test_main_static(::os::args().as_slice(), tests) @@ -332,15 +367,9 @@ fn mk_test_module(cx: &TestCtxt) -> Gc { }; let item_ = ast::ItemMod(testmod); - // This attribute tells resolve to let us call unexported functions - let resolve_unexported_str = InternedString::new("!resolve_unexported"); - let resolve_unexported_attr = - attr::mk_attr_inner(attr::mk_attr_id(), - attr::mk_word_item(resolve_unexported_str)); - let item = ast::Item { ident: token::str_to_ident("__test"), - attrs: vec!(resolve_unexported_attr), + attrs: Vec::new(), id: ast::DUMMY_NODE_ID, node: item_, vis: ast::Public, @@ -368,18 +397,6 @@ fn path_node(ids: Vec ) -> ast::Path { } } -fn path_node_global(ids: Vec ) -> ast::Path { - ast::Path { - span: DUMMY_SP, - global: true, - segments: ids.move_iter().map(|identifier| ast::PathSegment { - identifier: identifier, - lifetimes: Vec::new(), - types: OwnedSlice::empty(), - }).collect() - } -} - fn mk_tests(cx: &TestCtxt) -> Gc { // The vector of test_descs for this crate let test_descs = mk_test_descs(cx); @@ -399,13 +416,13 @@ fn is_test_crate(krate: &ast::Crate) -> bool { } fn mk_test_descs(cx: &TestCtxt) -> Gc { - debug!("building test vector from {} tests", cx.testfns.borrow().len()); + debug!("building test vector from {} tests", cx.testfns.len()); box(GC) ast::Expr { id: ast::DUMMY_NODE_ID, node: ast::ExprVstore(box(GC) ast::Expr { id: ast::DUMMY_NODE_ID, - node: ast::ExprVec(cx.testfns.borrow().iter().map(|test| { + node: ast::ExprVec(cx.testfns.iter().map(|test| { mk_test_desc_and_fn_rec(cx, test) }).collect()), span: DUMMY_SP, @@ -431,7 +448,12 @@ fn mk_test_desc_and_fn_rec(cx: &TestCtxt, test: &Test) -> Gc { span: span }; - let fn_path = path_node_global(path); + let mut visible_path = Vec::new(); + for ident in path.move_iter() { + visible_path.push(cx.reexport_mod_ident.clone()); + visible_path.push(ident); + } + let fn_path = cx.ext_cx.path_global(DUMMY_SP, visible_path); let fn_expr = box(GC) ast::Expr { id: ast::DUMMY_NODE_ID, diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index 439455ff3d15c..7997af1ee5e11 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -1618,8 +1618,8 @@ fn encode_macro_defs(ecx: &EncodeContext, krate: &Crate, ebml_w: &mut Encoder) { ebml_w.start_tag(tag_exported_macros); - for span in krate.exported_macros.iter() { - encode_macro_def(ecx, ebml_w, span); + for item in krate.exported_macros.iter() { + encode_macro_def(ecx, ebml_w, &item.span); } ebml_w.end_tag(); } diff --git a/src/librustc/middle/privacy.rs b/src/librustc/middle/privacy.rs index bad6a288294f4..62b5299f8fbc8 100644 --- a/src/librustc/middle/privacy.rs +++ b/src/librustc/middle/privacy.rs @@ -27,7 +27,6 @@ use util::nodemap::{NodeMap, NodeSet}; use syntax::ast; use syntax::ast_map; use syntax::ast_util::{is_local, local_def, PostExpansionMethod}; -use syntax::attr; use syntax::codemap::Span; use syntax::parse::token; use syntax::owned_slice::OwnedSlice; @@ -326,7 +325,7 @@ impl<'a> Visitor<()> for EmbargoVisitor<'a> { } fn visit_foreign_item(&mut self, a: &ast::ForeignItem, _: ()) { - if self.prev_exported && a.vis == ast::Public { + if (self.prev_exported && a.vis == ast::Public) || self.reexports.contains(&a.id) { self.exported_items.insert(a.id); } } @@ -786,12 +785,6 @@ impl<'a> PrivacyVisitor<'a> { impl<'a> Visitor<()> for PrivacyVisitor<'a> { fn visit_item(&mut self, item: &ast::Item, _: ()) { - // Do not check privacy inside items with the resolve_unexported - // attribute. This is used for the test runner. - if attr::contains_name(item.attrs.as_slice(), "!resolve_unexported") { - return; - } - let orig_curitem = replace(&mut self.curitem, item.id); visit::walk_item(self, item, ()); self.curitem = orig_curitem; diff --git a/src/librustc/middle/typeck/infer/test.rs b/src/librustc/middle/typeck/infer/test.rs index c8f6836b20596..637af96b6321a 100644 --- a/src/librustc/middle/typeck/infer/test.rs +++ b/src/librustc/middle/typeck/infer/test.rs @@ -117,7 +117,7 @@ fn test_env(_test_name: &str, let input = driver::StrInput(source_string.to_string()); let krate = driver::phase_1_parse_input(&sess, krate_config, &input); let (krate, ast_map) = - driver::phase_2_configure_and_expand(&sess, krate, "test") + driver::phase_2_configure_and_expand(&sess, krate, "test", None) .expect("phase 2 aborted"); // run just enough stuff to build a tcx: diff --git a/src/librustc/plugin/load.rs b/src/librustc/plugin/load.rs index 499cffa42aac9..4f38c74893e46 100644 --- a/src/librustc/plugin/load.rs +++ b/src/librustc/plugin/load.rs @@ -66,10 +66,24 @@ impl<'a> PluginLoader<'a> { } /// Read plugin metadata and dynamically load registrar functions. -pub fn load_plugins(sess: &Session, krate: &ast::Crate) -> Plugins { +pub fn load_plugins(sess: &Session, krate: &ast::Crate, + addl_plugins: Option) -> Plugins { let mut loader = PluginLoader::new(sess); visit::walk_crate(&mut loader, krate, ()); - loader.plugins + + let mut plugins = loader.plugins; + + match addl_plugins { + Some(addl_plugins) => { + // Add in the additional plugins requested by the frontend + let Plugins { macros: addl_macros, registrars: addl_registrars } = addl_plugins; + plugins.macros.push_all_move(addl_macros); + plugins.registrars.push_all_move(addl_registrars); + } + None => () + } + + return plugins; } // note that macros aren't expanded yet, and therefore macros can't add plugins. diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index e62c8b63a2940..7f021510f4a0e 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -77,8 +77,10 @@ pub struct CrateAnalysis { pub inlined: RefCell>>, } +pub type Externs = HashMap>; + /// Parses, resolves, and typechecks the given crate -fn get_ast_and_resolve(cpath: &Path, libs: HashSet, cfgs: Vec) +fn get_ast_and_resolve(cpath: &Path, libs: HashSet, cfgs: Vec, externs: Externs) -> (DocContext, CrateAnalysis) { use syntax::codemap::dummy_spanned; use rustc::driver::driver::{FileInput, @@ -96,6 +98,7 @@ fn get_ast_and_resolve(cpath: &Path, libs: HashSet, cfgs: Vec) addl_lib_search_paths: RefCell::new(libs), crate_types: vec!(driver::config::CrateTypeRlib), lint_opts: vec!((warning_lint, lint::Allow)), + externs: externs, ..rustc::driver::config::basic_options().clone() }; @@ -121,7 +124,7 @@ fn get_ast_and_resolve(cpath: &Path, libs: HashSet, cfgs: Vec) &input); let (krate, ast_map) - = phase_2_configure_and_expand(&sess, krate, name.as_slice()) + = phase_2_configure_and_expand(&sess, krate, name.as_slice(), None) .expect("phase_2_configure_and_expand aborted in rustdoc!"); let driver::driver::CrateAnalysis { @@ -148,9 +151,9 @@ fn get_ast_and_resolve(cpath: &Path, libs: HashSet, cfgs: Vec) }) } -pub fn run_core(libs: HashSet, cfgs: Vec, path: &Path) +pub fn run_core(libs: HashSet, cfgs: Vec, externs: Externs, path: &Path) -> (clean::Crate, CrateAnalysis) { - let (ctxt, analysis) = get_ast_and_resolve(path, libs, cfgs); + let (ctxt, analysis) = get_ast_and_resolve(path, libs, cfgs, externs); let ctxt = box(GC) ctxt; super::ctxtkey.replace(Some(ctxt)); diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 245dc9a0a34e5..a7c9ac1011829 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -30,6 +30,7 @@ extern crate time; use std::io; use std::io::{File, MemWriter}; use std::gc::Gc; +use std::collections::HashMap; use serialize::{json, Decodable, Encodable}; use externalfiles::ExternalHtml; @@ -104,6 +105,7 @@ pub fn opts() -> Vec { optmulti("L", "library-path", "directory to add to crate search path", "DIR"), optmulti("", "cfg", "pass a --cfg to rustc", ""), + optmulti("", "extern", "pass an --extern to rustc", "NAME=PATH"), optmulti("", "plugin-path", "directory to load plugins from", "DIR"), optmulti("", "passes", "space separated list of passes to also run, a \ value of `list` will print available passes", @@ -170,6 +172,13 @@ pub fn main_args(args: &[String]) -> int { let input = matches.free[0].as_slice(); let libs = matches.opt_strs("L").iter().map(|s| Path::new(s.as_slice())).collect(); + let externs = match parse_externs(&matches) { + Ok(ex) => ex, + Err(err) => { + println!("{}", err); + return 1; + } + }; let test_args = matches.opt_strs("test-args"); let test_args: Vec = test_args.iter() @@ -193,10 +202,10 @@ pub fn main_args(args: &[String]) -> int { match (should_test, markdown_input) { (true, true) => { - return markdown::test(input, libs, test_args) + return markdown::test(input, libs, externs, test_args) } (true, false) => { - return test::run(input, cfgs, libs, test_args) + return test::run(input, cfgs, libs, externs, test_args) } (false, true) => return markdown::render(input, output.unwrap_or(Path::new("doc")), &matches, &external_html), @@ -215,7 +224,7 @@ pub fn main_args(args: &[String]) -> int { return 0; } - let (krate, res) = match acquire_input(input, &matches) { + let (krate, res) = match acquire_input(input, externs, &matches) { Ok(pair) => pair, Err(s) => { println!("input error: {}", s); @@ -252,27 +261,53 @@ pub fn main_args(args: &[String]) -> int { /// Looks inside the command line arguments to extract the relevant input format /// and files and then generates the necessary rustdoc output for formatting. fn acquire_input(input: &str, + externs: core::Externs, matches: &getopts::Matches) -> Result { match matches.opt_str("r").as_ref().map(|s| s.as_slice()) { - Some("rust") => Ok(rust_input(input, matches)), + Some("rust") => Ok(rust_input(input, externs, matches)), Some("json") => json_input(input), Some(s) => Err(format!("unknown input format: {}", s)), None => { if input.ends_with(".json") { json_input(input) } else { - Ok(rust_input(input, matches)) + Ok(rust_input(input, externs, matches)) } } } } +/// Extracts `--extern CRATE=PATH` arguments from `matches` and +/// returns a `HashMap` mapping crate names to their paths or else an +/// error message. +fn parse_externs(matches: &getopts::Matches) -> Result { + let mut externs = HashMap::new(); + for arg in matches.opt_strs("extern").iter() { + let mut parts = arg.as_slice().splitn('=', 1); + let name = match parts.next() { + Some(s) => s, + None => { + return Err("--extern value must not be empty".to_string()); + } + }; + let location = match parts.next() { + Some(s) => s, + None => { + return Err("--extern value must be of the format `foo=bar`".to_string()); + } + }; + let locs = externs.find_or_insert(name.to_string(), Vec::new()); + locs.push(location.to_string()); + } + Ok(externs) +} + /// Interprets the input file as a rust source file, passing it through the /// compiler all the way through the analysis passes. The rustdoc output is then /// generated from the cleaned AST of the crate. /// /// This form of input will run all of the plug/cleaning passes -fn rust_input(cratefile: &str, matches: &getopts::Matches) -> Output { +fn rust_input(cratefile: &str, externs: core::Externs, matches: &getopts::Matches) -> Output { let mut default_passes = !matches.opt_present("no-defaults"); let mut passes = matches.opt_strs("passes"); let mut plugins = matches.opt_strs("plugins"); @@ -283,12 +318,14 @@ fn rust_input(cratefile: &str, matches: &getopts::Matches) -> Output { .map(|s| Path::new(s.as_slice())) .collect(); let cfgs = matches.opt_strs("cfg"); + let cr = Path::new(cratefile); info!("starting to run rustc"); let (krate, analysis) = std::task::try(proc() { let cr = cr; - core::run_core(libs.move_iter().map(|x| x.clone()).collect(), + core::run_core(libs.move_iter().collect(), cfgs, + externs, &cr) }).map_err(|boxed_any|format!("{:?}", boxed_any)).unwrap(); info!("finished with rustc"); diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs index f9bc59888ae3b..47009c1f2cc15 100644 --- a/src/librustdoc/markdown.rs +++ b/src/librustdoc/markdown.rs @@ -12,6 +12,7 @@ use std::collections::HashSet; use std::io; use std::string::String; +use core; use getopts; use testing; @@ -129,10 +130,11 @@ pub fn render(input: &str, mut output: Path, matches: &getopts::Matches, } /// Run any tests/code examples in the markdown file `input`. -pub fn test(input: &str, libs: HashSet, mut test_args: Vec) -> int { +pub fn test(input: &str, libs: HashSet, externs: core::Externs, + mut test_args: Vec) -> int { let input_str = load_or_return!(input, 1, 2); - let mut collector = Collector::new(input.to_string(), libs, true); + let mut collector = Collector::new(input.to_string(), libs, externs, true); find_testable_code(input_str.as_slice(), &mut collector); test_args.unshift("rustdoctest".to_string()); testing::test_main(test_args.as_slice(), collector.tests); diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index 055019aa481ff..2ed35469dfa8d 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -40,6 +40,7 @@ use visit_ast::RustdocVisitor; pub fn run(input: &str, cfgs: Vec, libs: HashSet, + externs: core::Externs, mut test_args: Vec) -> int { let input_path = Path::new(input); @@ -49,10 +50,10 @@ pub fn run(input: &str, maybe_sysroot: Some(os::self_exe_path().unwrap().dir_path()), addl_lib_search_paths: RefCell::new(libs.clone()), crate_types: vec!(config::CrateTypeDylib), + externs: externs.clone(), ..config::basic_options().clone() }; - let codemap = CodeMap::new(); let diagnostic_handler = diagnostic::default_handler(diagnostic::Auto, None); let span_diagnostic_handler = @@ -69,7 +70,7 @@ pub fn run(input: &str, })); let krate = driver::phase_1_parse_input(&sess, cfg, &input); let (krate, _) = driver::phase_2_configure_and_expand(&sess, krate, - "rustdoc-test") + "rustdoc-test", None) .expect("phase_2_configure_and_expand aborted in rustdoc!"); let ctx = box(GC) core::DocContext { @@ -92,6 +93,7 @@ pub fn run(input: &str, let mut collector = Collector::new(krate.name.to_string(), libs, + externs, false); collector.fold_crate(krate); @@ -102,8 +104,8 @@ pub fn run(input: &str, 0 } -fn runtest(test: &str, cratename: &str, libs: HashSet, should_fail: bool, - no_run: bool, as_test_harness: bool) { +fn runtest(test: &str, cratename: &str, libs: HashSet, externs: core::Externs, + should_fail: bool, no_run: bool, as_test_harness: bool) { // the test harness wants its own `main` & top level functions, so // never wrap the test in `fn main() { ... }` let test = maketest(test, Some(cratename), true, as_test_harness); @@ -115,6 +117,7 @@ fn runtest(test: &str, cratename: &str, libs: HashSet, should_fail: bool, crate_types: vec!(config::CrateTypeExecutable), output_types: vec!(link::OutputTypeExe), no_trans: no_run, + externs: externs, cg: config::CodegenOptions { prefer_dynamic: true, .. config::basic_codegen_options() @@ -166,7 +169,7 @@ fn runtest(test: &str, cratename: &str, libs: HashSet, should_fail: bool, let out = Some(outdir.path().clone()); let cfg = config::build_configuration(&sess); let libdir = sess.target_filesearch().get_lib_path(); - driver::compile_input(sess, cfg, &input, &out, &None); + driver::compile_input(sess, cfg, &input, &out, &None, None); if no_run { return } @@ -237,6 +240,7 @@ pub struct Collector { pub tests: Vec, names: Vec, libs: HashSet, + externs: core::Externs, cnt: uint, use_headers: bool, current_header: Option, @@ -244,12 +248,13 @@ pub struct Collector { } impl Collector { - pub fn new(cratename: String, libs: HashSet, + pub fn new(cratename: String, libs: HashSet, externs: core::Externs, use_headers: bool) -> Collector { Collector { tests: Vec::new(), names: Vec::new(), libs: libs, + externs: externs, cnt: 0, use_headers: use_headers, current_header: None, @@ -267,6 +272,7 @@ impl Collector { }; self.cnt += 1; let libs = self.libs.clone(); + let externs = self.externs.clone(); let cratename = self.cratename.to_string(); debug!("Creating test {}: {}", name, test); self.tests.push(testing::TestDescAndFn { @@ -279,6 +285,7 @@ impl Collector { runtest(test.as_slice(), cratename.as_slice(), libs, + externs, should_fail, no_run, as_test_harness); diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index c8f9ed64a77f8..594a235339669 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -26,6 +26,14 @@ use std::gc::{Gc, GC}; use core; use doctree::*; +// looks to me like the first two of these are actually +// output parameters, maybe only mutated once; perhaps +// better simply to have the visit method return a tuple +// containing them? + +// also, is there some reason that this doesn't use the 'visit' +// framework from syntax? + pub struct RustdocVisitor<'a> { pub module: Module, pub attrs: Vec, @@ -64,6 +72,9 @@ impl<'a> RustdocVisitor<'a> { ast::CRATE_NODE_ID, &krate.module, None); + // attach the crate's exported macros to the top-level module: + self.module.macros = krate.exported_macros.iter() + .map(|it| self.visit_macro(&**it)).collect(); self.module.is_crate = true; } @@ -323,15 +334,20 @@ impl<'a> RustdocVisitor<'a> { ast::ItemForeignMod(ref fm) => { om.foreigns.push(fm.clone()); } - ast::ItemMac(ref _m) => { - om.macros.push(Macro { - id: item.id, - attrs: item.attrs.iter().map(|x| *x).collect(), - name: item.ident, - where: item.span, - stab: self.stability(item.id), - }) + ast::ItemMac(_) => { + fail!("rustdoc: macros should be gone, after expansion"); } } } + + // convert each exported_macro into a doc item + fn visit_macro(&self, item: &ast::Item) -> Macro { + Macro { + id: item.id, + attrs: item.attrs.iter().map(|x| *x).collect(), + name: item.ident, + where: item.span, + stab: self.stability(item.id), + } + } } diff --git a/src/libstd/ascii.rs b/src/libstd/ascii.rs index b9c86e2b23586..966e4f8811eaa 100644 --- a/src/libstd/ascii.rs +++ b/src/libstd/ascii.rs @@ -20,7 +20,7 @@ use option::{Option, Some, None}; use slice::{ImmutableVector, MutableVector, Vector}; use str::{OwnedStr, Str, StrAllocating, StrSlice}; use string::String; -use to_str::{IntoStr}; +use to_string::IntoStr; use vec::Vec; /// Datatype to hold one ascii character. It wraps a `u8`, with the highest bit always zero. diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index ad6942712ac9a..e14092bc8dc16 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -239,7 +239,7 @@ pub mod gc; pub mod from_str; pub mod num; -pub mod to_str; +pub mod to_string; /* Common data structures */ diff --git a/src/libstd/prelude.rs b/src/libstd/prelude.rs index eee494c7bc0a1..0fa223305a669 100644 --- a/src/libstd/prelude.rs +++ b/src/libstd/prelude.rs @@ -78,7 +78,7 @@ #[doc(no_inline)] pub use io::{Buffer, Writer, Reader, Seek}; #[doc(no_inline)] pub use str::{Str, StrVector, StrSlice, OwnedStr}; #[doc(no_inline)] pub use str::{IntoMaybeOwned, StrAllocating, UnicodeStrSlice}; -#[doc(no_inline)] pub use to_str::{ToString, IntoStr}; +#[doc(no_inline)] pub use to_string::{ToString, IntoStr}; #[doc(no_inline)] pub use tuple::{Tuple1, Tuple2, Tuple3, Tuple4}; #[doc(no_inline)] pub use tuple::{Tuple5, Tuple6, Tuple7, Tuple8}; #[doc(no_inline)] pub use tuple::{Tuple9, Tuple10, Tuple11, Tuple12}; diff --git a/src/libstd/task.rs b/src/libstd/task.rs index 4b8c15a0152a3..19ad81a04834d 100644 --- a/src/libstd/task.rs +++ b/src/libstd/task.rs @@ -106,7 +106,7 @@ use rt::task::Task; use str::{Str, SendStr, IntoMaybeOwned}; use string::String; use sync::Future; -use to_str::ToString; +use to_string::ToString; /// A means of spawning a task pub trait Spawner { diff --git a/src/libstd/to_str.rs b/src/libstd/to_string.rs similarity index 100% rename from src/libstd/to_str.rs rename to src/libstd/to_string.rs diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 7ad9a18a15e1b..614bbd1c3ed00 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -256,7 +256,7 @@ pub struct Crate { pub attrs: Vec, pub config: CrateConfig, pub span: Span, - pub exported_macros: Vec + pub exported_macros: Vec> } pub type MetaItem = Spanned; diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 49bd3697884c7..5341f0c2d61b2 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -104,9 +104,9 @@ pub type IdentMacroExpanderFn = /// just into the compiler's internal macro table, for `make_def`). pub trait MacResult { /// Define a new macro. - // this should go away; the idea that a macro might expand into - // either a macro definition or an expression, depending on what - // the context wants, is kind of silly. + // this particular flavor should go away; the idea that a macro might + // expand into either a macro definition or an expression, depending + // on what the context wants, is kind of silly. fn make_def(&self) -> Option { None } @@ -431,7 +431,7 @@ pub struct ExtCtxt<'a> { pub mod_path: Vec , pub trace_mac: bool, - pub exported_macros: Vec + pub exported_macros: Vec> } impl<'a> ExtCtxt<'a> { @@ -562,9 +562,6 @@ impl<'a> ExtCtxt<'a> { pub fn name_of(&self, st: &str) -> ast::Name { token::intern(st) } - pub fn push_exported_macro(&mut self, span: codemap::Span) { - self.exported_macros.push(span); - } } /// Extract a string literal from the macro expanded version of `expr`, diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index fdb698441fc0c..c10f3ce07749b 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -536,7 +536,7 @@ fn expand_item_mac(it: Gc, fld: &mut MacroExpander) // create issue to recommend refactoring here? fld.extsbox.insert(intern(name.as_slice()), ext); if attr::contains_name(it.attrs.as_slice(), "macro_export") { - fld.cx.push_exported_macro(it.span); + fld.cx.exported_macros.push(it); } SmallVector::zero() } @@ -1039,7 +1039,7 @@ pub struct ExportedMacros { pub fn expand_crate(parse_sess: &parse::ParseSess, cfg: ExpansionConfig, // these are the macros being imported to this crate: - macros: Vec, + imported_macros: Vec, user_exts: Vec, c: Crate) -> Crate { let mut cx = ExtCtxt::new(parse_sess, c.config.clone(), cfg); @@ -1048,7 +1048,7 @@ pub fn expand_crate(parse_sess: &parse::ParseSess, cx: &mut cx, }; - for ExportedMacros { crate_name, macros } in macros.move_iter() { + for ExportedMacros { crate_name, macros } in imported_macros.move_iter() { let name = format!("<{} macros>", token::get_ident(crate_name)) .into_string(); diff --git a/src/libsyntax/ext/format.rs b/src/libsyntax/ext/format.rs index 4b245f2c9fd48..2e86d1c005d1c 100644 --- a/src/libsyntax/ext/format.rs +++ b/src/libsyntax/ext/format.rs @@ -49,6 +49,9 @@ struct Context<'a, 'b> { name_types: HashMap, name_ordering: Vec, + /// The latest consecutive literal strings + literal: Option, + /// Collection of the compiled `rt::Piece` structures pieces: Vec>, name_positions: HashMap, @@ -362,17 +365,29 @@ impl<'a, 'b> Context<'a, 'b> { } } + /// Translate the accumulated string literals to a static `rt::Piece` + fn trans_literal_string(&mut self) -> Option> { + let sp = self.fmtsp; + self.literal.take().map(|s| { + let s = token::intern_and_get_ident(s.as_slice()); + self.ecx.expr_call_global(sp, + self.rtpath("String"), + vec!( + self.ecx.expr_str(sp, s) + )) + }) + } + /// Translate a `parse::Piece` to a static `rt::Piece` - fn trans_piece(&mut self, piece: &parse::Piece) -> Gc { + fn trans_piece(&mut self, piece: &parse::Piece) -> Option> { let sp = self.fmtsp; match *piece { parse::String(s) => { - let s = token::intern_and_get_ident(s); - self.ecx.expr_call_global(sp, - self.rtpath("String"), - vec!( - self.ecx.expr_str(sp, s) - )) + match self.literal { + Some(ref mut sb) => sb.push_str(s), + ref mut empty => *empty = Some(String::from_str(s)), + } + None } parse::Argument(ref arg) => { // Translate the position @@ -430,7 +445,7 @@ impl<'a, 'b> Context<'a, 'b> { let s = self.ecx.expr_struct(sp, path, vec!( self.ecx.field_imm(sp, self.ecx.ident_of("position"), pos), self.ecx.field_imm(sp, self.ecx.ident_of("format"), fmt))); - self.ecx.expr_call_global(sp, self.rtpath("Argument"), vec!(s)) + Some(self.ecx.expr_call_global(sp, self.rtpath("Argument"), vec!(s))) } } } @@ -694,6 +709,7 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt, sp: Span, name_ordering: name_ordering, nest_level: 0, next_arg: 0, + literal: None, pieces: Vec::new(), method_statics: Vec::new(), fmtsp: sp, @@ -712,8 +728,14 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt, sp: Span, Some(piece) => { if parser.errors.len() > 0 { break } cx.verify_piece(&piece); - let piece = cx.trans_piece(&piece); - cx.pieces.push(piece); + match cx.trans_piece(&piece) { + Some(piece) => { + cx.trans_literal_string().map(|piece| + cx.pieces.push(piece)); + cx.pieces.push(piece); + } + None => {} + } } None => break } @@ -727,6 +749,7 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt, sp: Span, } None => {} } + cx.trans_literal_string().map(|piece| cx.pieces.push(piece)); // Make sure that all arguments were used and all arguments have types. for (i, ty) in cx.arg_types.iter().enumerate() { diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index e31ec04865384..271eee7d08a03 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -752,7 +752,7 @@ pub fn noop_fold_crate(c: Crate, folder: &mut T) -> Crate { attrs: c.attrs.iter().map(|x| folder.fold_attribute(*x)).collect(), config: c.config.iter().map(|x| fold_meta_item_(*x, folder)).collect(), span: folder.new_span(c.span), - exported_macros: c.exported_macros.iter().map(|sp| folder.new_span(*sp)).collect(), + exported_macros: c.exported_macros } } diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs index 15c5fa6b75a5a..46e2ca03ef6ed 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -842,7 +842,6 @@ pub fn run_tests_console(opts: &TestOpts, tests: Vec ) -> io::IoR #[test] fn should_sort_failures_before_printing_them() { use std::io::MemWriter; - use std::str; let test_a = TestDesc { name: StaticTestName("a"), diff --git a/src/libuuid/lib.rs b/src/libuuid/lib.rs index aa13ae82e76d9..0e29e6215032a 100644 --- a/src/libuuid/lib.rs +++ b/src/libuuid/lib.rs @@ -520,7 +520,6 @@ mod test { use super::{Uuid, VariantMicrosoft, VariantNCS, VariantRFC4122, Version1Mac, Version2Dce, Version3Md5, Version4Random, Version5Sha1}; - use std::str; use std::io::MemWriter; use std::rand; diff --git a/src/llvm b/src/llvm index 1bba09755d958..ab85d02e84ede 160000 --- a/src/llvm +++ b/src/llvm @@ -1 +1 @@ -Subproject commit 1bba09755d95892bc826c558630e93803b0a4ee6 +Subproject commit ab85d02e84edeea59ac38505a62ec7d0536cc726 diff --git a/src/rustllvm/llvm-auto-clean-trigger b/src/rustllvm/llvm-auto-clean-trigger index 1bd3434b46eca..348fb01b605ef 100644 --- a/src/rustllvm/llvm-auto-clean-trigger +++ b/src/rustllvm/llvm-auto-clean-trigger @@ -1,4 +1,4 @@ # If this file is modified, then llvm will be forcibly cleaned and then rebuilt. # The actual contents of this file do not matter, but to trigger a change on the # build bots then the contents should be changed so git updates the mtime. -2014-06-20.2 +2014-07-20 diff --git a/src/test/compile-fail/lint-dead-code-3.rs b/src/test/compile-fail/lint-dead-code-3.rs index 4687d66ca5391..e34bfb10a719b 100644 --- a/src/test/compile-fail/lint-dead-code-3.rs +++ b/src/test/compile-fail/lint-dead-code-3.rs @@ -16,6 +16,11 @@ extern crate libc; +pub use x = extern_foo; +extern { + fn extern_foo(); +} + struct Foo; //~ ERROR: code is never used impl Foo { fn foo(&self) { //~ ERROR: code is never used diff --git a/src/test/run-pass/class-cast-to-trait-cross-crate-2.rs b/src/test/run-pass/class-cast-to-trait-cross-crate-2.rs index e3dbaa62d3532..a2ae91abd131a 100644 --- a/src/test/run-pass/class-cast-to-trait-cross-crate-2.rs +++ b/src/test/run-pass/class-cast-to-trait-cross-crate-2.rs @@ -11,7 +11,7 @@ // aux-build:cci_class_cast.rs extern crate cci_class_cast; -use std::to_str::ToString; +use std::to_string::ToString; use cci_class_cast::kitty::cat; fn print_out(thing: Box, expected: String) { diff --git a/src/test/run-pass/send_str_treemap.rs b/src/test/run-pass/send_str_treemap.rs index f3a730aa2b395..e51c94428dae3 100644 --- a/src/test/run-pass/send_str_treemap.rs +++ b/src/test/run-pass/send_str_treemap.rs @@ -12,7 +12,7 @@ extern crate collections; use std::collections::{ Map, MutableMap}; use std::str::{SendStr, Owned, Slice}; -use std::to_str::ToString; +use std::to_string::ToString; use self::collections::TreeMap; use std::option::Some;