diff --git a/.gitmodules b/.gitmodules index 987791ac9db..6cd704b3703 100644 --- a/.gitmodules +++ b/.gitmodules @@ -11,3 +11,6 @@ [submodule "src/jemalloc"] path = src/jemalloc url = https://github.com/rust-lang/jemalloc.git +[submodule "src/rust-installer"] + path = src/rust-installer + url = https://github.com/rust-lang/rust-installer diff --git a/mk/ctags.mk b/mk/ctags.mk index 39b1c4d4d59..c7a3406a9e7 100644 --- a/mk/ctags.mk +++ b/mk/ctags.mk @@ -27,7 +27,7 @@ CTAGS_LOCATIONS=$(patsubst ${CFG_SRC_DIR}src/llvm,, \ $(patsubst ${CFG_SRC_DIR}src/rt/msvc,, \ $(patsubst ${CFG_SRC_DIR}src/rt/vg,, \ $(wildcard ${CFG_SRC_DIR}src/*) $(wildcard ${CFG_SRC_DIR}src/rt/*) \ - ))))))))) + )))))))) CTAGS_OPTS=--options="${CFG_SRC_DIR}src/etc/ctags.rust" --languages=-javascript --recurse ${CTAGS_LOCATIONS} # We could use `--languages=Rust`, but there is value in producing tags for the # C++ parts of the code base too (at the time of writing, those are .h and .cpp diff --git a/mk/dist.mk b/mk/dist.mk index 00f6e861739..2db26f819df 100644 --- a/mk/dist.mk +++ b/mk/dist.mk @@ -58,6 +58,7 @@ PKG_FILES := \ rt \ rustllvm \ snapshots.txt \ + rust-installer \ test) \ $(PKG_GITMODULES) \ $(filter-out config.stamp, \ @@ -209,33 +210,40 @@ distcheck-osx: dist-osx # Unix binary installer tarballs ###################################################################### +NON_INSTALLED_PREFIXES=COPYRIGHT,LICENSE-APACHE,LICENSE-MIT,README.md,doc + define DEF_INSTALLER $$(eval $$(call DEF_PREPARE,dir-$(1))) dist-install-dir-$(1): PREPARE_HOST=$(1) dist-install-dir-$(1): PREPARE_TARGETS=$(2) -dist-install-dir-$(1): PREPARE_DEST_DIR=tmp/dist/$$(PKG_NAME)-$(1) +dist-install-dir-$(1): PREPARE_DEST_DIR=tmp/dist/$$(PKG_NAME)-$(1)-image dist-install-dir-$(1): PREPARE_DIR_CMD=$(DEFAULT_PREPARE_DIR_CMD) dist-install-dir-$(1): PREPARE_BIN_CMD=$(DEFAULT_PREPARE_BIN_CMD) dist-install-dir-$(1): PREPARE_LIB_CMD=$(DEFAULT_PREPARE_LIB_CMD) dist-install-dir-$(1): PREPARE_MAN_CMD=$(DEFAULT_PREPARE_MAN_CMD) dist-install-dir-$(1): PREPARE_CLEAN=true dist-install-dir-$(1): prepare-base-dir-$(1) docs compiler-docs - $$(Q)(cd $$(PREPARE_DEST_DIR)/ && find . -type f | sed 's/^\.\///') \ - > tmp/dist/manifest-$(1).in - $$(Q)mv tmp/dist/manifest-$(1).in $$(PREPARE_DEST_DIR)/$$(CFG_LIBDIR_RELATIVE)/rustlib/manifest.in -# Add remaining non-installed files $$(Q)$$(PREPARE_MAN_CMD) $$(S)COPYRIGHT $$(PREPARE_DEST_DIR) $$(Q)$$(PREPARE_MAN_CMD) $$(S)LICENSE-APACHE $$(PREPARE_DEST_DIR) $$(Q)$$(PREPARE_MAN_CMD) $$(S)LICENSE-MIT $$(PREPARE_DEST_DIR) $$(Q)$$(PREPARE_MAN_CMD) $$(S)README.md $$(PREPARE_DEST_DIR) $$(Q)cp -r doc $$(PREPARE_DEST_DIR) - $$(Q)$$(PREPARE_BIN_CMD) $$(S)src/etc/install.sh $$(PREPARE_DEST_DIR) dist/$$(PKG_NAME)-$(1).tar.gz: dist-install-dir-$(1) @$(call E, build: $$@) - $$(Q)tar -czf dist/$$(PKG_NAME)-$(1).tar.gz -C tmp/dist $$(PKG_NAME)-$(1) + $$(Q)$$(S)src/rust-installer/gen-installer.sh \ + --product-name=Rust \ + --verify-bin=rustc \ + --rel-manifest-dir=rustlib \ + --success-message=Rust-is-ready-to-roll. \ + --image-dir=tmp/dist/$$(PKG_NAME)-$(1)-image \ + --work-dir=tmp/dist \ + --output-dir=dist \ + --non-installed-prefixes=$$(NON_INSTALLED_PREFIXES) \ + --package-name=$$(PKG_NAME)-$(1) + $$(Q)rm -R tmp/dist/$$(PKG_NAME)-$(1)-image endef diff --git a/mk/install.mk b/mk/install.mk index 88b451f661a..632df3c754b 100644 --- a/mk/install.mk +++ b/mk/install.mk @@ -25,7 +25,7 @@ endif # Remove tmp files because it's a decent amount of disk space $(Q)rm -R tmp/dist -prepare_install: dist-install-dir-$(CFG_BUILD) | tmp/empty_dir +prepare_install: dist/$(PKG_NAME)-$(CFG_BUILD).tar.gz | tmp/empty_dir uninstall: ifeq (root user, $(USER) $(patsubst %,user,$(SUDO_USER))) @@ -38,7 +38,7 @@ endif # Remove tmp files because it's a decent amount of disk space $(Q)rm -R tmp/dist -prepare_uninstall: dist-install-dir-$(CFG_BUILD) | tmp/empty_dir +prepare_uninstall: dist/$(PKG_NAME)-$(CFG_BUILD).tar.gz | tmp/empty_dir .PHONY: install prepare_install uninstall prepare_uninstall diff --git a/src/compiletest/compiletest.rs b/src/compiletest/compiletest.rs index 196c38215f4..59be0152d58 100644 --- a/src/compiletest/compiletest.rs +++ b/src/compiletest/compiletest.rs @@ -394,7 +394,7 @@ fn extract_gdb_version(full_version_line: Option) -> Option { match re.captures(full_version_line) { Some(captures) => { - Some(captures.at(2).to_string()) + Some(captures.at(2).unwrap_or("").to_string()) } None => { println!("Could not extract GDB version from line '{}'", @@ -428,7 +428,7 @@ fn extract_lldb_version(full_version_line: Option) -> Option { match re.captures(full_version_line) { Some(captures) => { - Some(captures.at(1).to_string()) + Some(captures.at(1).unwrap_or("").to_string()) } None => { println!("Could not extract LLDB version from line '{}'", diff --git a/src/compiletest/errors.rs b/src/compiletest/errors.rs index f15db7d9371..b7df43aabdd 100644 --- a/src/compiletest/errors.rs +++ b/src/compiletest/errors.rs @@ -66,10 +66,10 @@ fn parse_expected(last_nonfollow_error: Option, line: &str, re: &Regex) -> Option<(WhichLine, ExpectedError)> { re.captures(line).and_then(|caps| { - let adjusts = caps.name("adjusts").len(); - let kind = caps.name("kind").to_ascii_lower(); - let msg = caps.name("msg").trim().to_string(); - let follow = caps.name("follow").len() > 0; + let adjusts = caps.name("adjusts").unwrap_or("").len(); + let kind = caps.name("kind").unwrap_or("").to_ascii_lower(); + let msg = caps.name("msg").unwrap_or("").trim().to_string(); + let follow = caps.name("follow").unwrap_or("").len() > 0; let (which, line) = if follow { assert!(adjusts == 0, "use either //~| or //~^, not both."); diff --git a/src/doc/complement-lang-faq.md b/src/doc/complement-lang-faq.md index 62faecede55..9e73863239f 100644 --- a/src/doc/complement-lang-faq.md +++ b/src/doc/complement-lang-faq.md @@ -24,7 +24,7 @@ Some examples that demonstrate different aspects of the language: [HashMap]: https://github.com/rust-lang/rust/blob/master/src/libcollections/hashmap.rs [json]: https://github.com/rust-lang/rust/blob/master/src/libserialize/json.rs -You may also be interested in browsing [GitHub's Rust][github-rust] page. +You may also be interested in browsing [trending Rust repositories][github-rust] on GitHub. [github-rust]: https://github.com/trending?l=rust @@ -42,7 +42,7 @@ Let the fact that this is an easily countable number be a warning. ## Does it run on Windows? -Yes. All development happens in lock-step on all 3 target platforms. Using MinGW, not Cygwin. Note that the windows implementation currently has some limitations: in particular 64-bit build is [not fully supported yet][win64], and all executables created by rustc [depend on libgcc DLL at runtime][libgcc]. +Yes. All development happens in lockstep on all 3 target platforms (using MinGW, not Cygwin). Note that the Windows implementation currently has some limitations; in particular, the 64-bit build is [not fully supported yet][win64], and all executables created by rustc [depend on libgcc DLL at runtime][libgcc]. [win64]: https://github.com/rust-lang/rust/issues/1237 [libgcc]: https://github.com/rust-lang/rust/issues/11782 @@ -104,7 +104,7 @@ Similar to the reasoning about default-sync: it wires fewer assumptions into the ## Why are strings UTF-8 by default? Why not UCS2 or UCS4? -The `str` type is UTF-8 because we observe more text in the wild in this encoding -- particularly in network transmissions, which are endian-agnostic -- and we think it's best that the default treatment of I/O not involve having to recode codepoints in each direction. +The `str` type is UTF-8 because we observe more text in the wild in this encoding – particularly in network transmissions, which are endian-agnostic – and we think it's best that the default treatment of I/O not involve having to recode codepoints in each direction. This does mean that indexed access to a Unicode codepoint inside a `str` value is an O(n) operation. On the one hand, this is clearly undesirable; on the other hand, this problem is full of trade-offs and we'd like to point a few important qualifications: @@ -145,7 +145,7 @@ For simplicity, we do not plan to do so. Implementing automatic semicolon insert ## How do I get my program to display the output of logging macros? -**Short answer** set the RUST_LOG environment variable to the name of your source file, sans extension. +**Short Answer**: Set the `RUST_LOG` environment variable to the name of your source file, sans extension. ```sh rustc hello.rs @@ -153,15 +153,19 @@ export RUST_LOG=hello ./hello ``` -**Long answer** RUST_LOG takes a 'logging spec' that consists of a +**Long Answer**: `RUST_LOG` takes a 'logging spec' that consists of a comma-separated list of paths, where a path consists of the crate name and -sequence of module names, each separated by double-colons. For standalone .rs -files the crate is implicitly named after the source file, so in the above -example we were setting RUST_LOG to the name of the hello crate. Multiple paths +sequence of module names, each separated by double-colons. For standalone `.rs` +files, the crate is implicitly named after the source file, so in the above +example we were setting `RUST_LOG` to the name of the hello crate. Multiple paths can be combined to control the exact logging you want to see. For example, when -debugging linking in the compiler you might set -`RUST_LOG=rustc::metadata::creader,rustc::util::filesearch,rustc::back::rpath` -For a full description see [the logging crate][1]. +debugging linking in the compiler, you might set the following: + +```sh +RUST_LOG=rustc::metadata::creader,rustc::util::filesearch,rustc::back::rpath +``` + +For a full description, see [the logging crate][1]. ## How fast is Rust? @@ -172,6 +176,6 @@ performance. That said, it is an explicit goal of Rust to be as fast as C++ for most things. Language decisions are made with performance in mind, and we want Rust to be as fast as possible. Given that Rust is built on top of LLVM, any performance -improvements in it also help us be faster. +improvements in it also help Rust become faster. [1]:log/index.html diff --git a/src/doc/guide-macros.md b/src/doc/guide-macros.md index 65b6014b496..a7f4d103aca 100644 --- a/src/doc/guide-macros.md +++ b/src/doc/guide-macros.md @@ -195,7 +195,7 @@ early_return!(input_2, [T::SpecialB]); As the above example demonstrates, `$(...)*` is also valid on the right-hand side of a macro definition. The behavior of `*` in transcription, especially in cases where multiple `*`s are nested, and multiple different -names are involved, can seem somewhat magical and intuitive at first. The +names are involved, can seem somewhat magical and unintuitive at first. The system that interprets them is called "Macro By Example". The two rules to keep in mind are (1) the behavior of `$(...)*` is to walk through one "layer" of repetitions for all of the `$name`s it contains in lockstep, and (2) each diff --git a/src/doc/guide-ownership.md b/src/doc/guide-ownership.md index ddabb1de765..1a469704143 100644 --- a/src/doc/guide-ownership.md +++ b/src/doc/guide-ownership.md @@ -341,7 +341,7 @@ fn main() { { // | let y = &5i; // ---+ y goes into scope let f = Foo { x: y }; // ---+ f goes into scope - x = &f.x; // | | error here + x = &f.x; // | | error here } // ---+ f & y go out of scope // | println!("{}", x); // | @@ -416,7 +416,7 @@ note: `car` moved here because it has type `Car`, which is non-copyable ``` We need our `Car` to be pointed to by multiple `Wheel`s. We can't do that with -`Box`, because it has a single owner. We can do t with `Rc` instead: +`Box`, because it has a single owner. We can do it with `Rc` instead: ```rust use std::rc::Rc; diff --git a/src/doc/guide-testing.md b/src/doc/guide-testing.md index 0452ed0bfeb..682c89fcc53 100644 --- a/src/doc/guide-testing.md +++ b/src/doc/guide-testing.md @@ -357,7 +357,7 @@ Let's finally check out that third section: documentation tests. Nothing is better than documentation with examples. Nothing is worse than examples that don't actually work, because the code has changed since the -documentation has been written. To this end, Rust supports automaticaly +documentation has been written. To this end, Rust supports automatically running examples in your documentation. Here's a fleshed-out `src/lib.rs` with examples: diff --git a/src/doc/guide.md b/src/doc/guide.md index da111cbe6b4..08d2c5bf978 100644 --- a/src/doc/guide.md +++ b/src/doc/guide.md @@ -418,6 +418,19 @@ let x: int = 5; If I asked you to read this out loud to the rest of the class, you'd say "`x` is a binding with the type `int` and the value `five`." +In future examples, we may annotate the type in a comment. The examples will +look like this: + +```{rust} +fn main() { + let x = 5i; // x: int +} +``` + +Note the similarities between this annotation and the syntax you use with `let`. +Including these kinds of comments is not idiomatic Rust, but we'll occasionally +include them to help you understand what the types that Rust infers are. + By default, bindings are **immutable**. This code will not compile: ```{ignore} @@ -436,7 +449,7 @@ error: re-assignment of immutable variable `x` If you want a binding to be mutable, you can use `mut`: ```{rust} -let mut x = 5i; +let mut x = 5i; // mut x: int x = 10i; ``` @@ -538,7 +551,7 @@ format in a more detailed manner, there are a [wide number of options available](std/fmt/index.html). For now, we'll just stick to the default: integers aren't very complicated to print. -# If +# `if` Rust's take on `if` is not particularly complex, but it's much more like the `if` you'll find in a dynamically typed language than in a more traditional @@ -584,7 +597,7 @@ let y = if x == 5i { 10i } else { 15i -}; +}; // y: int ``` Which we can (and probably should) write like this: @@ -592,7 +605,7 @@ Which we can (and probably should) write like this: ```{rust} let x = 5i; -let y = if x == 5i { 10i } else { 15i }; +let y = if x == 5i { 10i } else { 15i }; // y: int ``` This reveals two interesting things about Rust: it is an expression-based @@ -928,8 +941,8 @@ destructuring. You can assign one tuple into another, if they have the same arity and contained types. ```rust -let mut x = (1i, 2i); -let y = (2i, 3i); +let mut x = (1i, 2i); // x: (int, int) +let y = (2i, 3i); // y: (int, int) x = y; ``` @@ -981,7 +994,7 @@ struct Point { } fn main() { - let origin = Point { x: 0i, y: 0i }; + let origin = Point { x: 0i, y: 0i }; // origin: Point println!("The origin is at ({}, {})", origin.x, origin.y); } @@ -1101,7 +1114,7 @@ fn main() { let x = 5i; let y = 10i; - let ordering = cmp(x, y); + let ordering = cmp(x, y); // ordering: Ordering if ordering == Less { println!("less"); @@ -1388,7 +1401,7 @@ Instead, it looks like this: ```{rust} for x in range(0i, 10i) { - println!("{}", x); + println!("{}", x); // x: int } ``` @@ -1423,8 +1436,8 @@ The other kind of looping construct in Rust is the `while` loop. It looks like this: ```{rust} -let mut x = 5u; -let mut done = false; +let mut x = 5u; // mut x: uint +let mut done = false; // mut done: bool while !done { x += x - 3; @@ -1520,7 +1533,7 @@ The first kind is a `&str`. This is pronounced a 'string slice.' String literals are of the type `&str`: ```{rust} -let string = "Hello there."; +let string = "Hello there."; // string: &str ``` This string is statically allocated, meaning that it's saved inside our @@ -1532,7 +1545,7 @@ A `String`, on the other hand, is an in-memory string. This string is growable, and is also guaranteed to be UTF-8. ```{rust} -let mut s = "Hello".to_string(); +let mut s = "Hello".to_string(); // mut s: String println!("{}", s); s.push_str(", world."); @@ -1588,16 +1601,19 @@ things. The most basic is the **array**, a fixed-size list of elements of the same type. By default, arrays are immutable. ```{rust} -let a = [1i, 2i, 3i]; -let mut m = [1i, 2i, 3i]; +let a = [1i, 2i, 3i]; // a: [int, ..3] +let mut m = [1i, 2i, 3i]; // mut m: [int, ..3] ``` You can create an array with a given number of elements, all initialized to the same value, with `[val, ..N]` syntax. The compiler ensures that arrays are always initialized. +There's a shorthand for initializing each element of an array to the same +value. In this example, each element of `a` will be initialized to `0i`: + ```{rust} -let a = [0i, ..20]; // Shorthand for array of 20 elements all initialized to 0 +let a = [0i, ..20]; // a: [int, ..20] ``` Arrays have type `[T,..N]`. We'll talk about this `T` notation later, when we @@ -1608,7 +1624,7 @@ You can get the number of elements in an array `a` with `a.len()`, and use number in order: ```{rust} -let a = [1i, 2, 3]; // Only the first item needs a type suffix +let a = [1i, 2, 3]; // Only the first item needs a type suffix println!("a has {} elements", a.len()); for e in a.iter() { @@ -1619,7 +1635,7 @@ for e in a.iter() { You can access a particular element of an array with **subscript notation**: ```{rust} -let names = ["Graydon", "Brian", "Niko"]; +let names = ["Graydon", "Brian", "Niko"]; // names: [&str, 3] println!("The second name is: {}", names[1]); ``` @@ -1637,7 +1653,7 @@ later). Vectors are to arrays what `String` is to `&str`. You can create them with the `vec!` macro: ```{rust} -let v = vec![1i, 2, 3]; +let v = vec![1i, 2, 3]; // v: Vec ``` (Notice that unlike the `println!` macro we've used in the past, we use square @@ -1648,8 +1664,10 @@ You can get the length of, iterate over, and subscript vectors just like arrays. In addition, (mutable) vectors can grow automatically: ```{rust} -let mut nums = vec![1i, 2, 3]; +let mut nums = vec![1i, 2, 3]; // mut nums: Vec + nums.push(4); + println!("The length of nums is now {}", nums.len()); // Prints 4 ``` @@ -1823,10 +1841,12 @@ use std::io; fn main() { println!("Type something!"); - let input = io::stdin() - .read_line() - .ok() - .expect("Failed to read line"); + // here, we'll show the types at each step + + let input = io::stdin() // std::io::stdio::StdinReader + .read_line() // IoResult + .ok() // Option + .expect("Failed to read line"); // String println!("{}", input); } @@ -1969,7 +1989,7 @@ use std::rand; fn main() { println!("Guess the number!"); - let secret_number = (rand::random() % 100i) + 1i; + let secret_number = (rand::random() % 100i) + 1i; // secret_number: int println!("The secret number is: {}", secret_number); @@ -2262,8 +2282,8 @@ 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 input_num = from_str::("5"); -let input_num: Option = from_str("5"); +let input_num = from_str::("5"); // input_num: Option +let input_num: Option = from_str("5"); // input_num: Option ``` Anyway, with us now converting our input to a number, our code looks like this: @@ -4419,7 +4439,7 @@ for i in range(0u, nums.len()) { ``` This is strictly worse than using an actual iterator. The `.iter()` method on -vectors returns an iterator which iterates through a reference to each element +vectors returns an iterator that iterates through a reference to each element of the vector in turn. So write this: ```{rust} diff --git a/src/etc/install.sh b/src/etc/install.sh deleted file mode 100644 index 8bc48fc7934..00000000000 --- a/src/etc/install.sh +++ /dev/null @@ -1,519 +0,0 @@ -#!/bin/sh -# Copyright 2014 The Rust Project Developers. See the COPYRIGHT -# file at the top-level directory of this distribution and at -# http://rust-lang.org/COPYRIGHT. -# -# Licensed under the Apache License, Version 2.0 or the MIT license -# , at your -# option. This file may not be copied, modified, or distributed -# except according to those terms. - -msg() { - echo "install: $1" -} - -step_msg() { - msg - msg "$1" - msg -} - -warn() { - echo "install: WARNING: $1" -} - -err() { - echo "install: error: $1" - exit 1 -} - -need_ok() { - if [ $? -ne 0 ] - then - err "$1" - fi -} - -need_cmd() { - if command -v $1 >/dev/null 2>&1 - then msg "found $1" - else err "need $1" - fi -} - -putvar() { - local T - eval T=\$$1 - eval TLEN=\${#$1} - if [ $TLEN -gt 35 ] - then - printf "install: %-20s := %.35s ...\n" $1 "$T" - else - printf "install: %-20s := %s %s\n" $1 "$T" "$2" - fi -} - -valopt() { - VAL_OPTIONS="$VAL_OPTIONS $1" - - local OP=$1 - local DEFAULT=$2 - shift - shift - local DOC="$*" - if [ $HELP -eq 0 ] - then - local UOP=$(echo $OP | tr '[:lower:]' '[:upper:]' | tr '\-' '\_') - local V="CFG_${UOP}" - eval $V="$DEFAULT" - for arg in $CFG_ARGS - do - if echo "$arg" | grep -q -- "--$OP=" - then - val=$(echo "$arg" | cut -f2 -d=) - eval $V=$val - fi - done - putvar $V - else - if [ -z "$DEFAULT" ] - then - DEFAULT="" - fi - OP="${OP}=[${DEFAULT}]" - printf " --%-30s %s\n" "$OP" "$DOC" - fi -} - -opt() { - BOOL_OPTIONS="$BOOL_OPTIONS $1" - - local OP=$1 - local DEFAULT=$2 - shift - shift - local DOC="$*" - local FLAG="" - - if [ $DEFAULT -eq 0 ] - then - FLAG="enable" - else - FLAG="disable" - DOC="don't $DOC" - fi - - if [ $HELP -eq 0 ] - then - for arg in $CFG_ARGS - do - if [ "$arg" = "--${FLAG}-${OP}" ] - then - OP=$(echo $OP | tr 'a-z-' 'A-Z_') - FLAG=$(echo $FLAG | tr 'a-z' 'A-Z') - local V="CFG_${FLAG}_${OP}" - eval $V=1 - putvar $V - fi - done - else - if [ ! -z "$META" ] - then - OP="$OP=<$META>" - fi - printf " --%-30s %s\n" "$FLAG-$OP" "$DOC" - fi -} - -flag() { - BOOL_OPTIONS="$BOOL_OPTIONS $1" - - local OP=$1 - shift - local DOC="$*" - - if [ $HELP -eq 0 ] - then - for arg in $CFG_ARGS - do - if [ "$arg" = "--${OP}" ] - then - OP=$(echo $OP | tr 'a-z-' 'A-Z_') - local V="CFG_${OP}" - eval $V=1 - putvar $V - fi - done - else - if [ ! -z "$META" ] - then - OP="$OP=<$META>" - fi - printf " --%-30s %s\n" "$OP" "$DOC" - fi -} - -validate_opt () { - for arg in $CFG_ARGS - do - isArgValid=0 - for option in $BOOL_OPTIONS - do - if test --disable-$option = $arg - then - isArgValid=1 - fi - if test --enable-$option = $arg - then - isArgValid=1 - fi - if test --$option = $arg - then - isArgValid=1 - fi - done - for option in $VAL_OPTIONS - do - if echo "$arg" | grep -q -- "--$option=" - then - isArgValid=1 - fi - done - if [ "$arg" = "--help" ] - then - echo - echo "No more help available for Configure options," - echo "check the Wiki or join our IRC channel" - break - else - if test $isArgValid -eq 0 - then - err "Option '$arg' is not recognized" - fi - fi - done -} - -absolutify() { - FILE_PATH="${1}" - FILE_PATH_DIRNAME="$(dirname ${FILE_PATH})" - FILE_PATH_BASENAME="$(basename ${FILE_PATH})" - FILE_ABS_PATH="$(cd ${FILE_PATH_DIRNAME} && pwd)" - FILE_PATH="${FILE_ABS_PATH}/${FILE_PATH_BASENAME}" - # This is the return value - ABSOLUTIFIED="${FILE_PATH}" -} - -msg "looking for install programs" -need_cmd mkdir -need_cmd printf -need_cmd cut -need_cmd grep -need_cmd uname -need_cmd tr -need_cmd sed - -CFG_SRC_DIR="$(cd $(dirname $0) && pwd)" -CFG_SELF="$0" -CFG_ARGS="$@" - -HELP=0 -if [ "$1" = "--help" ] -then - HELP=1 - shift - echo - echo "Usage: $CFG_SELF [options]" - echo - echo "Options:" - echo -else - step_msg "processing $CFG_SELF args" -fi - -# Check for mingw or cygwin in order to special case $CFG_LIBDIR_RELATIVE. -# This logic is duplicated from configure in order to get the correct libdir -# for Windows installs. -CFG_OSTYPE=$(uname -s) - -case $CFG_OSTYPE in - - MINGW32*) - CFG_OSTYPE=pc-mingw32 - ;; - - MINGW64*) - # msys2, MSYSTEM=MINGW64 - CFG_OSTYPE=w64-mingw32 - ;; - -# Thad's Cygwin identifers below - -# Vista 32 bit - CYGWIN_NT-6.0) - CFG_OSTYPE=pc-mingw32 - ;; - -# Vista 64 bit - CYGWIN_NT-6.0-WOW64) - CFG_OSTYPE=w64-mingw32 - ;; - -# Win 7 32 bit - CYGWIN_NT-6.1) - CFG_OSTYPE=pc-mingw32 - ;; - -# Win 7 64 bit - CYGWIN_NT-6.1-WOW64) - CFG_OSTYPE=w64-mingw32 - ;; -esac - -OPTIONS="" -BOOL_OPTIONS="" -VAL_OPTIONS="" - -# On windows we just store the libraries in the bin directory because -# there's no rpath. This is where the build system itself puts libraries; -# --libdir is used to configure the installation directory. -# FIXME: Thise needs to parameterized over target triples. Do it in platform.mk -CFG_LIBDIR_RELATIVE=lib -if [ "$CFG_OSTYPE" = "pc-mingw32" ] || [ "$CFG_OSTYPE" = "w64-mingw32" ] -then - CFG_LIBDIR_RELATIVE=bin -fi - -if [ "$CFG_OSTYPE" = "pc-mingw32" ] || [ "$CFG_OSTYPE" = "w64-mingw32" ] -then - CFG_LD_PATH_VAR=PATH - CFG_OLD_LD_PATH_VAR=$PATH -elif [ "$CFG_OSTYPE" = "Darwin" ] -then - CFG_LD_PATH_VAR=DYLD_LIBRARY_PATH - CFG_OLD_LD_PATH_VAR=$DYLD_LIBRARY_PATH -else - CFG_LD_PATH_VAR=LD_LIBRARY_PATH - CFG_OLD_LD_PATH_VAR=$LD_LIBRARY_PATH -fi - -flag uninstall "only uninstall from the installation prefix" -opt verify 1 "verify that the installed binaries run correctly" -valopt prefix "/usr/local" "set installation prefix" -# NB This is exactly the same definition as in `configure`. -valopt libdir "${CFG_PREFIX}/${CFG_LIBDIR_RELATIVE}" "install libraries" -case "$CFG_LIBDIR" in - "$CFG_PREFIX"/*) CAT_INC=2;; - "$CFG_PREFIX"*) CAT_INC=1;; - *) - err "libdir must begin with the prefix. Use --prefix to set it accordingly.";; -esac -CFG_LIBDIR_RELATIVE=`echo ${CFG_LIBDIR} | cut -c$((${#CFG_PREFIX}+${CAT_INC}))-` - -valopt mandir "${CFG_PREFIX}/share/man" "install man pages in PATH" - -if [ $HELP -eq 1 ] -then - echo - exit 0 -fi - -step_msg "validating $CFG_SELF args" -validate_opt - - -# OK, let's get installing ... - -# Sanity check: can we run the binaries? -if [ -z "${CFG_DISABLE_VERIFY}" ] -then - # Don't do this if uninstalling. Failure here won't help in any way. - if [ -z "${CFG_UNINSTALL}" ] - then - msg "verifying platform can run binaries" - export $CFG_LD_PATH_VAR="${CFG_SRC_DIR}/lib:$CFG_OLD_LD_PATH_VAR" - "${CFG_SRC_DIR}/bin/rustc" --version > /dev/null - if [ $? -ne 0 ] - then - err "can't execute rustc binary on this platform" - fi - export $CFG_LD_PATH_VAR=$CFG_OLD_LD_PATH_VAR - fi -fi - -# Sanity check: can we can write to the destination? -msg "verifying destination is writable" -umask 022 && mkdir -p "${CFG_LIBDIR}" -need_ok "can't write to destination. consider \`sudo\`." -touch "${CFG_LIBDIR}/rust-install-probe" > /dev/null -if [ $? -ne 0 ] -then - err "can't write to destination. consider \`sudo\`." -fi -rm -f "${CFG_LIBDIR}/rust-install-probe" -need_ok "failed to remove install probe" - -# Sanity check: don't install to the directory containing the installer. -# That would surely cause chaos. -msg "verifying destination is not the same as source" -INSTALLER_DIR="$(cd $(dirname $0) && pwd)" -PREFIX_DIR="$(cd ${CFG_PREFIX} && pwd)" -if [ "${INSTALLER_DIR}" = "${PREFIX_DIR}" ] -then - err "can't install to same directory as installer" -fi - -# Using an absolute path to libdir in a few places so that the status -# messages are consistently using absolute paths. -absolutify "${CFG_LIBDIR}" -ABS_LIBDIR="${ABSOLUTIFIED}" - -# The file name of the manifest we're going to create during install -INSTALLED_MANIFEST="${ABS_LIBDIR}/rustlib/manifest" - -# First, uninstall from the installation prefix. -# Errors are warnings - try to rm everything in the manifest even if some fail. -if [ -f "${INSTALLED_MANIFEST}" ] -then - # Iterate through installed manifest and remove files - while read p; do - # The installed manifest contains absolute paths - msg "removing $p" - if [ -f "$p" ] - then - rm -f "$p" - if [ $? -ne 0 ] - then - warn "failed to remove $p" - fi - else - warn "supposedly installed file $p does not exist!" - fi - done < "${INSTALLED_MANIFEST}" - - # If we fail to remove rustlib below, then the installed manifest will - # still be full; the installed manifest needs to be empty before install. - msg "removing ${INSTALLED_MANIFEST}" - rm -f "${INSTALLED_MANIFEST}" - # For the above reason, this is a hard error - need_ok "failed to remove installed manifest" - - # Remove 'rustlib' directory - msg "removing ${ABS_LIBDIR}/rustlib" - rm -Rf "${ABS_LIBDIR}/rustlib" - if [ $? -ne 0 ] - then - warn "failed to remove rustlib" - fi -else - # There's no manifest. If we were asked to uninstall, then that's a problem. - if [ -n "${CFG_UNINSTALL}" ] - then - err "unable to find installation manifest at ${CFG_LIBDIR}/rustlib" - fi -fi - -# If we're only uninstalling then exit -if [ -n "${CFG_UNINSTALL}" ] -then - echo - echo " Rust is uninstalled. Have a nice day." - echo - exit 0 -fi - -# Create the installed manifest, which we will fill in with absolute file paths -mkdir -p "${CFG_LIBDIR}/rustlib" -need_ok "failed to create rustlib" -touch "${INSTALLED_MANIFEST}" -need_ok "failed to create installed manifest" - -# Now install, iterate through the new manifest and copy files -while read p; do - - # Decide the destination of the file - FILE_INSTALL_PATH="${CFG_PREFIX}/$p" - - if echo "$p" | grep "^${CFG_LIBDIR_RELATIVE}/" > /dev/null - then - pp=`echo $p | sed "s%^${CFG_LIBDIR_RELATIVE}/%%"` - FILE_INSTALL_PATH="${CFG_LIBDIR}/$pp" - fi - - if echo "$p" | grep "^share/man/" > /dev/null - then - pp=`echo $p | sed 's/^share\/man\///'` - FILE_INSTALL_PATH="${CFG_MANDIR}/$pp" - fi - - # Make sure there's a directory for it - umask 022 && mkdir -p "$(dirname ${FILE_INSTALL_PATH})" - need_ok "directory creation failed" - - # Make the path absolute so we can uninstall it later without - # starting from the installation cwd - absolutify "${FILE_INSTALL_PATH}" - FILE_INSTALL_PATH="${ABSOLUTIFIED}" - - # Install the file - msg "${FILE_INSTALL_PATH}" - if echo "$p" | grep "^bin/" > /dev/null - then - install -m755 "${CFG_SRC_DIR}/$p" "${FILE_INSTALL_PATH}" - else - install -m644 "${CFG_SRC_DIR}/$p" "${FILE_INSTALL_PATH}" - fi - need_ok "file creation failed" - - # Update the manifest - echo "${FILE_INSTALL_PATH}" >> "${INSTALLED_MANIFEST}" - need_ok "failed to update manifest" - -# The manifest lists all files to install -done < "${CFG_SRC_DIR}/${CFG_LIBDIR_RELATIVE}/rustlib/manifest.in" - -# Run ldconfig to make dynamic libraries available to the linker -if [ "$CFG_OSTYPE" = "Linux" ] - then - ldconfig - if [ $? -ne 0 ] - then - warn "failed to run ldconfig." - warn "this may happen when not installing as root and may be fine" - fi -fi - -# Sanity check: can we run the installed binaries? -# -# As with the verification above, make sure the right LD_LIBRARY_PATH-equivalent -# is in place. Try first without this variable, and if that fails try again with -# the variable. If the second time tries, print a hopefully helpful message to -# add something to the appropriate environment variable. -if [ -z "${CFG_DISABLE_VERIFY}" ] -then - msg "verifying installed binaries are executable" - "${CFG_PREFIX}/bin/rustc" --version 2> /dev/null 1> /dev/null - if [ $? -ne 0 ] - then - export $CFG_LD_PATH_VAR="${CFG_PREFIX}/lib:$CFG_OLD_LD_PATH_VAR" - "${CFG_PREFIX}/bin/rustc" --version > /dev/null - if [ $? -ne 0 ] - then - ERR="can't execute installed rustc binary. " - ERR="${ERR}installation may be broken. " - ERR="${ERR}if this is expected then rerun install.sh with \`--disable-verify\` " - ERR="${ERR}or \`make install\` with \`--disable-verify-install\`" - err "${ERR}" - else - echo - echo " Note: please ensure '${CFG_PREFIX}/lib' is added to ${CFG_LD_PATH_VAR}" - fi - fi -fi - -echo -echo " Rust is ready to roll." -echo - - diff --git a/src/etc/make-win-dist.py b/src/etc/make-win-dist.py index 7fb86f904a2..95e647c91cf 100644 --- a/src/etc/make-win-dist.py +++ b/src/etc/make-win-dist.py @@ -107,7 +107,7 @@ def make_win_dist(rust_root, gcc_root, target_triple): for src in target_tools: shutil.copy(src, target_bin_dir) - # Copy platform libs to platform-spcific lib directory + # Copy platform libs to platform-specific lib directory target_lib_dir = os.path.join(gcc_root, "bin", "rustlib", target_triple, "lib") if not os.path.exists(target_lib_dir): os.makedirs(target_lib_dir) diff --git a/src/etc/rustup.sh b/src/etc/rustup.sh index b610bc65b09..5b8ccf924eb 100755 --- a/src/etc/rustup.sh +++ b/src/etc/rustup.sh @@ -231,6 +231,7 @@ validate_opt() { probe_need CFG_CURL curl probe_need CFG_TAR tar +probe_need CFG_FILE file CFG_SRC_DIR="$(cd $(dirname $0) && pwd)/" CFG_SELF="$0" @@ -359,7 +360,7 @@ esac # Detect 64 bit linux systems with 32 bit userland and force 32 bit compilation if [ $CFG_OSTYPE = unknown-linux-gnu -a $CFG_CPUTYPE = x86_64 ] then - file -L "$SHELL" | grep -q "x86[_-]64" + "${CFG_FILE}" -L "$SHELL" | grep -q "x86[_-]64" if [ $? != 0 ]; then CFG_CPUTYPE=i686 fi diff --git a/src/grammar/verify.rs b/src/grammar/verify.rs index e3ff20f7874..f7b19cf6fbf 100644 --- a/src/grammar/verify.rs +++ b/src/grammar/verify.rs @@ -173,10 +173,10 @@ fn parse_antlr_token(s: &str, tokens: &HashMap) -> TokenAn ); let m = re.captures(s).expect(format!("The regex didn't match {}", s).as_slice()); - let start = m.name("start"); - let end = m.name("end"); - let toknum = m.name("toknum"); - let content = m.name("content"); + let start = m.name("start").unwrap_or(""); + let end = m.name("end").unwrap_or(""); + let toknum = m.name("toknum").unwrap_or(""); + let content = m.name("content").unwrap_or(""); let proto_tok = tokens.get(toknum).expect(format!("didn't find token {} in the map", toknum).as_slice()); diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs index 1f1909fd33c..ee4efa2d273 100644 --- a/src/liballoc/arc.rs +++ b/src/liballoc/arc.rs @@ -14,6 +14,7 @@ //! between tasks. use core::atomic; +use core::borrow::BorrowFrom; use core::clone::Clone; use core::fmt::{mod, Show}; use core::cmp::{Eq, Ord, PartialEq, PartialOrd, Ordering}; @@ -155,6 +156,12 @@ impl Clone for Arc { } } +impl BorrowFrom> for T { + fn borrow_from(owned: &Arc) -> &T { + &**owned + } +} + #[experimental = "Deref is experimental."] impl Deref for Arc { #[inline] @@ -316,7 +323,9 @@ impl fmt::Show for Arc { } } +#[stable] impl Default for Arc { + #[stable] fn default() -> Arc { Arc::new(Default::default()) } } diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index c6afeb063fb..879a8cc6951 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -45,11 +45,15 @@ pub static HEAP: () = (); #[unstable = "custom allocators will add an additional type parameter (with default)"] pub struct Box(*mut T); +#[stable] impl Default for Box { + #[stable] fn default() -> Box { box Default::default() } } +#[stable] impl Default for Box<[T]> { + #[stable] fn default() -> Box<[T]> { box [] } } diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index 7af816f2e09..0257c640d3c 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -448,6 +448,7 @@ impl Default for Rc { /// let x: Rc = Default::default(); /// ``` #[inline] + #[stable] fn default() -> Rc { Rc::new(Default::default()) } diff --git a/src/libcollections/binary_heap.rs b/src/libcollections/binary_heap.rs index b107d6640a3..94211592698 100644 --- a/src/libcollections/binary_heap.rs +++ b/src/libcollections/binary_heap.rs @@ -172,8 +172,10 @@ pub struct BinaryHeap { data: Vec, } +#[stable] impl Default for BinaryHeap { #[inline] + #[stable] fn default() -> BinaryHeap { BinaryHeap::new() } } diff --git a/src/libcollections/bit.rs b/src/libcollections/bit.rs index 6113e2323c1..df860d6000e 100644 --- a/src/libcollections/bit.rs +++ b/src/libcollections/bit.rs @@ -824,8 +824,10 @@ pub fn from_fn(len: uint, mut f: F) -> Bitv where F: FnMut(uint) -> bool { bitv } +#[stable] impl Default for Bitv { #[inline] + #[stable] fn default() -> Bitv { Bitv::new() } } diff --git a/src/libcollections/btree/map.rs b/src/libcollections/btree/map.rs index 94dc1650a21..c7cbb5a1c29 100644 --- a/src/libcollections/btree/map.rs +++ b/src/libcollections/btree/map.rs @@ -29,6 +29,7 @@ use std::hash::{Writer, Hash}; use core::default::Default; use core::{iter, fmt, mem}; use core::fmt::Show; +use core::iter::Map; use ring_buf::RingBuf; @@ -110,12 +111,14 @@ pub struct MoveEntries { } /// An iterator over a BTreeMap's keys. -pub type Keys<'a, K, V> = - iter::Map<(&'a K, &'a V), &'a K, Entries<'a, K, V>, fn((&'a K, &'a V)) -> &'a K>; +pub struct Keys<'a, K: 'a, V: 'a> { + inner: Map<(&'a K, &'a V), &'a K, Entries<'a, K, V>, fn((&'a K, &'a V)) -> &'a K> +} /// An iterator over a BTreeMap's values. -pub type Values<'a, K, V> = - iter::Map<(&'a K, &'a V), &'a V, Entries<'a, K, V>, fn((&'a K, &'a V)) -> &'a V>; +pub struct Values<'a, K: 'a, V: 'a> { + inner: Map<(&'a K, &'a V), &'a V, Entries<'a, K, V>, fn((&'a K, &'a V)) -> &'a V> +} /// A view into a single entry in a map, which may either be vacant or occupied. pub enum Entry<'a, K:'a, V:'a> { @@ -829,7 +832,9 @@ impl, V: Hash> Hash for BTreeMap { } } +#[stable] impl Default for BTreeMap { + #[stable] fn default() -> BTreeMap { BTreeMap::new() } @@ -1054,6 +1059,25 @@ impl DoubleEndedIterator<(K, V)> for MoveEntries { impl ExactSizeIterator<(K, V)> for MoveEntries {} +impl<'a, K, V> Iterator<&'a K> for Keys<'a, K, V> { + fn next(&mut self) -> Option<(&'a K)> { self.inner.next() } + fn size_hint(&self) -> (uint, Option) { self.inner.size_hint() } +} +impl<'a, K, V> DoubleEndedIterator<&'a K> for Keys<'a, K, V> { + fn next_back(&mut self) -> Option<(&'a K)> { self.inner.next_back() } +} +impl<'a, K, V> ExactSizeIterator<&'a K> for Keys<'a, K, V> {} + + +impl<'a, K, V> Iterator<&'a V> for Values<'a, K, V> { + fn next(&mut self) -> Option<(&'a V)> { self.inner.next() } + fn size_hint(&self) -> (uint, Option) { self.inner.size_hint() } +} +impl<'a, K, V> DoubleEndedIterator<&'a V> for Values<'a, K, V> { + fn next_back(&mut self) -> Option<(&'a V)> { self.inner.next_back() } +} +impl<'a, K, V> ExactSizeIterator<&'a V> for Values<'a, K, V> {} + impl<'a, K: Ord, V> VacantEntry<'a, K, V> { /// Sets the value of the entry with the VacantEntry's key, @@ -1204,7 +1228,7 @@ impl BTreeMap { pub fn keys<'a>(&'a self) -> Keys<'a, K, V> { fn first((a, _): (A, B)) -> A { a } - self.iter().map(first) + Keys { inner: self.iter().map(first) } } /// Gets an iterator over the values of the map. @@ -1225,7 +1249,7 @@ impl BTreeMap { pub fn values<'a>(&'a self) -> Values<'a, K, V> { fn second((_, b): (A, B)) -> B { b } - self.iter().map(second) + Values { inner: self.iter().map(second) } } /// Return the number of elements in the map. diff --git a/src/libcollections/btree/node.rs b/src/libcollections/btree/node.rs index 3718dd516b2..9698b06c7fa 100644 --- a/src/libcollections/btree/node.rs +++ b/src/libcollections/btree/node.rs @@ -19,7 +19,6 @@ pub use self::TraversalItem::*; use core::prelude::*; use core::{slice, mem, ptr, cmp, num, raw}; -use core::kinds::marker; use core::iter::Zip; use core::borrow::BorrowFrom; use alloc::heap; @@ -176,7 +175,6 @@ fn calculate_offsets_generic(capacity: uint, is_leaf: bool) -> (uint, uint struct RawItems { head: *const T, tail: *const T, - marker: marker::NoCopy } impl RawItems { @@ -189,13 +187,11 @@ impl RawItems { RawItems { head: ptr, tail: (ptr as uint + len) as *const T, - marker: marker::NoCopy } } else { RawItems { head: ptr, tail: ptr.offset(len as int), - marker: marker::NoCopy } } } diff --git a/src/libcollections/btree/set.rs b/src/libcollections/btree/set.rs index c6d1898b87e..8f75113c01d 100644 --- a/src/libcollections/btree/set.rs +++ b/src/libcollections/btree/set.rs @@ -17,8 +17,8 @@ use btree_map::{BTreeMap, Keys, MoveEntries}; use std::hash::Hash; use core::borrow::BorrowFrom; use core::default::Default; -use core::{iter, fmt}; -use core::iter::Peekable; +use core::fmt; +use core::iter::{Peekable, Map}; use core::fmt::Show; // FIXME(conventions): implement bounded iterators @@ -33,11 +33,14 @@ pub struct BTreeSet{ } /// An iterator over a BTreeSet's items. -pub type Items<'a, T> = Keys<'a, T, ()>; +pub struct Items<'a, T: 'a> { + iter: Keys<'a, T, ()> +} /// An owning iterator over a BTreeSet's items. -pub type MoveItems = - iter::Map<(T, ()), T, MoveEntries, fn((T, ())) -> T>; +pub struct MoveItems { + iter: Map<(T, ()), T, MoveEntries, fn((T, ())) -> T> +} /// A lazy iterator producing elements in the set difference (in-order). pub struct DifferenceItems<'a, T:'a> { @@ -105,7 +108,7 @@ impl BTreeSet { /// ``` #[unstable = "matches collection reform specification, waiting for dust to settle"] pub fn iter<'a>(&'a self) -> Items<'a, T> { - self.map.keys() + Items { iter: self.map.keys() } } /// Gets an iterator for moving out the BtreeSet's contents. @@ -124,7 +127,7 @@ impl BTreeSet { pub fn into_iter(self) -> MoveItems { fn first((a, _): (A, B)) -> A { a } - self.map.into_iter().map(first) + MoveItems { iter: self.map.into_iter().map(first) } } } @@ -436,7 +439,9 @@ impl Extend for BTreeSet { } } +#[stable] impl Default for BTreeSet { + #[stable] fn default() -> BTreeSet { BTreeSet::new() } @@ -635,6 +640,25 @@ impl Show for BTreeSet { } } +impl<'a, T> Iterator<&'a T> for Items<'a, T> { + fn next(&mut self) -> Option<&'a T> { self.iter.next() } + fn size_hint(&self) -> (uint, Option) { self.iter.size_hint() } +} +impl<'a, T> DoubleEndedIterator<&'a T> for Items<'a, T> { + fn next_back(&mut self) -> Option<&'a T> { self.iter.next_back() } +} +impl<'a, T> ExactSizeIterator<&'a T> for Items<'a, T> {} + + +impl Iterator for MoveItems { + fn next(&mut self) -> Option { self.iter.next() } + fn size_hint(&self) -> (uint, Option) { self.iter.size_hint() } +} +impl DoubleEndedIterator for MoveItems { + fn next_back(&mut self) -> Option { self.iter.next_back() } +} +impl ExactSizeIterator for MoveItems {} + /// Compare `x` and `y`, but return `short` if x is None and `long` if y is None fn cmp_opt(x: Option<&T>, y: Option<&T>, short: Ordering, long: Ordering) -> Ordering { diff --git a/src/libcollections/dlist.rs b/src/libcollections/dlist.rs index 3ae66954e9c..e7454aef51e 100644 --- a/src/libcollections/dlist.rs +++ b/src/libcollections/dlist.rs @@ -192,8 +192,10 @@ impl DList { } } +#[stable] impl Default for DList { #[inline] + #[stable] fn default() -> DList { DList::new() } } diff --git a/src/libcollections/ring_buf.rs b/src/libcollections/ring_buf.rs index 084b585d7b9..cdb92d302e9 100644 --- a/src/libcollections/ring_buf.rs +++ b/src/libcollections/ring_buf.rs @@ -68,7 +68,9 @@ impl Drop for RingBuf { } } +#[stable] impl Default for RingBuf { + #[stable] #[inline] fn default() -> RingBuf { RingBuf::new() } } @@ -102,17 +104,15 @@ impl RingBuf { /// Copies a contiguous block of memory len long from src to dst #[inline] - fn copy(&self, dst: uint, src: uint, len: uint) { - unsafe { - debug_assert!(dst + len <= self.cap, "dst={} src={} len={} cap={}", dst, src, len, - self.cap); - debug_assert!(src + len <= self.cap, "dst={} src={} len={} cap={}", dst, src, len, - self.cap); - ptr::copy_memory( - self.ptr.offset(dst as int), - self.ptr.offset(src as int) as *const T, - len); - } + unsafe fn copy(&self, dst: uint, src: uint, len: uint) { + debug_assert!(dst + len <= self.cap, "dst={} src={} len={} cap={}", dst, src, len, + self.cap); + debug_assert!(src + len <= self.cap, "dst={} src={} len={} cap={}", dst, src, len, + self.cap); + ptr::copy_memory( + self.ptr.offset(dst as int), + self.ptr.offset(src as int) as *const T, + len); } } @@ -377,7 +377,7 @@ impl RingBuf { } } - /// Returns a front-to-back iterator which returns mutable references. + /// Returns a front-to-back iterator that returns mutable references. /// /// # Examples /// @@ -402,7 +402,6 @@ impl RingBuf { cap: self.cap, ptr: self.ptr, marker: marker::ContravariantLifetime::<'a>, - marker2: marker::NoCopy } } @@ -732,7 +731,7 @@ impl RingBuf { self.tail = self.wrap_index(self.tail - 1); }, - (true, true, _) => { + (true, true, _) => unsafe { // contiguous, insert closer to tail: // // T I H @@ -752,13 +751,15 @@ impl RingBuf { // [o I A o o o o o . . . . . . . o] // M M - let old_tail = self.tail; - self.tail = self.wrap_index(self.tail - 1); + let new_tail = self.wrap_index(self.tail - 1); - self.copy(self.tail, old_tail, 1); - self.copy(old_tail, old_tail + 1, i); + self.copy(new_tail, self.tail, 1); + // Already moved the tail, so we only copy `i - 1` elements. + self.copy(self.tail, self.tail + 1, i - 1); + + self.tail = new_tail; }, - (true, false, _) => { + (true, false, _) => unsafe { // contiguous, insert closer to head: // // T I H @@ -768,12 +769,11 @@ impl RingBuf { // [. . . o o o o I A o o . . . . .] // M M M - let old_head = self.head; + self.copy(idx + 1, idx, self.head - idx); self.head = self.wrap_index(self.head + 1); - self.copy(idx + 1, idx, old_head - idx); }, - (false, true, true) => { - // discontiguous, tail section, insert closer to tail: + (false, true, true) => unsafe { + // discontiguous, insert closer to tail, tail section: // // H T I // [o o o o o o . . . . . o o A o o] @@ -782,12 +782,11 @@ impl RingBuf { // [o o o o o o . . . . o o I A o o] // M M - let old_tail = self.tail; - self.tail = self.tail - 1; - self.copy(self.tail, old_tail, i); + self.copy(self.tail - 1, self.tail, i); + self.tail -= 1; }, - (false, false, true) => { - // discontiguous, tail section, insert closer to head: + (false, false, true) => unsafe { + // discontiguous, insert closer to head, tail section: // // H T I // [o o . . . . . . . o o o o o A o] @@ -796,20 +795,19 @@ impl RingBuf { // [o o o . . . . . . o o o o o I A] // M M M M - let old_head = self.head; - self.head = self.head + 1; - // copy elements up to new head - self.copy(1, 0, old_head); + self.copy(1, 0, self.head); // copy last element into empty spot at bottom of buffer self.copy(0, self.cap - 1, 1); // move elements from idx to end forward not including ^ element self.copy(idx + 1, idx, self.cap - 1 - idx); + + self.head += 1; }, - (false, true, false) if idx == 0 => { - // discontiguous, head section, insert is closer to tail, + (false, true, false) if idx == 0 => unsafe { + // discontiguous, insert is closer to tail, head section, // and is at index zero in the internal buffer: // // I H T @@ -819,16 +817,16 @@ impl RingBuf { // [A o o o o o o o o o . . o o o I] // M M M - let old_tail = self.tail; - self.tail = self.tail - 1; // copy elements up to new tail - self.copy(old_tail - 1, old_tail, i); + self.copy(self.tail - 1, self.tail, self.cap - self.tail); // copy last element into empty spot at bottom of buffer self.copy(self.cap - 1, 0, 1); + + self.tail -= 1; }, - (false, true, false) => { - // discontiguous, head section, insert closer to tail: + (false, true, false) => unsafe { + // discontiguous, insert closer to tail, head section: // // I H T // [o o o A o o o o o o . . . o o o] @@ -837,19 +835,19 @@ impl RingBuf { // [o o I A o o o o o o . . o o o o] // M M M M M M - let old_tail = self.tail; - self.tail = self.tail - 1; // copy elements up to new tail - self.copy(old_tail - 1, old_tail, i); + self.copy(self.tail - 1, self.tail, self.cap - self.tail); // copy last element into empty spot at bottom of buffer self.copy(self.cap - 1, 0, 1); // move elements from idx-1 to end forward not including ^ element self.copy(0, 1, idx - 1); - } - (false, false, false) => { - // discontiguous, head section, insert closer to head: + + self.tail -= 1; + }, + (false, false, false) => unsafe { + // discontiguous, insert closer to head, head section: // // I H T // [o o o o A o o . . . . . . o o o] @@ -858,9 +856,8 @@ impl RingBuf { // [o o o o I A o o . . . . . o o o] // M M M - let old_head = self.head; - self.head = self.head + 1; - self.copy(idx + 1, idx, old_head - idx); + self.copy(idx + 1, idx, self.head - idx); + self.head += 1; } } @@ -870,6 +867,170 @@ impl RingBuf { self.buffer_write(new_idx, t); } } + + /// Removes and returns the element at position `i` from the ringbuf. + /// Whichever end is closer to the removal point will be moved to make + /// room, and all the affected elements will be moved to new positions. + /// Returns `None` if `i` is out of bounds. + /// + /// # Example + /// ```rust + /// use std::collections::RingBuf; + /// + /// let mut buf = RingBuf::new(); + /// buf.push_back(5i); + /// buf.push_back(10i); + /// buf.push_back(12i); + /// buf.push_back(15); + /// buf.remove(2); + /// assert_eq!(Some(&15), buf.get(2)); + /// ``` + #[unstable = "matches collection reform specification; waiting on panic semantics"] + pub fn remove(&mut self, i: uint) -> Option { + if self.is_empty() || self.len() <= i { + return None; + } + + // There are three main cases: + // Elements are contiguous + // Elements are discontiguous and the removal is in the tail section + // Elements are discontiguous and the removal is in the head section + // - special case when elements are technically contiguous, + // but self.head = 0 + // + // For each of those there are two more cases: + // Insert is closer to tail + // Insert is closer to head + // + // Key: H - self.head + // T - self.tail + // o - Valid element + // x - Element marked for removal + // R - Indicates element that is being removed + // M - Indicates element was moved + + let idx = self.wrap_index(self.tail + i); + + let elem = unsafe { + Some(self.buffer_read(idx)) + }; + + let distance_to_tail = i; + let distance_to_head = self.len() - i; + + let contiguous = self.tail <= self.head; + + match (contiguous, distance_to_tail <= distance_to_head, idx >= self.tail) { + (true, true, _) => unsafe { + // contiguous, remove closer to tail: + // + // T R H + // [. . . o o x o o o o . . . . . .] + // + // T H + // [. . . . o o o o o o . . . . . .] + // M M + + self.copy(self.tail + 1, self.tail, i); + self.tail += 1; + }, + (true, false, _) => unsafe { + // contiguous, remove closer to head: + // + // T R H + // [. . . o o o o x o o . . . . . .] + // + // T H + // [. . . o o o o o o . . . . . . .] + // M M + + self.copy(idx, idx + 1, self.head - idx - 1); + self.head -= 1; + }, + (false, true, true) => unsafe { + // discontiguous, remove closer to tail, tail section: + // + // H T R + // [o o o o o o . . . . . o o x o o] + // + // H T + // [o o o o o o . . . . . . o o o o] + // M M + + self.copy(self.tail + 1, self.tail, i); + self.tail = self.wrap_index(self.tail + 1); + }, + (false, false, false) => unsafe { + // discontiguous, remove closer to head, head section: + // + // R H T + // [o o o o x o o . . . . . . o o o] + // + // H T + // [o o o o o o . . . . . . . o o o] + // M M + + self.copy(idx, idx + 1, self.head - idx - 1); + self.head -= 1; + }, + (false, false, true) => unsafe { + // discontiguous, remove closer to head, tail section: + // + // H T R + // [o o o . . . . . . o o o o o x o] + // + // H T + // [o o . . . . . . . o o o o o o o] + // M M M M + // + // or quasi-discontiguous, remove next to head, tail section: + // + // H T R + // [. . . . . . . . . o o o o o x o] + // + // T H + // [. . . . . . . . . o o o o o o .] + // M + + // draw in elements in the tail section + self.copy(idx, idx + 1, self.cap - idx - 1); + + // Prevents underflow. + if self.head != 0 { + // copy first element into empty spot + self.copy(self.cap - 1, 0, 1); + + // move elements in the head section backwards + self.copy(0, 1, self.head - 1); + } + + self.head = self.wrap_index(self.head - 1); + }, + (false, true, false) => unsafe { + // discontiguous, remove closer to tail, head section: + // + // R H T + // [o o x o o o o o o o . . . o o o] + // + // H T + // [o o o o o o o o o o . . . . o o] + // M M M M M + + // draw in elements up to idx + self.copy(1, 0, idx); + + // copy last element into empty spot + self.copy(0, self.cap - 1, 1); + + // move elements from tail to end forward, excluding the last one + self.copy(self.tail + 1, self.tail, self.cap - self.tail - 1); + + self.tail = self.wrap_index(self.tail + 1); + } + } + + return elem; + } } /// Returns the index in the underlying buffer for a given logical element index. @@ -952,7 +1113,6 @@ pub struct MutItems<'a, T:'a> { head: uint, cap: uint, marker: marker::ContravariantLifetime<'a>, - marker2: marker::NoCopy } impl<'a, T> Iterator<&'a mut T> for MutItems<'a, T> { @@ -1103,6 +1263,7 @@ mod tests { use core::iter; use self::Taggy::*; use self::Taggypar::*; + use std::cmp; use std::fmt::Show; use std::prelude::*; use std::hash; @@ -1892,11 +2053,11 @@ mod tests { #[test] fn test_insert() { // This test checks that every single combination of tail position, length, and - // insertion position is tested. Capacity 7 should be large enough to cover every case. + // insertion position is tested. Capacity 15 should be large enough to cover every case. - let mut tester = RingBuf::with_capacity(7); - // can't guarantee we got 7, so have to get what we got. - // 7 would be great, but we will definitely get 2^k - 1, for k >= 3, or else + let mut tester = RingBuf::with_capacity(15); + // can't guarantee we got 15, so have to get what we got. + // 15 would be great, but we will definitely get 2^k - 1, for k >= 4, or else // this test isn't covering what it wants to let cap = tester.capacity(); @@ -1915,6 +2076,45 @@ mod tests { } } tester.insert(to_insert, to_insert); + assert!(tester.tail < tester.cap); + assert!(tester.head < tester.cap); + assert_eq!(tester, expected); + } + } + } + } + + #[test] + fn test_remove() { + // This test checks that every single combination of tail position, length, and + // removal position is tested. Capacity 15 should be large enough to cover every case. + + let mut tester = RingBuf::with_capacity(15); + // can't guarantee we got 15, so have to get what we got. + // 15 would be great, but we will definitely get 2^k - 1, for k >= 4, or else + // this test isn't covering what it wants to + let cap = tester.capacity(); + + // len is the length *after* removal + for len in range(0, cap - 1) { + // 0, 1, 2, .., len - 1 + let expected = iter::count(0, 1).take(len).collect(); + for tail_pos in range(0, cap) { + for to_remove in range(0, len + 1) { + tester.tail = tail_pos; + tester.head = tail_pos; + for i in range(0, len) { + if i == to_remove { + tester.push_back(1234); + } + tester.push_back(i); + } + if to_remove == len { + tester.push_back(1234); + } + tester.remove(to_remove); + assert!(tester.tail < tester.cap); + assert!(tester.head < tester.cap); assert_eq!(tester, expected); } } diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs index d14552afebe..19ca1c9fd2b 100644 --- a/src/libcollections/str.rs +++ b/src/libcollections/str.rs @@ -1597,17 +1597,24 @@ mod tests { #[test] fn test_escape_unicode() { - assert_eq!("abc".escape_unicode(), String::from_str("\\x61\\x62\\x63")); - assert_eq!("a c".escape_unicode(), String::from_str("\\x61\\x20\\x63")); - assert_eq!("\r\n\t".escape_unicode(), String::from_str("\\x0d\\x0a\\x09")); - assert_eq!("'\"\\".escape_unicode(), String::from_str("\\x27\\x22\\x5c")); + assert_eq!("abc".escape_unicode(), + String::from_str("\\u{61}\\u{62}\\u{63}")); + assert_eq!("a c".escape_unicode(), + String::from_str("\\u{61}\\u{20}\\u{63}")); + assert_eq!("\r\n\t".escape_unicode(), + String::from_str("\\u{d}\\u{a}\\u{9}")); + assert_eq!("'\"\\".escape_unicode(), + String::from_str("\\u{27}\\u{22}\\u{5c}")); assert_eq!("\x00\x01\u{fe}\u{ff}".escape_unicode(), - String::from_str("\\x00\\x01\\u00fe\\u00ff")); - assert_eq!("\u{100}\u{ffff}".escape_unicode(), String::from_str("\\u0100\\uffff")); + String::from_str("\\u{0}\\u{1}\\u{fe}\\u{ff}")); + assert_eq!("\u{100}\u{ffff}".escape_unicode(), + String::from_str("\\u{100}\\u{ffff}")); assert_eq!("\u{10000}\u{10ffff}".escape_unicode(), - String::from_str("\\U00010000\\U0010ffff")); - assert_eq!("ab\u{fb00}".escape_unicode(), String::from_str("\\x61\\x62\\ufb00")); - assert_eq!("\u{1d4ea}\r".escape_unicode(), String::from_str("\\U0001d4ea\\x0d")); + String::from_str("\\u{10000}\\u{10ffff}")); + assert_eq!("ab\u{fb00}".escape_unicode(), + String::from_str("\\u{61}\\u{62}\\u{fb00}")); + assert_eq!("\u{1d4ea}\r".escape_unicode(), + String::from_str("\\u{1d4ea}\\u{d}")); } #[test] @@ -1616,11 +1623,14 @@ mod tests { assert_eq!("a c".escape_default(), String::from_str("a c")); assert_eq!("\r\n\t".escape_default(), String::from_str("\\r\\n\\t")); assert_eq!("'\"\\".escape_default(), String::from_str("\\'\\\"\\\\")); - assert_eq!("\u{100}\u{ffff}".escape_default(), String::from_str("\\u0100\\uffff")); + assert_eq!("\u{100}\u{ffff}".escape_default(), + String::from_str("\\u{100}\\u{ffff}")); assert_eq!("\u{10000}\u{10ffff}".escape_default(), - String::from_str("\\U00010000\\U0010ffff")); - assert_eq!("ab\u{fb00}".escape_default(), String::from_str("ab\\ufb00")); - assert_eq!("\u{1d4ea}\r".escape_default(), String::from_str("\\U0001d4ea\\r")); + String::from_str("\\u{10000}\\u{10ffff}")); + assert_eq!("ab\u{fb00}".escape_default(), + String::from_str("ab\\u{fb00}")); + assert_eq!("\u{1d4ea}\r".escape_default(), + String::from_str("\\u{1d4ea}\\r")); } #[test] diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index bc179cb37fb..ba89fc133c4 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -826,6 +826,7 @@ impl StrAllocating for String { #[stable] impl Default for String { + #[stable] fn default() -> String { String::new() } @@ -859,6 +860,16 @@ impl<'a, S: Str> Equiv for String { #[cfg(stage0)] #[experimental = "waiting on Add stabilization"] impl Add for String { + /// Concatenates `self` and `other` as a new mutable `String`. + /// + /// # Examples + /// + /// ``` + /// let string1 = "foo".to_string(); + /// let string2 = "bar".to_string(); + /// let string3 = string1 + string2; + /// assert_eq!(string3, "foobar".to_string()); + /// ``` fn add(&self, other: &S) -> String { let mut s = String::from_str(self.as_slice()); s.push_str(other.as_slice()); diff --git a/src/libcollections/tree/map.rs b/src/libcollections/tree/map.rs index 5c2cf4a8180..2b14f9569b0 100644 --- a/src/libcollections/tree/map.rs +++ b/src/libcollections/tree/map.rs @@ -185,8 +185,10 @@ impl Show for TreeMap { } } +#[stable] impl Default for TreeMap { #[inline] + #[stable] fn default() -> TreeMap { TreeMap::new() } } diff --git a/src/libcollections/tree/set.rs b/src/libcollections/tree/set.rs index 6a0986d3283..c3aebc2736c 100644 --- a/src/libcollections/tree/set.rs +++ b/src/libcollections/tree/set.rs @@ -134,8 +134,10 @@ impl Show for TreeSet { } } +#[stable] impl Default for TreeSet { #[inline] + #[stable] fn default() -> TreeSet { TreeSet::new() } } diff --git a/src/libcollections/trie/map.rs b/src/libcollections/trie/map.rs index a4dee807648..67c5407eb6e 100644 --- a/src/libcollections/trie/map.rs +++ b/src/libcollections/trie/map.rs @@ -150,8 +150,10 @@ impl Show for TrieMap { } } +#[stable] impl Default for TrieMap { #[inline] + #[stable] fn default() -> TrieMap { TrieMap::new() } } diff --git a/src/libcollections/trie/set.rs b/src/libcollections/trie/set.rs index 7b7b4d8280b..5d24673ae75 100644 --- a/src/libcollections/trie/set.rs +++ b/src/libcollections/trie/set.rs @@ -69,8 +69,10 @@ impl Show for TrieSet { } } +#[stable] impl Default for TrieSet { #[inline] + #[stable] fn default() -> TrieSet { TrieSet::new() } } diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index fa4cfc99753..75a389a7c95 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -11,6 +11,38 @@ //! A growable list type, written `Vec` but pronounced 'vector.' //! //! Vectors have `O(1)` indexing, push (to the end) and pop (from the end). +//! +//! # Examples +//! +//! Explicitly creating a `Vec` with `new()`: +//! +//! ``` +//! let xs: Vec = Vec::new(); +//! ``` +//! +//! Using the `vec!` macro: +//! +//! ``` +//! let ys: Vec = vec![]; +//! +//! let zs = vec![1i32, 2, 3, 4, 5]; +//! ``` +//! +//! Push: +//! +//! ``` +//! let mut xs = vec![1i32, 2]; +//! +//! xs.push(3); +//! ``` +//! +//! And pop: +//! +//! ``` +//! let mut xs = vec![1i32, 2]; +//! +//! let two = xs.pop(); +//! ``` use core::prelude::*; @@ -32,7 +64,7 @@ use core::uint; use slice::CloneSliceExt; -/// An owned, growable vector. +/// A growable list type, written `Vec` but pronounced 'vector.' /// /// # Examples /// @@ -66,7 +98,7 @@ use slice::CloneSliceExt; /// assert_eq!(vec, vec![1, 2, 3, 4]); /// ``` /// -/// Use a `Vec` as an efficient stack: +/// Use a `Vec` as an efficient stack: /// /// ``` /// let mut stack = Vec::new(); @@ -87,20 +119,17 @@ use slice::CloneSliceExt; /// /// # 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. +/// 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. +/// 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] #[stable] pub struct Vec { @@ -131,7 +160,7 @@ impl<'a, T> IntoCow<'a, Vec, [T]> for &'a [T] where T: Clone { } impl Vec { - /// Constructs a new, empty `Vec`. + /// Constructs a new, empty `Vec`. /// /// The vector will not allocate until elements are pushed onto it. /// @@ -150,16 +179,15 @@ impl Vec { Vec { ptr: EMPTY as *mut T, len: 0, cap: 0 } } - /// Constructs a new, empty `Vec` with the specified capacity. + /// Constructs a new, empty `Vec` with the specified capacity. /// - /// The vector will be able to hold exactly `capacity` elements without - /// reallocating. If `capacity` is 0, the vector will not allocate. + /// 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`. + /// 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`. /// /// # Examples /// @@ -193,10 +221,10 @@ impl Vec { } } - /// Creates and initializes a `Vec`. + /// Creates and initializes a `Vec`. /// - /// Creates a `Vec` of size `length` and initializes the elements to the - /// value returned by the closure `op`. + /// Creates a `Vec` of size `length` and initializes the elements to the value returned by + /// the closure `op`. /// /// # Examples /// @@ -261,10 +289,9 @@ impl Vec { /// Creates a vector by copying the elements from a raw pointer. /// - /// This function will copy `elts` contiguous elements starting at `ptr` - /// into a new allocation owned by the returned `Vec`. The elements of the - /// buffer are copied into the vector without cloning, as if `ptr::read()` - /// were called on them. + /// This function will copy `elts` contiguous elements starting at `ptr` into a new allocation + /// owned by the returned `Vec`. The elements of the buffer are copied into the vector + /// without cloning, as if `ptr::read()` were called on them. #[inline] #[unstable = "just renamed from raw::from_buf"] pub unsafe fn from_raw_buf(ptr: *const T, elts: uint) -> Vec { @@ -274,11 +301,10 @@ impl Vec { dst } - /// Consumes the `Vec`, partitioning it based on a predicate. + /// Consumes the `Vec`, partitioning it based on a predicate. /// - /// Partitions the `Vec` into two `Vec`s `(A,B)`, where all elements of `A` - /// satisfy `f` and all elements of `B` do not. The order of elements is - /// preserved. + /// Partitions the `Vec` into two `Vec`s `(A,B)`, where all elements of `A` satisfy `f` + /// and all elements of `B` do not. The order of elements is preserved. /// /// # Examples /// @@ -307,9 +333,9 @@ impl Vec { } impl Vec { - /// Constructs a `Vec` with copies of a value. + /// Constructs a `Vec` with copies of a value. /// - /// Creates a `Vec` with `length` copies of `value`. + /// Creates a `Vec` with `length` copies of `value`. /// /// # Examples /// @@ -332,10 +358,10 @@ impl Vec { } } - /// Appends all elements in a slice to the `Vec`. + /// Appends all elements in a slice to the `Vec`. /// /// Iterates over the slice `other`, clones each element, and then appends - /// it to this `Vec`. The `other` vector is traversed in-order. + /// it to this `Vec`. The `other` vector is traversed in-order. /// /// # Examples /// @@ -364,9 +390,9 @@ impl Vec { } } - /// Grows the `Vec` in-place. + /// Grows the `Vec` in-place. /// - /// Adds `n` copies of `value` to the `Vec`. + /// Adds `n` copies of `value` to the `Vec`. /// /// # Examples /// @@ -388,7 +414,7 @@ impl Vec { /// Partitions a vector based on a predicate. /// - /// Clones the elements of the vector, partitioning them into two `Vec`s + /// Clones the elements of the vector, partitioning them into two `Vec`s /// `(a, b)`, where all elements of `a` satisfy `f` and all elements of `b` /// do not. The order of elements is preserved. /// @@ -647,8 +673,7 @@ unsafe fn dealloc(ptr: *mut T, len: uint) { } impl Vec { - /// Returns the number of elements the vector can hold without - /// reallocating. + /// Returns the number of elements the vector can hold without reallocating. /// /// # Examples /// @@ -669,7 +694,7 @@ impl Vec { } /// Reserves capacity for at least `additional` more elements to be inserted in the given - /// `Vec`. The collection may reserve more space to avoid frequent reallocations. + /// `Vec`. The collection may reserve more space to avoid frequent reallocations. /// /// # Panics /// @@ -703,7 +728,7 @@ impl Vec { } /// Reserves the minimum capacity for exactly `additional` more elements to be inserted in the - /// given `Vec`. Does nothing if the capacity is already sufficient. + /// given `Vec`. Does nothing if the capacity is already sufficient. /// /// Note that the allocator may give the collection more space than it requests. Therefore /// capacity can not be relied upon to be precisely minimal. Prefer `reserve` if future @@ -730,16 +755,19 @@ impl Vec { } } - /// Shrinks the capacity of the vector as much as possible. It will drop - /// down as close as possible to the length but the allocator may still - /// inform the vector that there is space for a few more elements. + /// Shrinks the capacity of the vector as much as possible. + /// + /// It will drop down as close as possible to the length but the allocator may still inform the + /// vector that there is space for a few more elements. /// /// # Examples /// /// ``` /// let mut vec: Vec = Vec::with_capacity(10); + /// /// vec.push_all(&[1, 2, 3]); /// assert_eq!(vec.capacity(), 10); + /// /// vec.shrink_to_fit(); /// assert!(vec.capacity() >= 3); /// ``` @@ -828,14 +856,14 @@ impl Vec { } } - /// Creates a consuming iterator, that is, one that moves each - /// value out of the vector (from start to end). The vector cannot - /// be used after calling this. + /// Creates a consuming iterator, that is, one that moves each value out of the vector (from + /// start to end). The vector cannot be used after calling this. /// /// # Examples /// /// ``` /// let v = vec!["a".to_string(), "b".to_string()]; + /// /// for s in v.into_iter() { /// // s has type String, not &String /// println!("{}", s); @@ -860,9 +888,8 @@ impl Vec { /// Sets the length of a vector. /// - /// This will explicitly set the size of the vector, without actually - /// modifying its buffers, so it is up to the caller to ensure that the - /// vector is actually the specified size. + /// This will explicitly set the size of the vector, without actually modifying its buffers, so + /// it is up to the caller to ensure that the vector is actually the specified size. /// /// # Examples /// @@ -878,8 +905,10 @@ impl Vec { self.len = len; } - /// Removes an element from anywhere in the vector and return it, replacing - /// it with the last element. This does not preserve ordering, but is O(1). + /// Removes an element from anywhere in the vector and return it, replacing it with the last + /// element. + /// + /// This does not preserve ordering, but is O(1). /// /// Returns `None` if `index` is out of bounds. /// @@ -908,13 +937,12 @@ impl Vec { self.pop() } - /// Inserts an element at position `index` within the vector, shifting all - /// elements after position `i` one position to the right. + /// Inserts an element at position `index` within the vector, shifting all elements after + /// position `i` one position to the right. /// /// # Panics /// - /// Panics if `index` is not between `0` and the vector's length (both - /// bounds inclusive). + /// Panics if `index` is not between `0` and the vector's length (both bounds inclusive). /// /// # Examples /// @@ -947,9 +975,9 @@ impl Vec { } } - /// Removes and returns the element at position `index` within the vector, - /// shifting all elements after position `index` one position to the left. - /// Returns `None` if `i` is out of bounds. + /// Removes and returns the element at position `index` within the vector, shifting all + /// elements after position `index` one position to the left. Returns `None` if `i` is out of + /// bounds. /// /// # Examples /// @@ -988,8 +1016,8 @@ impl Vec { /// Retains only the elements specified by the predicate. /// - /// In other words, remove all elements `e` such that `f(&e)` returns false. - /// This method operates in place and preserves the order of the retained elements. + /// In other words, remove all elements `e` such that `f(&e)` returns false. This method + /// operates in place and preserves the order of the retained elements. /// /// # Examples /// @@ -1078,8 +1106,7 @@ impl Vec { } } - /// Removes the last element from a vector and returns it, or `None` if - /// it is empty. + /// Removes the last element from a vector and returns it, or `None` if it is empty. /// /// # Examples /// @@ -1107,7 +1134,9 @@ impl Vec { /// /// ``` /// let mut v = vec![1i, 2, 3]; + /// /// v.clear(); + /// /// assert!(v.is_empty()); /// ``` #[inline] @@ -1116,7 +1145,7 @@ impl Vec { self.truncate(0) } - /// Return the number of elements in the vector + /// Returns the number of elements in the vector. /// /// # Examples /// @@ -1128,13 +1157,14 @@ impl Vec { #[stable] pub fn len(&self) -> uint { self.len } - /// Returns true if the vector contains no elements + /// Returns `true` if the vector contains no elements. /// /// # Examples /// /// ``` /// let mut v = Vec::new(); /// assert!(v.is_empty()); + /// /// v.push(1i); /// assert!(!v.is_empty()); /// ``` @@ -1169,7 +1199,9 @@ impl Vec { /// /// ``` /// let mut vec = vec![1i, 2, 2, 3, 2]; + /// /// vec.dedup(); + /// /// assert_eq!(vec, vec![1i, 2, 3, 2]); /// ``` #[unstable = "this function may be renamed"] @@ -1330,6 +1362,7 @@ impl Drop for Vec { #[stable] impl Default for Vec { + #[stable] fn default() -> Vec { Vec::new() } @@ -1441,10 +1474,9 @@ impl Drop for MoveItems { /// Converts an iterator of pairs into a pair of vectors. /// -/// Returns a tuple containing two vectors where the i-th element of the first -/// vector contains the first element of the i-th tuple of the input iterator, -/// and the i-th element of the second vector contains the second element -/// of the i-th tuple of the input iterator. +/// Returns a tuple containing two vectors where the i-th element of the first vector contains the +/// first element of the i-th tuple of the input iterator, and the i-th element of the second +/// vector contains the second element of the i-th tuple of the input iterator. #[unstable = "this functionality may become more generic over time"] pub fn unzip>(mut iter: V) -> (Vec, Vec) { let (lo, _) = iter.size_hint(); diff --git a/src/libcollections/vec_map.rs b/src/libcollections/vec_map.rs index 5762acb8e71..9f1a0075352 100644 --- a/src/libcollections/vec_map.rs +++ b/src/libcollections/vec_map.rs @@ -19,7 +19,7 @@ use core::default::Default; use core::fmt; use core::hash::{Hash, Writer}; use core::iter; -use core::iter::{Enumerate, FilterMap}; +use core::iter::{Enumerate, FilterMap, Map}; use core::mem::replace; use core::ops::FnOnce; @@ -66,7 +66,9 @@ pub struct VecMap { v: Vec>, } +#[stable] impl Default for VecMap { + #[stable] #[inline] fn default() -> VecMap { VecMap::new() } } @@ -144,7 +146,7 @@ impl VecMap { pub fn keys<'r>(&'r self) -> Keys<'r, V> { fn first((a, _): (A, B)) -> A { a } - self.iter().map(first) + Keys { iter: self.iter().map(first) } } /// Returns an iterator visiting all values in ascending order by the keys. @@ -153,7 +155,7 @@ impl VecMap { pub fn values<'r>(&'r self) -> Values<'r, V> { fn second((_, b): (A, B)) -> B { b } - self.iter().map(second) + Values { iter: self.iter().map(second) } } /// Returns an iterator visiting all key-value pairs in ascending order by the keys. @@ -240,7 +242,7 @@ impl VecMap { } let values = replace(&mut self.v, vec!()); - values.into_iter().enumerate().filter_map(filter) + MoveItems { iter: values.into_iter().enumerate().filter_map(filter) } } /// Return the number of elements in the map. @@ -603,7 +605,7 @@ macro_rules! double_ended_iterator { } } -/// Forward iterator over a map. +/// An iterator over the key-value pairs of a map. pub struct Entries<'a, V:'a> { front: uint, back: uint, @@ -613,7 +615,7 @@ pub struct Entries<'a, V:'a> { iterator!(impl Entries -> (uint, &'a V), as_ref) double_ended_iterator!(impl Entries -> (uint, &'a V), as_ref) -/// Forward iterator over the key-value pairs of a map, with the +/// An iterator over the key-value pairs of a map, with the /// values being mutable. pub struct MutEntries<'a, V:'a> { front: uint, @@ -624,19 +626,50 @@ pub struct MutEntries<'a, V:'a> { iterator!(impl MutEntries -> (uint, &'a mut V), as_mut) double_ended_iterator!(impl MutEntries -> (uint, &'a mut V), as_mut) -/// Forward iterator over the keys of a map -pub type Keys<'a, V> = iter::Map<(uint, &'a V), uint, Entries<'a, V>, fn((uint, &'a V)) -> uint>; +/// An iterator over the keys of a map. +pub struct Keys<'a, V: 'a> { + iter: Map<(uint, &'a V), uint, Entries<'a, V>, fn((uint, &'a V)) -> uint> +} -/// Forward iterator over the values of a map -pub type Values<'a, V> = - iter::Map<(uint, &'a V), &'a V, Entries<'a, V>, fn((uint, &'a V)) -> &'a V>; +/// An iterator over the values of a map. +pub struct Values<'a, V: 'a> { + iter: Map<(uint, &'a V), &'a V, Entries<'a, V>, fn((uint, &'a V)) -> &'a V> +} -/// Iterator over the key-value pairs of a map, the iterator consumes the map -pub type MoveItems = FilterMap< +/// A consuming iterator over the key-value pairs of a map. +pub struct MoveItems { + iter: FilterMap< (uint, Option), (uint, V), Enumerate>>, - fn((uint, Option)) -> Option<(uint, V)>>; + fn((uint, Option)) -> Option<(uint, V)>> +} + +impl<'a, V> Iterator for Keys<'a, V> { + fn next(&mut self) -> Option { self.iter.next() } + fn size_hint(&self) -> (uint, Option) { self.iter.size_hint() } +} +impl<'a, V> DoubleEndedIterator for Keys<'a, V> { + fn next_back(&mut self) -> Option { self.iter.next_back() } +} + + +impl<'a, V> Iterator<&'a V> for Values<'a, V> { + fn next(&mut self) -> Option<(&'a V)> { self.iter.next() } + fn size_hint(&self) -> (uint, Option) { self.iter.size_hint() } +} +impl<'a, V> DoubleEndedIterator<&'a V> for Values<'a, V> { + fn next_back(&mut self) -> Option<(&'a V)> { self.iter.next_back() } +} + + +impl Iterator<(uint, V)> for MoveItems { + fn next(&mut self) -> Option<(uint, V)> { self.iter.next() } + fn size_hint(&self) -> (uint, Option) { self.iter.size_hint() } +} +impl DoubleEndedIterator<(uint, V)> for MoveItems { + fn next_back(&mut self) -> Option<(uint, V)> { self.iter.next_back() } +} #[cfg(test)] mod test_map { diff --git a/src/libcore/atomic.rs b/src/libcore/atomic.rs index 748f5d774a4..bb2fed19e2a 100644 --- a/src/libcore/atomic.rs +++ b/src/libcore/atomic.rs @@ -15,7 +15,6 @@ pub use self::Ordering::*; use intrinsics; -use std::kinds::marker; use cell::UnsafeCell; use kinds::Copy; @@ -23,28 +22,24 @@ use kinds::Copy; #[stable] pub struct AtomicBool { v: UnsafeCell, - nocopy: marker::NoCopy } /// A signed integer type which can be safely shared between threads. #[stable] pub struct AtomicInt { v: UnsafeCell, - nocopy: marker::NoCopy } /// An unsigned integer type which can be safely shared between threads. #[stable] pub struct AtomicUint { v: UnsafeCell, - nocopy: marker::NoCopy } /// A raw pointer type which can be safely shared between threads. #[stable] pub struct AtomicPtr { p: UnsafeCell, - nocopy: marker::NoCopy } /// Atomic memory orderings @@ -87,15 +82,15 @@ impl Copy for Ordering {} /// An `AtomicBool` initialized to `false`. #[unstable = "may be renamed, pending conventions for static initalizers"] pub const INIT_ATOMIC_BOOL: AtomicBool = - AtomicBool { v: UnsafeCell { value: 0 }, nocopy: marker::NoCopy }; + AtomicBool { v: UnsafeCell { value: 0 } }; /// An `AtomicInt` initialized to `0`. #[unstable = "may be renamed, pending conventions for static initalizers"] pub const INIT_ATOMIC_INT: AtomicInt = - AtomicInt { v: UnsafeCell { value: 0 }, nocopy: marker::NoCopy }; + AtomicInt { v: UnsafeCell { value: 0 } }; /// An `AtomicUint` initialized to `0`. #[unstable = "may be renamed, pending conventions for static initalizers"] pub const INIT_ATOMIC_UINT: AtomicUint = - AtomicUint { v: UnsafeCell { value: 0, }, nocopy: marker::NoCopy }; + AtomicUint { v: UnsafeCell { value: 0, } }; // NB: Needs to be -1 (0b11111111...) to make fetch_nand work correctly const UINT_TRUE: uint = -1; @@ -115,7 +110,7 @@ impl AtomicBool { #[stable] pub fn new(v: bool) -> AtomicBool { let val = if v { UINT_TRUE } else { 0 }; - AtomicBool { v: UnsafeCell::new(val), nocopy: marker::NoCopy } + AtomicBool { v: UnsafeCell::new(val) } } /// Loads a value from the bool. @@ -355,7 +350,7 @@ impl AtomicInt { #[inline] #[stable] pub fn new(v: int) -> AtomicInt { - AtomicInt {v: UnsafeCell::new(v), nocopy: marker::NoCopy} + AtomicInt {v: UnsafeCell::new(v)} } /// Loads a value from the int. @@ -541,7 +536,7 @@ impl AtomicUint { #[inline] #[stable] pub fn new(v: uint) -> AtomicUint { - AtomicUint { v: UnsafeCell::new(v), nocopy: marker::NoCopy } + AtomicUint { v: UnsafeCell::new(v) } } /// Loads a value from the uint. @@ -728,7 +723,7 @@ impl AtomicPtr { #[inline] #[stable] pub fn new(p: *mut T) -> AtomicPtr { - AtomicPtr { p: UnsafeCell::new(p as uint), nocopy: marker::NoCopy } + AtomicPtr { p: UnsafeCell::new(p as uint) } } /// Loads a value from the pointer. diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index 1ec2efaf801..01979e97577 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -215,8 +215,9 @@ impl Clone for Cell { } } -#[unstable] +#[stable] impl Default for Cell { + #[stable] fn default() -> Cell { Cell::new(Default::default()) } @@ -234,7 +235,6 @@ impl PartialEq for Cell { pub struct RefCell { value: UnsafeCell, borrow: Cell, - nocopy: marker::NoCopy, noshare: marker::NoSync, } @@ -251,7 +251,6 @@ impl RefCell { RefCell { value: UnsafeCell::new(value), borrow: Cell::new(UNUSED), - nocopy: marker::NoCopy, noshare: marker::NoSync, } } @@ -349,8 +348,9 @@ impl Clone for RefCell { } } -#[unstable] +#[stable] impl Default for RefCell { + #[stable] fn default() -> RefCell { RefCell::new(Default::default()) } diff --git a/src/libcore/char.rs b/src/libcore/char.rs index fbc444c2be3..9c12b3f68d3 100644 --- a/src/libcore/char.rs +++ b/src/libcore/char.rs @@ -15,11 +15,11 @@ #![allow(non_snake_case)] #![doc(primitive = "char")] +use iter::Iterator; use mem::transmute; use ops::FnMut; -use option::Option; use option::Option::{None, Some}; -use iter::{range_step, Iterator, RangeStep}; +use option::Option; use slice::SliceExt; // UTF-8 ranges and tags for encoding characters @@ -141,7 +141,7 @@ pub fn to_digit(c: char, radix: uint) -> Option { #[unstable = "pending decisions about costructors for primitives"] pub fn from_digit(num: uint, radix: uint) -> Option { if radix > 36 { - panic!("from_digit: radix is to high (maximum 36)"); + panic!("from_digit: radix is too high (maximum 36)"); } if num < radix { unsafe { @@ -156,15 +156,7 @@ pub fn from_digit(num: uint, radix: uint) -> Option { } } -/// -/// Returns the hexadecimal Unicode escape of a `char` -/// -/// The rules are as follows: -/// -/// - chars in [0,0xff] get 2-digit escapes: `\\xNN` -/// - chars in [0x100,0xffff] get 4-digit escapes: `\\u{NNNN}` -/// - chars above 0x10000 get 8-digit escapes: `\\u{{NNN}NNNNN}` -/// +/// Deprecated, call the escape_unicode method instead. #[deprecated = "use the Char::escape_unicode method"] pub fn escape_unicode(c: char, mut f: F) where F: FnMut(char) { for char in c.escape_unicode() { @@ -172,18 +164,7 @@ pub fn escape_unicode(c: char, mut f: F) where F: FnMut(char) { } } -/// -/// Returns a 'default' ASCII and C++11-like literal escape of a `char` -/// -/// The default is chosen with a bias toward producing literals that are -/// legal in a variety of languages, including C++11 and similar C-family -/// languages. The exact rules are: -/// -/// - Tab, CR and LF are escaped as '\t', '\r' and '\n' respectively. -/// - Single-quote, double-quote and backslash chars are backslash-escaped. -/// - Any other chars in the range [0x20,0x7e] are not escaped. -/// - Any other chars are given hex Unicode escapes; see `escape_unicode`. -/// +/// Deprecated, call the escape_default method instead. #[deprecated = "use the Char::escape_default method"] pub fn escape_default(c: char, mut f: F) where F: FnMut(char) { for c in c.escape_default() { @@ -267,13 +248,11 @@ pub trait Char { /// Returns an iterator that yields the hexadecimal Unicode escape /// of a character, as `char`s. /// - /// The rules are as follows: - /// - /// * Characters in [0,0xff] get 2-digit escapes: `\\xNN` - /// * Characters in [0x100,0xffff] get 4-digit escapes: `\\u{NNNN}`. - /// * Characters above 0x10000 get 8-digit escapes: `\\u{{NNN}NNNNN}`. + /// All characters are escaped with Rust syntax of the form `\\u{NNNN}` + /// where `NNNN` is the shortest hexadecimal representation of the code + /// point. #[unstable = "pending error conventions, trait organization"] - fn escape_unicode(self) -> UnicodeEscapedChars; + fn escape_unicode(self) -> EscapeUnicode; /// Returns an iterator that yields the 'default' ASCII and /// C++11-like literal escape of a character, as `char`s. @@ -288,7 +267,7 @@ pub trait Char { /// * Any other chars in the range [0x20,0x7e] are not escaped. /// * Any other chars are given hex Unicode escapes; see `escape_unicode`. #[unstable = "pending error conventions, trait organization"] - fn escape_default(self) -> DefaultEscapedChars; + fn escape_default(self) -> EscapeDefault; /// Returns the amount of bytes this character would need if encoded in /// UTF-8. @@ -358,23 +337,23 @@ impl Char for char { fn from_u32(i: u32) -> Option { from_u32(i) } #[unstable = "pending error conventions, trait organization"] - fn escape_unicode(self) -> UnicodeEscapedChars { - UnicodeEscapedChars { c: self, state: UnicodeEscapedCharsState::Backslash } + fn escape_unicode(self) -> EscapeUnicode { + EscapeUnicode { c: self, state: EscapeUnicodeState::Backslash } } #[unstable = "pending error conventions, trait organization"] - fn escape_default(self) -> DefaultEscapedChars { + fn escape_default(self) -> EscapeDefault { let init_state = match self { - '\t' => DefaultEscapedCharsState::Backslash('t'), - '\r' => DefaultEscapedCharsState::Backslash('r'), - '\n' => DefaultEscapedCharsState::Backslash('n'), - '\\' => DefaultEscapedCharsState::Backslash('\\'), - '\'' => DefaultEscapedCharsState::Backslash('\''), - '"' => DefaultEscapedCharsState::Backslash('"'), - '\x20' ... '\x7e' => DefaultEscapedCharsState::Char(self), - _ => DefaultEscapedCharsState::Unicode(self.escape_unicode()) + '\t' => EscapeDefaultState::Backslash('t'), + '\r' => EscapeDefaultState::Backslash('r'), + '\n' => EscapeDefaultState::Backslash('n'), + '\\' => EscapeDefaultState::Backslash('\\'), + '\'' => EscapeDefaultState::Backslash('\''), + '"' => EscapeDefaultState::Backslash('"'), + '\x20' ... '\x7e' => EscapeDefaultState::Char(self), + _ => EscapeDefaultState::Unicode(self.escape_unicode()) }; - DefaultEscapedChars { state: init_state } + EscapeDefault { state: init_state } } #[inline] @@ -451,72 +430,86 @@ impl Char for char { /// An iterator over the characters that represent a `char`, as escaped by /// Rust's unicode escaping rules. -pub struct UnicodeEscapedChars { +pub struct EscapeUnicode { c: char, - state: UnicodeEscapedCharsState + state: EscapeUnicodeState } -enum UnicodeEscapedCharsState { +enum EscapeUnicodeState { Backslash, Type, - Value(RangeStep), + LeftBrace, + Value(uint), + RightBrace, + Done, } -impl Iterator for UnicodeEscapedChars { +impl Iterator for EscapeUnicode { fn next(&mut self) -> Option { match self.state { - UnicodeEscapedCharsState::Backslash => { - self.state = UnicodeEscapedCharsState::Type; + EscapeUnicodeState::Backslash => { + self.state = EscapeUnicodeState::Type; Some('\\') } - UnicodeEscapedCharsState::Type => { - let (typechar, pad) = if self.c <= '\x7f' { ('x', 2) } - else if self.c <= '\u{ffff}' { ('u', 4) } - else { ('U', 8) }; - self.state = UnicodeEscapedCharsState::Value(range_step(4 * (pad - 1), -1, -4i32)); - Some(typechar) + EscapeUnicodeState::Type => { + self.state = EscapeUnicodeState::LeftBrace; + Some('u') } - UnicodeEscapedCharsState::Value(ref mut range_step) => match range_step.next() { - Some(offset) => { - let offset = offset as uint; - let v = match ((self.c as i32) >> offset) & 0xf { - i @ 0 ... 9 => '0' as i32 + i, - i => 'a' as i32 + (i - 10) - }; - Some(unsafe { transmute(v) }) + EscapeUnicodeState::LeftBrace => { + let mut n = 0u; + while (self.c as u32) >> (4 * (n + 1)) != 0 { + n += 1; } - None => None + self.state = EscapeUnicodeState::Value(n); + Some('{') } + EscapeUnicodeState::Value(offset) => { + let v = match ((self.c as i32) >> (offset * 4)) & 0xf { + i @ 0 ... 9 => '0' as i32 + i, + i => 'a' as i32 + (i - 10) + }; + if offset == 0 { + self.state = EscapeUnicodeState::RightBrace; + } else { + self.state = EscapeUnicodeState::Value(offset - 1); + } + Some(unsafe { transmute(v) }) + } + EscapeUnicodeState::RightBrace => { + self.state = EscapeUnicodeState::Done; + Some('}') + } + EscapeUnicodeState::Done => None, } } } /// An iterator over the characters that represent a `char`, escaped /// for maximum portability. -pub struct DefaultEscapedChars { - state: DefaultEscapedCharsState +pub struct EscapeDefault { + state: EscapeDefaultState } -enum DefaultEscapedCharsState { +enum EscapeDefaultState { Backslash(char), Char(char), Done, - Unicode(UnicodeEscapedChars), + Unicode(EscapeUnicode), } -impl Iterator for DefaultEscapedChars { +impl Iterator for EscapeDefault { fn next(&mut self) -> Option { match self.state { - DefaultEscapedCharsState::Backslash(c) => { - self.state = DefaultEscapedCharsState::Char(c); + EscapeDefaultState::Backslash(c) => { + self.state = EscapeDefaultState::Char(c); Some('\\') } - DefaultEscapedCharsState::Char(c) => { - self.state = DefaultEscapedCharsState::Done; + EscapeDefaultState::Char(c) => { + self.state = EscapeDefaultState::Done; Some(c) } - DefaultEscapedCharsState::Done => None, - DefaultEscapedCharsState::Unicode(ref mut iter) => iter.next() + EscapeDefaultState::Done => None, + EscapeDefaultState::Unicode(ref mut iter) => iter.next() } } } diff --git a/src/libcore/default.rs b/src/libcore/default.rs index 269a456542c..10facfe4750 100644 --- a/src/libcore/default.rs +++ b/src/libcore/default.rs @@ -97,6 +97,7 @@ /// bar: f32, /// } /// ``` +#[stable] pub trait Default { /// Returns the "default value" for a type. /// @@ -130,13 +131,16 @@ pub trait Default { /// fn default() -> Kind { Kind::A } /// } /// ``` + #[stable] fn default() -> Self; } macro_rules! default_impl( ($t:ty, $v:expr) => { + #[stable] impl Default for $t { #[inline] + #[stable] fn default() -> $t { $v } } } diff --git a/src/libcore/hash/sip.rs b/src/libcore/hash/sip.rs index 62752072e2f..1f511ed759e 100644 --- a/src/libcore/hash/sip.rs +++ b/src/libcore/hash/sip.rs @@ -203,8 +203,10 @@ impl Clone for SipState { } } +#[stable] impl Default for SipState { #[inline] + #[stable] fn default() -> SipState { SipState::new() } diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 2fc4d23e7fd..e2afee9905d 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -217,6 +217,7 @@ extern "rust-intrinsic" { /// /// `forget` is unsafe because the caller is responsible for /// ensuring the argument is deallocated already. + #[stable] pub fn forget(_: T) -> (); /// Unsafely transforms a value of one type into a value of another type. @@ -232,6 +233,7 @@ extern "rust-intrinsic" { /// let v: &[u8] = unsafe { mem::transmute("L") }; /// assert!(v == [76u8]); /// ``` + #[stable] pub fn transmute(e: T) -> U; /// Gives the address for the return value of the enclosing function. diff --git a/src/libcore/iter.rs b/src/libcore/iter.rs index 5405c7aa3b7..7e0380e8785 100644 --- a/src/libcore/iter.rs +++ b/src/libcore/iter.rs @@ -110,8 +110,8 @@ pub trait Iterator { #[unstable = "new convention for extension traits"] /// An extension trait providing numerous methods applicable to all iterators. pub trait IteratorExt: Iterator { - /// Chain this iterator with another, returning a new iterator which will - /// finish iterating over the current iterator, and then it will iterate + /// Chain this iterator with another, returning a new iterator that will + /// finish iterating over the current iterator, and then iterate /// over the other specified iterator. /// /// # Example @@ -130,7 +130,7 @@ pub trait IteratorExt: Iterator { Chain{a: self, b: other, flag: false} } - /// Creates an iterator which iterates over both this and the specified + /// Creates an iterator that iterates over both this and the specified /// iterators simultaneously, yielding the two elements as pairs. When /// either iterator returns None, all further invocations of next() will /// return None. @@ -151,7 +151,7 @@ pub trait IteratorExt: Iterator { Zip{a: self, b: other} } - /// Creates a new iterator which will apply the specified function to each + /// Creates a new iterator that will apply the specified function to each /// element returned by the first, yielding the mapped element instead. /// /// # Example @@ -169,8 +169,8 @@ pub trait IteratorExt: Iterator { Map{iter: self, f: f} } - /// Creates an iterator which applies the predicate to each element returned - /// by this iterator. Only elements which have the predicate evaluate to + /// Creates an iterator that applies the predicate to each element returned + /// by this iterator. Only elements that have the predicate evaluate to /// `true` will be yielded. /// /// # Example @@ -187,7 +187,7 @@ pub trait IteratorExt: Iterator { Filter{iter: self, predicate: predicate} } - /// Creates an iterator which both filters and maps elements. + /// Creates an iterator that both filters and maps elements. /// If the specified function returns None, the element is skipped. /// Otherwise the option is unwrapped and the new value is yielded. /// @@ -205,7 +205,7 @@ pub trait IteratorExt: Iterator { FilterMap { iter: self, f: f } } - /// Creates an iterator which yields a pair of the value returned by this + /// Creates an iterator that yields a pair of the value returned by this /// iterator plus the current index of iteration. /// /// # Example @@ -248,7 +248,7 @@ pub trait IteratorExt: Iterator { Peekable{iter: self, peeked: None} } - /// Creates an iterator which invokes the predicate on elements until it + /// Creates an iterator that invokes the predicate on elements until it /// returns false. Once the predicate returns false, all further elements are /// yielded. /// @@ -268,7 +268,7 @@ pub trait IteratorExt: Iterator { SkipWhile{iter: self, flag: false, predicate: predicate} } - /// Creates an iterator which yields elements so long as the predicate + /// Creates an iterator that yields elements so long as the predicate /// returns true. After the predicate returns false for the first time, no /// further elements will be yielded. /// @@ -287,8 +287,8 @@ pub trait IteratorExt: Iterator { TakeWhile{iter: self, flag: false, predicate: predicate} } - /// Creates an iterator which skips the first `n` elements of this iterator, - /// and then it yields all further items. + /// Creates an iterator that skips the first `n` elements of this iterator, + /// and then yields all further items. /// /// # Example /// @@ -305,8 +305,8 @@ pub trait IteratorExt: Iterator { Skip{iter: self, n: n} } - /// Creates an iterator which yields the first `n` elements of this - /// iterator, and then it will always return None. + /// Creates an iterator that yields the first `n` elements of this + /// iterator, and then will always return None. /// /// # Example /// @@ -324,7 +324,7 @@ pub trait IteratorExt: Iterator { Take{iter: self, n: n} } - /// Creates a new iterator which behaves in a similar fashion to fold. + /// Creates a new iterator that behaves in a similar fashion to fold. /// There is a state which is passed between each iteration and can be /// mutated as necessary. The yielded values from the closure are yielded /// from the Scan instance when not None. @@ -1223,7 +1223,7 @@ impl> RandomAccessIterator for Cycle } } -/// An iterator which strings two iterators together +/// An iterator that strings two iterators together #[deriving(Clone)] #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] #[stable] @@ -1297,7 +1297,7 @@ for Chain { } } -/// An iterator which iterates two other iterators simultaneously +/// An iterator that iterates two other iterators simultaneously #[deriving(Clone)] #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] #[stable] @@ -1380,7 +1380,7 @@ RandomAccessIterator<(A, B)> for Zip { } } -/// An iterator which maps the values of `iter` with `f` +/// An iterator that maps the values of `iter` with `f` #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] #[stable] pub struct Map, F: FnMut(A) -> B> { @@ -1388,6 +1388,19 @@ pub struct Map, F: FnMut(A) -> B> { f: F, } +// FIXME(#19839) Remove in favor of `#[deriving(Clone)]` +impl Clone for Map where + I: Clone + Iterator, + F: Clone + FnMut(A) -> B, +{ + fn clone(&self) -> Map { + Map { + iter: self.iter.clone(), + f: self.f.clone(), + } + } +} + impl Map where I: Iterator, F: FnMut(A) -> B { #[inline] fn do_map(&mut self, elt: Option) -> Option { @@ -1441,7 +1454,7 @@ impl RandomAccessIterator for Map where } } -/// An iterator which filters the elements of `iter` with `predicate` +/// An iterator that filters the elements of `iter` with `predicate` #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] #[stable] pub struct Filter where I: Iterator, P: FnMut(&A) -> bool { @@ -1449,6 +1462,19 @@ pub struct Filter where I: Iterator, P: FnMut(&A) -> bool { predicate: P, } +// FIXME(#19839) Remove in favor of `#[deriving(Clone)]` +impl Clone for Filter where + I: Clone + Iterator, + P: Clone + FnMut(&A) -> bool, +{ + fn clone(&self) -> Filter { + Filter { + iter: self.iter.clone(), + predicate: self.predicate.clone(), + } + } +} + #[unstable = "trait is unstable"] impl Iterator for Filter where I: Iterator, P: FnMut(&A) -> bool { #[inline] @@ -1486,7 +1512,7 @@ impl DoubleEndedIterator for Filter where } } -/// An iterator which uses `f` to both filter and map elements from `iter` +/// An iterator that uses `f` to both filter and map elements from `iter` #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] #[stable] pub struct FilterMap where I: Iterator, F: FnMut(A) -> Option { @@ -1494,6 +1520,19 @@ pub struct FilterMap where I: Iterator, F: FnMut(A) -> Option f: F, } +// FIXME(#19839) Remove in favor of `#[deriving(Clone)]` +impl Clone for FilterMap where + I: Clone + Iterator, + F: Clone + FnMut(A) -> Option, +{ + fn clone(&self) -> FilterMap { + FilterMap { + iter: self.iter.clone(), + f: self.f.clone(), + } + } +} + #[unstable = "trait is unstable"] impl Iterator for FilterMap where I: Iterator, @@ -1534,7 +1573,7 @@ impl DoubleEndedIterator for FilterMap where } } -/// An iterator which yields the current count and the element during iteration +/// An iterator that yields the current count and the element during iteration #[deriving(Clone)] #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] #[stable] @@ -1648,7 +1687,7 @@ impl<'a, A, T: Iterator> Peekable { } } -/// An iterator which rejects elements while `predicate` is true +/// An iterator that rejects elements while `predicate` is true #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] #[stable] pub struct SkipWhile where I: Iterator, P: FnMut(&A) -> bool { @@ -1657,6 +1696,20 @@ pub struct SkipWhile where I: Iterator, P: FnMut(&A) -> bool { predicate: P, } +// FIXME(#19839) Remove in favor of `#[deriving(Clone)]` +impl Clone for SkipWhile where + I: Clone + Iterator, + P: Clone + FnMut(&A) -> bool, +{ + fn clone(&self) -> SkipWhile { + SkipWhile { + iter: self.iter.clone(), + flag: self.flag, + predicate: self.predicate.clone(), + } + } +} + #[unstable = "trait is unstable"] impl Iterator for SkipWhile where I: Iterator, P: FnMut(&A) -> bool { #[inline] @@ -1677,7 +1730,7 @@ impl Iterator for SkipWhile where I: Iterator, P: FnMut( } } -/// An iterator which only accepts elements while `predicate` is true +/// An iterator that only accepts elements while `predicate` is true #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] #[stable] pub struct TakeWhile where I: Iterator, P: FnMut(&A) -> bool { @@ -1686,6 +1739,20 @@ pub struct TakeWhile where I: Iterator, P: FnMut(&A) -> bool { predicate: P, } +// FIXME(#19839) Remove in favor of `#[deriving(Clone)]` +impl Clone for TakeWhile where + I: Clone + Iterator, + P: Clone + FnMut(&A) -> bool, +{ + fn clone(&self) -> TakeWhile { + TakeWhile { + iter: self.iter.clone(), + flag: self.flag, + predicate: self.predicate.clone(), + } + } +} + #[unstable = "trait is unstable"] impl Iterator for TakeWhile where I: Iterator, P: FnMut(&A) -> bool { #[inline] @@ -1714,7 +1781,7 @@ impl Iterator for TakeWhile where I: Iterator, P: FnMut( } } -/// An iterator which skips over `n` elements of `iter`. +/// An iterator that skips over `n` elements of `iter`. #[deriving(Clone)] #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] #[stable] @@ -1782,7 +1849,7 @@ impl> RandomAccessIterator for Skip { } } -/// An iterator which only iterates over the first `n` iterations of `iter`. +/// An iterator that only iterates over the first `n` iterations of `iter`. #[deriving(Clone)] #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] #[stable] @@ -1847,6 +1914,21 @@ pub struct Scan where I: Iterator, F: FnMut(&mut St, A) -> Op pub state: St, } +// FIXME(#19839) Remove in favor of `#[deriving(Clone)]` +impl Clone for Scan where + I: Clone + Iterator, + St: Clone, + F: Clone + FnMut(&mut St, A) -> Option, +{ + fn clone(&self) -> Scan { + Scan { + iter: self.iter.clone(), + f: self.f.clone(), + state: self.state.clone(), + } + } +} + #[unstable = "trait is unstable"] impl Iterator for Scan where I: Iterator, @@ -1876,6 +1958,22 @@ pub struct FlatMap where I: Iterator, U: Iterator, F: FnMut backiter: Option, } +// FIXME(#19839) Remove in favor of `#[deriving(Clone)]` +impl Clone for FlatMap where + I: Clone + Iterator, + U: Clone + Iterator, + F: Clone + FnMut(A) -> U, +{ + fn clone(&self) -> FlatMap { + FlatMap { + iter: self.iter.clone(), + f: self.f.clone(), + frontiter: self.frontiter.clone(), + backiter: self.backiter.clone(), + } + } +} + #[unstable = "trait is unstable"] impl Iterator for FlatMap where I: Iterator, @@ -2020,6 +2118,19 @@ pub struct Inspect where I: Iterator, F: FnMut(&A) { f: F, } +// FIXME(#19839) Remove in favor of `#[deriving(Clone)]` +impl Clone for Inspect where + I: Clone + Iterator, + F: Clone + FnMut(&A), +{ + fn clone(&self) -> Inspect { + Inspect { + iter: self.iter.clone(), + f: self.f.clone(), + } + } +} + impl Inspect where I: Iterator, F: FnMut(&A) { #[inline] fn do_inspect(&mut self, elt: Option) -> Option { @@ -2075,7 +2186,7 @@ impl RandomAccessIterator for Inspect where } } -/// An iterator which passes mutable state to a closure and yields the result. +/// An iterator that passes mutable state to a closure and yields the result. /// /// # Example: The Fibonacci Sequence /// @@ -2114,6 +2225,19 @@ pub struct Unfold where F: FnMut(&mut St) -> Option { pub state: St, } +// FIXME(#19839) Remove in favor of `#[deriving(Clone)]` +impl Clone for Unfold where + F: Clone + FnMut(&mut St) -> Option, + St: Clone, +{ + fn clone(&self) -> Unfold { + Unfold { + f: self.f.clone(), + state: self.state.clone(), + } + } +} + #[experimental] impl Unfold where F: FnMut(&mut St) -> Option { /// Creates a new iterator with the specified closure as the "iterator diff --git a/src/libcore/kinds.rs b/src/libcore/kinds.rs index 2b92ae8af0a..69f65e23389 100644 --- a/src/libcore/kinds.rs +++ b/src/libcore/kinds.rs @@ -259,13 +259,14 @@ pub mod marker { #[deriving(Clone, PartialEq, Eq, PartialOrd, Ord)] pub struct InvariantLifetime<'a>; + impl<'a> Copy for InvariantLifetime<'a> {} + /// A type which is considered "not sendable", meaning that it cannot /// be safely sent between tasks, even if it is owned. This is /// typically embedded in other types, such as `Gc`, to ensure that /// their instances remain thread-local. #[lang="no_send_bound"] - #[deriving(Clone, PartialEq, Eq, PartialOrd, Ord)] - #[allow(missing_copy_implementations)] + #[deriving(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] pub struct NoSend; /// A type which is considered "not POD", meaning that it is not @@ -280,8 +281,7 @@ pub mod marker { /// its contents are not threadsafe, hence they cannot be /// shared between tasks. #[lang="no_sync_bound"] - #[deriving(Clone, PartialEq, Eq, PartialOrd, Ord)] - #[allow(missing_copy_implementations)] + #[deriving(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] pub struct NoSync; /// A type which is considered managed by the GC. This is typically diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index 937f73a3262..2620928acc1 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -13,9 +13,13 @@ //! This module contains functions for querying the size and alignment of //! types, initializing and manipulating memory. +#![stable] + +use kinds::Sized; use intrinsics; use ptr; +#[stable] pub use intrinsics::transmute; /// Moves a thing into the void. @@ -29,6 +33,14 @@ pub use intrinsics::transmute; pub use intrinsics::forget; /// Returns the size of a type in bytes. +/// +/// # Examples +/// +/// ``` +/// use std::mem; +/// +/// assert_eq!(4, mem::size_of::()); +/// ``` #[inline] #[stable] pub fn size_of() -> uint { @@ -36,6 +48,14 @@ pub fn size_of() -> uint { } /// Returns the size of the type that `_val` points to in bytes. +/// +/// # Examples +/// +/// ``` +/// use std::mem; +/// +/// assert_eq!(4, mem::size_of_val(&5i32)); +/// ``` #[inline] #[stable] pub fn size_of_val(_val: &T) -> uint { @@ -44,16 +64,30 @@ pub fn size_of_val(_val: &T) -> uint { /// Returns the ABI-required minimum alignment of a type /// -/// This is the alignment used for struct fields. It may be smaller -/// than the preferred alignment. +/// This is the alignment used for struct fields. It may be smaller than the preferred alignment. +/// +/// # Examples +/// +/// ``` +/// use std::mem; +/// +/// assert_eq!(4, mem::min_align_of::()); +/// ``` #[inline] #[stable] pub fn min_align_of() -> uint { unsafe { intrinsics::min_align_of::() } } -/// Returns the ABI-required minimum alignment of the type of the value that -/// `_val` points to +/// Returns the ABI-required minimum alignment of the type of the value that `_val` points to +/// +/// # Examples +/// +/// ``` +/// use std::mem; +/// +/// assert_eq!(4, mem::min_align_of_val(&5i32)); +/// ``` #[inline] #[stable] pub fn min_align_of_val(_val: &T) -> uint { @@ -62,9 +96,16 @@ pub fn min_align_of_val(_val: &T) -> uint { /// Returns the alignment in memory for a type. /// -/// This function will return the alignment, in bytes, of a type in memory. If -/// the alignment returned is adhered to, then the type is guaranteed to -/// function properly. +/// This function will return the alignment, in bytes, of a type in memory. If the alignment +/// returned is adhered to, then the type is guaranteed to function properly. +/// +/// # Examples +/// +/// ``` +/// use std::mem; +/// +/// assert_eq!(4, mem::align_of::()); +/// ``` #[inline] #[stable] pub fn align_of() -> uint { @@ -77,9 +118,16 @@ pub fn align_of() -> uint { /// Returns the alignment of the type of the value that `_val` points to. /// -/// This is similar to `align_of`, but function will properly handle types such -/// as trait objects (in the future), returning the alignment for an arbitrary -/// value at runtime. +/// This is similar to `align_of`, but function will properly handle types such as trait objects +/// (in the future), returning the alignment for an arbitrary value at runtime. +/// +/// # Examples +/// +/// ``` +/// use std::mem; +/// +/// assert_eq!(4, mem::align_of_val(&5i32)); +/// ``` #[inline] #[stable] pub fn align_of_val(_val: &T) -> uint { @@ -88,15 +136,22 @@ pub fn align_of_val(_val: &T) -> uint { /// Create a value initialized to zero. /// -/// This function is similar to allocating space for a local variable and -/// zeroing it out (an unsafe operation). +/// This function is similar to allocating space for a local variable and zeroing it out (an unsafe +/// operation). /// -/// Care must be taken when using this function, if the type `T` has a -/// destructor and the value falls out of scope (due to unwinding or returning) -/// before being initialized, then the destructor will run on zeroed -/// data, likely leading to crashes. +/// Care must be taken when using this function, if the type `T` has a destructor and the value +/// falls out of scope (due to unwinding or returning) before being initialized, then the +/// destructor will run on zeroed data, likely leading to crashes. /// /// This is useful for FFI functions sometimes, but should generally be avoided. +/// +/// # Examples +/// +/// ``` +/// use std::mem; +/// +/// let x: int = unsafe { mem::zeroed() }; +/// ``` #[inline] #[stable] pub unsafe fn zeroed() -> T { @@ -105,20 +160,41 @@ pub unsafe fn zeroed() -> T { /// Create an uninitialized value. /// -/// Care must be taken when using this function, if the type `T` has a -/// destructor and the value falls out of scope (due to unwinding or returning) -/// before being initialized, then the destructor will run on uninitialized -/// data, likely leading to crashes. +/// Care must be taken when using this function, if the type `T` has a destructor and the value +/// falls out of scope (due to unwinding or returning) before being initialized, then the +/// destructor will run on uninitialized data, likely leading to crashes. /// /// This is useful for FFI functions sometimes, but should generally be avoided. +/// +/// # Examples +/// +/// ``` +/// use std::mem; +/// +/// let x: int = unsafe { mem::uninitialized() }; +/// ``` #[inline] #[stable] pub unsafe fn uninitialized() -> T { intrinsics::uninit() } -/// Swap the values at two mutable locations of the same type, without -/// deinitialising or copying either one. +/// Swap the values at two mutable locations of the same type, without deinitialising or copying +/// either one. +/// +/// # Examples +/// +/// ``` +/// use std::mem; +/// +/// let x = &mut 5i; +/// let y = &mut 42i; +/// +/// mem::swap(x, y); +/// +/// assert_eq!(42i, *x); +/// assert_eq!(5i, *y); +/// ``` #[inline] #[stable] pub fn swap(x: &mut T, y: &mut T) { @@ -137,13 +213,26 @@ pub fn swap(x: &mut T, y: &mut T) { } } -/// Replace the value at a mutable location with a new one, returning the old -/// value, without deinitialising or copying either one. +/// Replace the value at a mutable location with a new one, returning the old value, without +/// deinitialising or copying either one. /// -/// This is primarily used for transferring and swapping ownership of a value -/// in a mutable location. For example, this function allows consumption of -/// one field of a struct by replacing it with another value. The normal approach -/// doesn't always work: +/// This is primarily used for transferring and swapping ownership of a value in a mutable +/// location. +/// +/// # Examples +/// +/// A simple example: +/// +/// ``` +/// use std::mem; +/// +/// let mut v: Vec = Vec::new(); +/// +/// mem::replace(&mut v, Vec::new()); +/// ``` +/// +/// This function allows consumption of one field of a struct by replacing it with another value. +/// The normal approach doesn't always work: /// /// ```rust,ignore /// struct Buffer { buf: Vec } @@ -158,16 +247,16 @@ pub fn swap(x: &mut T, y: &mut T) { /// } /// ``` /// -/// Note that `T` does not necessarily implement `Clone`, so it can't even -/// clone and reset `self.buf`. But `replace` can be used to disassociate -/// the original value of `self.buf` from `self`, allowing it to be returned: +/// Note that `T` does not necessarily implement `Clone`, so it can't even clone and reset +/// `self.buf`. But `replace` can be used to disassociate the original value of `self.buf` from +/// `self`, allowing it to be returned: /// /// ```rust +/// use std::mem; /// # struct Buffer { buf: Vec } /// impl Buffer { /// fn get_and_reset(&mut self) -> Vec { -/// use std::mem::replace; -/// replace(&mut self.buf, Vec::new()) +/// mem::replace(&mut self.buf, Vec::new()) /// } /// } /// ``` @@ -180,10 +269,10 @@ pub fn replace(dest: &mut T, mut src: T) -> T { /// Disposes of a value. /// -/// This function can be used to destroy any value by allowing `drop` to take -/// ownership of its argument. +/// This function can be used to destroy any value by allowing `drop` to take ownership of its +/// argument. /// -/// # Example +/// # Examples /// /// ``` /// use std::cell::RefCell; @@ -192,6 +281,7 @@ pub fn replace(dest: &mut T, mut src: T) -> T { /// /// let mut mutable_borrow = x.borrow_mut(); /// *mutable_borrow = 1; +/// /// drop(mutable_borrow); // relinquish the mutable borrow on this slot /// /// let borrow = x.borrow(); @@ -201,18 +291,25 @@ pub fn replace(dest: &mut T, mut src: T) -> T { #[stable] pub fn drop(_x: T) { } -/// Interprets `src` as `&U`, and then reads `src` without moving the contained -/// value. +/// Interprets `src` as `&U`, and then reads `src` without moving the contained value. /// -/// This function will unsafely assume the pointer `src` is valid for -/// `sizeof(U)` bytes by transmuting `&T` to `&U` and then reading the `&U`. It -/// will also unsafely create a copy of the contained value instead of moving -/// out of `src`. +/// This function will unsafely assume the pointer `src` is valid for `sizeof(U)` bytes by +/// transmuting `&T` to `&U` and then reading the `&U`. It will also unsafely create a copy of the +/// contained value instead of moving out of `src`. /// -/// It is not a compile-time error if `T` and `U` have different sizes, but it -/// is highly encouraged to only invoke this function where `T` and `U` have the -/// same size. This function triggers undefined behavior if `U` is larger than -/// `T`. +/// It is not a compile-time error if `T` and `U` have different sizes, but it is highly encouraged +/// to only invoke this function where `T` and `U` have the same size. This function triggers +/// undefined behavior if `U` is larger than `T`. +/// +/// # Examples +/// +/// ``` +/// use std::mem; +/// +/// let one = unsafe { mem::transmute_copy(&1i) }; +/// +/// assert_eq!(1u, one); +/// ``` #[inline] #[stable] pub unsafe fn transmute_copy(src: &T) -> U { @@ -223,7 +320,8 @@ pub unsafe fn transmute_copy(src: &T) -> U { #[inline] #[unstable = "this function may be removed in the future due to its \ questionable utility"] -pub unsafe fn copy_lifetime<'a, S, T:'a>(_ptr: &'a S, ptr: &T) -> &'a T { +pub unsafe fn copy_lifetime<'a, Sized? S, Sized? T: 'a>(_ptr: &'a S, + ptr: &T) -> &'a T { transmute(ptr) } @@ -231,7 +329,8 @@ pub unsafe fn copy_lifetime<'a, S, T:'a>(_ptr: &'a S, ptr: &T) -> &'a T { #[inline] #[unstable = "this function may be removed in the future due to its \ questionable utility"] -pub unsafe fn copy_mut_lifetime<'a, S, T:'a>(_ptr: &'a mut S, - ptr: &mut T) -> &'a mut T { +pub unsafe fn copy_mut_lifetime<'a, Sized? S, Sized? T: 'a>(_ptr: &'a mut S, + ptr: &mut T) + -> &'a mut T { transmute(ptr) } diff --git a/src/libcore/option.rs b/src/libcore/option.rs index 020e907a423..deb1cea1c0e 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -168,8 +168,10 @@ use ops::{Deref, FnOnce}; #[stable] pub enum Option { /// No value + #[stable] None, /// Some value `T` + #[stable] Some(T) } @@ -261,7 +263,7 @@ impl Option { /// assert_eq!(x, Some(42u)); /// ``` #[inline] - #[unstable = "waiting for mut conventions"] + #[stable] pub fn as_mut<'r>(&'r mut self) -> Option<&'r mut T> { match *self { Some(ref mut x) => Some(x), @@ -321,7 +323,7 @@ impl Option { /// x.expect("the world is ending"); // panics with `world is ending` /// ``` #[inline] - #[unstable = "waiting for conventions"] + #[stable] pub fn expect(self, msg: &str) -> T { match self { Some(val) => val, @@ -353,7 +355,7 @@ impl Option { /// assert_eq!(x.unwrap(), "air"); // fails /// ``` #[inline] - #[unstable = "waiting for conventions"] + #[stable] pub fn unwrap(self) -> T { match self { Some(val) => val, @@ -370,7 +372,7 @@ impl Option { /// assert_eq!(None.unwrap_or("bike"), "bike"); /// ``` #[inline] - #[unstable = "waiting for conventions"] + #[stable] pub fn unwrap_or(self, def: T) -> T { match self { Some(x) => x, @@ -388,7 +390,7 @@ impl Option { /// assert_eq!(None.unwrap_or_else(|| 2 * k), 20u); /// ``` #[inline] - #[unstable = "waiting for conventions"] + #[stable] pub fn unwrap_or_else T>(self, f: F) -> T { match self { Some(x) => x, @@ -412,7 +414,7 @@ impl Option { /// let num_as_int: Option = num_as_str.map(|n| n.len()); /// ``` #[inline] - #[unstable = "waiting for unboxed closures"] + #[stable] pub fn map U>(self, f: F) -> Option { match self { Some(x) => Some(f(x)), @@ -432,7 +434,7 @@ impl Option { /// assert_eq!(x.map_or(42u, |v| v.len()), 42u); /// ``` #[inline] - #[unstable = "waiting for unboxed closures"] + #[stable] pub fn map_or U>(self, def: U, f: F) -> U { match self { Some(t) => f(t), @@ -454,7 +456,7 @@ impl Option { /// assert_eq!(x.map_or_else(|| 2 * k, |v| v.len()), 42u); /// ``` #[inline] - #[unstable = "waiting for unboxed closures"] + #[stable] pub fn map_or_else U, F: FnOnce(T) -> U>(self, def: D, f: F) -> U { match self { Some(t) => f(t), @@ -520,9 +522,9 @@ impl Option { /// assert_eq!(x.iter().next(), None); /// ``` #[inline] - #[unstable = "waiting for iterator conventions"] - pub fn iter<'r>(&'r self) -> Item<&'r T> { - Item{opt: self.as_ref()} + #[stable] + pub fn iter(&self) -> Iter { + Iter { inner: Item { opt: self.as_ref() } } } /// Returns a mutable iterator over the possibly contained value. @@ -542,8 +544,8 @@ impl Option { /// ``` #[inline] #[unstable = "waiting for iterator conventions"] - pub fn iter_mut<'r>(&'r mut self) -> Item<&'r mut T> { - Item{opt: self.as_mut()} + pub fn iter_mut(&mut self) -> IterMut { + IterMut { inner: Item { opt: self.as_mut() } } } /// Returns a consuming iterator over the possibly contained value. @@ -560,9 +562,9 @@ impl Option { /// assert!(v.is_empty()); /// ``` #[inline] - #[unstable = "waiting for iterator conventions"] - pub fn into_iter(self) -> Item { - Item{opt: self} + #[stable] + pub fn into_iter(self) -> IntoIter { + IntoIter { inner: Item { opt: self } } } ///////////////////////////////////////////////////////////////////////// @@ -614,7 +616,7 @@ impl Option { /// assert_eq!(None.and_then(sq).and_then(sq), None); /// ``` #[inline] - #[unstable = "waiting for unboxed closures"] + #[stable] pub fn and_then Option>(self, f: F) -> Option { match self { Some(x) => f(x), @@ -666,7 +668,7 @@ impl Option { /// assert_eq!(None.or_else(nobody), None); /// ``` #[inline] - #[unstable = "waiting for unboxed closures"] + #[stable] pub fn or_else Option>(self, f: F) -> Option { match self { Some(_) => self, @@ -731,7 +733,7 @@ impl Option { /// assert_eq!(0i, bad_year); /// ``` #[inline] - #[unstable = "waiting for conventions"] + #[stable] pub fn unwrap_or_default(self) -> T { match self { Some(x) => x, @@ -744,6 +746,7 @@ impl Option { // Trait implementations ///////////////////////////////////////////////////////////////////////////// +#[unstable = "waiting on the stability of the trait itself"] impl AsSlice for Option { /// Convert from `Option` to `&[T]` (without copying) #[inline] @@ -760,21 +763,18 @@ impl AsSlice for Option { #[stable] impl Default for Option { + #[stable] #[inline] + #[stable] fn default() -> Option { None } } ///////////////////////////////////////////////////////////////////////////// -// The Option Iterator +// The Option Iterators ///////////////////////////////////////////////////////////////////////////// -/// An `Option` iterator that yields either one or zero elements -/// -/// The `Item` iterator is returned by the `iter`, `iter_mut` and `into_iter` -/// methods on `Option`. #[deriving(Clone)] -#[unstable = "waiting for iterator conventions"] -pub struct Item { +struct Item { opt: Option } @@ -802,6 +802,66 @@ impl DoubleEndedIterator for Item { impl ExactSizeIterator for Item {} +/// An iterator over a reference of the contained item in an Option. +#[stable] +pub struct Iter<'a, A: 'a> { inner: Item<&'a A> } + +impl<'a, A> Iterator<&'a A> for Iter<'a, A> { + #[inline] + fn next(&mut self) -> Option<&'a A> { self.inner.next() } + #[inline] + fn size_hint(&self) -> (uint, Option) { self.inner.size_hint() } +} + +impl<'a, A> DoubleEndedIterator<&'a A> for Iter<'a, A> { + #[inline] + fn next_back(&mut self) -> Option<&'a A> { self.inner.next_back() } +} + +impl<'a, A> ExactSizeIterator<&'a A> for Iter<'a, A> {} + +impl<'a, A> Clone for Iter<'a, A> { + fn clone(&self) -> Iter<'a, A> { + Iter { inner: self.inner.clone() } + } +} + +/// An iterator over a mutable reference of the contained item in an Option. +#[stable] +pub struct IterMut<'a, A: 'a> { inner: Item<&'a mut A> } + +impl<'a, A> Iterator<&'a mut A> for IterMut<'a, A> { + #[inline] + fn next(&mut self) -> Option<&'a mut A> { self.inner.next() } + #[inline] + fn size_hint(&self) -> (uint, Option) { self.inner.size_hint() } +} + +impl<'a, A> DoubleEndedIterator<&'a mut A> for IterMut<'a, A> { + #[inline] + fn next_back(&mut self) -> Option<&'a mut A> { self.inner.next_back() } +} + +impl<'a, A> ExactSizeIterator<&'a mut A> for IterMut<'a, A> {} + +/// An iterator over the item contained inside an Option. +#[stable] +pub struct IntoIter { inner: Item } + +impl Iterator for IntoIter { + #[inline] + fn next(&mut self) -> Option { self.inner.next() } + #[inline] + fn size_hint(&self) -> (uint, Option) { self.inner.size_hint() } +} + +impl DoubleEndedIterator for IntoIter { + #[inline] + fn next_back(&mut self) -> Option { self.inner.next_back() } +} + +impl ExactSizeIterator for IntoIter {} + ///////////////////////////////////////////////////////////////////////////// // FromIterator ///////////////////////////////////////////////////////////////////////////// @@ -826,6 +886,7 @@ impl> FromIterator> for Option { /// assert!(res == Some(vec!(2u, 3u))); /// ``` #[inline] + #[stable] fn from_iter>>(iter: I) -> Option { // FIXME(#11084): This could be replaced with Iterator::scan when this // performance bug is closed. @@ -860,5 +921,6 @@ impl> FromIterator> for Option { } } +#[stable] impl Copy for Option {} diff --git a/src/libcore/slice.rs b/src/libcore/slice.rs index a186d0a6fa5..411a46ee1bd 100644 --- a/src/libcore/slice.rs +++ b/src/libcore/slice.rs @@ -292,13 +292,11 @@ impl SliceExt for [T] { if mem::size_of::() == 0 { MutItems{ptr: p, end: (p as uint + self.len()) as *mut T, - marker: marker::ContravariantLifetime::<'a>, - marker2: marker::NoCopy} + marker: marker::ContravariantLifetime::<'a>} } else { MutItems{ptr: p, end: p.offset(self.len() as int), - marker: marker::ContravariantLifetime::<'a>, - marker2: marker::NoCopy} + marker: marker::ContravariantLifetime::<'a>} } } } @@ -647,8 +645,9 @@ impl<'a, T, Sized? U: AsSlice> AsSlice for &'a mut U { fn as_slice(&self) -> &[T] { AsSlice::as_slice(*self) } } -#[unstable = "waiting for DST"] +#[stable] impl<'a, T> Default for &'a [T] { + #[stable] fn default() -> &'a [T] { &[] } } @@ -818,7 +817,6 @@ pub struct MutItems<'a, T: 'a> { ptr: *mut T, end: *mut T, marker: marker::ContravariantLifetime<'a>, - marker2: marker::NoCopy } #[experimental] @@ -894,6 +892,17 @@ pub struct Splits<'a, T:'a, P> where P: FnMut(&T) -> bool { finished: bool } +// FIXME(#19839) Remove in favor of `#[deriving(Clone)]` +impl<'a, T, P> Clone for Splits<'a, T, P> where P: Clone + FnMut(&T) -> bool { + fn clone(&self) -> Splits<'a, T, P> { + Splits { + v: self.v, + pred: self.pred.clone(), + finished: self.finished, + } + } +} + #[experimental = "needs review"] impl<'a, T, P> Iterator<&'a [T]> for Splits<'a, T, P> where P: FnMut(&T) -> bool { #[inline] diff --git a/src/libcore/str.rs b/src/libcore/str.rs index bd9a4959c05..1a7467555a5 100644 --- a/src/libcore/str.rs +++ b/src/libcore/str.rs @@ -2349,7 +2349,9 @@ impl StrPrelude for str { fn len(&self) -> uint { self.repr().len } } +#[stable] impl<'a> Default for &'a str { + #[stable] fn default() -> &'a str { "" } } diff --git a/src/libcore/tuple/mod.rs b/src/libcore/tuple/mod.rs index 8160424be29..5ea84f7db91 100644 --- a/src/libcore/tuple/mod.rs +++ b/src/libcore/tuple/mod.rs @@ -182,6 +182,7 @@ macro_rules! tuple_impls { #[stable] impl<$($T:Default),+> Default for ($($T,)+) { + #[stable] #[inline] fn default() -> ($($T,)+) { ($({ let x: $T = Default::default(); x},)+) diff --git a/src/libcoretest/char.rs b/src/libcoretest/char.rs index e5561bebb22..bed38f8c296 100644 --- a/src/libcoretest/char.rs +++ b/src/libcoretest/char.rs @@ -135,38 +135,35 @@ fn test_escape_default() { let s = string('~'); assert_eq!(s, "~"); let s = string('\x00'); - assert_eq!(s, "\\x00"); + assert_eq!(s, "\\u{0}"); let s = string('\x1f'); - assert_eq!(s, "\\x1f"); + assert_eq!(s, "\\u{1f}"); let s = string('\x7f'); - assert_eq!(s, "\\x7f"); - let s = string('\u00ff'); - assert_eq!(s, "\\u00ff"); - let s = string('\u011b'); - assert_eq!(s, "\\u011b"); - let s = string('\U0001d4b6'); - assert_eq!(s, "\\U0001d4b6"); + assert_eq!(s, "\\u{7f}"); + let s = string('\u{ff}'); + assert_eq!(s, "\\u{ff}"); + let s = string('\u{11b}'); + assert_eq!(s, "\\u{11b}"); + let s = string('\u{1d4b6}'); + assert_eq!(s, "\\u{1d4b6}"); } #[test] fn test_escape_unicode() { - fn string(c: char) -> String { - let mut result = String::new(); - escape_unicode(c, |c| { result.push(c); }); - return result; - } + fn string(c: char) -> String { c.escape_unicode().collect() } + let s = string('\x00'); - assert_eq!(s, "\\x00"); + assert_eq!(s, "\\u{0}"); let s = string('\n'); - assert_eq!(s, "\\x0a"); + assert_eq!(s, "\\u{a}"); let s = string(' '); - assert_eq!(s, "\\x20"); + assert_eq!(s, "\\u{20}"); let s = string('a'); - assert_eq!(s, "\\x61"); - let s = string('\u011b'); - assert_eq!(s, "\\u011b"); - let s = string('\U0001d4b6'); - assert_eq!(s, "\\U0001d4b6"); + assert_eq!(s, "\\u{61}"); + let s = string('\u{11b}'); + assert_eq!(s, "\\u{11b}"); + let s = string('\u{1d4b6}'); + assert_eq!(s, "\\u{1d4b6}"); } #[test] diff --git a/src/libcoretest/tuple.rs b/src/libcoretest/tuple.rs index c53d82de23c..f7b714757f8 100644 --- a/src/libcoretest/tuple.rs +++ b/src/libcoretest/tuple.rs @@ -15,32 +15,6 @@ fn test_clone() { assert_eq!(a, b); } -#[test] -fn test_getters() { - macro_rules! test_getter( - ($x:expr, $valN:ident, $refN:ident, $mutN:ident, - $init:expr, $incr:expr, $result:expr) => ({ - assert_eq!($x.$valN(), $init); - assert_eq!(*$x.$refN(), $init); - *$x.$mutN() += $incr; - assert_eq!(*$x.$refN(), $result); - }) - ) - let mut x = (0u8, 1u16, 2u32, 3u64, 4u, 5i8, 6i16, 7i32, 8i64, 9i, 10f32, 11f64); - test_getter!(x, val0, ref0, mut0, 0, 1, 1); - test_getter!(x, val1, ref1, mut1, 1, 1, 2); - test_getter!(x, val2, ref2, mut2, 2, 1, 3); - test_getter!(x, val3, ref3, mut3, 3, 1, 4); - test_getter!(x, val4, ref4, mut4, 4, 1, 5); - test_getter!(x, val5, ref5, mut5, 5, 1, 6); - test_getter!(x, val6, ref6, mut6, 6, 1, 7); - test_getter!(x, val7, ref7, mut7, 7, 1, 8); - test_getter!(x, val8, ref8, mut8, 8, 1, 9); - test_getter!(x, val9, ref9, mut9, 9, 1, 10); - test_getter!(x, val10, ref10, mut10, 10.0, 1.0, 11.0); - test_getter!(x, val11, ref11, mut11, 11.0, 1.0, 12.0); -} - #[test] fn test_tuple_cmp() { let (small, big) = ((1u, 2u, 3u), (3u, 2u, 1u)); diff --git a/src/libgetopts/lib.rs b/src/libgetopts/lib.rs index 79c435f01e4..38729eece5a 100644 --- a/src/libgetopts/lib.rs +++ b/src/libgetopts/lib.rs @@ -78,7 +78,7 @@ //! ``` #![crate_name = "getopts"] -#![experimental] +#![experimental = "use the crates.io `getopts` library instead"] #![crate_type = "rlib"] #![crate_type = "dylib"] #![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", diff --git a/src/libgraphviz/lib.rs b/src/libgraphviz/lib.rs index 69eb87759fd..34e19aa4a03 100644 --- a/src/libgraphviz/lib.rs +++ b/src/libgraphviz/lib.rs @@ -421,6 +421,14 @@ pub trait Labeller<'a,N,E> { } impl<'a> LabelText<'a> { + pub fn label>(s: S) -> LabelText<'a> { + LabelStr(s.into_cow()) + } + + pub fn escaped>(s: S) -> LabelText<'a> { + EscStr(s.into_cow()) + } + fn escape_char(c: char, mut f: F) where F: FnMut(char) { match c { // not escaping \\, since Graphviz escString needs to @@ -505,11 +513,29 @@ pub trait GraphWalk<'a, N, E> { fn target(&'a self, edge: &E) -> N; } +#[deriving(Copy, PartialEq, Eq, Show)] +pub enum RenderOption { + NoEdgeLabels, + NoNodeLabels, +} + +/// Returns vec holding all the default render options. +pub fn default_options() -> Vec { vec![] } + /// Renders directed graph `g` into the writer `w` in DOT syntax. -/// (Main entry point for the library.) +/// (Simple wrapper around `render_opts` that passes a default set of options.) pub fn render<'a, N:Clone+'a, E:Clone+'a, G:Labeller<'a,N,E>+GraphWalk<'a,N,E>, W:Writer>( g: &'a G, - w: &mut W) -> io::IoResult<()> + w: &mut W) -> io::IoResult<()> { + render_opts(g, w, &[]) +} + +/// Renders directed graph `g` into the writer `w` in DOT syntax. +/// (Main entry point for the library.) +pub fn render_opts<'a, N:Clone+'a, E:Clone+'a, G:Labeller<'a,N,E>+GraphWalk<'a,N,E>, W:Writer>( + g: &'a G, + w: &mut W, + options: &[RenderOption]) -> io::IoResult<()> { fn writeln(w: &mut W, arg: &[&str]) -> io::IoResult<()> { for &s in arg.iter() { try!(w.write_str(s)); } @@ -524,9 +550,13 @@ pub fn render<'a, N:Clone+'a, E:Clone+'a, G:Labeller<'a,N,E>+GraphWalk<'a,N,E>, for n in g.nodes().iter() { try!(indent(w)); let id = g.node_id(n); - let escaped = g.node_label(n).escape(); - try!(writeln(w, &[id.as_slice(), - "[label=\"", escaped.as_slice(), "\"];"])); + if options.contains(&RenderOption::NoNodeLabels) { + try!(writeln(w, &[id.as_slice(), ";"])); + } else { + let escaped = g.node_label(n).escape(); + try!(writeln(w, &[id.as_slice(), + "[label=\"", escaped.as_slice(), "\"];"])); + } } for e in g.edges().iter() { @@ -536,8 +566,14 @@ pub fn render<'a, N:Clone+'a, E:Clone+'a, G:Labeller<'a,N,E>+GraphWalk<'a,N,E>, let target = g.target(e); let source_id = g.node_id(&source); let target_id = g.node_id(&target); - try!(writeln(w, &[source_id.as_slice(), " -> ", target_id.as_slice(), - "[label=\"", escaped_label.as_slice(), "\"];"])); + if options.contains(&RenderOption::NoEdgeLabels) { + try!(writeln(w, &[source_id.as_slice(), + " -> ", target_id.as_slice(), ";"])); + } else { + try!(writeln(w, &[source_id.as_slice(), + " -> ", target_id.as_slice(), + "[label=\"", escaped_label.as_slice(), "\"];"])); + } } writeln(w, &["}"]) diff --git a/src/liblog/lib.rs b/src/liblog/lib.rs index 0217c5b2713..976b9bcf37e 100644 --- a/src/liblog/lib.rs +++ b/src/liblog/lib.rs @@ -157,7 +157,7 @@ //! if logging is disabled, none of the components of the log will be executed. #![crate_name = "log"] -#![experimental] +#![experimental = "use the crates.io `log` library instead"] #![crate_type = "rlib"] #![crate_type = "dylib"] #![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", diff --git a/src/librand/lib.rs b/src/librand/lib.rs index 4fba3707703..dfcdad481a9 100644 --- a/src/librand/lib.rs +++ b/src/librand/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -185,7 +185,7 @@ pub trait Rng { Rand::rand(self) } - /// Return an iterator which will yield an infinite number of randomly + /// Return an iterator that will yield an infinite number of randomly /// generated items. /// /// # Example diff --git a/src/librand/reseeding.rs b/src/librand/reseeding.rs index 88c870579e6..46ee67940f2 100644 --- a/src/librand/reseeding.rs +++ b/src/librand/reseeding.rs @@ -142,7 +142,9 @@ impl Reseeder for ReseedWithDefault { *rng = Default::default(); } } +#[stable] impl Default for ReseedWithDefault { + #[stable] fn default() -> ReseedWithDefault { ReseedWithDefault } } diff --git a/src/librbml/lib.rs b/src/librbml/lib.rs index 28d5e1812f0..bbedbc75395 100644 --- a/src/librbml/lib.rs +++ b/src/librbml/lib.rs @@ -499,8 +499,9 @@ pub mod reader { Ok(result) } - fn read_enum_variant(&mut self, _: &[&str], f: F) -> DecodeResult where - F: FnOnce(&mut Decoder<'doc>, uint) -> DecodeResult, + fn read_enum_variant(&mut self, _: &[&str], + mut f: F) -> DecodeResult + where F: FnMut(&mut Decoder<'doc>, uint) -> DecodeResult, { debug!("read_enum_variant()"); let idx = try!(self._next_uint(EsEnumVid)); @@ -526,8 +527,9 @@ pub mod reader { f(self) } - fn read_enum_struct_variant(&mut self, _: &[&str], f: F) -> DecodeResult where - F: FnOnce(&mut Decoder<'doc>, uint) -> DecodeResult, + fn read_enum_struct_variant(&mut self, _: &[&str], + mut f: F) -> DecodeResult + where F: FnMut(&mut Decoder<'doc>, uint) -> DecodeResult, { debug!("read_enum_struct_variant()"); let idx = try!(self._next_uint(EsEnumVid)); @@ -610,8 +612,8 @@ pub mod reader { self.read_tuple_arg(idx, f) } - fn read_option(&mut self, f: F) -> DecodeResult where - F: FnOnce(&mut Decoder<'doc>, bool) -> DecodeResult, + fn read_option(&mut self, mut f: F) -> DecodeResult where + F: FnMut(&mut Decoder<'doc>, bool) -> DecodeResult, { debug!("read_option()"); self.read_enum("Option", move |this| { diff --git a/src/libregex/lib.rs b/src/libregex/lib.rs index 05f853a851e..9ad02afee99 100644 --- a/src/libregex/lib.rs +++ b/src/libregex/lib.rs @@ -103,7 +103,9 @@ //! let re = regex!(r"(\d{4})-(\d{2})-(\d{2})"); //! let text = "2012-03-14, 2013-01-01 and 2014-07-05"; //! for cap in re.captures_iter(text) { -//! println!("Month: {} Day: {} Year: {}", cap.at(2), cap.at(3), cap.at(1)); +//! println!("Month: {} Day: {} Year: {}", +//! cap.at(2).unwrap_or(""), cap.at(3).unwrap_or(""), +//! cap.at(1).unwrap_or("")); //! } //! // Output: //! // Month: 03 Day: 14 Year: 2012 @@ -285,7 +287,7 @@ //! # fn main() { //! let re = regex!(r"(?i)a+(?-i)b+"); //! let cap = re.captures("AaAaAbbBBBb").unwrap(); -//! assert_eq!(cap.at(0), "AaAaAbb"); +//! assert_eq!(cap.at(0), Some("AaAaAbb")); //! # } //! ``` //! @@ -362,7 +364,7 @@ #![crate_name = "regex"] #![crate_type = "rlib"] #![crate_type = "dylib"] -#![experimental] +#![experimental = "use the crates.io `regex` library instead"] #![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/nightly/", diff --git a/src/libregex/re.rs b/src/libregex/re.rs index 1504e191985..53181bfbb7e 100644 --- a/src/libregex/re.rs +++ b/src/libregex/re.rs @@ -273,9 +273,9 @@ impl Regex { /// let re = regex!(r"'([^']+)'\s+\((\d{4})\)"); /// let text = "Not my favorite movie: 'Citizen Kane' (1941)."; /// let caps = re.captures(text).unwrap(); - /// assert_eq!(caps.at(1), "Citizen Kane"); - /// assert_eq!(caps.at(2), "1941"); - /// assert_eq!(caps.at(0), "'Citizen Kane' (1941)"); + /// assert_eq!(caps.at(1), Some("Citizen Kane")); + /// assert_eq!(caps.at(2), Some("1941")); + /// assert_eq!(caps.at(0), Some("'Citizen Kane' (1941)")); /// # } /// ``` /// @@ -291,9 +291,9 @@ impl Regex { /// let re = regex!(r"'(?P[^']+)'\s+\((?P<year>\d{4})\)"); /// let text = "Not my favorite movie: 'Citizen Kane' (1941)."; /// let caps = re.captures(text).unwrap(); - /// assert_eq!(caps.name("title"), "Citizen Kane"); - /// assert_eq!(caps.name("year"), "1941"); - /// assert_eq!(caps.at(0), "'Citizen Kane' (1941)"); + /// assert_eq!(caps.name("title"), Some("Citizen Kane")); + /// assert_eq!(caps.name("year"), Some("1941")); + /// assert_eq!(caps.at(0), Some("'Citizen Kane' (1941)")); /// # } /// ``` /// @@ -434,7 +434,7 @@ impl Regex { /// # use regex::Captures; fn main() { /// let re = regex!(r"([^,\s]+),\s+(\S+)"); /// let result = re.replace("Springsteen, Bruce", |&: caps: &Captures| { - /// format!("{} {}", caps.at(2), caps.at(1)) + /// format!("{} {}", caps.at(2).unwrap_or(""), caps.at(1).unwrap_or("")) /// }); /// assert_eq!(result.as_slice(), "Bruce Springsteen"); /// # } @@ -712,27 +712,25 @@ impl<'t> Captures<'t> { Some((self.locs[s].unwrap(), self.locs[e].unwrap())) } - /// Returns the matched string for the capture group `i`. - /// If `i` isn't a valid capture group or didn't match anything, then the - /// empty string is returned. - pub fn at(&self, i: uint) -> &'t str { + /// Returns the matched string for the capture group `i`. If `i` isn't + /// a valid capture group or didn't match anything, then `None` is + /// returned. + pub fn at(&self, i: uint) -> Option<&'t str> { match self.pos(i) { - None => "", - Some((s, e)) => { - self.text.slice(s, e) - } + None => None, + Some((s, e)) => Some(self.text.slice(s, e)) } } - /// Returns the matched string for the capture group named `name`. - /// If `name` isn't a valid capture group or didn't match anything, then - /// the empty string is returned. - pub fn name(&self, name: &str) -> &'t str { + /// Returns the matched string for the capture group named `name`. If + /// `name` isn't a valid capture group or didn't match anything, then + /// `None` is returned. + pub fn name(&self, name: &str) -> Option<&'t str> { match self.named { - None => "", + None => None, Some(ref h) => { match h.get(name) { - None => "", + None => None, Some(i) => self.at(*i), } } @@ -769,11 +767,12 @@ impl<'t> Captures<'t> { // FIXME: Don't use regexes for this. It's completely unnecessary. let re = Regex::new(r"(^|[^$]|\b)\$(\w+)").unwrap(); let text = re.replace_all(text, |&mut: refs: &Captures| -> String { - let (pre, name) = (refs.at(1), refs.at(2)); + let pre = refs.at(1).unwrap_or(""); + let name = refs.at(2).unwrap_or(""); format!("{}{}", pre, match from_str::<uint>(name.as_slice()) { - None => self.name(name).to_string(), - Some(i) => self.at(i).to_string(), + None => self.name(name).unwrap_or("").to_string(), + Some(i) => self.at(i).unwrap_or("").to_string(), }) }); let re = Regex::new(r"\$\$").unwrap(); @@ -802,7 +801,7 @@ impl<'t> Iterator<&'t str> for SubCaptures<'t> { fn next(&mut self) -> Option<&'t str> { if self.idx < self.caps.len() { self.idx += 1; - Some(self.caps.at(self.idx - 1)) + Some(self.caps.at(self.idx - 1).unwrap_or("")) } else { None } diff --git a/src/libregex_macros/lib.rs b/src/libregex_macros/lib.rs index c1e8677fa8f..bf1095d21b2 100644 --- a/src/libregex_macros/lib.rs +++ b/src/libregex_macros/lib.rs @@ -13,7 +13,7 @@ #![crate_name = "regex_macros"] #![crate_type = "dylib"] -#![experimental] +#![experimental = "use the crates.io `regex_macros` library instead"] #![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/nightly/")] diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index 5f1ff352f96..cc383aa217a 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -364,12 +364,12 @@ fn encode_enum_variant_info(ecx: &EncodeContext, } } -fn encode_path<PI: Iterator<PathElem> + Clone>(rbml_w: &mut Encoder, - mut path: PI) { +fn encode_path<PI: Iterator<PathElem>>(rbml_w: &mut Encoder, path: PI) { + let path = path.collect::<Vec<_>>(); rbml_w.start_tag(tag_path); - rbml_w.wr_tagged_u32(tag_path_len, path.clone().count() as u32); - for pe in path { - let tag = match pe { + rbml_w.wr_tagged_u32(tag_path_len, path.len() as u32); + for pe in path.iter() { + let tag = match *pe { ast_map::PathMod(_) => tag_path_elem_mod, ast_map::PathName(_) => tag_path_elem_name }; diff --git a/src/librustc/middle/cfg/construct.rs b/src/librustc/middle/cfg/construct.rs index 5c39c9fa74d..0e10155beb4 100644 --- a/src/librustc/middle/cfg/construct.rs +++ b/src/librustc/middle/cfg/construct.rs @@ -462,15 +462,13 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { self.straightline(expr, pred, [r, l].iter().map(|&e| &**e)) } + ast::ExprBox(Some(ref l), ref r) | ast::ExprIndex(ref l, ref r) | ast::ExprBinary(_, ref l, ref r) => { // NB: && and || handled earlier self.straightline(expr, pred, [l, r].iter().map(|&e| &**e)) } - ast::ExprBox(ref p, ref e) => { - self.straightline(expr, pred, [p, e].iter().map(|&e| &**e)) - } - + ast::ExprBox(None, ref e) | ast::ExprAddrOf(_, ref e) | ast::ExprCast(ref e, _) | ast::ExprUnary(_, ref e) | diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 746a6fc6e70..2cb78beff4c 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -631,7 +631,10 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> { } ast::ExprBox(ref place, ref base) => { - self.consume_expr(&**place); + match *place { + Some(ref place) => self.consume_expr(&**place), + None => {} + } self.consume_expr(&**base); } diff --git a/src/librustc/middle/infer/coercion.rs b/src/librustc/middle/infer/coercion.rs index 1d1ee39d684..e268160a42b 100644 --- a/src/librustc/middle/infer/coercion.rs +++ b/src/librustc/middle/infer/coercion.rs @@ -552,17 +552,18 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { b.repr(self.get_ref().infcx.tcx)); let mt_a = match *sty_a { - ty::ty_rptr(_, mt) => mt, + ty::ty_rptr(_, mt) | ty::ty_ptr(mt) => mt, _ => { return self.subtype(a, b); } }; // Check that the types which they point at are compatible. - // Note that we don't adjust the mutability here. We cannot change - // the mutability and the kind of pointer in a single coercion. - let a_unsafe = ty::mk_ptr(self.get_ref().infcx.tcx, mt_a); + let a_unsafe = ty::mk_ptr(self.get_ref().infcx.tcx, ty::mt{ mutbl: mutbl_b, ty: mt_a.ty }); try!(self.subtype(a_unsafe, b)); + if !can_coerce_mutbls(mt_a.mutbl, mutbl_b) { + return Err(ty::terr_mutability); + } // Although references and unsafe ptrs have the same // representation, we still register an AutoDerefRef so that diff --git a/src/librustc/middle/infer/mod.rs b/src/librustc/middle/infer/mod.rs index 3cd981b5784..14153907ee7 100644 --- a/src/librustc/middle/infer/mod.rs +++ b/src/librustc/middle/infer/mod.rs @@ -814,8 +814,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { self.region_vars.new_bound(debruijn) } - pub fn resolve_regions_and_report_errors(&self) { - let errors = self.region_vars.resolve_regions(); + pub fn resolve_regions_and_report_errors(&self, subject_node_id: ast::NodeId) { + let errors = self.region_vars.resolve_regions(subject_node_id); self.report_region_errors(&errors); // see error_reporting.rs } diff --git a/src/librustc/middle/infer/region_inference/graphviz.rs b/src/librustc/middle/infer/region_inference/graphviz.rs new file mode 100644 index 00000000000..720de357a27 --- /dev/null +++ b/src/librustc/middle/infer/region_inference/graphviz.rs @@ -0,0 +1,227 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! This module provides linkage between libgraphviz traits and +//! `rustc::middle::typeck::infer::region_inference`, generating a +//! rendering of the graph represented by the list of `Constraint` +//! instances (which make up the edges of the graph), as well as the +//! origin for each constraint (which are attached to the labels on +//! each edge). + +/// For clarity, rename the graphviz crate locally to dot. +use graphviz as dot; + +use middle::ty; +use super::Constraint; +use middle::infer::SubregionOrigin; +use middle::infer::region_inference::RegionVarBindings; +use session::config; +use util::nodemap::{FnvHashMap, FnvHashSet}; +use util::ppaux::Repr; + +use std::collections::hash_map::Vacant; +use std::io::{mod, File}; +use std::os; +use std::sync::atomic; +use syntax::ast; + +fn print_help_message() { + println!("\ +-Z print-region-graph by default prints a region constraint graph for every \n\ +function body, to the path `/tmp/constraints.nodeXXX.dot`, where the XXX is \n\ +replaced with the node id of the function under analysis. \n\ + \n\ +To select one particular function body, set `RUST_REGION_GRAPH_NODE=XXX`, \n\ +where XXX is the node id desired. \n\ + \n\ +To generate output to some path other than the default \n\ +`/tmp/constraints.nodeXXX.dot`, set `RUST_REGION_GRAPH=/path/desired.dot`; \n\ +occurrences of the character `%` in the requested path will be replaced with\n\ +the node id of the function under analysis. \n\ + \n\ +(Since you requested help via RUST_REGION_GRAPH=help, no region constraint \n\ +graphs will be printed. \n\ +"); +} + +pub fn maybe_print_constraints_for<'a, 'tcx>(region_vars: &RegionVarBindings<'a, 'tcx>, + subject_node: ast::NodeId) { + let tcx = region_vars.tcx; + + if !region_vars.tcx.sess.debugging_opt(config::PRINT_REGION_GRAPH) { + return; + } + + let requested_node : Option<ast::NodeId> = + os::getenv("RUST_REGION_GRAPH_NODE").and_then(|s|from_str(s.as_slice())); + + if requested_node.is_some() && requested_node != Some(subject_node) { + return; + } + + let requested_output = os::getenv("RUST_REGION_GRAPH"); + debug!("requested_output: {} requested_node: {}", + requested_output, requested_node); + + let output_path = { + let output_template = match requested_output { + Some(ref s) if s.as_slice() == "help" => { + static PRINTED_YET : atomic::AtomicBool = atomic::INIT_ATOMIC_BOOL; + if !PRINTED_YET.load(atomic::SeqCst) { + print_help_message(); + PRINTED_YET.store(true, atomic::SeqCst); + } + return; + } + + Some(other_path) => other_path, + None => "/tmp/constraints.node%.dot".to_string(), + }; + + if output_template.len() == 0 { + tcx.sess.bug("empty string provided as RUST_REGION_GRAPH"); + } + + if output_template.contains_char('%') { + let mut new_str = String::new(); + for c in output_template.chars() { + if c == '%' { + new_str.push_str(subject_node.to_string().as_slice()); + } else { + new_str.push(c); + } + } + new_str + } else { + output_template + } + }; + + let constraints = &*region_vars.constraints.borrow(); + match dump_region_constraints_to(tcx, constraints, output_path.as_slice()) { + Ok(()) => {} + Err(e) => { + let msg = format!("io error dumping region constraints: {}", e); + region_vars.tcx.sess.err(msg.as_slice()) + } + } +} + +struct ConstraintGraph<'a, 'tcx: 'a> { + tcx: &'a ty::ctxt<'tcx>, + graph_name: String, + map: &'a FnvHashMap<Constraint, SubregionOrigin<'tcx>>, + node_ids: FnvHashMap<Node, uint>, +} + +#[deriving(Clone, Hash, PartialEq, Eq, Show)] +enum Node { + RegionVid(ty::RegionVid), + Region(ty::Region), +} + +type Edge = Constraint; + +impl<'a, 'tcx> ConstraintGraph<'a, 'tcx> { + fn new(tcx: &'a ty::ctxt<'tcx>, + name: String, + map: &'a ConstraintMap<'tcx>) -> ConstraintGraph<'a, 'tcx> { + let mut i = 0; + let mut node_ids = FnvHashMap::new(); + { + let add_node = |node| { + if let Vacant(e) = node_ids.entry(node) { + e.set(i); + i += 1; + } + }; + + for (n1, n2) in map.keys().map(|c|constraint_to_nodes(c)) { + add_node(n1); + add_node(n2); + } + } + + ConstraintGraph { tcx: tcx, + graph_name: name, + map: map, + node_ids: node_ids } + } +} + +impl<'a, 'tcx> dot::Labeller<'a, Node, Edge> for ConstraintGraph<'a, 'tcx> { + fn graph_id(&self) -> dot::Id { + dot::Id::new(self.graph_name.as_slice()).unwrap() + } + fn node_id(&self, n: &Node) -> dot::Id { + dot::Id::new(format!("node_{}", self.node_ids.get(n).unwrap())).unwrap() + } + fn node_label(&self, n: &Node) -> dot::LabelText { + match *n { + Node::RegionVid(n_vid) => + dot::LabelText::label(format!("{}", n_vid)), + Node::Region(n_rgn) => + dot::LabelText::label(format!("{}", n_rgn.repr(self.tcx))), + } + } + fn edge_label(&self, e: &Edge) -> dot::LabelText { + dot::LabelText::label(format!("{}", self.map.get(e).unwrap().repr(self.tcx))) + } +} + +fn constraint_to_nodes(c: &Constraint) -> (Node, Node) { + match *c { + Constraint::ConstrainVarSubVar(rv_1, rv_2) => (Node::RegionVid(rv_1), + Node::RegionVid(rv_2)), + Constraint::ConstrainRegSubVar(r_1, rv_2) => (Node::Region(r_1), + Node::RegionVid(rv_2)), + Constraint::ConstrainVarSubReg(rv_1, r_2) => (Node::RegionVid(rv_1), + Node::Region(r_2)), + } +} + +impl<'a, 'tcx> dot::GraphWalk<'a, Node, Edge> for ConstraintGraph<'a, 'tcx> { + fn nodes(&self) -> dot::Nodes<Node> { + let mut set = FnvHashSet::new(); + for constraint in self.map.keys() { + let (n1, n2) = constraint_to_nodes(constraint); + set.insert(n1); + set.insert(n2); + } + debug!("constraint graph has {} nodes", set.len()); + set.into_iter().collect() + } + fn edges(&self) -> dot::Edges<Edge> { + debug!("constraint graph has {} edges", self.map.len()); + self.map.keys().map(|e|*e).collect() + } + fn source(&self, edge: &Edge) -> Node { + let (n1, _) = constraint_to_nodes(edge); + debug!("edge {} has source {}", edge, n1); + n1 + } + fn target(&self, edge: &Edge) -> Node { + let (_, n2) = constraint_to_nodes(edge); + debug!("edge {} has target {}", edge, n2); + n2 + } +} + +pub type ConstraintMap<'tcx> = FnvHashMap<Constraint, SubregionOrigin<'tcx>>; + +fn dump_region_constraints_to<'a, 'tcx:'a >(tcx: &'a ty::ctxt<'tcx>, + map: &ConstraintMap<'tcx>, + path: &str) -> io::IoResult<()> { + debug!("dump_region_constraints map (len: {}) path: {}", map.len(), path); + let g = ConstraintGraph::new(tcx, format!("region_constraints"), map); + let mut f = File::create(&Path::new(path)); + debug!("dump_region_constraints calling render"); + dot::render(&g, &mut f) +} diff --git a/src/librustc/middle/infer/region_inference/mod.rs b/src/librustc/middle/infer/region_inference/mod.rs index e855511e26f..ca2860ae6b3 100644 --- a/src/librustc/middle/infer/region_inference/mod.rs +++ b/src/librustc/middle/infer/region_inference/mod.rs @@ -37,9 +37,10 @@ use std::uint; use syntax::ast; mod doc; +mod graphviz; // A constraint that influences the inference process. -#[deriving(PartialEq, Eq, Hash)] +#[deriving(Clone, PartialEq, Eq, Hash, Show)] pub enum Constraint { // One region variable is subregion of another ConstrainVarSubVar(RegionVid, RegionVid), @@ -706,10 +707,10 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { /// fixed-point iteration to find region values which satisfy all /// constraints, assuming such values can be found; if they cannot, /// errors are reported. - pub fn resolve_regions(&self) -> Vec<RegionResolutionError<'tcx>> { + pub fn resolve_regions(&self, subject_node: ast::NodeId) -> Vec<RegionResolutionError<'tcx>> { debug!("RegionVarBindings: resolve_regions()"); let mut errors = vec!(); - let v = self.infer_variable_values(&mut errors); + let v = self.infer_variable_values(&mut errors, subject_node); *self.values.borrow_mut() = Some(v); errors } @@ -958,14 +959,15 @@ type RegionGraph = graph::Graph<(), Constraint>; impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { fn infer_variable_values(&self, - errors: &mut Vec<RegionResolutionError<'tcx>>) - -> Vec<VarValue> + errors: &mut Vec<RegionResolutionError<'tcx>>, + subject: ast::NodeId) -> Vec<VarValue> { let mut var_data = self.construct_var_data(); // Dorky hack to cause `dump_constraints` to only get called // if debug mode is enabled: debug!("----() End constraint listing {}---", self.dump_constraints()); + graphviz::maybe_print_constraints_for(self, subject); self.expansion(var_data.as_mut_slice()); self.contraction(var_data.as_mut_slice()); diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index 31bcdff9cd5..c76d9bc6b1f 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -1199,7 +1199,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { ast::ExprIndex(ref l, ref r) | ast::ExprBinary(_, ref l, ref r) | - ast::ExprBox(ref l, ref r) => { + ast::ExprBox(Some(ref l), ref r) => { let r_succ = self.propagate_through_expr(&**r, succ); self.propagate_through_expr(&**l, r_succ) } @@ -1210,6 +1210,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { self.propagate_through_expr(&**e1, succ) } + ast::ExprBox(None, ref e) | ast::ExprAddrOf(_, ref e) | ast::ExprCast(ref e, _) | ast::ExprUnary(_, ref e) | diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs index 8b31132f736..f551ff06165 100644 --- a/src/librustc/middle/traits/select.rs +++ b/src/librustc/middle/traits/select.rs @@ -1209,6 +1209,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // is reserve judgement and then intertwine this // analysis with closure inference. assert_eq!(def_id.krate, ast::LOCAL_CRATE); + + // Unboxed closures shouldn't be + // implicitly copyable + if bound == ty::BoundCopy { + return Ok(ParameterBuiltin); + } + match self.tcx().freevars.borrow().get(&def_id.node) { None => { // No upvars. diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 50c324c49c3..84b69eb8471 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -4320,12 +4320,13 @@ pub fn expr_kind(tcx: &ctxt, expr: &ast::Expr) -> ExprKind { ast::ExprLit(_) | // Note: LitStr is carved out above ast::ExprUnary(..) | + ast::ExprBox(None, _) | ast::ExprAddrOf(..) | ast::ExprBinary(..) => { RvalueDatumExpr } - ast::ExprBox(ref place, _) => { + ast::ExprBox(Some(ref place), _) => { // Special case `Box<T>` for now: let definition = match tcx.def_map.borrow().get(&place.id) { Some(&def) => def, @@ -5825,126 +5826,153 @@ pub fn trait_item_of_item(tcx: &ctxt, def_id: ast::DefId) /// context it's calculated within. This is used by the `type_id` intrinsic. pub fn hash_crate_independent(tcx: &ctxt, ty: Ty, svh: &Svh) -> u64 { let mut state = sip::SipState::new(); - macro_rules! byte( ($b:expr) => { ($b as u8).hash(&mut state) } ); - macro_rules! hash( ($e:expr) => { $e.hash(&mut state) } ); + helper(tcx, ty, svh, &mut state); + return state.result(); - let region = |_state: &mut sip::SipState, r: Region| { - match r { - ReStatic => {} + fn helper(tcx: &ctxt, ty: Ty, svh: &Svh, state: &mut sip::SipState) { + macro_rules! byte( ($b:expr) => { ($b as u8).hash(state) } ); + macro_rules! hash( ($e:expr) => { $e.hash(state) } ); - ReEmpty | - ReEarlyBound(..) | - ReLateBound(..) | - ReFree(..) | - ReScope(..) | - ReInfer(..) => { - tcx.sess.bug("non-static region found when hashing a type") - } - } - }; - let did = |state: &mut sip::SipState, did: DefId| { - let h = if ast_util::is_local(did) { - svh.clone() - } else { - tcx.sess.cstore.get_crate_hash(did.krate) - }; - h.as_str().hash(state); - did.node.hash(state); - }; - let mt = |state: &mut sip::SipState, mt: mt| { - mt.mutbl.hash(state); - }; - ty::walk_ty(ty, |ty| { - match ty.sty { - ty_bool => byte!(2), - ty_char => byte!(3), - ty_int(i) => { - byte!(4); - hash!(i); - } - ty_uint(u) => { - byte!(5); - hash!(u); - } - ty_float(f) => { - byte!(6); - hash!(f); - } - ty_str => { - byte!(7); - } - ty_enum(d, _) => { - byte!(8); - did(&mut state, d); - } - ty_uniq(_) => { - byte!(9); - } - ty_vec(_, Some(n)) => { - byte!(10); - n.hash(&mut state); - } - ty_vec(_, None) => { - byte!(11); - } - ty_ptr(m) => { - byte!(12); - mt(&mut state, m); - } - ty_rptr(r, m) => { - byte!(13); - region(&mut state, r); - mt(&mut state, m); - } - ty_bare_fn(ref b) => { - byte!(14); - hash!(b.unsafety); - hash!(b.abi); - } - ty_closure(ref c) => { - byte!(15); - hash!(c.unsafety); - hash!(c.onceness); - hash!(c.bounds); - match c.store { - UniqTraitStore => byte!(0), - RegionTraitStore(r, m) => { - byte!(1) - region(&mut state, r); - assert_eq!(m, ast::MutMutable); - } + let region = |state: &mut sip::SipState, r: Region| { + match r { + ReStatic => {} + ReLateBound(db, BrAnon(i)) => { + db.hash(state); + i.hash(state); + } + ReEmpty | + ReEarlyBound(..) | + ReLateBound(..) | + ReFree(..) | + ReScope(..) | + ReInfer(..) => { + tcx.sess.bug("unexpected region found when hashing a type") } } - ty_trait(box TyTrait { ref principal, bounds }) => { - byte!(17); - did(&mut state, principal.def_id); - hash!(bounds); + }; + let did = |state: &mut sip::SipState, did: DefId| { + let h = if ast_util::is_local(did) { + svh.clone() + } else { + tcx.sess.cstore.get_crate_hash(did.krate) + }; + h.as_str().hash(state); + did.node.hash(state); + }; + let mt = |state: &mut sip::SipState, mt: mt| { + mt.mutbl.hash(state); + }; + let fn_sig = |state: &mut sip::SipState, sig: &FnSig| { + let sig = anonymize_late_bound_regions(tcx, sig); + for a in sig.inputs.iter() { helper(tcx, *a, svh, state); } + if let ty::FnConverging(output) = sig.output { + helper(tcx, output, svh, state); } - ty_struct(d, _) => { - byte!(18); - did(&mut state, d); - } - ty_tup(ref inner) => { - byte!(19); - hash!(inner.len()); - } - ty_param(p) => { - byte!(20); - hash!(p.idx); - did(&mut state, p.def_id); - } - ty_open(_) => byte!(22), - ty_infer(_) => unreachable!(), - ty_err => byte!(23), - ty_unboxed_closure(d, r, _) => { - byte!(24); - did(&mut state, d); - region(&mut state, r); - } - } - }); + }; + maybe_walk_ty(ty, |ty| { + match ty.sty { + ty_bool => byte!(2), + ty_char => byte!(3), + ty_int(i) => { + byte!(4); + hash!(i); + } + ty_uint(u) => { + byte!(5); + hash!(u); + } + ty_float(f) => { + byte!(6); + hash!(f); + } + ty_str => { + byte!(7); + } + ty_enum(d, _) => { + byte!(8); + did(state, d); + } + ty_uniq(_) => { + byte!(9); + } + ty_vec(_, Some(n)) => { + byte!(10); + n.hash(state); + } + ty_vec(_, None) => { + byte!(11); + } + ty_ptr(m) => { + byte!(12); + mt(state, m); + } + ty_rptr(r, m) => { + byte!(13); + region(state, r); + mt(state, m); + } + ty_bare_fn(ref b) => { + byte!(14); + hash!(b.unsafety); + hash!(b.abi); + fn_sig(state, &b.sig); + return false; + } + ty_closure(ref c) => { + byte!(15); + hash!(c.unsafety); + hash!(c.onceness); + hash!(c.bounds); + match c.store { + UniqTraitStore => byte!(0), + RegionTraitStore(r, m) => { + byte!(1); + region(state, r); + assert_eq!(m, ast::MutMutable); + } + } - state.result() + fn_sig(state, &c.sig); + + return false; + } + ty_trait(box TyTrait { ref principal, bounds }) => { + byte!(17); + did(state, principal.def_id); + hash!(bounds); + + let principal = anonymize_late_bound_regions(tcx, principal); + for subty in principal.substs.types.iter() { + helper(tcx, *subty, svh, state); + } + + return false; + } + ty_struct(d, _) => { + byte!(18); + did(state, d); + } + ty_tup(ref inner) => { + byte!(19); + hash!(inner.len()); + } + ty_param(p) => { + byte!(20); + hash!(p.idx); + did(state, p.def_id); + } + ty_open(_) => byte!(22), + ty_infer(_) => unreachable!(), + ty_err => byte!(23), + ty_unboxed_closure(d, r, _) => { + byte!(24); + did(state, d); + region(state, r); + } + } + true + }); + } } impl Variance { @@ -6284,6 +6312,23 @@ pub fn erase_late_bound_regions<'tcx, HR>( replace_late_bound_regions(tcx, value, |_, _| ty::ReStatic).0 } +/// Rewrite any late-bound regions so that they are anonymous. Region numbers are +/// assigned starting at 1 and increasing monotonically in the order traversed +/// by the fold operation. +/// +/// The chief purpose of this function is to canonicalize regions so that two +/// `FnSig`s or `TraitRef`s which are equivalent up to region naming will become +/// structurally identical. For example, `for<'a, 'b> fn(&'a int, &'b int)` and +/// `for<'a, 'b> fn(&'b int, &'a int)` will become identical after anonymization. +pub fn anonymize_late_bound_regions<'tcx, HR>(tcx: &ctxt<'tcx>, sig: &HR) -> HR + where HR: HigherRankedFoldable<'tcx> { + let mut counter = 0; + replace_late_bound_regions(tcx, sig, |_, db| { + counter += 1; + ReLateBound(db, BrAnon(counter)) + }).0 +} + /// Replaces the late-bound-regions in `value` that are bound by `value`. pub fn replace_late_bound_regions<'tcx, HR, F>( tcx: &ty::ctxt<'tcx>, diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index c7b5e1e8de9..b3b44b60b6e 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -276,7 +276,8 @@ debugging_opts!( FLOWGRAPH_PRINT_MOVES, FLOWGRAPH_PRINT_ASSIGNS, FLOWGRAPH_PRINT_ALL, - PRINT_SYSROOT + PRINT_SYSROOT, + PRINT_REGION_GRAPH ] 0 ) @@ -322,7 +323,10 @@ pub fn debugging_opts_map() -> Vec<(&'static str, &'static str, u64)> { ("flowgraph-print-all", "Include all dataflow analysis data in \ --pretty flowgraph output", FLOWGRAPH_PRINT_ALL), ("print-sysroot", "Print the sysroot as used by this rustc invocation", - PRINT_SYSROOT)] + PRINT_SYSROOT), + ("print-region-graph", "Prints region inference graph. \ + Use with RUST_REGION_GRAPH=help for more info", + PRINT_REGION_GRAPH)] } #[deriving(Clone)] diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 74e312803f3..13b5c262bf7 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -428,17 +428,19 @@ pub fn ty_to_string<'tcx>(cx: &ctxt<'tcx>, typ: &ty::TyS<'tcx>) -> String { ty_enum(did, ref substs) | ty_struct(did, ref substs) => { let base = ty::item_path_str(cx, did); let generics = ty::lookup_item_type(cx, did).generics; - parameterized(cx, base.as_slice(), substs, &generics) + parameterized(cx, base.as_slice(), substs, &generics, did) } ty_trait(box ty::TyTrait { ref principal, ref bounds }) => { let base = ty::item_path_str(cx, principal.def_id); let trait_def = ty::lookup_trait_def(cx, principal.def_id); + let did = trait_def.trait_ref.def_id; let ty = parameterized(cx, base.as_slice(), - &principal.substs, &trait_def.generics); + &principal.substs, &trait_def.generics, + did); let bound_str = bounds.user_string(cx); - let bound_sep = if bound_str.is_empty() { "" } else { "+" }; + let bound_sep = if bound_str.is_empty() { "" } else { " + " }; format!("{}{}{}", ty, bound_sep, @@ -484,7 +486,8 @@ pub fn explicit_self_category_to_str(category: &ty::ExplicitSelfCategory) pub fn parameterized<'tcx>(cx: &ctxt<'tcx>, base: &str, substs: &subst::Substs<'tcx>, - generics: &ty::Generics<'tcx>) + generics: &ty::Generics<'tcx>, + did: ast::DefId) -> String { if cx.sess.verbose() { @@ -537,7 +540,12 @@ pub fn parameterized<'tcx>(cx: &ctxt<'tcx>, strs.push(ty_to_string(cx, *t)) } - if strs.len() > 0u { + if cx.lang_items.fn_trait_kind(did).is_some() { + format!("{}({}){}", + base, + strs[0][1 .. strs[0].len() - (strs[0].ends_with(",)") as uint+1)], + if &*strs[1] == "()" { String::new() } else { format!(" -> {}", strs[1]) }) + } else if strs.len() > 0 { format!("{}<{}>", base, strs.connect(", ")) } else { format!("{}", base) @@ -743,7 +751,7 @@ impl<'tcx> Repr<'tcx> for ty::TraitRef<'tcx> { let trait_def = ty::lookup_trait_def(tcx, self.def_id); format!("<{} : {}>", self.substs.self_ty().repr(tcx), - parameterized(tcx, base.as_slice(), &self.substs, &trait_def.generics)) + parameterized(tcx, base.as_slice(), &self.substs, &trait_def.generics, self.def_id)) } } @@ -1116,7 +1124,7 @@ impl<'tcx> UserString<'tcx> for ty::ParamBounds<'tcx> { for n in self.trait_bounds.iter() { result.push(n.user_string(tcx)); } - result.connect("+") + result.connect(" + ") } } @@ -1189,7 +1197,8 @@ impl<'tcx> UserString<'tcx> for ty::TraitRef<'tcx> { }; let trait_def = ty::lookup_trait_def(tcx, self.def_id); - parameterized(tcx, base.as_slice(), &trait_ref.substs, &trait_def.generics) + let did = trait_def.trait_ref.def_id; + parameterized(tcx, base.as_slice(), &trait_ref.substs, &trait_def.generics, did) } } diff --git a/src/librustc/util/snapshot_vec.rs b/src/librustc/util/snapshot_vec.rs index 519cd6b1675..e80e8dc5351 100644 --- a/src/librustc/util/snapshot_vec.rs +++ b/src/librustc/util/snapshot_vec.rs @@ -20,7 +20,6 @@ //! those changes. use self::UndoLog::*; -use std::kinds::marker; use std::mem; #[deriving(PartialEq)] @@ -47,10 +46,9 @@ pub struct SnapshotVec<T,U,D> { delegate: D } +// Snapshots are tokens that should be created/consumed linearly. +#[allow(missing_copy_implementations)] pub struct Snapshot { - // Snapshots are tokens that should be created/consumed linearly. - marker: marker::NoCopy, - // Length of the undo log at the time the snapshot was taken. length: uint, } @@ -112,8 +110,7 @@ impl<T,U,D:SnapshotVecDelegate<T,U>> SnapshotVec<T,U,D> { pub fn start_snapshot(&mut self) -> Snapshot { let length = self.undo_log.len(); self.undo_log.push(OpenSnapshot); - Snapshot { length: length, - marker: marker::NoCopy } + Snapshot { length: length } } fn assert_open_snapshot(&self, snapshot: &Snapshot) { diff --git a/src/librustc_borrowck/lib.rs b/src/librustc_borrowck/lib.rs index db19a09deba..ffc5a3919b6 100644 --- a/src/librustc_borrowck/lib.rs +++ b/src/librustc_borrowck/lib.rs @@ -16,8 +16,8 @@ html_favicon_url = "http://www.rust-lang.org/favicon.ico", html_root_url = "http://doc.rust-lang.org/nightly/")] -#![feature(default_type_params, globs, if_let, import_shadowing, macro_rules, phase, quote)] -#![feature(slicing_syntax, tuple_indexing, unsafe_destructor)] +#![feature(default_type_params, globs, import_shadowing, macro_rules, phase, quote)] +#![feature(slicing_syntax, unsafe_destructor)] #![feature(rustc_diagnostic_macros)] #![feature(unboxed_closures)] #![allow(non_camel_case_types)] diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs index 7ec05b6a030..57004d71c75 100644 --- a/src/librustc_driver/pretty.rs +++ b/src/librustc_driver/pretty.rs @@ -325,7 +325,7 @@ impl FromStr for UserIdentifiedItem { } enum NodesMatchingUII<'a, 'ast: 'a> { - NodesMatchingDirect(option::Item<ast::NodeId>), + NodesMatchingDirect(option::IntoIter<ast::NodeId>), NodesMatchingSuffix(ast_map::NodesMatchingSuffix<'a, 'ast, String>), } diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index 6a50af3bc79..508af4c28e6 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -139,7 +139,7 @@ fn test_env<F>(source_string: &str, stability_index); let infcx = infer::new_infer_ctxt(&tcx); body(Env { infcx: &infcx }); - infcx.resolve_regions_and_report_errors(); + infcx.resolve_regions_and_report_errors(ast::CRATE_NODE_ID); assert_eq!(tcx.sess.err_count(), expected_err_count); } diff --git a/src/librustc_trans/trans/debuginfo.rs b/src/librustc_trans/trans/debuginfo.rs index 3f8c951786d..c97e6a09529 100644 --- a/src/librustc_trans/trans/debuginfo.rs +++ b/src/librustc_trans/trans/debuginfo.rs @@ -3472,7 +3472,8 @@ fn populate_scope_map(cx: &CrateContext, walk_expr(cx, &**sub_exp, scope_stack, scope_map), ast::ExprBox(ref place, ref sub_expr) => { - walk_expr(cx, &**place, scope_stack, scope_map); + place.as_ref().map( + |e| walk_expr(cx, &**e, scope_stack, scope_map)); walk_expr(cx, &**sub_expr, scope_stack, scope_map); } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 28e0a1a0fac..f3b9e98ad48 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1188,7 +1188,7 @@ fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>, // Finally, resolve all regions. This catches wily misuses of lifetime // parameters. - infcx.resolve_regions_and_report_errors(); + infcx.resolve_regions_and_report_errors(impl_m_body_id); /// Check that region bounds on impl method are the same as those on the trait. In principle, /// it could be ok for there to be fewer region bounds on the impl method, but this leads to an @@ -3662,22 +3662,25 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, let tcx = fcx.ccx.tcx; let id = expr.id; match expr.node { - ast::ExprBox(ref place, ref subexpr) => { - check_expr(fcx, &**place); + ast::ExprBox(ref opt_place, ref subexpr) => { + opt_place.as_ref().map(|place|check_expr(fcx, &**place)); check_expr(fcx, &**subexpr); let mut checked = false; - if let ast::ExprPath(ref path) = place.node { - // FIXME(pcwalton): For now we hardcode the two permissible - // places: the exchange heap and the managed heap. - let definition = lookup_def(fcx, path.span, place.id); - let def_id = definition.def_id(); - let referent_ty = fcx.expr_ty(&**subexpr); - if tcx.lang_items.exchange_heap() == Some(def_id) { - fcx.write_ty(id, ty::mk_uniq(tcx, referent_ty)); - checked = true + opt_place.as_ref().map(|place| match place.node { + ast::ExprPath(ref path) => { + // FIXME(pcwalton): For now we hardcode the two permissible + // places: the exchange heap and the managed heap. + let definition = lookup_def(fcx, path.span, place.id); + let def_id = definition.def_id(); + let referent_ty = fcx.expr_ty(&**subexpr); + if tcx.lang_items.exchange_heap() == Some(def_id) { + fcx.write_ty(id, ty::mk_uniq(tcx, referent_ty)); + checked = true + } } - } + _ => {} + }); if !checked { span_err!(tcx.sess, expr.span, E0066, diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index 217d178fe3b..6cfe24342e2 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -139,27 +139,31 @@ use syntax::visit::Visitor; use std::cell::{RefCell}; use std::collections::hash_map::{Vacant, Occupied}; +use self::RepeatingScope::Repeating; +use self::SubjectNode::Subject; + + /////////////////////////////////////////////////////////////////////////// // PUBLIC ENTRY POINTS pub fn regionck_expr(fcx: &FnCtxt, e: &ast::Expr) { - let mut rcx = Rcx::new(fcx, e.id); + let mut rcx = Rcx::new(fcx, Repeating(e.id), Subject(e.id)); if fcx.err_count_since_creation() == 0 { // regionck assumes typeck succeeded rcx.visit_expr(e); rcx.visit_region_obligations(e.id); } - fcx.infcx().resolve_regions_and_report_errors(); + rcx.resolve_regions_and_report_errors(); } pub fn regionck_item(fcx: &FnCtxt, item: &ast::Item) { - let mut rcx = Rcx::new(fcx, item.id); + let mut rcx = Rcx::new(fcx, Repeating(item.id), Subject(item.id)); rcx.visit_region_obligations(item.id); - fcx.infcx().resolve_regions_and_report_errors(); + rcx.resolve_regions_and_report_errors(); } pub fn regionck_fn(fcx: &FnCtxt, id: ast::NodeId, decl: &ast::FnDecl, blk: &ast::Block) { - let mut rcx = Rcx::new(fcx, blk.id); + let mut rcx = Rcx::new(fcx, Repeating(blk.id), Subject(id)); if fcx.err_count_since_creation() == 0 { // regionck assumes typeck succeeded rcx.visit_fn_body(id, decl, blk); @@ -169,7 +173,7 @@ pub fn regionck_fn(fcx: &FnCtxt, id: ast::NodeId, decl: &ast::FnDecl, blk: &ast: // particularly around closure bounds. vtable::select_all_fcx_obligations_or_error(fcx); - fcx.infcx().resolve_regions_and_report_errors(); + rcx.resolve_regions_and_report_errors(); } /// Checks that the types in `component_tys` are well-formed. This will add constraints into the @@ -177,7 +181,7 @@ pub fn regionck_fn(fcx: &FnCtxt, id: ast::NodeId, decl: &ast::FnDecl, blk: &ast: pub fn regionck_ensure_component_tys_wf<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, span: Span, component_tys: &[Ty<'tcx>]) { - let mut rcx = Rcx::new(fcx, 0); + let mut rcx = Rcx::new(fcx, Repeating(0), SubjectNode::None); for &component_ty in component_tys.iter() { // Check that each type outlives the empty region. Since the // empty region is a subregion of all others, this can't fail @@ -225,6 +229,9 @@ pub struct Rcx<'a, 'tcx: 'a> { // id of innermost fn or loop repeating_scope: ast::NodeId, + // id of AST node being analyzed (the subject of the analysis). + subject: SubjectNode, + // Possible region links we will establish if an upvar // turns out to be unique/mutable maybe_links: MaybeLinkMap<'tcx> @@ -251,11 +258,17 @@ fn region_of_def(fcx: &FnCtxt, def: def::Def) -> ty::Region { } } +pub enum RepeatingScope { Repeating(ast::NodeId) } +pub enum SubjectNode { Subject(ast::NodeId), None } + impl<'a, 'tcx> Rcx<'a, 'tcx> { pub fn new(fcx: &'a FnCtxt<'a, 'tcx>, - initial_repeating_scope: ast::NodeId) -> Rcx<'a, 'tcx> { + initial_repeating_scope: RepeatingScope, + subject: SubjectNode) -> Rcx<'a, 'tcx> { + let Repeating(initial_repeating_scope) = initial_repeating_scope; Rcx { fcx: fcx, repeating_scope: initial_repeating_scope, + subject: subject, region_param_pairs: Vec::new(), maybe_links: RefCell::new(FnvHashMap::new()) } } @@ -425,6 +438,18 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> { debug!("<< relate_free_regions"); } + + fn resolve_regions_and_report_errors(&self) { + let subject_node_id = match self.subject { + Subject(s) => s, + SubjectNode::None => { + self.tcx().sess.bug("cannot resolve_regions_and_report_errors \ + without subject node"); + } + }; + + self.fcx.infcx().resolve_regions_and_report_errors(subject_node_id); + } } impl<'fcx, 'tcx> mc::Typer<'tcx> for Rcx<'fcx, 'tcx> { diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 08b465dfa80..91947f67dd7 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -2237,6 +2237,6 @@ fn check_method_self_type<'a, 'tcx, RS:RegionScope>( format!("mismatched self type: expected `{}`", ppaux::ty_to_string(crate_context.tcx, required_type)) })); - infcx.resolve_regions_and_report_errors(); + infcx.resolve_regions_and_report_errors(body_id); } } diff --git a/src/librustrt/lib.rs b/src/librustrt/lib.rs index f12f8e49801..02ca7d3ce6d 100644 --- a/src/librustrt/lib.rs +++ b/src/librustrt/lib.rs @@ -128,5 +128,5 @@ pub mod shouldnt_be_public { #[cfg(not(test))] mod std { - pub use core::{fmt, option, cmp}; + pub use core::{fmt, option, cmp, kinds}; } diff --git a/src/librustrt/libunwind.rs b/src/librustrt/libunwind.rs index e4565be284f..2feea7fa0a4 100644 --- a/src/librustrt/libunwind.rs +++ b/src/librustrt/libunwind.rs @@ -25,6 +25,7 @@ use libc; #[cfg(any(not(target_arch = "arm"), target_os = "ios"))] #[repr(C)] +#[deriving(Copy)] pub enum _Unwind_Action { _UA_SEARCH_PHASE = 1, _UA_CLEANUP_PHASE = 2, diff --git a/src/librustrt/task.rs b/src/librustrt/task.rs index 37632f509c1..b942a3819cc 100644 --- a/src/librustrt/task.rs +++ b/src/librustrt/task.rs @@ -20,7 +20,6 @@ use alloc::boxed::Box; use core::any::Any; use core::atomic::{AtomicUint, SeqCst}; use core::iter::{IteratorExt, Take}; -use core::kinds::marker; use core::ops::FnOnce; use core::mem; use core::ops::FnMut; @@ -95,7 +94,6 @@ pub enum BlockedTask { /// Per-task state related to task death, killing, panic, etc. pub struct Death { pub on_exit: Option<Thunk<Result>>, - marker: marker::NoCopy, } pub struct BlockedTasks { @@ -499,7 +497,7 @@ impl BlockedTask { impl Death { pub fn new() -> Death { - Death { on_exit: None, marker: marker::NoCopy } + Death { on_exit: None } } } diff --git a/src/libserialize/json.rs b/src/libserialize/json.rs index d17f293b443..c811a16e2b1 100644 --- a/src/libserialize/json.rs +++ b/src/libserialize/json.rs @@ -367,8 +367,8 @@ fn escape_str(writer: &mut io::Writer, v: &str) -> Result<(), io::IoError> { fn escape_char(writer: &mut io::Writer, v: char) -> Result<(), io::IoError> { let mut buf = [0, .. 4]; - v.encode_utf8(&mut buf); - escape_bytes(writer, &mut buf) + let len = v.encode_utf8(&mut buf).unwrap(); + escape_bytes(writer, buf[mut ..len]) } fn spaces(wr: &mut io::Writer, mut n: uint) -> Result<(), io::IoError> { @@ -2082,8 +2082,9 @@ impl ::Decoder<DecoderError> for Decoder { f(self) } - fn read_enum_variant<T, F>(&mut self, names: &[&str], f: F) -> DecodeResult<T> where - F: FnOnce(&mut Decoder, uint) -> DecodeResult<T>, + fn read_enum_variant<T, F>(&mut self, names: &[&str], + mut f: F) -> DecodeResult<T> + where F: FnMut(&mut Decoder, uint) -> DecodeResult<T>, { debug!("read_enum_variant(names={})", names); let name = match self.pop() { @@ -2133,7 +2134,7 @@ impl ::Decoder<DecoderError> for Decoder { } fn read_enum_struct_variant<T, F>(&mut self, names: &[&str], f: F) -> DecodeResult<T> where - F: FnOnce(&mut Decoder, uint) -> DecodeResult<T>, + F: FnMut(&mut Decoder, uint) -> DecodeResult<T>, { debug!("read_enum_struct_variant(names={})", names); self.read_enum_variant(names, f) @@ -2230,8 +2231,8 @@ impl ::Decoder<DecoderError> for Decoder { self.read_tuple_arg(idx, f) } - fn read_option<T, F>(&mut self, f: F) -> DecodeResult<T> where - F: FnOnce(&mut Decoder, bool) -> DecodeResult<T>, + fn read_option<T, F>(&mut self, mut f: F) -> DecodeResult<T> where + F: FnMut(&mut Decoder, bool) -> DecodeResult<T>, { debug!("read_option()"); match self.pop() { @@ -2729,37 +2730,39 @@ mod tests { ); } + macro_rules! check_encoder_for_simple( + ($value:expr, $expected:expr) => ({ + let s = with_str_writer(|writer| { + let mut encoder = Encoder::new(writer); + $value.encode(&mut encoder).unwrap(); + }); + assert_eq!(s, $expected); + + let s = with_str_writer(|writer| { + let mut encoder = PrettyEncoder::new(writer); + $value.encode(&mut encoder).unwrap(); + }); + assert_eq!(s, $expected); + }) + ) + #[test] fn test_write_some() { - let value = Some("jodhpurs".into_string()); - let s = with_str_writer(|writer| { - let mut encoder = Encoder::new(writer); - value.encode(&mut encoder).unwrap(); - }); - assert_eq!(s, "\"jodhpurs\""); - - let value = Some("jodhpurs".into_string()); - let s = with_str_writer(|writer| { - let mut encoder = PrettyEncoder::new(writer); - value.encode(&mut encoder).unwrap(); - }); - assert_eq!(s, "\"jodhpurs\""); + check_encoder_for_simple!(Some("jodhpurs".to_string()), "\"jodhpurs\""); } #[test] fn test_write_none() { - let value: Option<string::String> = None; - let s = with_str_writer(|writer| { - let mut encoder = Encoder::new(writer); - value.encode(&mut encoder).unwrap(); - }); - assert_eq!(s, "null"); + check_encoder_for_simple!(None::<string::String>, "null"); + } - let s = with_str_writer(|writer| { - let mut encoder = Encoder::new(writer); - value.encode(&mut encoder).unwrap(); - }); - assert_eq!(s, "null"); + #[test] + fn test_write_char() { + check_encoder_for_simple!('a', "\"a\""); + check_encoder_for_simple!('\t', "\"\\t\""); + check_encoder_for_simple!('\u00a0', "\"\u00a0\""); + check_encoder_for_simple!('\uabcd', "\"\uabcd\""); + check_encoder_for_simple!('\U0010ffff', "\"\U0010ffff\""); } #[test] diff --git a/src/libserialize/serialize.rs b/src/libserialize/serialize.rs index 98bd2f6bc93..0e0d3b4115b 100644 --- a/src/libserialize/serialize.rs +++ b/src/libserialize/serialize.rs @@ -120,12 +120,12 @@ pub trait Decoder<E> { F: FnOnce(&mut Self) -> Result<T, E>; fn read_enum_variant<T, F>(&mut self, names: &[&str], f: F) -> Result<T, E> where - F: FnOnce(&mut Self, uint) -> Result<T, E>; + F: FnMut(&mut Self, uint) -> Result<T, E>; fn read_enum_variant_arg<T, F>(&mut self, a_idx: uint, f: F) -> Result<T, E> where F: FnOnce(&mut Self) -> Result<T, E>; fn read_enum_struct_variant<T, F>(&mut self, names: &[&str], f: F) -> Result<T, E> where - F: FnOnce(&mut Self, uint) -> Result<T, E>; + F: FnMut(&mut Self, uint) -> Result<T, E>; fn read_enum_struct_variant_field<T, F>(&mut self, &f_name: &str, f_idx: uint, @@ -154,7 +154,7 @@ pub trait Decoder<E> { // Specialized types: fn read_option<T, F>(&mut self, f: F) -> Result<T, E> where - F: FnOnce(&mut Self, bool) -> Result<T, E>; + F: FnMut(&mut Self, bool) -> Result<T, E>; fn read_seq<T, F>(&mut self, f: F) -> Result<T, E> where F: FnOnce(&mut Self, uint) -> Result<T, E>; diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 2a8d97eed05..0ff29a94f2f 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -20,7 +20,7 @@ use cmp::{max, Eq, Equiv, PartialEq}; use default::Default; use fmt::{mod, Show}; use hash::{Hash, Hasher, RandomSipHasher}; -use iter::{mod, Iterator, IteratorExt, FromIterator, Extend}; +use iter::{mod, Iterator, IteratorExt, FromIterator, Extend, Map}; use kinds::Sized; use mem::{mod, replace}; use num::{Int, UnsignedInt}; @@ -297,7 +297,7 @@ pub struct HashMap<K, V, H = RandomSipHasher> { /// Search for a pre-hashed key. fn search_hashed<K, V, M, F>(table: M, - hash: &SafeHash, + hash: SafeHash, mut is_match: F) -> SearchResult<K, V, M> where M: Deref<RawTable<K, V>>, @@ -320,14 +320,9 @@ fn search_hashed<K, V, M, F>(table: M, } // If the hash doesn't match, it can't be this one.. - if *hash == full.hash() { - let matched = { - let (k, _) = full.read(); - is_match(k) - }; - + if hash == full.hash() { // If the key doesn't match, it can't be this one.. - if matched { + if is_match(full.read().0) { return FoundExisting(full); } } @@ -353,7 +348,7 @@ fn pop_internal<K, V>(starting_bucket: FullBucketMut<K, V>) -> (K, V) { } // Now we've done all our shifting. Return the value we grabbed earlier. - return (retkey, retval); + (retkey, retval) } /// Perform robin hood bucket stealing at the given `bucket`. You must @@ -389,10 +384,11 @@ fn robin_hood<'a, K: 'a, V: 'a>(mut bucket: FullBucketMut<'a, K, V>, let b = bucket.put(old_hash, old_key, old_val); // Now that it's stolen, just read the value's pointer // right out of the table! - let (_, v) = Bucket::at_index(b.into_table(), starting_index).peek() - .expect_full() - .into_mut_refs(); - return v; + return Bucket::at_index(b.into_table(), starting_index) + .peek() + .expect_full() + .into_mut_refs() + .1; }, table::Full(bucket) => bucket }; @@ -441,14 +437,14 @@ impl<K: Eq + Hash<S>, V, S, H: Hasher<S>> HashMap<K, V, H> { fn search_equiv<'a, Sized? Q: Hash<S> + Equiv<K>>(&'a self, q: &Q) -> Option<FullBucketImm<'a, K, V>> { let hash = self.make_hash(q); - search_hashed(&self.table, &hash, |k| q.equiv(k)).into_option() + search_hashed(&self.table, hash, |k| q.equiv(k)).into_option() } #[allow(deprecated)] fn search_equiv_mut<'a, Sized? Q: Hash<S> + Equiv<K>>(&'a mut self, q: &Q) -> Option<FullBucketMut<'a, K, V>> { let hash = self.make_hash(q); - search_hashed(&mut self.table, &hash, |k| q.equiv(k)).into_option() + search_hashed(&mut self.table, hash, |k| q.equiv(k)).into_option() } /// Search for a key, yielding the index if it's found in the hashtable. @@ -458,7 +454,7 @@ impl<K: Eq + Hash<S>, V, S, H: Hasher<S>> HashMap<K, V, H> { where Q: BorrowFrom<K> + Eq + Hash<S> { let hash = self.make_hash(q); - search_hashed(&self.table, &hash, |k| q.eq(BorrowFrom::borrow_from(k))) + search_hashed(&self.table, hash, |k| q.eq(BorrowFrom::borrow_from(k))) .into_option() } @@ -466,14 +462,14 @@ impl<K: Eq + Hash<S>, V, S, H: Hasher<S>> HashMap<K, V, H> { where Q: BorrowFrom<K> + Eq + Hash<S> { let hash = self.make_hash(q); - search_hashed(&mut self.table, &hash, |k| q.eq(BorrowFrom::borrow_from(k))) + search_hashed(&mut self.table, hash, |k| q.eq(BorrowFrom::borrow_from(k))) .into_option() } // The caller should ensure that invariants by Robin Hood Hashing hold. fn insert_hashed_ordered(&mut self, hash: SafeHash, k: K, v: V) { let cap = self.table.capacity(); - let mut buckets = Bucket::new(&mut self.table, &hash); + let mut buckets = Bucket::new(&mut self.table, hash); let ib = buckets.index(); while buckets.index() != ib + cap { @@ -762,26 +758,22 @@ impl<K: Eq + Hash<S>, V, S, H: Hasher<S>> HashMap<K, V, H> { { // Worst case, we'll find one empty bucket among `size + 1` buckets. let size = self.table.size(); - let mut probe = Bucket::new(&mut self.table, &hash); + let mut probe = Bucket::new(&mut self.table, hash); let ib = probe.index(); loop { let mut bucket = match probe.peek() { Empty(bucket) => { // Found a hole! - let bucket = bucket.put(hash, k, v); - let (_, val) = bucket.into_mut_refs(); - return val; - }, + return bucket.put(hash, k, v).into_mut_refs().1; + } Full(bucket) => bucket }; + // hash matches? if bucket.hash() == hash { - let found_match = { - let (bucket_k, _) = bucket.read_mut(); - k == *bucket_k - }; - if found_match { + // key matches? + if k == *bucket.read_mut().0 { let (bucket_k, bucket_v) = bucket.into_mut_refs(); debug_assert!(k == *bucket_k); // Key already exists. Get its reference. @@ -811,13 +803,7 @@ impl<K: Eq + Hash<S>, V, S, H: Hasher<S>> HashMap<K, V, H> { /// Deprecated: use `get` and `BorrowFrom` instead. #[deprecated = "use get and BorrowFrom instead"] pub fn find_equiv<'a, Sized? Q: Hash<S> + Equiv<K>>(&'a self, k: &Q) -> Option<&'a V> { - match self.search_equiv(k) { - None => None, - Some(bucket) => { - let (_, v_ref) = bucket.into_refs(); - Some(v_ref) - } - } + self.search_equiv(k).map(|bucket| bucket.into_refs().1) } /// Deprecated: use `remove` and `BorrowFrom` instead. @@ -829,13 +815,7 @@ impl<K: Eq + Hash<S>, V, S, H: Hasher<S>> HashMap<K, V, H> { self.reserve(1); - match self.search_equiv_mut(k) { - Some(bucket) => { - let (_k, val) = pop_internal(bucket); - Some(val) - } - _ => None - } + self.search_equiv_mut(k).map(|bucket| pop_internal(bucket).1) } /// An iterator visiting all keys in arbitrary order. @@ -859,7 +839,7 @@ impl<K: Eq + Hash<S>, V, S, H: Hasher<S>> HashMap<K, V, H> { pub fn keys(&self) -> Keys<K, V> { fn first<A, B>((a, _): (A, B)) -> A { a } - self.iter().map(first) + Keys { inner: self.iter().map(first) } } /// An iterator visiting all values in arbitrary order. @@ -883,7 +863,7 @@ impl<K: Eq + Hash<S>, V, S, H: Hasher<S>> HashMap<K, V, H> { pub fn values(&self) -> Values<K, V> { fn second<A, B>((_, b): (A, B)) -> B { b } - self.iter().map(second) + Values { inner: self.iter().map(second) } } /// An iterator visiting all key-value pairs in arbitrary order. @@ -1022,11 +1002,8 @@ impl<K: Eq + Hash<S>, V, S, H: Hasher<S>> HashMap<K, V, H> { while buckets.index() != cap { buckets = match buckets.peek() { - Empty(b) => b.next(), - Full(full) => { - let (b, _, _) = full.take(); - b.next() - } + Empty(b) => b.next(), + Full(full) => full.take().0.next(), }; } } @@ -1057,10 +1034,7 @@ impl<K: Eq + Hash<S>, V, S, H: Hasher<S>> HashMap<K, V, H> { pub fn get<Sized? Q>(&self, k: &Q) -> Option<&V> where Q: Hash<S> + Eq + BorrowFrom<K> { - self.search(k).map(|bucket| { - let (_, v) = bucket.into_refs(); - v - }) + self.search(k).map(|bucket| bucket.into_refs().1) } /// Returns true if the map contains a value for the specified key. @@ -1115,13 +1089,7 @@ impl<K: Eq + Hash<S>, V, S, H: Hasher<S>> HashMap<K, V, H> { pub fn get_mut<Sized? Q>(&mut self, k: &Q) -> Option<&mut V> where Q: Hash<S> + Eq + BorrowFrom<K> { - match self.search_mut(k) { - Some(bucket) => { - let (_, v) = bucket.into_mut_refs(); - Some(v) - } - _ => None - } + self.search_mut(k).map(|bucket| bucket.into_mut_refs().1) } /// Deprecated: Renamed to `insert`. @@ -1189,10 +1157,7 @@ impl<K: Eq + Hash<S>, V, S, H: Hasher<S>> HashMap<K, V, H> { return None } - self.search_mut(k).map(|bucket| { - let (_k, val) = pop_internal(bucket); - val - }) + self.search_mut(k).map(|bucket| pop_internal(bucket).1) } } @@ -1200,7 +1165,7 @@ fn search_entry_hashed<'a, K: Eq, V>(table: &'a mut RawTable<K,V>, hash: SafeHas -> Entry<'a, K, V> { // Worst case, we'll find one empty bucket among `size + 1` buckets. let size = table.size(); - let mut probe = Bucket::new(table, &hash); + let mut probe = Bucket::new(table, hash); let ib = probe.index(); loop { @@ -1216,13 +1181,10 @@ fn search_entry_hashed<'a, K: Eq, V>(table: &'a mut RawTable<K,V>, hash: SafeHas Full(bucket) => bucket }; + // hash matches? if bucket.hash() == hash { - let is_eq = { - let (bucket_k, _) = bucket.read(); - k == *bucket_k - }; - - if is_eq { + // key matches? + if k == *bucket.read().0 { return Occupied(OccupiedEntry{ elem: bucket, }); @@ -1288,7 +1250,9 @@ impl<K: Eq + Hash<S> + Show, V: Show, S, H: Hasher<S>> Show for HashMap<K, V, H> } } +#[stable] impl<K: Eq + Hash<S>, V, S, H: Hasher<S> + Default> Default for HashMap<K, V, H> { + #[stable] fn default() -> HashMap<K, V, H> { HashMap::with_hasher(Default::default()) } @@ -1308,10 +1272,7 @@ impl<K: Hash<S> + Eq, Sized? Q, V, S, H: Hasher<S>> IndexMut<Q, V> for HashMap<K { #[inline] fn index_mut<'a>(&'a mut self, index: &Q) -> &'a mut V { - match self.get_mut(index) { - Some(v) => v, - None => panic!("no entry found for key") - } + self.get_mut(index).expect("no entry found for key") } } @@ -1335,6 +1296,16 @@ pub struct MoveEntries<K, V> { > } +/// HashMap keys iterator +pub struct Keys<'a, K: 'a, V: 'a> { + inner: Map<(&'a K, &'a V), &'a K, Entries<'a, K, V>, fn((&'a K, &'a V)) -> &'a K> +} + +/// HashMap values iterator +pub struct Values<'a, K: 'a, V: 'a> { + inner: Map<(&'a K, &'a V), &'a V, Entries<'a, K, V>, fn((&'a K, &'a V)) -> &'a V> +} + /// A view into a single occupied location in a HashMap pub struct OccupiedEntry<'a, K:'a, V:'a> { elem: FullBucket<K, V, &'a mut RawTable<K, V>>, @@ -1365,56 +1336,45 @@ enum VacantEntryState<K, V, M> { } impl<'a, K, V> Iterator<(&'a K, &'a V)> for Entries<'a, K, V> { - #[inline] - fn next(&mut self) -> Option<(&'a K, &'a V)> { - self.inner.next() - } - #[inline] - fn size_hint(&self) -> (uint, Option<uint>) { - self.inner.size_hint() - } + #[inline] fn next(&mut self) -> Option<(&'a K, &'a V)> { self.inner.next() } + #[inline] fn size_hint(&self) -> (uint, Option<uint>) { self.inner.size_hint() } } impl<'a, K, V> Iterator<(&'a K, &'a mut V)> for MutEntries<'a, K, V> { - #[inline] - fn next(&mut self) -> Option<(&'a K, &'a mut V)> { - self.inner.next() - } - #[inline] - fn size_hint(&self) -> (uint, Option<uint>) { - self.inner.size_hint() - } + #[inline] fn next(&mut self) -> Option<(&'a K, &'a mut V)> { self.inner.next() } + #[inline] fn size_hint(&self) -> (uint, Option<uint>) { self.inner.size_hint() } } impl<K, V> Iterator<(K, V)> for MoveEntries<K, V> { - #[inline] - fn next(&mut self) -> Option<(K, V)> { - self.inner.next() - } - #[inline] - fn size_hint(&self) -> (uint, Option<uint>) { - self.inner.size_hint() - } + #[inline] fn next(&mut self) -> Option<(K, V)> { self.inner.next() } + #[inline] fn size_hint(&self) -> (uint, Option<uint>) { self.inner.size_hint() } +} + +impl<'a, K, V> Iterator<&'a K> for Keys<'a, K, V> { + #[inline] fn next(&mut self) -> Option<(&'a K)> { self.inner.next() } + #[inline] fn size_hint(&self) -> (uint, Option<uint>) { self.inner.size_hint() } +} + +impl<'a, K, V> Iterator<&'a V> for Values<'a, K, V> { + #[inline] fn next(&mut self) -> Option<(&'a V)> { self.inner.next() } + #[inline] fn size_hint(&self) -> (uint, Option<uint>) { self.inner.size_hint() } } impl<'a, K, V> OccupiedEntry<'a, K, V> { /// Gets a reference to the value in the entry pub fn get(&self) -> &V { - let (_, v) = self.elem.read(); - v + self.elem.read().1 } /// Gets a mutable reference to the value in the entry pub fn get_mut(&mut self) -> &mut V { - let (_, v) = self.elem.read_mut(); - v + self.elem.read_mut().1 } /// Converts the OccupiedEntry into a mutable reference to the value in the entry /// with a lifetime bound to the map itself pub fn into_mut(self) -> &'a mut V { - let (_, v) = self.elem.into_mut_refs(); - v + self.elem.into_mut_refs().1 } /// Sets the value of the entry, and returns the entry's old value @@ -1426,8 +1386,7 @@ impl<'a, K, V> OccupiedEntry<'a, K, V> { /// Takes the value out of the entry, and returns it pub fn take(self) -> V { - let (_, v) = pop_internal(self.elem); - v + pop_internal(self.elem).1 } } @@ -1440,25 +1399,15 @@ impl<'a, K, V> VacantEntry<'a, K, V> { robin_hood(bucket, ib, self.hash, self.key, value) } NoElem(bucket) => { - let full = bucket.put(self.hash, self.key, value); - let (_, v) = full.into_mut_refs(); - v + bucket.put(self.hash, self.key, value).into_mut_refs().1 } } } } -/// HashMap keys iterator -pub type Keys<'a, K, V> = - iter::Map<(&'a K, &'a V), &'a K, Entries<'a, K, V>, fn((&'a K, &'a V)) -> &'a K>; - -/// HashMap values iterator -pub type Values<'a, K, V> = - iter::Map<(&'a K, &'a V), &'a V, Entries<'a, K, V>, fn((&'a K, &'a V)) -> &'a V>; - impl<K: Eq + Hash<S>, V, S, H: Hasher<S> + Default> FromIterator<(K, V)> for HashMap<K, V, H> { fn from_iter<T: Iterator<(K, V)>>(iter: T) -> HashMap<K, V, H> { - let (lower, _) = iter.size_hint(); + let lower = iter.size_hint().0; let mut map = HashMap::with_capacity_and_hasher(lower, Default::default()); map.extend(iter); map diff --git a/src/libstd/collections/hash/set.rs b/src/libstd/collections/hash/set.rs index c71f0d5b935..67c0f887832 100644 --- a/src/libstd/collections/hash/set.rs +++ b/src/libstd/collections/hash/set.rs @@ -17,12 +17,11 @@ use default::Default; use fmt::Show; use fmt; use hash::{Hash, Hasher, RandomSipHasher}; -use iter::{Iterator, IteratorExt, FromIterator, FilterMap, Chain, Repeat, Zip, Extend, repeat}; -use iter; +use iter::{Iterator, IteratorExt, FromIterator, Map, FilterMap, Chain, Repeat, Zip, Extend, repeat}; use option::Option::{Some, None, mod}; use result::Result::{Ok, Err}; -use super::map::{HashMap, Entries, MoveEntries, INITIAL_CAPACITY}; +use super::map::{HashMap, MoveEntries, Keys, INITIAL_CAPACITY}; // FIXME(conventions): implement BitOr, BitAnd, BitXor, and Sub @@ -252,7 +251,7 @@ impl<T: Eq + Hash<S>, S, H: Hasher<S>> HashSet<T, H> { /// ``` #[unstable = "matches collection reform specification, waiting for dust to settle"] pub fn iter<'a>(&'a self) -> SetItems<'a, T> { - self.map.keys() + SetItems { iter: self.map.keys() } } /// Creates a consuming iterator, that is, one that moves each value out @@ -279,7 +278,7 @@ impl<T: Eq + Hash<S>, S, H: Hasher<S>> HashSet<T, H> { pub fn into_iter(self) -> SetMoveItems<T> { fn first<A, B>((a, _): (A, B)) -> A { a } - self.map.into_iter().map(first) + SetMoveItems { iter: self.map.into_iter().map(first) } } /// Visit the values representing the difference. @@ -312,7 +311,7 @@ impl<T: Eq + Hash<S>, S, H: Hasher<S>> HashSet<T, H> { if !other.contains(elt) { Some(elt) } else { None } } - repeat(other).zip(self.iter()).filter_map(filter) + SetAlgebraItems { iter: repeat(other).zip(self.iter()).filter_map(filter) } } /// Visit the values representing the symmetric difference. @@ -337,8 +336,8 @@ impl<T: Eq + Hash<S>, S, H: Hasher<S>> HashSet<T, H> { /// ``` #[unstable = "matches collection reform specification, waiting for dust to settle"] pub fn symmetric_difference<'a>(&'a self, other: &'a HashSet<T, H>) - -> Chain<SetAlgebraItems<'a, T, H>, SetAlgebraItems<'a, T, H>> { - self.difference(other).chain(other.difference(self)) + -> SymDifferenceItems<'a, T, H> { + SymDifferenceItems { iter: self.difference(other).chain(other.difference(self)) } } /// Visit the values representing the intersection. @@ -366,7 +365,7 @@ impl<T: Eq + Hash<S>, S, H: Hasher<S>> HashSet<T, H> { if other.contains(elt) { Some(elt) } else { None } } - repeat(other).zip(self.iter()).filter_map(filter) + SetAlgebraItems { iter: repeat(other).zip(self.iter()).filter_map(filter) } } /// Visit the values representing the union. @@ -387,9 +386,8 @@ impl<T: Eq + Hash<S>, S, H: Hasher<S>> HashSet<T, H> { /// assert_eq!(diff, [1i, 2, 3, 4].iter().map(|&x| x).collect()); /// ``` #[unstable = "matches collection reform specification, waiting for dust to settle"] - pub fn union<'a>(&'a self, other: &'a HashSet<T, H>) - -> Chain<SetItems<'a, T>, SetAlgebraItems<'a, T, H>> { - self.iter().chain(other.difference(self)) + pub fn union<'a>(&'a self, other: &'a HashSet<T, H>) -> UnionItems<'a, T, H> { + UnionItems { iter: self.iter().chain(other.difference(self)) } } /// Return the number of elements in the set @@ -595,7 +593,7 @@ impl<T: Eq + Hash<S> + fmt::Show, S, H: Hasher<S>> fmt::Show for HashSet<T, H> { impl<T: Eq + Hash<S>, S, H: Hasher<S> + Default> FromIterator<T> for HashSet<T, H> { fn from_iter<I: Iterator<T>>(iter: I) -> HashSet<T, H> { - let (lower, _) = iter.size_hint(); + let lower = iter.size_hint().0; let mut set = HashSet::with_capacity_and_hasher(lower, Default::default()); set.extend(iter); set @@ -610,28 +608,70 @@ impl<T: Eq + Hash<S>, S, H: Hasher<S> + Default> Extend<T> for HashSet<T, H> { } } +#[stable] impl<T: Eq + Hash<S>, S, H: Hasher<S> + Default> Default for HashSet<T, H> { + #[stable] fn default() -> HashSet<T, H> { HashSet::with_hasher(Default::default()) } } /// HashSet iterator -pub type SetItems<'a, K> = - iter::Map<(&'a K, &'a ()), &'a K, Entries<'a, K, ()>, fn((&'a K, &'a ())) -> &'a K>; +pub struct SetItems<'a, K: 'a> { + iter: Keys<'a, K, ()> +} /// HashSet move iterator -pub type SetMoveItems<K> = iter::Map<(K, ()), K, MoveEntries<K, ()>, fn((K, ())) -> K>; +pub struct SetMoveItems<K> { + iter: Map<(K, ()), K, MoveEntries<K, ()>, fn((K, ())) -> K> +} // `Repeat` is used to feed the filter closure an explicit capture // of a reference to the other set -/// Set operations iterator -pub type SetAlgebraItems<'a, T, H> = FilterMap< - (&'a HashSet<T, H>, &'a T), - &'a T, - Zip<Repeat<&'a HashSet<T, H>>, SetItems<'a, T>>, - for<'b> fn((&HashSet<T, H>, &'b T)) -> Option<&'b T>, ->; +/// Set operations iterator, used directly for intersection and difference +pub struct SetAlgebraItems<'a, T: 'a, H: 'a> { + iter: FilterMap< + (&'a HashSet<T, H>, &'a T), + &'a T, + Zip<Repeat<&'a HashSet<T, H>>, SetItems<'a, T>>, + for<'b> fn((&HashSet<T, H>, &'b T)) -> Option<&'b T>, + > +} + +/// Symmetric difference iterator. +pub struct SymDifferenceItems<'a, T: 'a, H: 'a> { + iter: Chain<SetAlgebraItems<'a, T, H>, SetAlgebraItems<'a, T, H>> +} + +/// Set union iterator. +pub struct UnionItems<'a, T: 'a, H: 'a> { + iter: Chain<SetItems<'a, T>, SetAlgebraItems<'a, T, H>> +} + +impl<'a, K> Iterator<&'a K> for SetItems<'a, K> { + fn next(&mut self) -> Option<&'a K> { self.iter.next() } + fn size_hint(&self) -> (uint, Option<uint>) { self.iter.size_hint() } +} + +impl<K> Iterator<K> for SetMoveItems<K> { + fn next(&mut self) -> Option<K> { self.iter.next() } + fn size_hint(&self) -> (uint, Option<uint>) { self.iter.size_hint() } +} + +impl<'a, T, H> Iterator<&'a T> for SetAlgebraItems<'a, T, H> { + fn next(&mut self) -> Option<&'a T> { self.iter.next() } + fn size_hint(&self) -> (uint, Option<uint>) { self.iter.size_hint() } +} + +impl<'a, T, H> Iterator<&'a T> for SymDifferenceItems<'a, T, H> { + fn next(&mut self) -> Option<&'a T> { self.iter.next() } + fn size_hint(&self) -> (uint, Option<uint>) { self.iter.size_hint() } +} + +impl<'a, T, H> Iterator<&'a T> for UnionItems<'a, T, H> { + fn next(&mut self) -> Option<&'a T> { self.iter.next() } + fn size_hint(&self) -> (uint, Option<uint>) { self.iter.size_hint() } +} #[cfg(test)] mod test_set { diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs index ef4cabedc47..da06387e9a5 100644 --- a/src/libstd/collections/hash/table.rs +++ b/src/libstd/collections/hash/table.rs @@ -124,7 +124,7 @@ struct GapThenFull<K, V, M> { /// A hash that is not zero, since we use a hash of zero to represent empty /// buckets. -#[deriving(PartialEq)] +#[deriving(PartialEq, Copy)] pub struct SafeHash { hash: u64, } @@ -211,7 +211,7 @@ impl<K, V, M> Bucket<K, V, M> { } impl<K, V, M: Deref<RawTable<K, V>>> Bucket<K, V, M> { - pub fn new(table: M, hash: &SafeHash) -> Bucket<K, V, M> { + pub fn new(table: M, hash: SafeHash) -> Bucket<K, V, M> { Bucket::at_index(table, hash.inspect() as uint) } diff --git a/src/libstd/comm/mod.rs b/src/libstd/comm/mod.rs index 0a5b3e5771b..72ddbe19f54 100644 --- a/src/libstd/comm/mod.rs +++ b/src/libstd/comm/mod.rs @@ -81,7 +81,7 @@ //! Shared usage: //! //! ``` -//! // Create a shared channel which can be sent along from many tasks +//! // Create a shared channel that can be sent along from many tasks //! // where tx is the sending half (tx for transmission), and rx is the receiving //! // half (rx for receiving). //! let (tx, rx) = channel(); @@ -176,7 +176,7 @@ // The choice of implementation of all channels is to be built on lock-free data // structures. The channels themselves are then consequently also lock-free data // structures. As always with lock-free code, this is a very "here be dragons" -// territory, especially because I'm unaware of any academic papers which have +// territory, especially because I'm unaware of any academic papers that have // gone into great length about channels of these flavors. // // ## Flavors of channels @@ -190,7 +190,7 @@ // They contain as few atomics as possible and involve one and // exactly one allocation. // * Streams - these channels are optimized for the non-shared use case. They -// use a different concurrent queue which is more tailored for this +// use a different concurrent queue that is more tailored for this // use case. The initial allocation of this flavor of channel is not // optimized. // * Shared - this is the most general form of channel that this module offers, @@ -205,7 +205,7 @@ // shared and concurrent queue holding all of the actual data. // // With two flavors of channels, two flavors of queues are also used. We have -// chosen to use queues from a well-known author which are abbreviated as SPSC +// chosen to use queues from a well-known author that are abbreviated as SPSC // and MPSC (single producer, single consumer and multiple producer, single // consumer). SPSC queues are used for streams while MPSC queues are used for // shared channels. @@ -309,7 +309,7 @@ // // Sadly this current implementation requires multiple allocations, so I have // seen the throughput of select() be much worse than it should be. I do not -// believe that there is anything fundamental which needs to change about these +// believe that there is anything fundamental that needs to change about these // channels, however, in order to support a more efficient select(). // // # Conclusion @@ -910,7 +910,7 @@ impl<T: Send> Receiver<T> { } } - /// Returns an iterator which will block waiting for messages, but never + /// Returns an iterator that will block waiting for messages, but never /// `panic!`. It will return `None` when the channel has hung up. #[unstable] pub fn iter<'a>(&'a self) -> Messages<'a, T> { diff --git a/src/libstd/hash.rs b/src/libstd/hash.rs index a63abec96d5..52e3c718b2d 100644 --- a/src/libstd/hash.rs +++ b/src/libstd/hash.rs @@ -95,7 +95,9 @@ impl Hasher<sip::SipState> for RandomSipHasher { } } +#[stable] impl Default for RandomSipHasher { + #[stable] #[inline] fn default() -> RandomSipHasher { RandomSipHasher::new() diff --git a/src/libstd/io/fs.rs b/src/libstd/io/fs.rs index 40c28877548..f8df7e9b1f3 100644 --- a/src/libstd/io/fs.rs +++ b/src/libstd/io/fs.rs @@ -200,7 +200,7 @@ impl File { .update_desc("couldn't create file") } - /// Returns the original path which was used to open this file. + /// Returns the original path that was used to open this file. pub fn path<'a>(&'a self) -> &'a Path { &self.path } @@ -215,7 +215,7 @@ impl File { } /// This function is similar to `fsync`, except that it may not synchronize - /// file metadata to the filesystem. This is intended for use case which + /// file metadata to the filesystem. This is intended for use cases that /// must synchronize content, but don't need the metadata on disk. The goal /// of this method is to reduce disk operations. pub fn datasync(&mut self) -> IoResult<()> { @@ -456,7 +456,7 @@ pub fn symlink(src: &Path, dst: &Path) -> IoResult<()> { /// # Error /// /// This function will return an error on failure. Failure conditions include -/// reading a file that does not exist or reading a file which is not a symlink. +/// reading a file that does not exist or reading a file that is not a symlink. pub fn readlink(path: &Path) -> IoResult<Path> { fs_imp::readlink(path) .update_err("couldn't resolve symlink for path", |e| @@ -546,7 +546,7 @@ pub fn readdir(path: &Path) -> IoResult<Vec<Path>> { |e| format!("{}; path={}", e, path.display())) } -/// Returns an iterator which will recursively walk the directory structure +/// Returns an iterator that will recursively walk the directory structure /// rooted at `path`. The path given will not be iterated over, and this will /// perform iteration in some top-down order. The contents of unreadable /// subdirectories are ignored. @@ -557,7 +557,7 @@ pub fn walk_dir(path: &Path) -> IoResult<Directories> { }) } -/// An iterator which walks over a directory +/// An iterator that walks over a directory pub struct Directories { stack: Vec<Path>, } diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index 6fc9d0bd172..6a6d467e86c 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -1911,7 +1911,9 @@ bitflags! { } +#[stable] impl Default for FilePermission { + #[stable] #[inline] fn default() -> FilePermission { FilePermission::empty() } } diff --git a/src/libstd/io/net/udp.rs b/src/libstd/io/net/udp.rs index 78951b8dae2..ce7e5ca5f5e 100644 --- a/src/libstd/io/net/udp.rs +++ b/src/libstd/io/net/udp.rs @@ -557,11 +557,12 @@ mod test { let addr1 = next_test_ip4(); let addr2 = next_test_ip4(); let mut a = UdpSocket::bind(addr1).unwrap(); + let a2 = UdpSocket::bind(addr2).unwrap(); let (tx, rx) = channel(); let (tx2, rx2) = channel(); spawn(move|| { - let mut a = UdpSocket::bind(addr2).unwrap(); + let mut a = a2; assert_eq!(a.recv_from(&mut [0]), Ok((1, addr1))); assert_eq!(a.send_to(&[0], addr1), Ok(())); rx.recv(); diff --git a/src/libstd/io/stdio.rs b/src/libstd/io/stdio.rs index c180476efb8..844814fbfdd 100644 --- a/src/libstd/io/stdio.rs +++ b/src/libstd/io/stdio.rs @@ -41,6 +41,7 @@ use option::Option; use option::Option::{Some, None}; use ops::{Deref, DerefMut, FnOnce}; use result::Result::{Ok, Err}; +use rt; use rustrt; use rustrt::local::Local; use rustrt::task::Task; @@ -224,6 +225,12 @@ pub fn stdin() -> StdinReader { inner: Arc::new(Mutex::new(stdin)) }; STDIN = mem::transmute(box stdin); + + // Make sure to free it at exit + rt::at_exit(|| { + mem::transmute::<_, Box<StdinReader>>(STDIN); + STDIN = 0 as *const _; + }); }); (*STDIN).clone() diff --git a/src/libstd/rand/os.rs b/src/libstd/rand/os.rs index bbe8edc0f00..6bccef07131 100644 --- a/src/libstd/rand/os.rs +++ b/src/libstd/rand/os.rs @@ -117,7 +117,8 @@ mod imp { /// `/dev/urandom`, or from `getrandom(2)` system call if available. /// - Windows: calls `CryptGenRandom`, using the default cryptographic /// service provider with the `PROV_RSA_FULL` type. - /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed + /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed. + /// /// This does not block. pub struct OsRng { inner: OsRngInner, @@ -184,10 +185,13 @@ mod imp { /// `/dev/urandom`, or from `getrandom(2)` system call if available. /// - Windows: calls `CryptGenRandom`, using the default cryptographic /// service provider with the `PROV_RSA_FULL` type. - /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed + /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed. + /// /// This does not block. + #[allow(missing_copy_implementations)] pub struct OsRng { - marker: marker::NoCopy + // dummy field to ensure that this struct cannot be constructed outside of this module + _dummy: (), } #[repr(C)] @@ -205,7 +209,7 @@ mod imp { impl OsRng { /// Create a new `OsRng`. pub fn new() -> IoResult<OsRng> { - Ok(OsRng {marker: marker::NoCopy} ) + Ok(OsRng { _dummy: () }) } } @@ -254,7 +258,8 @@ mod imp { /// `/dev/urandom`, or from `getrandom(2)` system call if available. /// - Windows: calls `CryptGenRandom`, using the default cryptographic /// service provider with the `PROV_RSA_FULL` type. - /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed + /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed. + /// /// This does not block. pub struct OsRng { hcryptprov: HCRYPTPROV diff --git a/src/libstd/sys/common/thread_local.rs b/src/libstd/sys/common/thread_local.rs index 3eb0e3f46cb..cf56a71d67a 100644 --- a/src/libstd/sys/common/thread_local.rs +++ b/src/libstd/sys/common/thread_local.rs @@ -58,7 +58,6 @@ use prelude::*; -use kinds::marker; use rustrt::exclusive::Exclusive; use sync::atomic::{mod, AtomicUint}; use sync::{Once, ONCE_INIT}; @@ -100,7 +99,6 @@ pub struct StaticKey { /// Inner contents of `StaticKey`, created by the `INIT_INNER` constant. pub struct StaticKeyInner { key: AtomicUint, - nc: marker::NoCopy, } /// A type for a safely managed OS-based TLS slot. @@ -141,7 +139,6 @@ pub const INIT: StaticKey = StaticKey { /// This value allows specific configuration of the destructor for a TLS key. pub const INIT_INNER: StaticKeyInner = StaticKeyInner { key: atomic::INIT_ATOMIC_UINT, - nc: marker::NoCopy, }; static INIT_KEYS: Once = ONCE_INIT; diff --git a/src/libstd/task.rs b/src/libstd/task.rs index 562afd33e2f..324b594209a 100644 --- a/src/libstd/task.rs +++ b/src/libstd/task.rs @@ -49,7 +49,7 @@ use boxed::Box; use comm::channel; use core::ops::FnOnce; use io::{Writer, stdio}; -use kinds::{Send, marker}; +use kinds::Send; use option::Option; use option::Option::{None, Some}; use result::Result; @@ -83,7 +83,6 @@ pub struct TaskBuilder { stderr: Option<Box<Writer + Send>>, // Optionally wrap the eventual task body gen_body: Option<Thunk<Thunk, Thunk>>, - nocopy: marker::NoCopy, } impl TaskBuilder { @@ -96,7 +95,6 @@ impl TaskBuilder { stdout: None, stderr: None, gen_body: None, - nocopy: marker::NoCopy, } } } @@ -137,7 +135,7 @@ impl TaskBuilder { on_exit: Option<Thunk<task::Result>>) { let TaskBuilder { - name, stack_size, stdout, stderr, mut gen_body, nocopy: _ + name, stack_size, stdout, stderr, mut gen_body } = self; let f = match gen_body.take() { diff --git a/src/libstd/thread_local/mod.rs b/src/libstd/thread_local/mod.rs index 2d5766c2393..76fb703514b 100644 --- a/src/libstd/thread_local/mod.rs +++ b/src/libstd/thread_local/mod.rs @@ -185,7 +185,6 @@ macro_rules! __thread_local_inner( inner: ::std::cell::UnsafeCell { value: $init }, dtor_registered: ::std::cell::UnsafeCell { value: false }, dtor_running: ::std::cell::UnsafeCell { value: false }, - marker: ::std::kinds::marker::NoCopy, } }; @@ -247,7 +246,6 @@ mod imp { use cell::UnsafeCell; use intrinsics; - use kinds::marker; use ptr; #[doc(hidden)] @@ -264,9 +262,6 @@ mod imp { // these variables are thread-local, not global. pub dtor_registered: UnsafeCell<bool>, // should be Cell pub dtor_running: UnsafeCell<bool>, // should be Cell - - // These shouldn't be copied around. - pub marker: marker::NoCopy, } #[doc(hidden)] diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 206fb26eb55..98d858babb1 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -696,7 +696,7 @@ pub struct Expr { #[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] pub enum Expr_ { /// First expr is the place; second expr is the value. - ExprBox(P<Expr>, P<Expr>), + ExprBox(Option<P<Expr>>, P<Expr>), ExprVec(Vec<P<Expr>>), ExprCall(P<Expr>, Vec<P<Expr>>), ExprMethodCall(SpannedIdent, Vec<P<Ty>>, Vec<P<Expr>>), diff --git a/src/libsyntax/ext/deriving/generic/mod.rs b/src/libsyntax/ext/deriving/generic/mod.rs index f40be823a1a..b31758e2d2a 100644 --- a/src/libsyntax/ext/deriving/generic/mod.rs +++ b/src/libsyntax/ext/deriving/generic/mod.rs @@ -388,7 +388,7 @@ impl<'a> TraitDef<'a> { methods: Vec<P<ast::Method>>) -> P<ast::Item> { let trait_path = self.path.to_path(cx, self.span, type_ident, generics); - let Generics { mut lifetimes, ty_params, where_clause: _ } = + let Generics { mut lifetimes, ty_params, mut where_clause } = self.generics.to_generics(cx, self.span, type_ident, generics); let mut ty_params = ty_params.into_vec(); @@ -420,13 +420,33 @@ impl<'a> TraitDef<'a> { ty_param.unbound.clone(), None) })); + + // and similarly for where clauses + where_clause.predicates.extend(generics.where_clause.predicates.iter().map(|clause| { + match *clause { + ast::WherePredicate::BoundPredicate(ref wb) => { + ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate { + id: ast::DUMMY_NODE_ID, + span: self.span, + ident: wb.ident, + bounds: OwnedSlice::from_vec(wb.bounds.iter().map(|b| b.clone()).collect()) + }) + } + ast::WherePredicate::EqPredicate(ref we) => { + ast::WherePredicate::EqPredicate(ast::WhereEqPredicate { + id: ast::DUMMY_NODE_ID, + span: self.span, + path: we.path.clone(), + ty: we.ty.clone() + }) + } + } + })); + let trait_generics = Generics { lifetimes: lifetimes, ty_params: OwnedSlice::from_vec(ty_params), - where_clause: ast::WhereClause { - id: ast::DUMMY_NODE_ID, - predicates: Vec::new(), - }, + where_clause: where_clause }; // Create the reference to the trait. diff --git a/src/libsyntax/ext/deriving/mod.rs b/src/libsyntax/ext/deriving/mod.rs index fccef47d1ea..839e99c81d1 100644 --- a/src/libsyntax/ext/deriving/mod.rs +++ b/src/libsyntax/ext/deriving/mod.rs @@ -70,8 +70,28 @@ pub fn expand_meta_deriving(cx: &mut ExtCtxt, "Hash" => expand!(hash::expand_deriving_hash), - "Encodable" => expand!(encodable::expand_deriving_encodable), - "Decodable" => expand!(decodable::expand_deriving_decodable), + "RustcEncodable" => { + expand!(encodable::expand_deriving_encodable) + } + "RustcDecodable" => { + expand!(decodable::expand_deriving_decodable) + } + "Encodable" => { + // NOTE: uncomment after a stage0 snap + // cx.span_warn(titem.span, + // "deriving(Encodable) is deprecated \ + // in favor of deriving(RustcEncodable)"); + + expand!(encodable::expand_deriving_encodable) + } + "Decodable" => { + // NOTE: uncomment after a stage0 snap + // cx.span_warn(titem.span, + // "deriving(Decodable) is deprecated \ + // in favor of deriving(RustcDecodable)"); + + expand!(decodable::expand_deriving_decodable) + } "PartialEq" => expand!(eq::expand_deriving_eq), "Eq" => expand!(totaleq::expand_deriving_totaleq), diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 8a578c2cb05..7d2acd08d94 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -1282,7 +1282,7 @@ pub fn noop_fold_expr<T: Folder>(Expr {id, node, span}: Expr, folder: &mut T) -> id: folder.new_id(id), node: match node { ExprBox(p, e) => { - ExprBox(folder.fold_expr(p), folder.fold_expr(e)) + ExprBox(p.map(|e|folder.fold_expr(e)), folder.fold_expr(e)) } ExprVec(exprs) => { ExprVec(exprs.move_map(|x| folder.fold_expr(x))) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index b9ef3fdbd49..6e3cfe5854a 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2888,7 +2888,7 @@ impl<'a> Parser<'a> { } let subexpression = self.parse_prefix_expr(); hi = subexpression.span.hi; - ex = ExprBox(place, subexpression); + ex = ExprBox(Some(place), subexpression); return self.mk_expr(lo, hi, ex); } } @@ -2896,6 +2896,9 @@ impl<'a> Parser<'a> { // Otherwise, we use the unique pointer default. let subexpression = self.parse_prefix_expr(); hi = subexpression.span.hi; + // FIXME (pnkfelix): After working out kinks with box + // desugaring, should be `ExprBox(None, subexpression)` + // instead. ex = self.mk_unary(UnUniq, subexpression); } _ => return self.parse_dot_or_call_expr() diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index db122f271a9..cbbfcfef72e 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1005,8 +1005,13 @@ impl<'a> State<'a> { fn print_poly_trait_ref(&mut self, t: &ast::PolyTraitRef) -> IoResult<()> { if !t.bound_lifetimes.is_empty() { try!(word(&mut self.s, "for<")); + let mut comma = false; for lifetime_def in t.bound_lifetimes.iter() { + if comma { + try!(self.word_space(",")) + } try!(self.print_lifetime_def(lifetime_def)); + comma = true; } try!(word(&mut self.s, ">")); } @@ -1057,6 +1062,7 @@ impl<'a> State<'a> { span: codemap::Span) -> IoResult<()> { try!(self.print_ident(ident)); try!(self.print_generics(generics)); + try!(self.print_where_clause(generics)); if ast_util::struct_def_is_tuple_like(struct_def) { if !struct_def.fields.is_empty() { try!(self.popen()); @@ -1495,7 +1501,7 @@ impl<'a> State<'a> { ast::ExprBox(ref p, ref e) => { try!(word(&mut self.s, "box")); try!(word(&mut self.s, "(")); - try!(self.print_expr(&**p)); + try!(p.as_ref().map_or(Ok(()), |e|self.print_expr(&**e))); try!(self.word_space(")")); try!(self.print_expr(&**e)); } diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 3535c6e267e..95d7906b443 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -555,14 +555,18 @@ pub fn walk_ty_param_bound<'v, V: Visitor<'v>>(visitor: &mut V, } } +pub fn walk_ty_param<'v, V: Visitor<'v>>(visitor: &mut V, param: &'v TyParam) { + visitor.visit_ident(param.span, param.ident); + walk_ty_param_bounds_helper(visitor, ¶m.bounds); + match param.default { + Some(ref ty) => visitor.visit_ty(&**ty), + None => {} + } +} + pub fn walk_generics<'v, V: Visitor<'v>>(visitor: &mut V, generics: &'v Generics) { for type_parameter in generics.ty_params.iter() { - visitor.visit_ident(type_parameter.span, type_parameter.ident); - walk_ty_param_bounds_helper(visitor, &type_parameter.bounds); - match type_parameter.default { - Some(ref ty) => visitor.visit_ty(&**ty), - None => {} - } + walk_ty_param(visitor, type_parameter); } walk_lifetime_decls_helper(visitor, &generics.lifetimes); for predicate in generics.where_clause.predicates.iter() { @@ -665,8 +669,7 @@ pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_method: &'v Tr RequiredMethod(ref method_type) => visitor.visit_ty_method(method_type), ProvidedMethod(ref method) => walk_method_helper(visitor, &**method), TypeTraitItem(ref associated_type) => { - visitor.visit_ident(associated_type.ty_param.span, - associated_type.ty_param.ident) + walk_ty_param(visitor, &associated_type.ty_param); } } } @@ -739,7 +742,7 @@ pub fn walk_mac<'v, V: Visitor<'v>>(_: &mut V, _: &'v Mac) { pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) { match expression.node { ExprBox(ref place, ref subexpression) => { - visitor.visit_expr(&**place); + place.as_ref().map(|e|visitor.visit_expr(&**e)); visitor.visit_expr(&**subexpression) } ExprVec(ref subexpressions) => { diff --git a/src/rust-installer b/src/rust-installer new file mode 160000 index 00000000000..aed73472416 --- /dev/null +++ b/src/rust-installer @@ -0,0 +1 @@ +Subproject commit aed73472416064642911af790b25d57c9390b6c7 diff --git a/src/test/compile-fail-fulldeps/macro-crate-cannot-read-embedded-ident.rs b/src/test/compile-fail-fulldeps/macro-crate-cannot-read-embedded-ident.rs index 268b6e6aa0f..fc7664c480f 100644 --- a/src/test/compile-fail-fulldeps/macro-crate-cannot-read-embedded-ident.rs +++ b/src/test/compile-fail-fulldeps/macro-crate-cannot-read-embedded-ident.rs @@ -11,7 +11,7 @@ // aux-build:macro_crate_test.rs // ignore-stage1 // ignore-android -// error-pattern: unknown start of token: \x00 +// error-pattern: unknown start of token: \u{0} // Issue #15750 and #15962 : this test is checking that the standard // parser rejects embedded idents. pnkfelix did not want to attempt diff --git a/src/test/compile-fail/fn-trait-formatting.rs b/src/test/compile-fail/fn-trait-formatting.rs new file mode 100644 index 00000000000..3eeb4c177ca --- /dev/null +++ b/src/test/compile-fail/fn-trait-formatting.rs @@ -0,0 +1,24 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(unboxed_closures)] + +fn needs_fn<F>(x: F) where F: Fn(int) -> int {} + +fn main() { + let _: () = (box |:_: int| {}) as Box<FnOnce(int)>; //~ ERROR object-safe + //~^ ERROR Box<core::ops::FnOnce(int)> + let _: () = (box |&:_: int, int| {}) as Box<Fn(int, int)>; + //~^ ERROR Box<core::ops::Fn(int, int)> + let _: () = (box |&mut:| -> int unimplemented!()) as Box<FnMut() -> int>; + //~^ ERROR Box<core::ops::FnMut() -> int> + + needs_fn(1i); //~ ERROR `core::ops::Fn(int) -> int` +} diff --git a/src/test/compile-fail/ptr-coercion.rs b/src/test/compile-fail/ptr-coercion.rs new file mode 100644 index 00000000000..d9b20748a7a --- /dev/null +++ b/src/test/compile-fail/ptr-coercion.rs @@ -0,0 +1,24 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test coercions between pointers which don't do anything fancy like unsizing. +// These are testing that we don't lose mutability when converting to raw pointers. + +pub fn main() { + // *const -> *mut + let x: *const int = &42i; + let x: *mut int = x; //~ERROR values differ in mutability + + // & -> *mut + let x: *mut int = &42; //~ERROR values differ in mutability + + let x: *const int = &42; + let x: *mut int = x; //~ERROR values differ in mutability +} diff --git a/src/test/compile-fail/unboxed-closer-non-implicit-copyable.rs b/src/test/compile-fail/unboxed-closer-non-implicit-copyable.rs new file mode 100644 index 00000000000..182c632d062 --- /dev/null +++ b/src/test/compile-fail/unboxed-closer-non-implicit-copyable.rs @@ -0,0 +1,17 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(unboxed_closures)] + +fn main() { + let f = move|:| (); + f(); + f(); //~ ERROR use of moved value +} diff --git a/src/test/run-pass-valgrind/cleanup-stdin.rs b/src/test/run-pass-valgrind/cleanup-stdin.rs new file mode 100644 index 00000000000..21160553f79 --- /dev/null +++ b/src/test/run-pass-valgrind/cleanup-stdin.rs @@ -0,0 +1,13 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + let _ = std::io::stdin(); +} diff --git a/src/test/run-pass/associated-types-resolve-lifetime.rs b/src/test/run-pass/associated-types-resolve-lifetime.rs new file mode 100644 index 00000000000..1be09e1e068 --- /dev/null +++ b/src/test/run-pass/associated-types-resolve-lifetime.rs @@ -0,0 +1,22 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(associated_types)] + +trait Get<T> { + fn get(&self) -> T; +} + +trait Trait<'a> { + type T: 'static; + type U: Get<&'a int>; +} + +fn main() {} diff --git a/src/test/run-pass/issue-12677.rs b/src/test/run-pass/issue-12677.rs new file mode 100644 index 00000000000..ef68daa8ce5 --- /dev/null +++ b/src/test/run-pass/issue-12677.rs @@ -0,0 +1,17 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + let s = "Hello"; + let first = s.bytes(); + let second = first.clone(); + + assert_eq!(first.collect::<Vec<u8>>(), second.collect::<Vec<u8>>()) +} diff --git a/src/test/run-pass/issue-19129-1.rs b/src/test/run-pass/issue-19129-1.rs new file mode 100644 index 00000000000..eecc073b047 --- /dev/null +++ b/src/test/run-pass/issue-19129-1.rs @@ -0,0 +1,25 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(associated_types)] + +trait Trait<Input> { + type Output; + + fn method() -> <Self as Trait<Input>>::Output; +} + +impl<T> Trait<T> for () { + type Output = (); + + fn method() {} +} + +fn main() {} diff --git a/src/test/run-pass/issue-19129-2.rs b/src/test/run-pass/issue-19129-2.rs new file mode 100644 index 00000000000..aeaf5e37644 --- /dev/null +++ b/src/test/run-pass/issue-19129-2.rs @@ -0,0 +1,19 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(associated_types)] + +trait Trait<Input> { + type Output; + + fn method() -> bool { false } +} + +fn main() {} diff --git a/src/test/run-pass/issue-19358.rs b/src/test/run-pass/issue-19358.rs new file mode 100644 index 00000000000..e4c190f4116 --- /dev/null +++ b/src/test/run-pass/issue-19358.rs @@ -0,0 +1,29 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +trait Trait {} + +#[deriving(Show)] +struct Foo<T: Trait> { + foo: T, +} + +#[deriving(Show)] +struct Bar<T> where T: Trait { + bar: T, +} + +impl Trait for int {} + +fn main() { + let a = Foo { foo: 12i }; + let b = Bar { bar: 12i }; + println!("{} {}", a, b); +} diff --git a/src/test/run-pass/ptr-coercion.rs b/src/test/run-pass/ptr-coercion.rs new file mode 100644 index 00000000000..1b77c1316ed --- /dev/null +++ b/src/test/run-pass/ptr-coercion.rs @@ -0,0 +1,35 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test coercions between pointers which don't do anything fancy like unsizing. + +pub fn main() { + // &mut -> & + let x: &mut int = &mut 42i; + let x: &int = x; + + let x: &int = &mut 42i; + + // & -> *const + let x: &int = &42i; + let x: *const int = x; + + let x: *const int = &42i; + + // &mut -> *const + let x: &mut int = &mut 42i; + let x: *const int = x; + + let x: *const int = &mut 42i; + + // *mut -> *const + let x: *mut int = &mut 42i; + let x: *const int = x; +} diff --git a/src/test/run-pass/type-id-higher-rank.rs b/src/test/run-pass/type-id-higher-rank.rs new file mode 100644 index 00000000000..efda7771403 --- /dev/null +++ b/src/test/run-pass/type-id-higher-rank.rs @@ -0,0 +1,85 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that type IDs correctly account for higher-rank lifetimes +// Also acts as a regression test for an ICE (issue #19791) + +#![feature(unboxed_closures)] + +use std::intrinsics::TypeId; + +fn main() { + // Bare fns + { + let a = TypeId::of::<fn(&'static int, &'static int)>(); + let b = TypeId::of::<for<'a> fn(&'static int, &'a int)>(); + let c = TypeId::of::<for<'a, 'b> fn(&'a int, &'b int)>(); + let d = TypeId::of::<for<'a, 'b> fn(&'b int, &'a int)>(); + assert!(a != b); + assert!(a != c); + assert!(a != d); + assert!(b != c); + assert!(b != d); + assert_eq!(c, d); + + // Make sure De Bruijn indices are handled correctly + let e = TypeId::of::<for<'a> fn(fn(&'a int) -> &'a int)>(); + let f = TypeId::of::<fn(for<'a> fn(&'a int) -> &'a int)>(); + assert!(e != f); + } + // Stack closures + { + let a = TypeId::of::<|&'static int, &'static int|>(); + let b = TypeId::of::<for<'a> |&'static int, &'a int|>(); + let c = TypeId::of::<for<'a, 'b> |&'a int, &'b int|>(); + let d = TypeId::of::<for<'a, 'b> |&'b int, &'a int|>(); + assert!(a != b); + assert!(a != c); + assert!(a != d); + assert!(b != c); + assert!(b != d); + assert_eq!(c, d); + + // Make sure De Bruijn indices are handled correctly + let e = TypeId::of::<for<'a> |(|&'a int| -> &'a int)|>(); + let f = TypeId::of::<|for<'a> |&'a int| -> &'a int|>(); + assert!(e != f); + } + // Boxed unboxed closures + { + let a = TypeId::of::<Box<Fn(&'static int, &'static int)>>(); + let b = TypeId::of::<Box<for<'a> Fn(&'static int, &'a int)>>(); + let c = TypeId::of::<Box<for<'a, 'b> Fn(&'a int, &'b int)>>(); + let d = TypeId::of::<Box<for<'a, 'b> Fn(&'b int, &'a int)>>(); + assert!(a != b); + assert!(a != c); + assert!(a != d); + assert!(b != c); + assert!(b != d); + assert_eq!(c, d); + + // Make sure De Bruijn indices are handled correctly + let e = TypeId::of::<Box<for<'a> Fn(Box<Fn(&'a int) -> &'a int>)>>(); + let f = TypeId::of::<Box<Fn(Box<for<'a> Fn(&'a int) -> &'a int>)>>(); + assert!(e != f); + } + // Raw unboxed closures + // Note that every unboxed closure has its own anonymous type, + // so no two IDs should equal each other, even when compatible + { + let a = id(|&: _: &int, _: &int| {}); + let b = id(|&: _: &int, _: &int| {}); + assert!(a != b); + } + + fn id<T:'static>(_: T) -> TypeId { + TypeId::of::<T>() + } +}