From fca79e472689bb7f580a947e9268f4cabc2d298d Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Tue, 15 Jul 2014 16:05:27 -0400 Subject: [PATCH 01/36] Guide: improve error handling --- src/doc/guide.md | 180 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 131 insertions(+), 49 deletions(-) diff --git a/src/doc/guide.md b/src/doc/guide.md index 0175817e66a7e..cac122ee895c6 100644 --- a/src/doc/guide.md +++ b/src/doc/guide.md @@ -1143,25 +1143,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 } +} + +fn main() { + let x = 5i; + let y = 10i; -let ordering = x.cmp(&y); + 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"); + } } ``` -`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 +1178,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 +1267,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 } +} + +fn main() { + let x = 5i; + let y = 10i; -let ordering = x.cmp(&y); + 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 } +} -match x.cmp(&y) { - Less => println!("less"), - Greater => println!("greater"), - Equal => println!("equal"), +fn main() { + let x = 5i; + let y = 10i; + + match cmp(x, y) { + Less => println!("less"), + Greater => println!("greater"), + Equal => println!("equal"), + } } ``` @@ -1297,17 +1319,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; -println!("{}", result); + let result = match cmp(x, y) { + Less => "less", + Greater => "greater", + Equal => "equal", + }; + + println!("{}", result); +} ``` In this case, it doesn't make a lot of sense, as we are just making a temporary @@ -1527,16 +1557,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: From e8c9d21130ff2f25b18978119e1f123a219af056 Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Tue, 15 Jul 2014 16:21:51 -0400 Subject: [PATCH 02/36] Guessing game explanation We now build the game at the end of the first section. I wanted to do it as we went along, but it's too hard with these fundamentals not in place. The rest will do the 'as we go' approach, but I think this is better. --- src/doc/guide.md | 949 +++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 879 insertions(+), 70 deletions(-) diff --git a/src/doc/guide.md b/src/doc/guide.md index cac122ee895c6..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 @@ -1493,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!"); @@ -1504,7 +1446,7 @@ fn main() { Let's go over these chunks, one by one: -```{rust} +```{rust,ignore} std::io::stdin(); ``` @@ -1644,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 From 1607064cfed6d7d4d963de8bb038079592b20995 Mon Sep 17 00:00:00 2001 From: John Clements Date: Thu, 17 Jul 2014 09:45:31 -0700 Subject: [PATCH 03/36] repair macro docs In f1ad425199b0d89dab275a8c8f6f29a73d316f70, I changed the handling of macros, to prevent macro invocations from occurring in fully expanded source. Instead, I added a side table. It contained only the spans of the macros, because this was the only information required in order to make macro export work. However, librustdoc was also affected by this change, since it extracts macro information in a similar way. As a result of the earlier change, exported macros were no longer documented. In order to repair this, I've adjusted the side table to contain whole items, rather than just the spans. --- src/librustc/metadata/encoder.rs | 4 ++-- src/librustdoc/visit_ast.rs | 32 ++++++++++++++++++++++++-------- src/libsyntax/ast.rs | 2 +- src/libsyntax/ext/base.rs | 11 ++++------- src/libsyntax/ext/expand.rs | 6 +++--- src/libsyntax/fold.rs | 2 +- 6 files changed, 35 insertions(+), 22 deletions(-) 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/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/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/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 } } From a491551597c4eff030e3f64158569de4de71292a Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 17 Jul 2014 21:34:41 -0700 Subject: [PATCH 04/36] rustc: Print a smaller hash on -v The long hash just takes up space and you can discover the main hash through the `rustc --version verbose` command. --- mk/docs.mk | 4 ++-- mk/main.mk | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) 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 From fcaee85ced65fae0aad4249e19ec85cbffd4d21c Mon Sep 17 00:00:00 2001 From: Ilya Dmitrichenko Date: Sun, 20 Jul 2014 14:05:28 +0100 Subject: [PATCH 05/36] rlibc: fix bug in `memcmp()` --- src/librlibc/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librlibc/lib.rs b/src/librlibc/lib.rs index cb27596c98c6b..3e45964cd12dc 100644 --- a/src/librlibc/lib.rs +++ b/src/librlibc/lib.rs @@ -95,7 +95,7 @@ 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; } From d32fe7e51bf520f4c0416df0dd9cdf0662ea1cbe Mon Sep 17 00:00:00 2001 From: Ilya Dmitrichenko Date: Sun, 20 Jul 2014 14:05:53 +0100 Subject: [PATCH 06/36] rlibc: add unit tests --- src/librlibc/lib.rs | 108 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 104 insertions(+), 4 deletions(-) diff --git a/src/librlibc/lib.rs b/src/librlibc/lib.rs index 3e45964cd12dc..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 @@ -102,4 +106,100 @@ pub unsafe extern "C" fn memcmp(s1: *const u8, s2: *const u8, n: uint) -> i32 { 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; + } + } + } + } +} From 9631bf2e2526173b21070eb532c6cb590c5869b8 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Sat, 19 Jul 2014 01:29:57 -0700 Subject: [PATCH 07/36] rustc: Make `monitor` public. It's harder to run rustc correctly without it. --- src/librustc/driver/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/driver/mod.rs b/src/librustc/driver/mod.rs index e433c3df8644c..ee490ad43ebad 100644 --- a/src/librustc/driver/mod.rs +++ b/src/librustc/driver/mod.rs @@ -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. From 1c3655bed192e31bdf649ed5f4e728201ede17b2 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Sat, 19 Jul 2014 21:11:26 -0700 Subject: [PATCH 08/36] rustc: Extract --crate-type parsing to its own function Helpful for users of rustc as a library. --- src/librustc/driver/config.rs | 43 +++++++++++++++++++++-------------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/src/librustc/driver/config.rs b/src/librustc/driver/config.rs index ee611293475f9..4752997a3fcea 100644 --- a/src/librustc/driver/config.rs +++ b/src/librustc/driver/config.rs @@ -593,24 +593,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"); @@ -804,6 +790,29 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { } } +pub fn parse_crate_types_from_list(crate_types_list_list: Vec) -> Result, String> { + + let mut crate_types: Vec = Vec::new(); + for unparsed_crate_type in crate_types_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 { From c88bf10c37d32f18774cfa3ef480eb77df294565 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Sat, 19 Jul 2014 21:54:37 -0700 Subject: [PATCH 09/36] rustc: Pass optional additional plugins to compile_input This provides a way for clients of the rustc library to add their own features to the pipeline. --- src/librustc/driver/driver.rs | 14 +++++++++----- src/librustc/driver/mod.rs | 2 +- src/librustc/middle/typeck/infer/test.rs | 2 +- src/librustc/plugin/load.rs | 18 ++++++++++++++++-- src/librustdoc/core.rs | 2 +- src/librustdoc/test.rs | 4 ++-- 6 files changed, 30 insertions(+), 12 deletions(-) diff --git a/src/librustc/driver/driver.rs b/src/librustc/driver/driver.rs index 81ace4d015c85..311d9fb93a121 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, }; @@ -186,7 +188,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 +215,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 +701,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 ee490ad43ebad..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 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..b1c715ae5b36a 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -121,7 +121,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 { diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index 055019aa481ff..8fe28d1eab824 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -69,7 +69,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 { @@ -166,7 +166,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 } From ec0f1cb709cb59e160083cb95f99aa8fc851a9b8 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Sat, 19 Jul 2014 22:40:39 -0700 Subject: [PATCH 10/36] rustc: Allow the crate linked to as 'std' to be customized This adds the alt_std_name field to the Session's Options type. I'm using this in an external tool to control which libraries a crate links to. --- src/librustc/driver/config.rs | 3 +++ src/librustc/front/std_inject.rs | 9 ++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/librustc/driver/config.rs b/src/librustc/driver/config.rs index 4752997a3fcea..890093a10ecc7 100644 --- a/src/librustc/driver/config.rs +++ b/src/librustc/driver/config.rs @@ -97,6 +97,7 @@ pub struct Options { pub color: ColorConfig, pub externs: HashMap>, pub crate_name: Option, + pub alt_std_name: Option } /// Some reasonable defaults @@ -124,6 +125,7 @@ pub fn basic_options() -> Options { color: Auto, externs: HashMap::new(), crate_name: None, + alt_std_name: None, } } @@ -787,6 +789,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { color: color, externs: externs, crate_name: crate_name, + alt_std_name: None } } 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( From 97ca98f5ccda65589049397723662e634ada04a4 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Sun, 20 Jul 2014 16:32:46 -0700 Subject: [PATCH 11/36] Address review feedback --- src/librustc/driver/config.rs | 7 +++++-- src/librustc/driver/driver.rs | 1 + 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/librustc/driver/config.rs b/src/librustc/driver/config.rs index 890093a10ecc7..2d200c82a94a2 100644 --- a/src/librustc/driver/config.rs +++ b/src/librustc/driver/config.rs @@ -97,6 +97,9 @@ 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 } @@ -793,10 +796,10 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { } } -pub fn parse_crate_types_from_list(crate_types_list_list: Vec) -> Result, String> { +pub fn parse_crate_types_from_list(list_list: Vec) -> Result, String> { let mut crate_types: Vec = Vec::new(); - for unparsed_crate_type in crate_types_list_list.iter() { + 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(), diff --git a/src/librustc/driver/driver.rs b/src/librustc/driver/driver.rs index 311d9fb93a121..9796aab51fb6b 100644 --- a/src/librustc/driver/driver.rs +++ b/src/librustc/driver/driver.rs @@ -181,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. From ec70f2bb6e8cd3dd187abba351e6cf9eb14a37c1 Mon Sep 17 00:00:00 2001 From: Tom Jakubowski Date: Sat, 19 Jul 2014 23:02:14 -0700 Subject: [PATCH 12/36] rustdoc: Add an --extern flag analagous to rustc's This adds an `--extern` flag to `rustdoc` much like the compiler's to specify the path where a given crate can be found. --- src/librustc/driver/config.rs | 2 +- src/librustdoc/core.rs | 9 ++++--- src/librustdoc/lib.rs | 51 ++++++++++++++++++++++++++++++----- src/librustdoc/markdown.rs | 6 +++-- src/librustdoc/test.rs | 15 ++++++++--- 5 files changed, 66 insertions(+), 17 deletions(-) diff --git a/src/librustc/driver/config.rs b/src/librustc/driver/config.rs index 2d200c82a94a2..dd951d963e0d7 100644 --- a/src/librustc/driver/config.rs +++ b/src/librustc/driver/config.rs @@ -582,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"), ) } diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index b1c715ae5b36a..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() }; @@ -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 8fe28d1eab824..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 = @@ -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() @@ -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); From c86873bda4d0d32a595dbaf24745c1f7cd9b89da Mon Sep 17 00:00:00 2001 From: Jonas Hietala Date: Sun, 20 Jul 2014 14:12:26 +0200 Subject: [PATCH 13/36] Document Deque. --- src/libcollections/lib.rs | 183 +++++++++++++++++++++++++++++++++++--- 1 file changed, 173 insertions(+), 10 deletions(-) diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs index d3c0c8856bd47..abcd677bba664 100644 --- a/src/libcollections/lib.rs +++ b/src/libcollections/lib.rs @@ -327,33 +327,196 @@ 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 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); +/// } +/// ``` +/// +/// We can simulate a queue: +/// +/// ``` +/// 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); +/// } +/// ``` +/// +/// 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 + /// 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 + /// 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; } From 9aaaa6b31e644f174051e30a48ec6fa350e7591d Mon Sep 17 00:00:00 2001 From: Jonas Hietala Date: Sun, 20 Jul 2014 14:16:47 +0200 Subject: [PATCH 14/36] Move in-place functions below their iterator variants. --- src/libcollections/bitv.rs | 48 +++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/src/libcollections/bitv.rs b/src/libcollections/bitv.rs index 226da13f9e228..094a65b24bb58 100644 --- a/src/libcollections/bitv.rs +++ b/src/libcollections/bitv.rs @@ -723,30 +723,6 @@ 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 #[inline] pub fn iter<'a>(&'a self) -> BitPositions<'a> { @@ -801,6 +777,30 @@ impl BitvSet { next_idx: 0 } } + + /// 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); + } } impl fmt::Show for BitvSet { From 2e40078fc3325f336b1e0d27313d67ad6ae19419 Mon Sep 17 00:00:00 2001 From: Jonas Hietala Date: Sun, 20 Jul 2014 14:18:04 +0200 Subject: [PATCH 15/36] Place union as the first function, for consistency. --- src/libcollections/bitv.rs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/libcollections/bitv.rs b/src/libcollections/bitv.rs index 094a65b24bb58..3521c4df6e715 100644 --- a/src/libcollections/bitv.rs +++ b/src/libcollections/bitv.rs @@ -729,6 +729,18 @@ impl BitvSet { BitPositions {set: self, next_idx: 0} } + /// Iterator over each uint stored in `self` union `other` + #[inline] + pub fn union<'a>(&'a self, other: &'a BitvSet) -> TwoBitPositions<'a> { + TwoBitPositions { + set: self, + other: other, + merge: |w1, w2| w1 | w2, + current_word: 0, + next_idx: 0 + } + } + /// Iterator over each uint stored in the `self` setminus `other` #[inline] pub fn difference<'a>(&'a self, other: &'a BitvSet) -> TwoBitPositions<'a> { @@ -766,18 +778,6 @@ impl BitvSet { }.take(min) } - /// Iterator over each uint stored in `self` union `other` - #[inline] - pub fn union<'a>(&'a self, other: &'a BitvSet) -> TwoBitPositions<'a> { - TwoBitPositions { - set: self, - other: other, - merge: |w1, w2| w1 | w2, - current_word: 0, - next_idx: 0 - } - } - /// Union in-place with the specified other bit vector #[inline] pub fn union_with(&mut self, other: &BitvSet) { From f4d9dca10dfa73c7d1a9d3be7c63e943d29a43c9 Mon Sep 17 00:00:00 2001 From: Jonas Hietala Date: Sun, 20 Jul 2014 14:21:47 +0200 Subject: [PATCH 16/36] Group union, intersect and difference in Bitv. --- src/libcollections/bitv.rs | 44 +++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/src/libcollections/bitv.rs b/src/libcollections/bitv.rs index 3521c4df6e715..3c95d500f1682 100644 --- a/src/libcollections/bitv.rs +++ b/src/libcollections/bitv.rs @@ -170,28 +170,6 @@ 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` #[inline] pub fn get(&self, i: uint) -> bool { @@ -229,6 +207,28 @@ impl Bitv { for w in self.storage.mut_iter() { *w = !*w; } } + /** + * 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) + } + /** * Calculate the difference between two bitvectors * From 681aa582142abb0d74e20fc90ff93152acd2a006 Mon Sep 17 00:00:00 2001 From: Jonas Hietala Date: Sun, 20 Jul 2014 14:28:40 +0200 Subject: [PATCH 17/36] Document Bitv. --- src/libcollections/bitv.rs | 401 ++++++++++++++++++++++++++++--------- 1 file changed, 307 insertions(+), 94 deletions(-) diff --git a/src/libcollections/bitv.rs b/src/libcollections/bitv.rs index 3c95d500f1682..2718cb624494e 100644 --- a/src/libcollections/bitv.rs +++ b/src/libcollections/bitv.rs @@ -155,13 +155,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,7 +189,21 @@ impl Bitv { } } - /// 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 = [false, true].iter().map(|n| *n).collect(); + /// assert_eq!(bv.get(0), false); + /// assert_eq!(bv.get(1), true); + /// ``` #[inline] pub fn get(&self, i: uint) -> bool { assert!(i < self.nbits); @@ -180,11 +213,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.get(3), true); + /// ``` #[inline] pub fn set(&mut self, i: uint, x: bool) { assert!(i < self.nbits); @@ -195,55 +238,128 @@ impl Bitv { else { *self.storage.get(w) & !flag }; } - /// Set all bits to 1 + /// Set all bits to 1. + /// + /// # Example + /// + /// ``` + /// use std::collections::Bitv; + /// + /// let mut bv: Bitv = [false, true, false].iter().map(|n| *n).collect(); + /// bv.set_all(); + /// assert!(bv.eq_vec([true, true, true])); #[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 mut bv: Bitv = [false, true, false].iter().map(|n| *n).collect(); + /// bv.negate(); + /// assert!(bv.eq_vec([true, false, true])); #[inline] pub fn negate(&mut self) { for w in self.storage.mut_iter() { *w = !*w; } } - /** - * 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. - */ + /// 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 mut bv1: Bitv = [false, true, true, false].iter().map(|n| *n).collect(); + /// let bv2: Bitv = [false, true, false, true].iter().map(|n| *n).collect(); + /// let res: Bitv = [false, true, true, true].iter().map(|n| *n).collect(); + /// + /// assert!(bv1.union(&bv2)); + /// assert_eq!(bv1, res); + /// ``` #[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. - */ + /// 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 mut bv1: Bitv = [false, true, true, false].iter().map(|n| *n).collect(); + /// let bv2: Bitv = [false, true, false, true].iter().map(|n| *n).collect(); + /// let res: Bitv = [false, true, false, false].iter().map(|n| *n).collect(); + /// + /// assert!(bv1.intersect(&bv2)); + /// assert_eq!(bv1, res); + /// ``` #[inline] pub fn intersect(&mut self, other: &Bitv) -> bool { self.process(other, |w1, w2| w1 & w2) } - /** - * 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 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 mut bv1: Bitv = [false, true, true, false].iter().map(|n| *n).collect(); + /// let bv2: Bitv = [false, true, false, true].iter().map(|n| *n).collect(); + /// let res: Bitv = [false, false, true, false].iter().map(|n| *n).collect(); + /// + /// assert!(bv1.difference(&bv2)); + /// assert_eq!(bv1, res); + /// ``` #[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::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 +370,83 @@ 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; + /// ``` + /// use std::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()); + /// + /// assert_eq!(bv.iter().filter(|x| *x).count(), 5); /// ``` #[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::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::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/0. + /// + /// # Example + /// + /// ``` + /// use std::collections::bitv::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 +471,35 @@ 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::Bitv; + /// + /// let bv: Bitv = [true, false, true].iter().map(|n| *n).collect(); + /// assert_eq!(bv.to_bools(), vec!(true, false, true)); + /// ``` 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 = [false, true, true].iter().map(|n| *n).collect(); + /// + /// assert!(bv.eq_vec([false, true, true])); + /// ``` pub fn eq_vec(&self, v: &[bool]) -> bool { assert_eq!(self.nbits, v.len()); let mut i = 0; @@ -344,12 +517,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::Bitv; + /// + /// let mut bv: Bitv = [false, true, true, false].iter().map(|n| *n).collect(); + /// bv.truncate(2); + /// assert!(bv.eq_vec([false, true])); /// ``` pub fn truncate(&mut self, len: uint) { if len < self.len() { @@ -363,7 +536,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::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 +556,33 @@ 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::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::Bitv; + /// + /// let mut bv: Bitv = [false, true, true, false].iter().map(|n| *n).collect(); + /// bv.grow(2, true); + /// assert!(bv.eq_vec([false, true, true, false, true, true])); /// ``` pub fn grow(&mut self, n: uint, value: bool) { let new_nbits = self.nbits + n; @@ -420,17 +613,20 @@ 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::Bitv; + /// + /// let mut bv: Bitv = [false, true, true, false].iter().map(|n| *n).collect(); + /// assert_eq!(bv.pop(), false); + /// assert!(bv.eq_vec([false, true, true])); /// ``` pub fn pop(&mut self) -> bool { let ret = self.get(self.nbits - 1); @@ -442,17 +638,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::Bitv; + /// + /// let mut bv: Bitv = [false, true].iter().map(|n| *n).collect(); + /// bv.push(true); + /// bv.push(false); + /// assert!(bv.eq_vec([false, true, true, false])); /// ``` pub fn push(&mut self, elem: bool) { let insert_pos = self.nbits; @@ -464,11 +660,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::from_bytes; +/// +/// let bv = 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 +683,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) { From b05f6050b67d1485702ff5ffed666290d4bd1e4d Mon Sep 17 00:00:00 2001 From: Jonas Hietala Date: Sun, 20 Jul 2014 14:32:18 +0200 Subject: [PATCH 18/36] Document BitvSet. --- src/libcollections/bitv.rs | 316 ++++++++++++++++++++++++++++++++++--- 1 file changed, 297 insertions(+), 19 deletions(-) diff --git a/src/libcollections/bitv.rs b/src/libcollections/bitv.rs index 2718cb624494e..ce1683ea879cb 100644 --- a/src/libcollections/bitv.rs +++ b/src/libcollections/bitv.rs @@ -839,11 +839,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::from_bytes; +/// +/// // 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(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); @@ -853,20 +887,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 = [false, true, true, false].iter().map(|n| *n).collect(); + /// 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) @@ -874,33 +937,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.get(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; @@ -922,8 +1045,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 @@ -936,13 +1076,43 @@ impl BitvSet { bitv.nbits = trunc_len * uint::BITS; } - /// 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::from_bytes; + /// + /// let s = BitvSet::from_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 `self` union `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::from_bytes; + /// + /// let a = BitvSet::from_bitv(from_bytes([0b01101000])); + /// let b = BitvSet::from_bitv(from_bytes([0b10100000])); + /// + /// // Print 0, 1, 2, 4 in arbitrary order + /// for x in a.union(&b) { + /// println!("{}", x); + /// } + /// ``` #[inline] pub fn union<'a>(&'a self, other: &'a BitvSet) -> TwoBitPositions<'a> { TwoBitPositions { @@ -954,7 +1124,30 @@ impl BitvSet { } } - /// Iterator over each uint stored in the `self` setminus `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::from_bytes; + /// + /// let a = BitvSet::from_bitv(from_bytes([0b01101000])); + /// let b = BitvSet::from_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 difference<'a>(&'a self, other: &'a BitvSet) -> TwoBitPositions<'a> { TwoBitPositions { @@ -966,7 +1159,24 @@ impl BitvSet { } } - /// Iterator over each uint stored in the symmetric difference of `self` and `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::from_bytes; + /// + /// let a = BitvSet::from_bitv(from_bytes([0b01101000])); + /// let b = BitvSet::from_bitv(from_bytes([0b10100000])); + /// + /// // Print 0, 1, 4 in arbitrary order + /// for x in a.symmetric_difference(&b) { + /// println!("{}", x); + /// } + /// ``` #[inline] pub fn symmetric_difference<'a>(&'a self, other: &'a BitvSet) -> TwoBitPositions<'a> { TwoBitPositions { @@ -978,7 +1188,23 @@ impl BitvSet { } } - /// Iterator over each uint stored in `self` intersect `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::from_bytes; + /// + /// let a = BitvSet::from_bitv(from_bytes([0b01101000])); + /// let b = BitvSet::from_bitv(from_bytes([0b10100000])); + /// + /// // Print 2 + /// for x in a.intersection(&b) { + /// println!("{}", x); + /// } + /// ``` #[inline] pub fn intersection<'a>(&'a self, other: &'a BitvSet) -> Take> { let min = cmp::min(self.capacity(), other.capacity()); @@ -991,25 +1217,77 @@ impl BitvSet { }.take(min) } - /// Union in-place with the specified other bit vector + /// Union in-place with the specified other bit vector. + /// + /// # Example + /// + /// ``` + /// use std::collections::BitvSet; + /// use std::collections::bitv::from_bytes; + /// + /// let mut a = BitvSet::from_bitv(from_bytes([0b01101000])); + /// let b = BitvSet::from_bitv(from_bytes([0b10100000])); + /// + /// a.union_with(&b); + /// assert_eq!(a.unwrap(), from_bytes([0b11101000])); + /// ``` #[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 + /// Intersect in-place with the specified other bit vector. + /// + /// # Example + /// + /// ``` + /// use std::collections::BitvSet; + /// use std::collections::bitv::from_bytes; + /// + /// let mut a = BitvSet::from_bitv(from_bytes([0b01101000])); + /// let b = BitvSet::from_bitv(from_bytes([0b10100000])); + /// + /// a.intersect_with(&b); + /// assert_eq!(a.unwrap(), from_bytes([0b00100000])); + /// ``` #[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 + /// Difference in-place with the specified other bit vector. + /// + /// # Example + /// + /// ``` + /// use std::collections::BitvSet; + /// use std::collections::bitv::from_bytes; + /// + /// let mut a = BitvSet::from_bitv(from_bytes([0b01101000])); + /// let b = BitvSet::from_bitv(from_bytes([0b10100000])); + /// + /// a.difference_with(&b); + /// assert_eq!(a.unwrap(), from_bytes([0b01001000])); + /// ``` #[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 + /// Symmetric difference in-place with the specified other bit vector. + /// + /// # Example + /// + /// ``` + /// use std::collections::BitvSet; + /// use std::collections::bitv::from_bytes; + /// + /// let mut a = BitvSet::from_bitv(from_bytes([0b01101000])); + /// let b = BitvSet::from_bitv(from_bytes([0b10100000])); + /// + /// a.symmetric_difference_with(&b); + /// assert_eq!(a.unwrap(), from_bytes([0b11001000])); + /// ``` #[inline] pub fn symmetric_difference_with(&mut self, other: &BitvSet) { self.other_op(other, |w1, w2| w1 ^ w2); From 26047f15e5f1db33d66979554c29fba3cf4d2c33 Mon Sep 17 00:00:00 2001 From: Jonas Hietala Date: Sun, 20 Jul 2014 14:33:27 +0200 Subject: [PATCH 19/36] Move intersection above difference and symmetric_differance. So all comes in the order union, intersection, difference and symmetric_difference. --- src/libcollections/bitv.rs | 58 +++++++++++++++++++------------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/src/libcollections/bitv.rs b/src/libcollections/bitv.rs index ce1683ea879cb..08720341dbf7e 100644 --- a/src/libcollections/bitv.rs +++ b/src/libcollections/bitv.rs @@ -1124,8 +1124,8 @@ impl BitvSet { } } - /// Iterator over each uint stored in the `self` setminus `other`. - /// See [difference_with](#method.difference_with) for an efficient in-place version. + /// Iterator over each uint stored in `self` intersect `other`. + /// See [intersect_with](#method.intersect_with) for an efficient in-place version. /// /// # Example /// @@ -1136,32 +1136,25 @@ impl BitvSet { /// let a = BitvSet::from_bitv(from_bytes([0b01101000])); /// let b = BitvSet::from_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) { + /// // Print 2 + /// for x in a.intersection(&b) { /// println!("{}", x); /// } /// ``` #[inline] - pub fn 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 the symmetric difference of `self` and `other`. - /// See [symmetric_difference_with](#method.symmetric_difference_with) for - /// an efficient in-place version. + /// Iterator over each uint stored in the `self` setminus `other`. + /// See [difference_with](#method.difference_with) for an efficient in-place version. /// /// # Example /// @@ -1172,24 +1165,32 @@ impl BitvSet { /// let a = BitvSet::from_bitv(from_bytes([0b01101000])); /// let b = BitvSet::from_bitv(from_bytes([0b10100000])); /// - /// // Print 0, 1, 4 in arbitrary order - /// for x in a.symmetric_difference(&b) { + /// // 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 symmetric_difference<'a>(&'a self, other: &'a BitvSet) -> TwoBitPositions<'a> { + 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 } } - /// Iterator over each uint stored in `self` intersect `other`. - /// See [intersect_with](#method.intersect_with) for an efficient in-place version. + /// 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 /// @@ -1200,21 +1201,20 @@ impl BitvSet { /// let a = BitvSet::from_bitv(from_bytes([0b01101000])); /// let b = BitvSet::from_bitv(from_bytes([0b10100000])); /// - /// // Print 2 - /// for x in a.intersection(&b) { + /// // Print 0, 1, 4 in arbitrary order + /// for x in a.symmetric_difference(&b) { /// println!("{}", x); /// } /// ``` #[inline] - pub fn intersection<'a>(&'a self, other: &'a BitvSet) -> Take> { - let min = cmp::min(self.capacity(), other.capacity()); + 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 - }.take(min) + } } /// Union in-place with the specified other bit vector. From 4574b2fbaa866fbe73224f57981151aab1f1f15b Mon Sep 17 00:00:00 2001 From: Jonas Hietala Date: Sun, 20 Jul 2014 14:45:33 +0200 Subject: [PATCH 20/36] Main bitv example: prime sieve. --- src/libcollections/bitv.rs | 49 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/src/libcollections/bitv.rs b/src/libcollections/bitv.rs index 08720341dbf7e..75e7642b3e9d8 100644 --- a/src/libcollections/bitv.rs +++ b/src/libcollections/bitv.rs @@ -8,6 +8,55 @@ // 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 = { +//! 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.get(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::*; From 71afdc4323773b1351e7ddccecdfeec2b65e932f Mon Sep 17 00:00:00 2001 From: Jonas Hietala Date: Sun, 20 Jul 2014 14:47:13 +0200 Subject: [PATCH 21/36] Enclose None as `None`. --- src/libcollections/lib.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs index abcd677bba664..773650d4d3aa5 100644 --- a/src/libcollections/lib.rs +++ b/src/libcollections/lib.rs @@ -423,7 +423,7 @@ pub trait Deque : Mutable { /// ``` fn front_mut<'a>(&'a mut self) -> Option<&'a mut T>; - /// Provide a reference to the back element, or None if the sequence is + /// Provide a reference to the back element, or `None` if the sequence is /// empty. /// /// # Example @@ -440,7 +440,7 @@ pub trait Deque : Mutable { /// ``` fn back<'a>(&'a self) -> Option<&'a T>; - /// Provide a mutable reference to the back element, or None if the sequence + /// Provide a mutable reference to the back element, or `None` if the sequence /// is empty. /// /// # Example @@ -487,7 +487,7 @@ pub trait Deque : Mutable { /// 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 /// @@ -503,7 +503,7 @@ pub trait Deque : Mutable { /// 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 /// From e68333a689dc0f665018514f966b3f1098a8adf0 Mon Sep 17 00:00:00 2001 From: Jonas Hietala Date: Sun, 20 Jul 2014 14:59:13 +0200 Subject: [PATCH 22/36] Polish bitv docs. --- src/libcollections/bitv.rs | 83 ++++++++++++++++++++------------------ src/libcollections/lib.rs | 38 +++++++++-------- 2 files changed, 65 insertions(+), 56 deletions(-) diff --git a/src/libcollections/bitv.rs b/src/libcollections/bitv.rs index 75e7642b3e9d8..e8439d83e5e01 100644 --- a/src/libcollections/bitv.rs +++ b/src/libcollections/bitv.rs @@ -25,6 +25,8 @@ //! //! // 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 @@ -33,8 +35,8 @@ //! //! for i in range(2, max_prime) { //! // if i is a prime -//! if bv.get(i) { -//! // mark all multiples of i as non-prime (any multiples below i * i +//! 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) } //! } @@ -252,6 +254,9 @@ impl Bitv { /// let bv: Bitv = [false, true].iter().map(|n| *n).collect(); /// 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 { @@ -275,7 +280,7 @@ impl Bitv { /// /// let mut bv = Bitv::with_capacity(5, false); /// bv.set(3, true); - /// assert_eq!(bv.get(3), true); + /// assert_eq!(bv[3], true); /// ``` #[inline] pub fn set(&mut self, i: uint, x: bool) { @@ -478,7 +483,7 @@ impl Bitv { /// 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. + /// will be filled-in with `false`. /// /// # Example /// @@ -716,9 +721,9 @@ impl Bitv { /// # Example /// /// ``` -/// use std::collections::bitv::from_bytes; +/// use std::collections::bitv; /// -/// let bv = from_bytes([0b10100000, 0b00010010]); +/// let bv = bitv::from_bytes([0b10100000, 0b00010010]); /// assert!(bv.eq_vec([true, false, true, false, /// false, false, false, false, /// false, false, false, true, @@ -898,7 +903,7 @@ impl<'a> RandomAccessIterator for Bits<'a> { /// /// ``` /// use std::collections::{BitvSet, Bitv}; -/// use std::collections::bitv::from_bytes; +/// use std::collections::bitv; /// /// // It's a regular set /// let mut s = BitvSet::new(); @@ -913,7 +918,7 @@ impl<'a> RandomAccessIterator for Bits<'a> { /// } /// /// // Can initialize from a `Bitv` -/// let other = BitvSet::from_bitv(from_bytes([0b11010000])); +/// let other = BitvSet::from_bitv(bitv::from_bytes([0b11010000])); /// /// s.union_with(&other); /// @@ -1048,7 +1053,7 @@ impl BitvSet { /// s.insert(0); /// /// let bv = s.get_ref(); - /// assert_eq!(bv.get(0), true); + /// assert_eq!(bv[0], true); /// ``` #[inline] pub fn get_ref<'a>(&'a self) -> &'a Bitv { @@ -1131,9 +1136,9 @@ impl BitvSet { /// /// ``` /// use std::collections::BitvSet; - /// use std::collections::bitv::from_bytes; + /// use std::collections::bitv; /// - /// let s = BitvSet::from_bitv(from_bytes([0b01001010])); + /// let s = BitvSet::from_bitv(bitv::from_bytes([0b01001010])); /// /// // Print 1, 4, 6 in arbitrary order /// for x in s.iter() { @@ -1152,10 +1157,10 @@ impl BitvSet { /// /// ``` /// use std::collections::BitvSet; - /// use std::collections::bitv::from_bytes; + /// use std::collections::bitv; /// - /// let a = BitvSet::from_bitv(from_bytes([0b01101000])); - /// let b = BitvSet::from_bitv(from_bytes([0b10100000])); + /// 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) { @@ -1180,10 +1185,10 @@ impl BitvSet { /// /// ``` /// use std::collections::BitvSet; - /// use std::collections::bitv::from_bytes; + /// use std::collections::bitv; /// - /// let a = BitvSet::from_bitv(from_bytes([0b01101000])); - /// let b = BitvSet::from_bitv(from_bytes([0b10100000])); + /// 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) { @@ -1209,10 +1214,10 @@ impl BitvSet { /// /// ``` /// use std::collections::BitvSet; - /// use std::collections::bitv::from_bytes; + /// use std::collections::bitv; /// - /// let a = BitvSet::from_bitv(from_bytes([0b01101000])); - /// let b = BitvSet::from_bitv(from_bytes([0b10100000])); + /// 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) { @@ -1245,10 +1250,10 @@ impl BitvSet { /// /// ``` /// use std::collections::BitvSet; - /// use std::collections::bitv::from_bytes; + /// use std::collections::bitv; /// - /// let a = BitvSet::from_bitv(from_bytes([0b01101000])); - /// let b = BitvSet::from_bitv(from_bytes([0b10100000])); + /// 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) { @@ -1272,13 +1277,13 @@ impl BitvSet { /// /// ``` /// use std::collections::BitvSet; - /// use std::collections::bitv::from_bytes; + /// use std::collections::bitv; /// - /// let mut a = BitvSet::from_bitv(from_bytes([0b01101000])); - /// let b = BitvSet::from_bitv(from_bytes([0b10100000])); + /// let mut a = BitvSet::from_bitv(bitv::from_bytes([0b01101000])); + /// let b = BitvSet::from_bitv(bitv::from_bytes([0b10100000])); /// /// a.union_with(&b); - /// assert_eq!(a.unwrap(), from_bytes([0b11101000])); + /// assert_eq!(a.unwrap(), bitv::from_bytes([0b11101000])); /// ``` #[inline] pub fn union_with(&mut self, other: &BitvSet) { @@ -1291,13 +1296,13 @@ impl BitvSet { /// /// ``` /// use std::collections::BitvSet; - /// use std::collections::bitv::from_bytes; + /// use std::collections::bitv; /// - /// let mut a = BitvSet::from_bitv(from_bytes([0b01101000])); - /// let b = BitvSet::from_bitv(from_bytes([0b10100000])); + /// let mut a = BitvSet::from_bitv(bitv::from_bytes([0b01101000])); + /// let b = BitvSet::from_bitv(bitv::from_bytes([0b10100000])); /// /// a.intersect_with(&b); - /// assert_eq!(a.unwrap(), from_bytes([0b00100000])); + /// assert_eq!(a.unwrap(), bitv::from_bytes([0b00100000])); /// ``` #[inline] pub fn intersect_with(&mut self, other: &BitvSet) { @@ -1310,13 +1315,13 @@ impl BitvSet { /// /// ``` /// use std::collections::BitvSet; - /// use std::collections::bitv::from_bytes; + /// use std::collections::bitv; /// - /// let mut a = BitvSet::from_bitv(from_bytes([0b01101000])); - /// let b = BitvSet::from_bitv(from_bytes([0b10100000])); + /// let mut a = BitvSet::from_bitv(bitv::from_bytes([0b01101000])); + /// let b = BitvSet::from_bitv(bitv::from_bytes([0b10100000])); /// /// a.difference_with(&b); - /// assert_eq!(a.unwrap(), from_bytes([0b01001000])); + /// assert_eq!(a.unwrap(), bitv::from_bytes([0b01001000])); /// ``` #[inline] pub fn difference_with(&mut self, other: &BitvSet) { @@ -1329,13 +1334,13 @@ impl BitvSet { /// /// ``` /// use std::collections::BitvSet; - /// use std::collections::bitv::from_bytes; + /// use std::collections::bitv; /// - /// let mut a = BitvSet::from_bitv(from_bytes([0b01101000])); - /// let b = BitvSet::from_bitv(from_bytes([0b10100000])); + /// let mut a = BitvSet::from_bitv(bitv::from_bytes([0b01101000])); + /// let b = BitvSet::from_bitv(bitv::from_bytes([0b10100000])); /// /// a.symmetric_difference_with(&b); - /// assert_eq!(a.unwrap(), from_bytes([0b11001000])); + /// assert_eq!(a.unwrap(), bitv::from_bytes([0b11001000])); /// ``` #[inline] pub fn symmetric_difference_with(&mut self, other: &BitvSet) { diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs index 773650d4d3aa5..fba89df1bbc6b 100644 --- a/src/libcollections/lib.rs +++ b/src/libcollections/lib.rs @@ -330,36 +330,36 @@ pub trait MutableSet: Set + Mutable { /// /// # Example /// -/// With a `Deque` we can simulate a stack: +/// With a `Deque` we can simulate a queue efficiently: /// /// ``` /// use std::collections::{RingBuf, Deque}; /// -/// let mut stack = RingBuf::new(); -/// stack.push_front(1i); -/// stack.push_front(2i); -/// stack.push_front(3i); +/// let mut queue = RingBuf::new(); +/// queue.push_back(1i); +/// queue.push_back(2i); +/// queue.push_back(3i); /// -/// // Will print 3, 2, 1 -/// while !stack.is_empty() { -/// let x = stack.pop_front().unwrap(); +/// // Will print 1, 2, 3 +/// while !queue.is_empty() { +/// let x = queue.pop_front().unwrap(); /// println!("{}", x); /// } /// ``` /// -/// We can simulate a queue: +/// We can also simulate a stack: /// /// ``` /// use std::collections::{RingBuf, Deque}; /// -/// let mut queue = RingBuf::new(); -/// queue.push_back(1i); -/// queue.push_back(2i); -/// queue.push_back(3i); +/// let mut stack = RingBuf::new(); +/// stack.push_front(1i); +/// stack.push_front(2i); +/// stack.push_front(3i); /// -/// // Will print 1, 2, 3 -/// while !queue.is_empty() { -/// let x = queue.pop_front().unwrap(); +/// // Will print 3, 2, 1 +/// while !stack.is_empty() { +/// let x = stack.pop_front().unwrap(); /// println!("{}", x); /// } /// ``` @@ -385,7 +385,7 @@ pub trait MutableSet: Set + Mutable { /// } /// ``` pub trait Deque : Mutable { - /// Provide a reference to the front element, or `None` if the sequence is. + /// Provide a reference to the front element, or `None` if the sequence is /// empty. /// /// # Example @@ -472,6 +472,7 @@ pub trait Deque : Mutable { /// 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. @@ -485,6 +486,7 @@ pub trait Deque : Mutable { /// 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. @@ -501,6 +503,7 @@ pub trait Deque : Mutable { /// 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. @@ -517,6 +520,7 @@ pub trait Deque : Mutable { /// 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; } From 2957644e087844f92fe84647b286f1f999f040c1 Mon Sep 17 00:00:00 2001 From: Jonas Hietala Date: Sun, 20 Jul 2014 15:15:48 +0200 Subject: [PATCH 23/36] Describe BitPositions and TwoBitPositions. --- src/libcollections/bitv.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libcollections/bitv.rs b/src/libcollections/bitv.rs index e8439d83e5e01..1449b6ce550da 100644 --- a/src/libcollections/bitv.rs +++ b/src/libcollections/bitv.rs @@ -1450,11 +1450,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, From 2357c443e02b185fe6be3a8ab54f3d04d1c80dd0 Mon Sep 17 00:00:00 2001 From: Jonas Hietala Date: Sun, 20 Jul 2014 17:09:53 +0200 Subject: [PATCH 24/36] Simplify and cleanup bitv examples. --- src/libcollections/bitv.rs | 194 +++++++++++++++++++++++-------------- 1 file changed, 120 insertions(+), 74 deletions(-) diff --git a/src/libcollections/bitv.rs b/src/libcollections/bitv.rs index 1449b6ce550da..f1e9eabe8d1ed 100644 --- a/src/libcollections/bitv.rs +++ b/src/libcollections/bitv.rs @@ -98,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); /// @@ -249,9 +249,9 @@ impl Bitv { /// # Example /// /// ``` - /// use std::collections::Bitv; + /// use std::collections::bitv; /// - /// let bv: Bitv = [false, true].iter().map(|n| *n).collect(); + /// let bv = bitv::from_bytes([0b01100000]); /// assert_eq!(bv.get(0), false); /// assert_eq!(bv.get(1), true); /// @@ -297,11 +297,15 @@ impl Bitv { /// # Example /// /// ``` - /// use std::collections::Bitv; + /// use std::collections::bitv; /// - /// let mut bv: Bitv = [false, true, false].iter().map(|n| *n).collect(); + /// let before = 0b01100000; + /// let after = 0b11111111; + /// + /// let mut bv = bitv::from_bytes([before]); /// bv.set_all(); - /// assert!(bv.eq_vec([true, true, true])); + /// assert_eq!(bv, bitv::from_bytes([after])); + /// ``` #[inline] pub fn set_all(&mut self) { for w in self.storage.mut_iter() { *w = !0u; } @@ -312,11 +316,15 @@ impl Bitv { /// # Example /// /// ``` - /// use std::collections::Bitv; + /// use std::collections::bitv; + /// + /// let before = 0b01100000; + /// let after = 0b10011111; /// - /// let mut bv: Bitv = [false, true, false].iter().map(|n| *n).collect(); + /// let mut bv = bitv::from_bytes([before]); /// bv.negate(); - /// assert!(bv.eq_vec([true, false, true])); + /// assert_eq!(bv, bitv::from_bytes([after])); + /// ``` #[inline] pub fn negate(&mut self) { for w in self.storage.mut_iter() { *w = !*w; } @@ -334,14 +342,17 @@ impl Bitv { /// # Example /// /// ``` - /// use std::collections::Bitv; + /// use std::collections::bitv; + /// + /// let a = 0b01100100; + /// let b = 0b01011010; + /// let res = 0b01111110; /// - /// let mut bv1: Bitv = [false, true, true, false].iter().map(|n| *n).collect(); - /// let bv2: Bitv = [false, true, false, true].iter().map(|n| *n).collect(); - /// let res: Bitv = [false, true, true, true].iter().map(|n| *n).collect(); + /// let mut a = bitv::from_bytes([a]); + /// let b = bitv::from_bytes([b]); /// - /// assert!(bv1.union(&bv2)); - /// assert_eq!(bv1, res); + /// assert!(a.union(&b)); + /// assert_eq!(a, bitv::from_bytes([res])); /// ``` #[inline] pub fn union(&mut self, other: &Bitv) -> bool { @@ -360,14 +371,17 @@ impl Bitv { /// # Example /// /// ``` - /// use std::collections::Bitv; + /// use std::collections::bitv; /// - /// let mut bv1: Bitv = [false, true, true, false].iter().map(|n| *n).collect(); - /// let bv2: Bitv = [false, true, false, true].iter().map(|n| *n).collect(); - /// let res: Bitv = [false, true, false, false].iter().map(|n| *n).collect(); + /// let a = 0b01100100; + /// let b = 0b01011010; + /// let res = 0b01000000; /// - /// assert!(bv1.intersect(&bv2)); - /// assert_eq!(bv1, res); + /// 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 { @@ -387,14 +401,24 @@ impl Bitv { /// # Example /// /// ``` - /// use std::collections::Bitv; + /// 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]); /// - /// let mut bv1: Bitv = [false, true, true, false].iter().map(|n| *n).collect(); - /// let bv2: Bitv = [false, true, false, true].iter().map(|n| *n).collect(); - /// let res: Bitv = [false, false, true, false].iter().map(|n| *n).collect(); + /// assert!(bva.difference(&bvb)); + /// assert_eq!(bva, bitv::from_bytes([a_b])); /// - /// assert!(bv1.difference(&bv2)); - /// assert_eq!(bv1, res); + /// 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 { @@ -406,7 +430,7 @@ impl Bitv { /// # Example /// /// ``` - /// use std::collections::bitv::Bitv; + /// use std::collections::Bitv; /// /// let mut bv = Bitv::with_capacity(5, true); /// assert_eq!(bv.all(), true); @@ -429,16 +453,10 @@ impl Bitv { /// # Example /// /// ``` - /// use std::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); + /// use std::collections::bitv; /// - /// assert_eq!(bv.iter().filter(|x| *x).count(), 5); + /// 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> { @@ -450,7 +468,7 @@ impl Bitv { /// # Example /// /// ``` - /// use std::collections::bitv::Bitv; + /// use std::collections::Bitv; /// /// let mut bv = Bitv::with_capacity(10, false); /// assert_eq!(bv.none(), true); @@ -467,7 +485,7 @@ impl Bitv { /// # Example /// /// ``` - /// use std::collections::bitv::Bitv; + /// use std::collections::Bitv; /// /// let mut bv = Bitv::with_capacity(10, false); /// assert_eq!(bv.any(), false); @@ -488,7 +506,7 @@ impl Bitv { /// # Example /// /// ``` - /// use std::collections::bitv::Bitv; + /// use std::collections::Bitv; /// /// let mut bv = Bitv::with_capacity(3, true); /// bv.set(1, false); @@ -530,10 +548,11 @@ impl Bitv { /// # Example /// /// ``` - /// use std::collections::bitv::Bitv; + /// use std::collections::bitv; /// - /// let bv: Bitv = [true, false, true].iter().map(|n| *n).collect(); - /// assert_eq!(bv.to_bools(), vec!(true, false, true)); + /// 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)) @@ -548,11 +567,12 @@ impl Bitv { /// # Example /// /// ``` - /// use std::collections::Bitv; + /// use std::collections::bitv; /// - /// let bv: Bitv = [false, true, true].iter().map(|n| *n).collect(); + /// let bv = bitv::from_bytes([0b10100000]); /// - /// assert!(bv.eq_vec([false, true, true])); + /// 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()); @@ -572,9 +592,9 @@ impl Bitv { /// # Example /// /// ``` - /// use std::collections::bitv::Bitv; + /// use std::collections::bitv; /// - /// let mut bv: Bitv = [false, true, true, false].iter().map(|n| *n).collect(); + /// let mut bv = bitv::from_bytes([0b01001011]); /// bv.truncate(2); /// assert!(bv.eq_vec([false, true])); /// ``` @@ -595,7 +615,7 @@ impl Bitv { /// # Example /// /// ``` - /// use std::collections::bitv::Bitv; + /// use std::collections::Bitv; /// /// let mut bv = Bitv::with_capacity(3, false); /// bv.reserve(10); @@ -616,7 +636,7 @@ impl Bitv { /// # Example /// /// ``` - /// use std::collections::bitv::Bitv; + /// use std::collections::Bitv; /// /// let mut bv = Bitv::new(); /// bv.reserve(10); @@ -632,11 +652,12 @@ impl Bitv { /// # Example /// /// ``` - /// use std::collections::bitv::Bitv; + /// use std::collections::bitv; /// - /// let mut bv: Bitv = [false, true, true, false].iter().map(|n| *n).collect(); + /// let mut bv = bitv::from_bytes([0b01001011]); /// bv.grow(2, true); - /// assert!(bv.eq_vec([false, true, true, false, true, 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; @@ -676,11 +697,13 @@ impl Bitv { /// # Example /// /// ``` - /// use std::collections::bitv::Bitv; + /// use std::collections::bitv; /// - /// let mut bv: Bitv = [false, true, true, false].iter().map(|n| *n).collect(); + /// let mut bv = bitv::from_bytes([0b01001001]); + /// assert_eq!(bv.pop(), true); /// assert_eq!(bv.pop(), false); - /// assert!(bv.eq_vec([false, true, true])); + /// 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); @@ -697,12 +720,12 @@ impl Bitv { /// # Example /// /// ``` - /// use std::collections::bitv::Bitv; + /// use std::collections::Bitv; /// - /// let mut bv: Bitv = [false, true].iter().map(|n| *n).collect(); + /// let mut bv = Bitv::new(); /// bv.push(true); /// bv.push(false); - /// assert!(bv.eq_vec([false, true, true, false])); + /// assert!(bv.eq_vec([true, false])); /// ``` pub fn push(&mut self, elem: bool) { let insert_pos = self.nbits; @@ -974,9 +997,9 @@ impl BitvSet { /// # Example /// /// ``` - /// use std::collections::{Bitv, BitvSet}; + /// use std::collections::{bitv, BitvSet}; /// - /// let bv: Bitv = [false, true, true, false].iter().map(|n| *n).collect(); + /// let bv = bitv::from_bytes([0b01100000]); /// let s = BitvSet::from_bitv(bv); /// /// // Print 1, 2 in arbitrary order @@ -1279,11 +1302,15 @@ impl BitvSet { /// use std::collections::BitvSet; /// use std::collections::bitv; /// - /// let mut a = BitvSet::from_bitv(bitv::from_bytes([0b01101000])); - /// let b = BitvSet::from_bitv(bitv::from_bytes([0b10100000])); + /// 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([0b11101000])); + /// assert_eq!(a.unwrap(), bitv::from_bytes([res])); /// ``` #[inline] pub fn union_with(&mut self, other: &BitvSet) { @@ -1298,11 +1325,15 @@ impl BitvSet { /// use std::collections::BitvSet; /// use std::collections::bitv; /// - /// let mut a = BitvSet::from_bitv(bitv::from_bytes([0b01101000])); - /// let b = BitvSet::from_bitv(bitv::from_bytes([0b10100000])); + /// 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([0b00100000])); + /// assert_eq!(a.unwrap(), bitv::from_bytes([res])); /// ``` #[inline] pub fn intersect_with(&mut self, other: &BitvSet) { @@ -1317,11 +1348,22 @@ impl BitvSet { /// use std::collections::BitvSet; /// use std::collections::bitv; /// - /// let mut a = BitvSet::from_bitv(bitv::from_bytes([0b01101000])); - /// let b = BitvSet::from_bitv(bitv::from_bytes([0b10100000])); + /// 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])); /// - /// a.difference_with(&b); - /// assert_eq!(a.unwrap(), bitv::from_bytes([0b01001000])); + /// 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) { @@ -1336,11 +1378,15 @@ impl BitvSet { /// use std::collections::BitvSet; /// use std::collections::bitv; /// - /// let mut a = BitvSet::from_bitv(bitv::from_bytes([0b01101000])); - /// let b = BitvSet::from_bitv(bitv::from_bytes([0b10100000])); + /// 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([0b11001000])); + /// assert_eq!(a.unwrap(), bitv::from_bytes([res])); /// ``` #[inline] pub fn symmetric_difference_with(&mut self, other: &BitvSet) { From 0e1880d8fe123354910a42f8046240dee6c6a668 Mon Sep 17 00:00:00 2001 From: root Date: Sun, 20 Jul 2014 16:31:43 +0200 Subject: [PATCH 25/36] syntax: Join consecutive string literals in format strings together Emit a single rt::Piece per consecutive string literals. String literals are split on {{ or }} escapes. Saves a small amount of static storage and emitted code size. --- src/libsyntax/ext/format.rs | 43 ++++++++++++++++++++++++++++--------- 1 file changed, 33 insertions(+), 10 deletions(-) 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() { From e3887a7766eca68c6fa4382b28c863fb31ba00aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Steinbrink?= Date: Sun, 20 Jul 2014 22:19:17 +0200 Subject: [PATCH 26/36] Update LLVM to include NullCheckElimination pass Fixes #11751 --- src/llvm | 2 +- src/rustllvm/llvm-auto-clean-trigger | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) 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 From 2e24ef377e32ee2fe253046fdc073840279e4b95 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 20 Jul 2014 17:12:40 -0700 Subject: [PATCH 27/36] Rename to_str to to_string Closes #15796. [breaking-change] --- src/libstd/ascii.rs | 2 +- src/libstd/lib.rs | 2 +- src/libstd/prelude.rs | 2 +- src/libstd/task.rs | 2 +- src/libstd/{to_str.rs => to_string.rs} | 0 src/test/run-pass/class-cast-to-trait-cross-crate-2.rs | 2 +- src/test/run-pass/send_str_treemap.rs | 2 +- 7 files changed, 6 insertions(+), 6 deletions(-) rename src/libstd/{to_str.rs => to_string.rs} (100%) 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/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; From 456884b7a0eb90038d915d8bc251a725451d284b Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 20 Jul 2014 18:05:59 -0700 Subject: [PATCH 28/36] Remove useless RefCells --- src/librustc/front/test.rs | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/src/librustc/front/test.rs b/src/librustc/front/test.rs index 0860d111a9ef0..889af7a884666 100644 --- a/src/librustc/front/test.rs +++ b/src/librustc/front/test.rs @@ -16,7 +16,6 @@ use driver::session::Session; use front::config; -use std::cell::RefCell; use std::gc::{Gc, GC}; use std::slice; use std::vec; @@ -46,9 +45,9 @@ struct Test { struct TestCtxt<'a> { sess: &'a Session, - path: RefCell>, + path: Vec, ext_cx: ExtCtxt<'a>, - testfns: RefCell >, + testfns: Vec, is_test_crate: bool, config: ast::CrateConfig, } @@ -86,9 +85,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,12 +101,12 @@ 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); // debug!("have {} test/bench functions", // cx.testfns.len()); } @@ -115,7 +114,7 @@ impl<'a> fold::Folder for TestHarnessGenerator<'a> { } let res = fold::noop_fold_item(&*i, self); - self.cx.path.borrow_mut().pop(); + self.cx.path.pop(); res } @@ -155,8 +154,8 @@ 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(), + testfns: Vec::new(), is_test_crate: is_test_crate(&krate), config: krate.config.clone(), }; @@ -399,13 +398,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, From d27918ac7c56cd3ddb89a188c389df9ed7f9689b Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 20 Jul 2014 22:10:11 -0700 Subject: [PATCH 29/36] Restructure test harness We now build up a set of modules that reexport everything the test framework needs, instead of turning off privacy. --- src/librustc/front/test.rs | 85 ++++++++++++++++++++++++-------------- 1 file changed, 53 insertions(+), 32 deletions(-) diff --git a/src/librustc/front/test.rs b/src/librustc/front/test.rs index 889af7a884666..3e6b8a92d2d63 100644 --- a/src/librustc/front/test.rs +++ b/src/librustc/front/test.rs @@ -18,6 +18,7 @@ use front::config; use std::gc::{Gc, GC}; use std::slice; +use std::mem; use std::vec; use syntax::ast_util::*; use syntax::attr::AttrMetaMethods; @@ -25,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,8 +48,10 @@ struct Test { struct TestCtxt<'a> { sess: &'a Session, path: Vec, + reexports: Vec>, ext_cx: ExtCtxt<'a>, testfns: Vec, + reexport_mod_ident: ast::Ident, is_test_crate: bool, config: ast::CrateConfig, } @@ -107,25 +111,35 @@ impl<'a> fold::Folder for TestHarnessGenerator<'a> { should_fail: should_fail(i) }; 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); + // 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 @@ -135,18 +149,37 @@ 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); + } + 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,7 +188,9 @@ fn generate_test_harness(sess: &Session, krate: ast::Crate) crate_name: "test".to_string(), }), 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(), }; @@ -170,7 +205,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(); @@ -274,7 +309,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) @@ -331,15 +365,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, @@ -367,18 +395,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); @@ -430,7 +446,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, From 6531d02b79b8ecb39055f5464451ef144827870b Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 20 Jul 2014 22:11:43 -0700 Subject: [PATCH 30/36] Purge !resolve_unexported --- src/librustc/middle/privacy.rs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/librustc/middle/privacy.rs b/src/librustc/middle/privacy.rs index bad6a288294f4..910f4ad212ae5 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; @@ -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; From 2daa097077dc988bb7fc818754950b21cd42727c Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 20 Jul 2014 22:34:09 -0700 Subject: [PATCH 31/36] Don't create reexport module if there are none --- src/librustc/front/test.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/librustc/front/test.rs b/src/librustc/front/test.rs index 3e6b8a92d2d63..08907f6c0ed5d 100644 --- a/src/librustc/front/test.rs +++ b/src/librustc/front/test.rs @@ -152,8 +152,10 @@ impl<'a> fold::Folder for TestHarnessGenerator<'a> { for i in mod_folded.items.mut_iter() { *i = nomain(*i); } - mod_folded.items.push(mk_reexport_mod(&mut self.cx, reexports)); - self.cx.reexports.push(self.cx.path.clone()); + 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 } From 6807349e8fe37eb19dd6d9c41fb24430fdf0e54b Mon Sep 17 00:00:00 2001 From: Kiet Tran Date: Sun, 20 Jul 2014 22:11:43 -0700 Subject: [PATCH 32/36] privacy: Add publically-reexported foreign item to exported item set Close #15740 --- src/librustc/middle/privacy.rs | 2 +- src/test/compile-fail/lint-dead-code-3.rs | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/librustc/middle/privacy.rs b/src/librustc/middle/privacy.rs index 910f4ad212ae5..62b5299f8fbc8 100644 --- a/src/librustc/middle/privacy.rs +++ b/src/librustc/middle/privacy.rs @@ -325,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); } } 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 From dfacef532d61b1ab3cefb4164faa77b290f9abc5 Mon Sep 17 00:00:00 2001 From: Ted Horst Date: Mon, 21 Jul 2014 00:43:08 -0500 Subject: [PATCH 33/36] fix string in from_utf8_lossy_100_multibyte benchmark --- src/libcollections/string.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) 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); From 36e1f2db301d33fd0efaa093c5a190a3879ccc93 Mon Sep 17 00:00:00 2001 From: Piotr Jawniak Date: Sun, 20 Jul 2014 17:20:37 +0200 Subject: [PATCH 34/36] Get rid of few warnings in tests --- src/libgraphviz/lib.rs | 14 +++++++------- src/libtest/lib.rs | 1 - src/libuuid/lib.rs | 1 - 3 files changed, 7 insertions(+), 9 deletions(-) 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/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; From 37bb6ed30294d3847386b284f39f90fd245f9be9 Mon Sep 17 00:00:00 2001 From: P1start Date: Mon, 21 Jul 2014 20:33:20 +1200 Subject: [PATCH 35/36] Clarify the std::vec::Vec docs regarding capacity --- src/libcollections/vec.rs | 40 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 37 insertions(+), 3 deletions(-) diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index 96228531ae54f..d028be50ee179 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(0u, 10) { + /// vec.push(i); + /// } + /// + /// // ...but this may make the vector reallocate + /// vec.push(11); /// ``` #[inline] pub fn with_capacity(capacity: uint) -> Vec { From 414862db3cb7ff75f8d2373466e547a0464d683d Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 21 Jul 2014 10:18:17 -0700 Subject: [PATCH 36/36] Test fixes from the rollup Closes #15690 (Guide: improve error handling) Closes #15729 (Guide: guessing game) Closes #15751 (repair macro docs) Closes #15766 (rustc: Print a smaller hash on -v) Closes #15815 (Add unit test for rlibc) Closes #15820 (Minor refactoring and features in rustc driver for embedders) Closes #15822 (rustdoc: Add an --extern flag analagous to rustc's) Closes #15824 (Document Deque trait and bitv.) Closes #15832 (syntax: Join consecutive string literals in format strings together) Closes #15837 (Update LLVM to include NullCheckElimination pass) Closes #15841 (Rename to_str to to_string) Closes #15847 (Purge #[!resolve_unexported] from the compiler) Closes #15848 (privacy: Add publically-reexported foreign item to exported item set) Closes #15849 (fix string in from_utf8_lossy_100_multibyte benchmark) Closes #15850 (Get rid of few warnings in tests) Closes #15852 (Clarify the std::vec::Vec::with_capacity docs) --- src/libcollections/vec.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index d028be50ee179..751775888b759 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -120,7 +120,7 @@ impl Vec { /// assert_eq!(vec.len(), 0); /// /// // These are all done without reallocating... - /// for i in range(0u, 10) { + /// for i in range(0i, 10) { /// vec.push(i); /// } ///