Imported Upstream version 1.0.0~beta

This commit is contained in:
Angus Lees 2015-04-16 20:08:53 +10:00
parent 85aaf69fd1
commit c34b17963d
3783 changed files with 81416 additions and 61182 deletions

View File

@ -606,7 +606,7 @@ Peter Schuller <peter.schuller@infidyne.com>
Peter Williams <peter@newton.cx> Peter Williams <peter@newton.cx>
Peter Zotov <whitequark@whitequark.org> Peter Zotov <whitequark@whitequark.org>
Petter Remen <petter.remen@gmail.com> Petter Remen <petter.remen@gmail.com>
Phil Dawes <pdawes@drw.com> Phil Dawes <phil@phildawes.net>
Phil Ruffwind <rf@rufflewind.com> Phil Ruffwind <rf@rufflewind.com>
Philip Munksgaard <pmunksgaard@gmail.com> Philip Munksgaard <pmunksgaard@gmail.com>
Philipp Brüschweiler <blei42@gmail.com> Philipp Brüschweiler <blei42@gmail.com>

View File

@ -14,7 +14,7 @@ links to the major sections:
If you have questions, please make a post on [internals.rust-lang.org][internals] or If you have questions, please make a post on [internals.rust-lang.org][internals] or
hop on [#rust-internals][pound-rust-internals]. hop on [#rust-internals][pound-rust-internals].
As a reminder, all contributors are expected to follow our [Code of Conduct](coc). As a reminder, all contributors are expected to follow our [Code of Conduct][coc].
[pound-rust-internals]: http://chat.mibbit.com/?server=irc.mozilla.org&channel=%23rust-internals [pound-rust-internals]: http://chat.mibbit.com/?server=irc.mozilla.org&channel=%23rust-internals
[internals]: http://internals.rust-lang.org [internals]: http://internals.rust-lang.org

View File

@ -97,12 +97,7 @@
# make check-stage1-rpass TESTNAME=my-shiny-new-test # make check-stage1-rpass TESTNAME=my-shiny-new-test
# #
# // Having trouble figuring out which test is failing? Turn off parallel tests # // Having trouble figuring out which test is failing? Turn off parallel tests
# make check-stage1-std RUST_TEST_TASKS=1 # make check-stage1-std RUST_TEST_THREADS=1
#
# This is hardly all there is to know of The Rust Build System's
# mysteries. The tale continues on the wiki[1].
#
# [1]: https://github.com/rust-lang/rust/wiki/Note-testsuite
# #
# If you really feel like getting your hands dirty, then: # If you really feel like getting your hands dirty, then:
# #

View File

@ -15,6 +15,7 @@ Read ["Installing Rust"] from [The Book].
## Building from Source ## Building from Source
1. Make sure you have installed the dependencies: 1. Make sure you have installed the dependencies:
* `g++` 4.7 or `clang++` 3.x * `g++` 4.7 or `clang++` 3.x
* `python` 2.6 or later (but not 3.x) * `python` 2.6 or later (but not 3.x)
* GNU `make` 3.81 or later * GNU `make` 3.81 or later
@ -23,20 +24,25 @@ Read ["Installing Rust"] from [The Book].
2. Clone the [source] with `git`: 2. Clone the [source] with `git`:
```sh
$ git clone https://github.com/rust-lang/rust.git $ git clone https://github.com/rust-lang/rust.git
$ cd rust $ cd rust
```
[source]: https://github.com/rust-lang/rust [source]: https://github.com/rust-lang/rust
3. Build and install: 3. Build and install:
```sh
$ ./configure $ ./configure
$ make && make install $ make && make install
```
> ***Note:*** You may need to use `sudo make install` if you do not normally have > ***Note:*** You may need to use `sudo make install` if you do not
> permission to modify the destination directory. The install locations can > normally have permission to modify the destination directory. The
> be adjusted by passing a `--prefix` argument to `configure`. Various other > install locations can be adjusted by passing a `--prefix` argument
> options are also supported, pass `--help` for more information on them. > to `configure`. Various other options are also supported pass
> `--help` for more information on them.
When complete, `make install` will place several programs into When complete, `make install` will place several programs into
`/usr/local/bin`: `rustc`, the Rust compiler, and `rustdoc`, the `/usr/local/bin`: `rustc`, the Rust compiler, and `rustdoc`, the
@ -47,27 +53,30 @@ Read ["Installing Rust"] from [The Book].
### Building on Windows ### Building on Windows
To easily build on windows we can use [MSYS2](http://msys2.github.io/): [MSYS2](http://msys2.github.io/) can be used to easily build Rust on Windows:
1. Grab the latest MSYS2 installer and go through the installer. 1. Grab the latest MSYS2 installer and go through the installer.
2. Now from the MSYS2 terminal we want to install the mingw64 toolchain and the other
tools we need.
```bash 2. From the MSYS2 terminal, install the `mingw64` toolchain and other required
# choose one based on platform tools.
```sh
# Choose one based on platform:
$ pacman -S mingw-w64-i686-toolchain $ pacman -S mingw-w64-i686-toolchain
$ pacman -S mingw-w64-x86_64-toolchain $ pacman -S mingw-w64-x86_64-toolchain
$ pacman -S base-devel $ pacman -S base-devel
``` ```
3. With that now start `mingw32_shell.bat` or `mingw64_shell.bat` 3. Run `mingw32_shell.bat` or `mingw64_shell.bat` from wherever you installed
from where you installed MSYS2 (i.e. `C:\msys`). Which one you MYSY2 (i.e. `C:\msys`), depending on whether you want 32-bit or 64-bit Rust.
choose depends on if you want 32 or 64 bit Rust.
4. From there just navigate to where you have Rust's source code, configure and build it:
4. Navigate to Rust's source code, configure and build it:
```sh
$ ./configure $ ./configure
$ make && make install $ make && make install
```
## Notes ## Notes
@ -92,12 +101,12 @@ There is more advice about hacking on Rust in [CONTRIBUTING.md].
[CONTRIBUTING.md]: https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.md [CONTRIBUTING.md]: https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.md
## Getting help ## Getting Help
The Rust community congregates in a few places: The Rust community congregates in a few places:
* [StackOverflow] - Direct questions about using the language here. * [Stack Overflow] - Direct questions about using the language.
* [users.rust-lang.org] - General discussion, broader questions. * [users.rust-lang.org] - General discussion and broader questions.
* [/r/rust] - News and general discussion. * [/r/rust] - News and general discussion.
[Stack Overflow]: http://stackoverflow.com/questions/tagged/rust [Stack Overflow]: http://stackoverflow.com/questions/tagged/rust
@ -106,12 +115,12 @@ The Rust community congregates in a few places:
## Contributing ## Contributing
To contribute to Rust, please see [CONTRIBUTING.md](CONTRIBUTING.md). To contribute to Rust, please see [CONTRIBUTING](CONTRIBUTING.md).
Rust has an [IRC] culture and most real-time collaboration happens in a Rust has an [IRC] culture and most real-time collaboration happens in a
variety of channels on Mozilla's IRC network, irc.mozilla.org. The variety of channels on Mozilla's IRC network, irc.mozilla.org. The
most popular channel is [#rust], a venue for general discussion about most popular channel is [#rust], a venue for general discussion about
Rust, and a good place to ask for help, Rust, and a good place to ask for help.
[IRC]: https://en.wikipedia.org/wiki/Internet_Relay_Chat [IRC]: https://en.wikipedia.org/wiki/Internet_Relay_Chat
[#rust]: irc://irc.mozilla.org/rust [#rust]: irc://irc.mozilla.org/rust
@ -122,4 +131,4 @@ Rust is primarily distributed under the terms of both the MIT license
and the Apache License (Version 2.0), with portions covered by various and the Apache License (Version 2.0), with portions covered by various
BSD-like licenses. BSD-like licenses.
See LICENSE-APACHE, LICENSE-MIT, and COPYRIGHT for details. See [LICENSE-APACHE](LICENSE-APACHE), [LICENSE-MIT](LICENSE-MIT), and [COPYRIGHT](COPYRIGHT) for details.

View File

@ -1,3 +1,102 @@
Version 1.0.0-beta (April 2015)
-------------------------------------
* ~1100 changes, numerous bugfixes
* Highlights
* The big news is that the vast majority of the standard library
is now `#[stable]` -- 75% of the non-deprecated API surface at
last count. Numerous crates are now running on stable
Rust. Starting with this release, it is not possible to use
unstable features on a stable build.
* Arithmetic on basic integer types now
[checks for overflow in debug builds][overflow].
* Language
* [`Send` no longer implies `'static`][send-rfc], which made
possible the [`thread::scoped` API][scoped]. Scoped threads can
borrow data from their parent's stack frame -- safely!
* [UFCS now supports trait-less associated paths][moar-ufcs] like
`MyType::default()`.
* Primitive types [now have inherent methods][prim-inherent],
obviating the need for extension traits like `SliceExt`.
* Methods with `Self: Sized` in their `where` clause are
[considered object-safe][self-sized], allowing many extension
traits like `IteratorExt` to be merged into the traits they
extended.
* You can now [refer to associated types][assoc-where] whose
corresponding trait bounds appear only in a `where` clause.
* The final bits of [OIBIT landed][oibit-final], meaning that
traits like `Send` and `Sync` are now library-defined.
* A [Reflect trait][reflect] was introduced, which means that
downcasting via the `Any` trait is effectively limited to
concrete types. This helps retain the potentially-important
"parametricity" property: generic code cannot behave differently
for different type arguments except in minor ways.
* The `unsafe_destructor` feature is now deprecated in favor of
the [new `dropck`][dropck]. This change is a major reduction in
unsafe code.
* Trait coherence was [revised again][fundamental], this time with
an eye toward API evolution over time.
* Libraries
* The new path and IO modules are complete and `#[stable]`. This
was the major library focus for this cycle.
* The path API was [revised][path-normalize] to normalize `.`,
adjusting the tradeoffs in favor of the most common usage.
* A large number of remaining APIs in `std` were also stabilized
during this cycle; about 75% of the non-deprecated API surface
is now stable.
* The new [string pattern API][string-pattern] landed, which makes
the string slice API much more internally consistent and flexible.
* A shiny [framework for Debug implementations][debug-builder] landed.
This makes it possible to opt in to "pretty-printed" debugging output.
* A new set of [generic conversion traits][conversion] replaced
many existing ad hoc traits.
* Generic numeric traits were
[completely removed][num-traits]. This was made possible thanks
to inherent methods for primitive types, and the removal gives
maximal flexibility for designing a numeric hierarchy in the future.
* The `Fn` traits are now related via [inheritance][fn-inherit]
and provide ergonomic [blanket implementations][fn-blanket].
* The `Index` and `IndexMut` traits were changed to
[take the index by value][index-value], enabling code like
`hash_map["string"]` to work.
* `Copy` now [inherits][copy-clone] from `Clone`, meaning that all
`Copy` data is known to be `Clone` as well.
* Infrastructure
* Metadata was tuned, shrinking binaries [by 27%][metadata-shrink].
* Much headway was made on ecosystem-wide CI, making it possible
to [compare builds for breakage][ci-compare].
[send-rfc]: https://github.com/rust-lang/rfcs/blob/master/text/0458-send-improvements.md
[scoped]: http://static.rust-lang.org/doc/master/std/thread/fn.scoped.html
[moar-ufcs]: https://github.com/rust-lang/rust/pull/22172
[prim-inherent]: https://github.com/rust-lang/rust/pull/23104
[overflow]: https://github.com/rust-lang/rfcs/blob/master/text/0560-integer-overflow.md
[metadata-shrink]: https://github.com/rust-lang/rust/pull/22971
[self-sized]: https://github.com/rust-lang/rust/pull/22301
[assoc-where]: https://github.com/rust-lang/rust/pull/22512
[string-pattern]: https://github.com/rust-lang/rust/pull/22466
[oibit-final]: https://github.com/rust-lang/rust/pull/21689
[reflect]: https://github.com/rust-lang/rust/pull/23712
[debug-builder]: https://github.com/rust-lang/rfcs/blob/master/text/0640-debug-improvements.md
[conversion]: https://github.com/rust-lang/rfcs/pull/529
[num-traits]: https://github.com/rust-lang/rust/pull/23549
[index-value]: https://github.com/rust-lang/rust/pull/23601
[dropck]: https://github.com/rust-lang/rfcs/pull/769
[fundamental]: https://github.com/rust-lang/rfcs/pull/1023
[ci-compare]: https://gist.github.com/brson/a30a77836fbec057cbee
[fn-inherit]: https://github.com/rust-lang/rust/pull/23282
[fn-blanket]: https://github.com/rust-lang/rust/pull/23895
[copy-clone]: https://github.com/rust-lang/rust/pull/23860
[path-normalize]: https://github.com/rust-lang/rust/pull/23229
Version 1.0.0-alpha.2 (February 2015) Version 1.0.0-alpha.2 (February 2015)
------------------------------------- -------------------------------------
@ -51,7 +150,7 @@ Version 1.0.0-alpha.2 (February 2015)
* Abstract [OS-specific string types][osstr], `std::ff::{OsString, * Abstract [OS-specific string types][osstr], `std::ff::{OsString,
OsStr}`, provide strings in platform-specific encodings for easier OsStr}`, provide strings in platform-specific encodings for easier
interop with system APIs. [RFC][osstr-rfc]. interop with system APIs. [RFC][osstr-rfc].
* The `boxed::into_raw` and `Box::frow_raw` functions [convert * The `boxed::into_raw` and `Box::from_raw` functions [convert
between `Box<T>` and `*mut T`][boxraw], a common pattern for between `Box<T>` and `*mut T`][boxraw], a common pattern for
creating raw pointers. creating raw pointers.

51
configure vendored
View File

@ -374,6 +374,10 @@ case $CFG_OSTYPE in
CFG_OSTYPE=unknown-dragonfly CFG_OSTYPE=unknown-dragonfly
;; ;;
Bitrig)
CFG_OSTYPE=unknown-bitrig
;;
OpenBSD) OpenBSD)
CFG_OSTYPE=unknown-openbsd CFG_OSTYPE=unknown-openbsd
;; ;;
@ -400,7 +404,7 @@ case $CFG_OSTYPE in
CFG_OSTYPE=pc-windows-gnu CFG_OSTYPE=pc-windows-gnu
;; ;;
# Thad's Cygwin identifers below # Thad's Cygwin identifiers below
# Vista 32 bit # Vista 32 bit
CYGWIN_NT-6.0) CYGWIN_NT-6.0)
@ -426,6 +430,10 @@ case $CFG_OSTYPE in
CFG_CPUTYPE=x86_64 CFG_CPUTYPE=x86_64
;; ;;
# Win 8 # uname -s on 64-bit cygwin does not contain WOW64, so simply use uname -m to detect arch (works in my install)
CYGWIN_NT-6.3)
CFG_OSTYPE=pc-windows-gnu
;;
# We do not detect other OS such as XP/2003 using 64 bit using uname. # We do not detect other OS such as XP/2003 using 64 bit using uname.
# If we want to in the future, we will need to use Cygwin - Chuck's csih helper in /usr/lib/csih/winProductName.exe or alternative. # If we want to in the future, we will need to use Cygwin - Chuck's csih helper in /usr/lib/csih/winProductName.exe or alternative.
*) *)
@ -453,7 +461,10 @@ case $CFG_CPUTYPE in
CFG_CPUTYPE=aarch64 CFG_CPUTYPE=aarch64
;; ;;
powerpc) # At some point, when ppc64[le] support happens, this will need to do
# something clever. For now it's safe to assume that we're only ever
# interested in building 32 bit.
powerpc | ppc | ppc64)
CFG_CPUTYPE=powerpc CFG_CPUTYPE=powerpc
;; ;;
@ -468,11 +479,20 @@ esac
# Detect 64 bit linux systems with 32 bit userland and force 32 bit compilation # 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 ] if [ $CFG_OSTYPE = unknown-linux-gnu -a $CFG_CPUTYPE = x86_64 ]
then then
file -L "$SHELL" | grep -q "x86[_-]64" # $SHELL does not exist in standard 'sh', so probably only exists
# if configure is running in an interactive bash shell. /usr/bin/env
# exists *everywhere*.
BIN_TO_PROBE="$SHELL"
if [ -z "$BIN_TO_PROBE" -a -e "/usr/bin/env" ]; then
BIN_TO_PROBE="/usr/bin/env"
fi
if [ -n "$BIN_TO_PROBE" ]; then
file -L "$BIN_TO_PROBE" | grep -q "x86[_-]64"
if [ $? != 0 ]; then if [ $? != 0 ]; then
CFG_CPUTYPE=i686 CFG_CPUTYPE=i686
fi fi
fi fi
fi
DEFAULT_BUILD="${CFG_CPUTYPE}-${CFG_OSTYPE}" DEFAULT_BUILD="${CFG_CPUTYPE}-${CFG_OSTYPE}"
@ -506,7 +526,8 @@ VAL_OPTIONS=""
opt valgrind 0 "run tests with valgrind (memcheck by default)" opt valgrind 0 "run tests with valgrind (memcheck by default)"
opt helgrind 0 "run tests with helgrind instead of memcheck" opt helgrind 0 "run tests with helgrind instead of memcheck"
opt valgrind-rpass 1 "run rpass-valgrind tests with valgrind" opt valgrind-rpass 1 "run rpass-valgrind tests with valgrind"
opt docs 1 "build documentation" opt docs 1 "build standard library documentation"
opt compiler-docs 0 "build compiler documentation"
opt optimize 1 "build optimized rust code" opt optimize 1 "build optimized rust code"
opt optimize-cxx 1 "build optimized C++ code" opt optimize-cxx 1 "build optimized C++ code"
opt optimize-llvm 1 "build optimized LLVM" opt optimize-llvm 1 "build optimized LLVM"
@ -693,15 +714,17 @@ probe CFG_ADB adb
if [ ! -z "$CFG_PANDOC" ] if [ ! -z "$CFG_PANDOC" ]
then then
PV_MAJOR_MINOR=$(pandoc --version | grep '^pandoc\(.exe\)\? ' | # Extract "MAJOR MINOR" from Pandoc's version number
# extract the first 2 version fields, ignore everything else PV_MAJOR_MINOR=$(pandoc --version | grep '^pandoc' |
sed 's/pandoc\(.exe\)\? \([0-9]*\)\.\([0-9]*\).*/\2 \3/') sed -E 's/pandoc(.exe)? ([0-9]+)\.([0-9]+).*/\2 \3/')
MIN_PV_MAJOR="1" MIN_PV_MAJOR="1"
MIN_PV_MINOR="9" MIN_PV_MINOR="9"
# these patterns are shell globs, *not* regexps # these patterns are shell globs, *not* regexps
PV_MAJOR=${PV_MAJOR_MINOR% *} PV_MAJOR=${PV_MAJOR_MINOR% *}
PV_MINOR=${PV_MAJOR_MINOR#* } PV_MINOR=${PV_MAJOR_MINOR#* }
if [ "$PV_MAJOR" -lt "$MIN_PV_MAJOR" ] || [ "$PV_MINOR" -lt "$MIN_PV_MINOR" ] if [ "$PV_MAJOR" -lt "$MIN_PV_MAJOR" ] || [ "$PV_MINOR" -lt "$MIN_PV_MINOR" ]
then then
step_msg "pandoc $PV_MAJOR.$PV_MINOR is too old. Need at least $MIN_PV_MAJOR.$MIN_PV_MINOR. Disabling" step_msg "pandoc $PV_MAJOR.$PV_MINOR is too old. Need at least $MIN_PV_MAJOR.$MIN_PV_MINOR. Disabling"
@ -747,6 +770,14 @@ then
CFG_ENABLE_CLANG=1 CFG_ENABLE_CLANG=1
fi fi
# Force bitrig to build with clang; gcc doesn't like us there
if [ $CFG_OSTYPE = unknown-bitrig ]
then
step_msg "on Bitrig, forcing use of clang, disabling jemalloc"
CFG_ENABLE_CLANG=1
CFG_ENABLE_JEMALLOC=0
fi
if [ -z "$CFG_ENABLE_CLANG" -a -z "$CFG_GCC" ] if [ -z "$CFG_ENABLE_CLANG" -a -z "$CFG_GCC" ]
then then
err "either clang or gcc is required" err "either clang or gcc is required"
@ -805,11 +836,11 @@ then
LLVM_VERSION=$($LLVM_CONFIG --version) LLVM_VERSION=$($LLVM_CONFIG --version)
case $LLVM_VERSION in case $LLVM_VERSION in
(3.[2-6]*) (3.[5-6]*)
msg "found ok version of LLVM: $LLVM_VERSION" msg "found ok version of LLVM: $LLVM_VERSION"
;; ;;
(*) (*)
err "bad LLVM version: $LLVM_VERSION, need >=3.0svn" err "bad LLVM version: $LLVM_VERSION, need >=3.5"
;; ;;
esac esac
fi fi
@ -864,7 +895,7 @@ then
| cut -d ' ' -f 2) | cut -d ' ' -f 2)
case $CFG_CLANG_VERSION in case $CFG_CLANG_VERSION in
(3.0svn | 3.0 | 3.1* | 3.2* | 3.3* | 3.4* | 3.5* | 3.6*) (3.2* | 3.3* | 3.4* | 3.5* | 3.6*)
step_msg "found ok version of CLANG: $CFG_CLANG_VERSION" step_msg "found ok version of CLANG: $CFG_CLANG_VERSION"
if [ -z "$CC" ] if [ -z "$CC" ]
then then

View File

@ -7,224 +7,289 @@ rustc \- The Rust compiler
.SH DESCRIPTION .SH DESCRIPTION
This program is a compiler for the Rust language, available at This program is a compiler for the Rust language, available at
<\fBhttps://www.rust-lang.org\fR>. .UR https://www.rust\-lang.org
.UE .
.SH OPTIONS .SH OPTIONS
.TP .TP
\fB\-h\fR, \fB\-\-help\fR \fB\-h\fR, \fB\-\-help\fR
Display the help message Display the help message.
.TP .TP
\fB\-\-cfg\fR SPEC \fB\-\-cfg\fR \fISPEC\fR
Configure the compilation environment Configure the compilation environment.
.TP .TP
\fB\-L\fR [KIND=]PATH \fB\-L\fR [\fIKIND\fR=]\fIPATH\fR
Add a directory to the library search path. The optional KIND can be one of: Add a directory to the library search path.
dependency = only lookup transitive dependencies here The optional \fIKIND\fR can be one of:
crate = only lookup local `extern crate` directives here .RS
native = only lookup native libraries here
framework = only look for OSX frameworks here
all = look for anything here (the default)
.TP .TP
\fB\-l\fR [KIND=]NAME \fBdependency\fR
Link the generated crate(s) to the specified native library NAME. The optional only lookup transitive dependencies here
KIND can be one of, static, dylib, or framework. If omitted, dylib is assumed.
.TP .TP
\fB\-\-crate-type\fR [bin|lib|rlib|dylib|staticlib] .B crate
Comma separated list of types of crates for the compiler to emit only lookup local `extern crate` directives here
.TP .TP
\fB\-\-crate-name NAME\fR .B native
Specify the name of the crate being built only lookup native libraries here
.TP .TP
\fB\-\-emit\fR [asm|llvm-bc|llvm-ir|obj|link|dep-info] .B framework
Configure the output that rustc will produce only look for OSX frameworks here
.TP .TP
\fB\-\-print\fR [crate-name|file-names|sysroot] .B all
Comma separated list of compiler information to print on stdout look for anything here (the default)
.RE
.TP
\fB\-l\fR [\fIKIND\fR=]\fINAME\fR
Link the generated crate(s) to the specified native library \fINAME\fR.
The optional \fIKIND\fR can be one of \fIstatic\fR, \fIdylib\fR, or
\fIframework\fR.
If omitted, \fIdylib\fR is assumed.
.TP
\fB\-\-crate\-type\fR [bin|lib|rlib|dylib|staticlib]
Comma separated list of types of crates for the compiler to emit.
.TP
\fB\-\-crate\-name\fR \fINAME\fR
Specify the name of the crate being built.
.TP
\fB\-\-emit\fR [asm|llvm\-bc|llvm\-ir|obj|link|dep\-info]
Configure the output that \fBrustc\fR will produce.
.TP
\fB\-\-print\fR [crate\-name|file\-names|sysroot]
Comma separated list of compiler information to print on stdout.
.TP .TP
\fB\-g\fR \fB\-g\fR
Equivalent to \fI\-C\fR debuginfo=2 Equivalent to \fI\-C\ debuginfo=2\fR.
.TP .TP
\fB\-O\fR \fB\-O\fR
Equivalent to \fI\-C\fR opt-level=2 Equivalent to \fI\-C\ opt\-level=2\fR.
.TP .TP
\fB\-o\fR FILENAME \fB\-o\fR \fIFILENAME\fR
Write output to <filename>. Ignored if multiple \fI\-\-emit\fR outputs are Write output to \fIFILENAME\fR.
specified. Ignored if multiple \fI\-\-emit\fR outputs are specified.
.TP .TP
\fB\-\-out\-dir\fR DIR \fB\-\-out\-dir\fR \fIDIR\fR
Write output to compiler-chosen filename in <dir>. Ignored if \fI\-o\fR is Write output to compiler\[hy]chosen filename in \fIDIR\fR.
specified. Defaults to the current directory. Ignored if \fI\-o\fR is specified.
Defaults to the current directory.
.TP .TP
\fB\-\-explain\fR OPT \fB\-\-explain\fR \fIOPT\fR
Provide a detailed explanation of an error message Provide a detailed explanation of an error message.
.TP .TP
\fB\-\-test\fR \fB\-\-test\fR
Build a test harness Build a test harness.
.TP .TP
\fB\-\-target\fR TRIPLE \fB\-\-target\fR \fITRIPLE\fR
Target triple cpu-manufacturer-kernel[-os] to compile for (see chapter 3.4 of Target triple \fIcpu\fR\-\fImanufacturer\fR\-\fIkernel\fR[\-\fIos\fR]
http://www.sourceware.org/autobook/ for details) to compile for (see chapter 3.4 of
.UR http://www.sourceware.org/autobook/
.UE
for details).
.TP .TP
\fB\-W\fR help \fB\-W help\fR
Print 'lint' options and default settings Print 'lint' options and default settings.
.TP .TP
\fB\-W\fR OPT, \fB\-\-warn\fR OPT \fB\-W\fR \fIOPT\fR, \fB\-\-warn\fR \fIOPT\fR
Set lint warnings Set lint warnings.
.TP .TP
\fB\-A\fR OPT, \fB\-\-allow\fR OPT \fB\-A\fR \fIOPT\fR, \fB\-\-allow\fR \fIOPT\fR
Set lint allowed Set lint allowed.
.TP .TP
\fB\-D\fR OPT, \fB\-\-deny\fR OPT \fB\-D\fR \fIOPT\fR, \fB\-\-deny\fR \fIOPT\fR
Set lint denied Set lint denied.
.TP .TP
\fB\-F\fR OPT, \fB\-\-forbid\fR OPT \fB\-F\fR \fIOPT\fR, \fB\-\-forbid\fR \fIOPT\fR
Set lint forbidden Set lint forbidden.
.TP .TP
\fB\-C\fR FLAG[=VAL], \fB\-\-codegen\fR FLAG[=VAL] \fB\-C\fR \fIFLAG\fR[=\fIVAL\fR], \fB\-\-codegen\fR \fIFLAG\fR[=\fIVAL\fR]
Set a codegen-related flag to the value specified. Use "-C help" to print Set a codegen\[hy]related flag to the value specified.
available flags. See CODEGEN OPTIONS below Use \fI\-C help\fR to print available flags.
See CODEGEN OPTIONS below.
.TP .TP
\fB\-V\fR, \fB\-\-version\fR \fB\-V\fR, \fB\-\-version\fR
Print version info and exit Print version info and exit.
.TP .TP
\fB\-v\fR, \fB\-\-verbose\fR \fB\-v\fR, \fB\-\-verbose\fR
Use verbose output Use verbose output.
.TP .TP
\fB\-\-extern\fR NAME=PATH \fB\-\-extern\fR \fINAME\fR=\fIPATH\fR
Specify where an external rust library is located Specify where an external rust library is located.
.TP .TP
\fB\-\-sysroot\fR PATH \fB\-\-sysroot\fR \fIPATH\fR
Override the system root Override the system root.
.TP .TP
\fB\-Z\fR FLAG \fB\-Z\fR \fIFLAG\fR
Set internal debugging options. Use "-Z help" to print available options. Set internal debugging options.
Use \fI\-Z help\fR to print available options.
.TP .TP
\fB\-\-color\fR auto|always|never \fB\-\-color\fR auto|always|never
Configure coloring of output: Configure coloring of output:
auto = colorize, if output goes to a tty (default); .RS
always = always colorize output; .TP
never = never colorize output .B auto
colorize, if output goes to a tty (default);
.TP
.B always
always colorize output;
.TP
.B never
never colorize output.
.RE
.SH CODEGEN OPTIONS .SH CODEGEN OPTIONS
.TP .TP
\fBar\fR=/path/to/ar \fBar\fR=\fI/path/to/ar\fR
Path to the archive utility to use when assembling archives. Path to the archive utility to use when assembling archives.
.TP .TP
\fBlinker\fR=/path/to/cc \fBlinker\fR=\fI/path/to/cc\fR
Path to the linker utility to use when linking libraries, executables, and Path to the linker utility to use when linking libraries, executables, and
objects. objects.
.TP .TP
\fBlink-args\fR='-flag1 -flag2' \fBlink\-args\fR='\fI\-flag1 \-flag2\fR'
A space-separated list of extra arguments to pass to the linker when the linker A space\[hy]separated list of extra arguments to pass to the linker when the linker
is invoked. is invoked.
.TP .TP
\fBlto\fR \fBlto\fR
Perform LLVM link-time optimizations. Perform LLVM link\[hy]time optimizations.
.TP .TP
\fBtarget-cpu\fR=help \fBtarget\-cpu\fR=\fIhelp\fR
Selects a target processor. If the value is 'help', then a list of available Selects a target processor.
CPUs is printed. If the value is 'help', then a list of available CPUs is printed.
.TP .TP
\fBtarget-feature\fR='+feature1,-feature2' \fBtarget\-feature\fR='\fI+feature1\fR,\fI\-feature2\fR'
A comma-separated list of features to enable or disable for the target. A A comma\[hy]separated list of features to enable or disable for the target.
preceding '+' enables a feature while a preceding '-' disables it. Available A preceding '+' enables a feature while a preceding '\-' disables it.
features can be discovered through target-cpu=help. Available features can be discovered through \fItarget\-cpu=help\fR.
.TP .TP
\fBpasses\fR=list \fBpasses\fR=\fIval\fR
A space-separated list of extra LLVM passes to run. A value of 'list' will A space\[hy]separated list of extra LLVM passes to run.
cause rustc to print all known passes and exit. The passes specified are A value of 'list' will cause \fBrustc\fR to print all known passes and
appended at the end of the normal pass manager. exit.
The passes specified are appended at the end of the normal pass manager.
.TP .TP
\fBllvm-args\fR='-arg1 -arg2' \fBllvm\-args\fR='\fI\-arg1\fR \fI\-arg2\fR'
A space-separated list of arguments to pass through to LLVM. A space\[hy]separated list of arguments to pass through to LLVM.
.TP .TP
\fBsave-temps\fR \fBsave\-temps\fR
If specified, the compiler will save more files (.bc, .o, .no-opt.bc) generated If specified, the compiler will save more files (.bc, .o, .no\-opt.bc) generated
throughout compilation in the output directory. throughout compilation in the output directory.
.TP .TP
\fBrpath\fR \fBrpath\fR
If specified, then the rpath value for dynamic libraries will be set in If specified, then the rpath value for dynamic libraries will be set in
either dynamic library or executable outputs. either dynamic library or executable outputs.
.TP .TP
\fBno-prepopulate-passes\fR \fBno\-prepopulate\-passes\fR
Suppresses pre-population of the LLVM pass manager that is run over the module. Suppresses pre\[hy]population of the LLVM pass manager that is run over the module.
.TP .TP
\fBno-vectorize-loops\fR \fBno\-vectorize\-loops\fR
Suppresses running the loop vectorization LLVM pass, regardless of optimization Suppresses running the loop vectorization LLVM pass, regardless of optimization
level. level.
.TP .TP
\fBno-vectorize-slp\fR \fBno\-vectorize\-slp\fR
Suppresses running the LLVM SLP vectorization pass, regardless of optimization Suppresses running the LLVM SLP vectorization pass, regardless of optimization
level. level.
.TP .TP
\fBsoft-float\fR \fBsoft\-float\fR
Generates software floating point library calls instead of hardware Generates software floating point library calls instead of hardware
instructions. instructions.
.TP .TP
\fBprefer-dynamic\fR \fBprefer\-dynamic\fR
Prefers dynamic linking to static linking. Prefers dynamic linking to static linking.
.TP .TP
\fBno-integrated-as\fR \fBno\-integrated\-as\fR
Force usage of an external assembler rather than LLVM's integrated one. Force usage of an external assembler rather than LLVM's integrated one.
.TP .TP
\fBno-redzone\fR \fBno\-redzone\fR
Disable the use of the redzone. Disable the use of the redzone.
.TP .TP
\fBrelocation-model\fR=[pic,static,dynamic-no-pic] \fBrelocation\-model\fR=[pic,static,dynamic\-no\-pic]
The relocation model to use. (Default: pic) The relocation model to use.
(Default: \fIpic\fR)
.TP .TP
\fBcode-model\fR=[small,kernel,medium,large] \fBcode\-model\fR=[small,kernel,medium,large]
Choose the code model to use. Choose the code model to use.
.TP .TP
\fBmetadata\fR=val \fBmetadata\fR=\fIval\fR
Metadata to mangle symbol names with. Metadata to mangle symbol names with.
.TP .TP
\fBextra-filename\fR=val \fBextra\-filename\fR=\fIval\fR
Extra data to put in each output filename. Extra data to put in each output filename.
.TP .TP
\fBcodegen-units\fR=val \fBcodegen\-units\fR=\fIn\fR
Divide crate into N units to optimize in parallel. Divide crate into \fIn\fR units to optimize in parallel.
.TP .TP
\fBremark\fR=val \fBremark\fR=\fIval\fR
Print remarks for these optimization passes (space separated, or "all"). Print remarks for these optimization passes (space separated, or "all").
.TP .TP
\fBno-stack-check\fR \fBno\-stack\-check\fR
Disable checks for stack exhaustion (a memory-safety hazard!). Disable checks for stack exhaustion (a memory\[hy]safety hazard!).
.TP .TP
\fBdebuginfo\fR=val \fBdebuginfo\fR=\fIval\fR
Debug info emission level: Debug info emission level:
0 = no debug info; .RS
1 = line-tables only (for stacktraces and breakpoints);
2 = full debug info with variable and type information.
.TP .TP
\fBopt-level\fR=val .B 0
Optimize with possible levels 0-3 no debug info;
.TP
.B 1
line\[hy]tables only (for stacktraces and breakpoints);
.TP
.B 2
full debug info with variable and type information.
.RE
.TP
\fBopt\-level\fR=\fIVAL\fR
Optimize with possible levels 0\[en]3
.SH ENVIRONMENT
Some of these affect the output of the compiler, while others affect programs
which link to the standard library.
.TP
\fBRUST_TEST_THREADS\fR
The test framework Rust provides executes tests in parallel. This variable sets
the maximum number of threads used for this purpose.
.TP
\fBRUST_TEST_NOCAPTURE\fR
A synonym for the --nocapture flag.
.TP
\fBRUST_MIN_STACK\fR
Sets the minimum stack size for new threads.
.TP
\fBRUST_BACKTRACE\fR
If set, produces a backtrace in the output of a program which panics.
.SH "EXAMPLES" .SH "EXAMPLES"
To build an executable from a source file with a main function: To build an executable from a source file with a main function:
$ rustc -o hello hello.rs $ rustc \-o hello hello.rs
To build a library from a source file: To build a library from a source file:
$ rustc --crate-type=lib hello-lib.rs $ rustc \-\-crate\-type=lib hello\-lib.rs
To build either with a crate (.rs) file: To build either with a crate (.rs) file:
$ rustc hello.rs $ rustc hello.rs
To build an executable with debug info: To build an executable with debug info:
$ rustc -g -o hello hello.rs $ rustc \-g \-o hello hello.rs
.SH "SEE ALSO" .SH "SEE ALSO"
rustdoc .BR rustdoc (1)
.SH "BUGS" .SH "BUGS"
See <\fBhttps://github.com/rust-lang/rust/issues\fR> for issues. See
.UR https://github.com/rust\-lang/rust/issues
.UE
for issues.
.SH "AUTHOR" .SH "AUTHOR"
See \fBAUTHORS.txt\fR in the Rust source distribution. See \fIAUTHORS.txt\fR in the Rust source distribution.
.SH "COPYRIGHT" .SH "COPYRIGHT"
This work is dual-licensed under Apache 2.0 and MIT terms. See \fBCOPYRIGHT\fR This work is dual\[hy]licensed under Apache\ 2.0 and MIT terms.
file in the rust source distribution. See \fICOPYRIGHT\fR file in the rust source distribution.

View File

@ -8,76 +8,79 @@ rustdoc \- generate documentation from Rust source code
.SH DESCRIPTION .SH DESCRIPTION
This tool generates API reference documentation by extracting comments from This tool generates API reference documentation by extracting comments from
source code written in the Rust language, available at source code written in the Rust language, available at
<\fBhttps://www.rust-lang.org\fR>. It accepts several input formats and provides .UR https://www.rust\-lang.org
several output formats for the generated documentation. .UE .
It accepts several input formats and provides several output formats
for the generated documentation.
.SH OPTIONS .SH OPTIONS
.TP .TP
-r --input-format <val> \fB\-r\fR, \fB\-\-input\-format\fR \fIFORMAT\fR
html or json (default: inferred) html or json (default: inferred)
.TP .TP
-w --output-format <val> \fB\-w\fR, \fB\-\-output\-format\fR \fIFORMAT\fR
html or json (default: html) html or json (default: html)
.TP .TP
-o --output <val> \fB\-o\fR, \fB\-\-output\fR \fIOUTPUT\fR
where to place the output (default: doc/ for html, doc.json for json) where to place the output (default: \fIdoc/\fR for html,
\fIdoc.json\fR for json)
.TP .TP
--passes <val> \fB\-\-passes\fR \fILIST\fR
space-separated list of passes to run (default: '') space\[hy]separated list of passes to run (default: '')
.TP .TP
--no-defaults \fB\-\-no\-defaults\fR
don't run the default passes don't run the default passes
.TP .TP
--plugins <val> \fB\-\-plugins\fR \fILIST\fR
space-separated list of plugins to run (default: '') space-separated list of plugins to run (default: '')
.TP .TP
--plugin-path <val> \fB\-\-plugin\-path\fR \fIDIR\fR
directory to load plugins from (default: /tmp/rustdoc_ng/plugins) directory to load plugins from (default: \fI/tmp/rustdoc_ng/plugins\fR)
.TP .TP
--target <val> \fB\-\-target\fR \fITRIPLE\fR
target triple to document target triple to document
.TP .TP
--crate-name <val> \fB\-\-crate\-name\fR \fINAME\fR
specify the name of this crate specify the name of this crate
.TP .TP
-L --library-path <val> \fB\-L\fR, \fB\-\-library\-path\fR \fIDIR\fR
directory to add to crate search path directory to add to crate search path
.TP .TP
--cfg <val> \fB\-\-cfg\fR \fISPEC\fR
pass a --cfg to rustc pass a \fI\-\-cfg\fR to rustc
.TP .TP
--extern <val> \fB\-\-extern\fR \fIVAL\fR
pass an --extern to rustc pass an \fI\-\-extern\fR to rustc
.TP .TP
--test \fB\-\-test\fR
run code examples as tests run code examples as tests
.TP .TP
--test-args <val> \fB\-\-test\-args\fR \fIARGS\fR
pass arguments to the test runner pass arguments to the test runner
.TP .TP
--html-in-header <val> \fB\-\-html\-in\-header\fR \fIFILE\fR
file to add to <head> file to add to <head>
.TP .TP
--html-before-content <val> \fB\-\-html\-before\-content\fR \fIFILE\fR
file to add in <body>, before content file to add in <body>, before content
.TP .TP
--html-after-content <val> \fB\-\-html\-after\-content\fR \fIFILE\fR
file to add in <body>, after content file to add in <body>, after content
.TP .TP
--markdown-css <val> \fB\-\-markdown\-css\fR \fIFILE\fR
CSS files to include via <link> in a rendered Markdown file CSS files to include via <link> in a rendered Markdown file
.TP .TP
--markdown-playground-url <val> \fB\-\-markdown\-playground\-url\fR \fIURL\fR
URL to send code snippets to URL to send code snippets to
.TP .TP
--markdown-no-toc \fB\-\-markdown\-no\-toc\fR
don't include table of contents don't include table of contents
.TP .TP
-h, --help \fB\-h\fR, \fB\-\-help\fR
Print help Print help
.TP .TP
-V, --version \fB\-V\fR, \fB\-\-version\fR
Print rustdoc's version Print rustdoc's version
.SH "OUTPUT FORMATS" .SH "OUTPUT FORMATS"
@ -85,14 +88,15 @@ Print rustdoc's version
The rustdoc tool can generate output in either an HTML or JSON format. The rustdoc tool can generate output in either an HTML or JSON format.
If using an HTML format, then the specified output destination will be the root If using an HTML format, then the specified output destination will be the root
directory of an HTML structure for all the documentation. Pages will be placed directory of an HTML structure for all the documentation.
into this directory, and source files will also possibly be rendered into it as Pages will be placed into this directory, and source files will also
well. possibly be rendered into it as well.
If using a JSON format, then the specified output destination will have the If using a JSON format, then the specified output destination will have the
rustdoc output serialized as JSON into it. This output format exists to rustdoc output serialized as JSON into it.
pre-compile documentation for crates, and for usage in non-rustdoc tools. The This output format exists to pre\[hy]compile documentation for crates,
JSON output is the following hash: and for usage in non\[hy]rustdoc tools.
The JSON output is the following hash:
{ {
"schema": VERSION, "schema": VERSION,
@ -100,11 +104,12 @@ JSON output is the following hash:
"plugins": ..., "plugins": ...,
} }
The schema version indicates what the structure of crate/plugins will look The schema version indicates what the structure of crate/plugins will
like. Within a schema version the structure will remain the same. The `crate` look like.
field will contain all relevant documentation for the source being documented, Within a schema version the structure will remain the same.
and the `plugins` field will contain the output of the plugins run over the The \fIcrate\fR field will contain all relevant documentation for the
crate. source being documented, and the \fIplugins\fR field will contain the
output of the plugins run over the crate.
.SH "EXAMPLES" .SH "EXAMPLES"
@ -112,25 +117,28 @@ To generate documentation for the source in the current directory:
$ rustdoc hello.rs $ rustdoc hello.rs
List all available passes that rustdoc has, along with default passes: List all available passes that rustdoc has, along with default passes:
$ rustdoc --passes list $ rustdoc \-\-passes list
To precompile the documentation for a crate, and then use it to render html at To precompile the documentation for a crate, and then use it to render html at
a later date: a later date:
$ rustdoc -w json hello.rs $ rustdoc \-w json hello.rs
$ rustdoc doc.json $ rustdoc doc.json
The generated HTML can be viewed with any standard web browser. The generated HTML can be viewed with any standard web browser.
.SH "SEE ALSO" .SH "SEE ALSO"
rustc .BR rustc (1)
.SH "BUGS" .SH "BUGS"
See <\fBhttps://github.com/rust-lang/rust/issues\fR> for issues. See
.UR https://github.com/rust\-lang/rust/issues
.UE
for issues.
.SH "AUTHOR" .SH "AUTHOR"
See \fBAUTHORS.txt\fR in the Rust source distribution. See \fIAUTHORS.txt\fR in the Rust source distribution.
.SH "COPYRIGHT" .SH "COPYRIGHT"
This work is dual-licensed under Apache 2.0 and MIT terms. See \fBCOPYRIGHT\fR This work is dual\[hy]licensed under Apache\ 2.0 and MIT terms.
file in the rust source distribution. See \fICOPYRIGHT\fR file in the rust source distribution.

View File

@ -0,0 +1,26 @@
# x86_64-unknown-bitrig-elf configuration
CC_x86_64-unknown-bitrig=$(CC)
CXX_x86_64-unknown-bitrig=$(CXX)
CPP_x86_64-unknown-bitrig=$(CPP)
AR_x86_64-unknown-bitrig=$(AR)
CFG_LIB_NAME_x86_64-unknown-bitrig=lib$(1).so
CFG_STATIC_LIB_NAME_x86_64-unknown-bitrig=lib$(1).a
CFG_LIB_GLOB_x86_64-unknown-bitrig=lib$(1)-*.so
CFG_LIB_DSYM_GLOB_x86_64-unknown-bitrig=$(1)-*.dylib.dSYM
CFG_JEMALLOC_CFLAGS_x86_64-unknown-bitrig := -m64 -I/usr/include $(CFLAGS)
CFG_GCCISH_CFLAGS_x86_64-unknown-bitrig := -Wall -Werror -fPIC -m64 -I/usr/include $(CFLAGS)
CFG_GCCISH_LINK_FLAGS_x86_64-unknown-bitrig := -shared -pic -pthread -m64 $(LDFLAGS)
CFG_GCCISH_DEF_FLAG_x86_64-unknown-bitrig := -Wl,--export-dynamic,--dynamic-list=
CFG_GCCISH_PRE_LIB_FLAGS_x86_64-unknown-bitrig := -Wl,-pic -Wl,-whole-archive
CFG_GCCISH_POST_LIB_FLAGS_x86_64-unknown-bitrig := -Wl,-no-whole-archive
CFG_DEF_SUFFIX_x86_64-unknown-bitrig := .bsd.def
CFG_LLC_FLAGS_x86_64-unknown-bitrig :=
CFG_INSTALL_NAME_x86_64-unknown-bitrig =
CFG_EXE_SUFFIX_x86_64-unknown-bitrig :=
CFG_WINDOWSY_x86_64-unknown-bitrig :=
CFG_UNIXY_x86_64-unknown-bitrig := 1
CFG_PATH_MUNGE_x86_64-unknown-bitrig :=
CFG_LDPATH_x86_64-unknown-bitrig :=
CFG_RUN_x86_64-unknown-bitrig=$(2)
CFG_RUN_TARG_x86_64-unknown-bitrig=$(call CFG_RUN_x86_64-unknown-bitrig,,$(2))
CFG_GNU_TRIPLE_x86_64-unknown-bitrig := x86_64-unknown-bitrig

View File

@ -25,4 +25,3 @@ CFG_LDPATH_x86_64-unknown-linux-gnu :=
CFG_RUN_x86_64-unknown-linux-gnu=$(2) CFG_RUN_x86_64-unknown-linux-gnu=$(2)
CFG_RUN_TARG_x86_64-unknown-linux-gnu=$(call CFG_RUN_x86_64-unknown-linux-gnu,,$(2)) CFG_RUN_TARG_x86_64-unknown-linux-gnu=$(call CFG_RUN_x86_64-unknown-linux-gnu,,$(2))
CFG_GNU_TRIPLE_x86_64-unknown-linux-gnu := x86_64-unknown-linux-gnu CFG_GNU_TRIPLE_x86_64-unknown-linux-gnu := x86_64-unknown-linux-gnu

View File

@ -54,7 +54,7 @@ TARGET_CRATES := libc std flate arena term \
log graphviz core rbml alloc \ log graphviz core rbml alloc \
unicode rustc_bitflags unicode rustc_bitflags
RUSTC_CRATES := rustc rustc_typeck rustc_borrowck rustc_resolve rustc_driver \ RUSTC_CRATES := rustc rustc_typeck rustc_borrowck rustc_resolve rustc_driver \
rustc_trans rustc_back rustc_llvm rustc_privacy rustc_trans rustc_back rustc_llvm rustc_privacy rustc_lint
HOST_CRATES := syntax $(RUSTC_CRATES) rustdoc fmt_macros HOST_CRATES := syntax $(RUSTC_CRATES) rustdoc fmt_macros
CRATES := $(TARGET_CRATES) $(HOST_CRATES) CRATES := $(TARGET_CRATES) $(HOST_CRATES)
TOOLS := compiletest rustdoc rustc rustbook TOOLS := compiletest rustdoc rustc rustbook
@ -70,7 +70,7 @@ DEPS_graphviz := std
DEPS_syntax := std term serialize log fmt_macros arena libc DEPS_syntax := std term serialize log fmt_macros arena libc
DEPS_rustc_driver := arena flate getopts graphviz libc rustc rustc_back rustc_borrowck \ DEPS_rustc_driver := arena flate getopts graphviz libc rustc rustc_back rustc_borrowck \
rustc_typeck rustc_resolve log syntax serialize rustc_llvm \ rustc_typeck rustc_resolve log syntax serialize rustc_llvm \
rustc_trans rustc_privacy rustc_trans rustc_privacy rustc_lint
DEPS_rustc_trans := arena flate getopts graphviz libc rustc rustc_back \ DEPS_rustc_trans := arena flate getopts graphviz libc rustc rustc_back \
log syntax serialize rustc_llvm log syntax serialize rustc_llvm
@ -78,12 +78,13 @@ DEPS_rustc_typeck := rustc syntax
DEPS_rustc_borrowck := rustc log graphviz syntax DEPS_rustc_borrowck := rustc log graphviz syntax
DEPS_rustc_resolve := rustc log syntax DEPS_rustc_resolve := rustc log syntax
DEPS_rustc_privacy := rustc log syntax DEPS_rustc_privacy := rustc log syntax
DEPS_rustc_lint := rustc log syntax
DEPS_rustc := syntax flate arena serialize getopts rbml \ DEPS_rustc := syntax flate arena serialize getopts rbml \
log graphviz rustc_llvm rustc_back log graphviz rustc_llvm rustc_back
DEPS_rustc_llvm := native:rustllvm libc std DEPS_rustc_llvm := native:rustllvm libc std
DEPS_rustc_back := std syntax rustc_llvm flate log libc DEPS_rustc_back := std syntax rustc_llvm flate log libc
DEPS_rustdoc := rustc rustc_driver native:hoedown serialize getopts \ DEPS_rustdoc := rustc rustc_driver native:hoedown serialize getopts \
test test rustc_lint
DEPS_rustc_bitflags := core DEPS_rustc_bitflags := core
DEPS_flate := std native:miniz DEPS_flate := std native:miniz
DEPS_arena := std DEPS_arena := std
@ -121,6 +122,21 @@ ONLY_RLIB_rustc_bitflags := 1
# You should not need to edit below this line # You should not need to edit below this line
################################################################################ ################################################################################
# On channels where the only usable crate is std, only build documentation for
# std. This keeps distributions small and doesn't clutter up the API docs with
# confusing internal details from the crates behind the facade.
#
# (Disabled while cmr figures out how to change rustdoc to make reexports work
# slightly nicer. Otherwise, all cross-crate links to Vec will go to
# libcollections, breaking them, and [src] links for anything reexported will
# not work.)
#ifeq ($(CFG_RELEASE_CHANNEL),stable)
#DOC_CRATES := std
#else
#ifeq ($(CFG_RELEASE_CHANNEL),beta)
#DOC_CRATES := std
#else
DOC_CRATES := $(filter-out rustc, \ DOC_CRATES := $(filter-out rustc, \
$(filter-out rustc_trans, \ $(filter-out rustc_trans, \
$(filter-out rustc_typeck, \ $(filter-out rustc_typeck, \
@ -128,11 +144,15 @@ DOC_CRATES := $(filter-out rustc, \
$(filter-out rustc_resolve, \ $(filter-out rustc_resolve, \
$(filter-out rustc_driver, \ $(filter-out rustc_driver, \
$(filter-out rustc_privacy, \ $(filter-out rustc_privacy, \
$(filter-out rustc_lint, \
$(filter-out log, \ $(filter-out log, \
$(filter-out getopts, \ $(filter-out getopts, \
$(filter-out syntax, $(CRATES))))))))))) $(filter-out syntax, $(CRATES))))))))))))
#endif
#endif
COMPILER_DOC_CRATES := rustc rustc_trans rustc_borrowck rustc_resolve \ COMPILER_DOC_CRATES := rustc rustc_trans rustc_borrowck rustc_resolve \
rustc_typeck rustc_driver syntax rustc_privacy rustc_typeck rustc_driver syntax rustc_privacy \
rustc_lint
# This macro creates some simple definitions for each crate being built, just # This macro creates some simple definitions for each crate being built, just
# some munging of all of the parameters above. # some munging of all of the parameters above.

View File

@ -56,29 +56,32 @@ define DEF_INSTALL_DEBUGGER_SCRIPTS_HOST
tmp/install-debugger-scripts$(1)_H_$(2)-gdb.done: \ tmp/install-debugger-scripts$(1)_H_$(2)-gdb.done: \
$$(DEBUGGER_RUSTLIB_ETC_SCRIPTS_GDB_ABS) \ $$(DEBUGGER_RUSTLIB_ETC_SCRIPTS_GDB_ABS) \
$$(DEBUGGER_BIN_SCRIPTS_GDB_ABS) $$(DEBUGGER_BIN_SCRIPTS_GDB_ABS)
$(Q)touch $$@.start_time
$(Q)mkdir -p $$(HBIN$(1)_H_$(2)) $(Q)mkdir -p $$(HBIN$(1)_H_$(2))
$(Q)mkdir -p $$(HLIB$(1)_H_$(2))/rustlib/etc $(Q)mkdir -p $$(HLIB$(1)_H_$(2))/rustlib/etc
$(Q)install $$(DEBUGGER_BIN_SCRIPTS_GDB_ABS) $$(HBIN$(1)_H_$(2)) $(Q)install $$(DEBUGGER_BIN_SCRIPTS_GDB_ABS) $$(HBIN$(1)_H_$(2))
$(Q)install $$(DEBUGGER_RUSTLIB_ETC_SCRIPTS_GDB_ABS) $$(HLIB$(1)_H_$(2))/rustlib/etc $(Q)install $$(DEBUGGER_RUSTLIB_ETC_SCRIPTS_GDB_ABS) $$(HLIB$(1)_H_$(2))/rustlib/etc
$(Q)touch $$@ $(Q)touch -r $$@.start_time $$@ && rm $$@.start_time
tmp/install-debugger-scripts$(1)_H_$(2)-lldb.done: \ tmp/install-debugger-scripts$(1)_H_$(2)-lldb.done: \
$$(DEBUGGER_RUSTLIB_ETC_SCRIPTS_LLDB_ABS) \ $$(DEBUGGER_RUSTLIB_ETC_SCRIPTS_LLDB_ABS) \
$$(DEBUGGER_BIN_SCRIPTS_LLDB_ABS) $$(DEBUGGER_BIN_SCRIPTS_LLDB_ABS)
$(Q)touch $$@.start_time
$(Q)mkdir -p $$(HBIN$(1)_H_$(2)) $(Q)mkdir -p $$(HBIN$(1)_H_$(2))
$(Q)mkdir -p $$(HLIB$(1)_H_$(2))/rustlib/etc $(Q)mkdir -p $$(HLIB$(1)_H_$(2))/rustlib/etc
$(Q)install $$(DEBUGGER_BIN_SCRIPTS_LLDB_ABS) $$(HBIN$(1)_H_$(2)) $(Q)install $$(DEBUGGER_BIN_SCRIPTS_LLDB_ABS) $$(HBIN$(1)_H_$(2))
$(Q)install $$(DEBUGGER_RUSTLIB_ETC_SCRIPTS_LLDB_ABS) $$(HLIB$(1)_H_$(2))/rustlib/etc $(Q)install $$(DEBUGGER_RUSTLIB_ETC_SCRIPTS_LLDB_ABS) $$(HLIB$(1)_H_$(2))/rustlib/etc
$(Q)touch $$@ $(Q)touch -r $$@.start_time $$@ && rm $$@.start_time
tmp/install-debugger-scripts$(1)_H_$(2)-all.done: \ tmp/install-debugger-scripts$(1)_H_$(2)-all.done: \
$$(DEBUGGER_RUSTLIB_ETC_SCRIPTS_ALL_ABS) \ $$(DEBUGGER_RUSTLIB_ETC_SCRIPTS_ALL_ABS) \
$$(DEBUGGER_BIN_SCRIPTS_ALL_ABS) $$(DEBUGGER_BIN_SCRIPTS_ALL_ABS)
$(Q)touch $$@.start_time
$(Q)mkdir -p $$(HBIN$(1)_H_$(2)) $(Q)mkdir -p $$(HBIN$(1)_H_$(2))
$(Q)mkdir -p $$(HLIB$(1)_H_$(2))/rustlib/etc $(Q)mkdir -p $$(HLIB$(1)_H_$(2))/rustlib/etc
$(Q)install $$(DEBUGGER_BIN_SCRIPTS_ALL_ABS) $$(HBIN$(1)_H_$(2)) $(Q)install $$(DEBUGGER_BIN_SCRIPTS_ALL_ABS) $$(HBIN$(1)_H_$(2))
$(Q)install $$(DEBUGGER_RUSTLIB_ETC_SCRIPTS_ALL_ABS) $$(HLIB$(1)_H_$(2))/rustlib/etc $(Q)install $$(DEBUGGER_RUSTLIB_ETC_SCRIPTS_ALL_ABS) $$(HLIB$(1)_H_$(2))/rustlib/etc
$(Q)touch $$@ $(Q)touch -r $$@.start_time $$@ && rm $$@.start_time
tmp/install-debugger-scripts$(1)_H_$(2)-none.done: tmp/install-debugger-scripts$(1)_H_$(2)-none.done:
$(Q)touch $$@ $(Q)touch $$@
@ -98,29 +101,32 @@ define DEF_INSTALL_DEBUGGER_SCRIPTS_TARGET
tmp/install-debugger-scripts$(1)_T_$(2)_H_$(3)-gdb.done: \ tmp/install-debugger-scripts$(1)_T_$(2)_H_$(3)-gdb.done: \
$$(DEBUGGER_RUSTLIB_ETC_SCRIPTS_GDB_ABS) \ $$(DEBUGGER_RUSTLIB_ETC_SCRIPTS_GDB_ABS) \
$$(DEBUGGER_BIN_SCRIPTS_GDB_ABS) $$(DEBUGGER_BIN_SCRIPTS_GDB_ABS)
$(Q)touch $$@.start_time
$(Q)mkdir -p $$(TBIN$(1)_T_$(2)_H_$(3)) $(Q)mkdir -p $$(TBIN$(1)_T_$(2)_H_$(3))
$(Q)mkdir -p $$(TLIB$(1)_T_$(2)_H_$(3))/rustlib/etc $(Q)mkdir -p $$(TLIB$(1)_T_$(2)_H_$(3))/rustlib/etc
$(Q)install $(DEBUGGER_BIN_SCRIPTS_GDB_ABS) $$(TBIN$(1)_T_$(2)_H_$(3)) $(Q)install $(DEBUGGER_BIN_SCRIPTS_GDB_ABS) $$(TBIN$(1)_T_$(2)_H_$(3))
$(Q)install $(DEBUGGER_RUSTLIB_ETC_SCRIPTS_GDB_ABS) $$(TLIB$(1)_T_$(2)_H_$(3))/rustlib/etc $(Q)install $(DEBUGGER_RUSTLIB_ETC_SCRIPTS_GDB_ABS) $$(TLIB$(1)_T_$(2)_H_$(3))/rustlib/etc
$(Q)touch $$@ $(Q)touch -r $$@.start_time $$@ && rm $$@.start_time
tmp/install-debugger-scripts$(1)_T_$(2)_H_$(3)-lldb.done: \ tmp/install-debugger-scripts$(1)_T_$(2)_H_$(3)-lldb.done: \
$$(DEBUGGER_RUSTLIB_ETC_SCRIPTS_LLDB_ABS) \ $$(DEBUGGER_RUSTLIB_ETC_SCRIPTS_LLDB_ABS) \
$$(DEBUGGER_BIN_SCRIPTS_LLDB_ABS) $$(DEBUGGER_BIN_SCRIPTS_LLDB_ABS)
$(Q)touch $$@.start_time
$(Q)mkdir -p $$(TBIN$(1)_T_$(2)_H_$(3)) $(Q)mkdir -p $$(TBIN$(1)_T_$(2)_H_$(3))
$(Q)mkdir -p $$(TLIB$(1)_T_$(2)_H_$(3))/rustlib/etc $(Q)mkdir -p $$(TLIB$(1)_T_$(2)_H_$(3))/rustlib/etc
$(Q)install $(DEBUGGER_BIN_SCRIPTS_LLDB_ABS) $$(TBIN$(1)_T_$(2)_H_$(3)) $(Q)install $(DEBUGGER_BIN_SCRIPTS_LLDB_ABS) $$(TBIN$(1)_T_$(2)_H_$(3))
$(Q)install $(DEBUGGER_RUSTLIB_ETC_SCRIPTS_LLDB_ABS) $$(TLIB$(1)_T_$(2)_H_$(3))/rustlib/etc $(Q)install $(DEBUGGER_RUSTLIB_ETC_SCRIPTS_LLDB_ABS) $$(TLIB$(1)_T_$(2)_H_$(3))/rustlib/etc
$(Q)touch $$@ $(Q)touch -r $$@.start_time $$@ && rm $$@.start_time
tmp/install-debugger-scripts$(1)_T_$(2)_H_$(3)-all.done: \ tmp/install-debugger-scripts$(1)_T_$(2)_H_$(3)-all.done: \
$$(DEBUGGER_RUSTLIB_ETC_SCRIPTS_ALL_ABS) \ $$(DEBUGGER_RUSTLIB_ETC_SCRIPTS_ALL_ABS) \
$$(DEBUGGER_BIN_SCRIPTS_ALL_ABS) $$(DEBUGGER_BIN_SCRIPTS_ALL_ABS)
$(Q)touch $$@.start_time
$(Q)mkdir -p $$(TBIN$(1)_T_$(2)_H_$(3)) $(Q)mkdir -p $$(TBIN$(1)_T_$(2)_H_$(3))
$(Q)mkdir -p $$(TLIB$(1)_T_$(2)_H_$(3))/rustlib/etc $(Q)mkdir -p $$(TLIB$(1)_T_$(2)_H_$(3))/rustlib/etc
$(Q)install $(DEBUGGER_BIN_SCRIPTS_ALL_ABS) $$(TBIN$(1)_T_$(2)_H_$(3)) $(Q)install $(DEBUGGER_BIN_SCRIPTS_ALL_ABS) $$(TBIN$(1)_T_$(2)_H_$(3))
$(Q)install $(DEBUGGER_RUSTLIB_ETC_SCRIPTS_ALL_ABS) $$(TLIB$(1)_T_$(2)_H_$(3))/rustlib/etc $(Q)install $(DEBUGGER_RUSTLIB_ETC_SCRIPTS_ALL_ABS) $$(TLIB$(1)_T_$(2)_H_$(3))/rustlib/etc
$(Q)touch $$@ $(Q)touch -r $$@.start_time $$@ && rm $$@.start_time
tmp/install-debugger-scripts$(1)_T_$(2)_H_$(3)-none.done: tmp/install-debugger-scripts$(1)_T_$(2)_H_$(3)-none.done:
$(Q)touch $$@ $(Q)touch $$@

View File

@ -53,6 +53,7 @@ PKG_FILES := \
driver \ driver \
etc \ etc \
$(foreach crate,$(CRATES),lib$(crate)) \ $(foreach crate,$(CRATES),lib$(crate)) \
libcollectionstest \
libcoretest \ libcoretest \
libbacktrace \ libbacktrace \
rt \ rt \

View File

@ -259,7 +259,10 @@ doc/$(1)/index.html: $$(LIB_DOC_DEP_$(1)) doc/$(1)/
endef endef
$(foreach crate,$(DOC_CRATES),$(eval $(call DEF_LIB_DOC,$(crate),DOC_TARGETS))) $(foreach crate,$(DOC_CRATES),$(eval $(call DEF_LIB_DOC,$(crate),DOC_TARGETS)))
ifdef CFG_COMPILER_DOCS
$(foreach crate,$(COMPILER_DOC_CRATES),$(eval $(call DEF_LIB_DOC,$(crate),COMPILER_DOC_TARGETS))) $(foreach crate,$(COMPILER_DOC_CRATES),$(eval $(call DEF_LIB_DOC,$(crate),COMPILER_DOC_TARGETS)))
endif
ifdef CFG_DISABLE_DOCS ifdef CFG_DISABLE_DOCS
$(info cfg: disabling doc build (CFG_DISABLE_DOCS)) $(info cfg: disabling doc build (CFG_DISABLE_DOCS))
@ -273,11 +276,13 @@ compiler-docs: $(COMPILER_DOC_TARGETS)
trpl: doc/book/index.html trpl: doc/book/index.html
doc/book/index.html: $(RUSTBOOK_EXE) $(wildcard $(S)/src/doc/trpl/*.md) | doc/ doc/book/index.html: $(RUSTBOOK_EXE) $(wildcard $(S)/src/doc/trpl/*.md) | doc/
@$(call E, rustbook: $@)
$(Q)rm -rf doc/book $(Q)rm -rf doc/book
$(Q)$(RUSTBOOK) build $(S)src/doc/trpl doc/book $(Q)$(RUSTBOOK) build $(S)src/doc/trpl doc/book
style: doc/style/index.html style: doc/style/index.html
doc/style/index.html: $(RUSTBOOK_EXE) $(wildcard $(S)/src/doc/style/*.md) | doc/ doc/style/index.html: $(RUSTBOOK_EXE) $(wildcard $(S)/src/doc/style/*.md) | doc/
@$(call E, rustbook: $@)
$(Q)rm -rf doc/style $(Q)rm -rf doc/style
$(Q)$(RUSTBOOK) build $(S)src/doc/style doc/style $(Q)$(RUSTBOOK) build $(S)src/doc/style doc/style

View File

@ -38,15 +38,16 @@ endif
# the stamp in the source dir. # the stamp in the source dir.
$$(LLVM_STAMP_$(1)): $(S)src/rustllvm/llvm-auto-clean-trigger $$(LLVM_STAMP_$(1)): $(S)src/rustllvm/llvm-auto-clean-trigger
@$$(call E, make: cleaning llvm) @$$(call E, make: cleaning llvm)
$(Q)touch $$@.start_time
$(Q)$(MAKE) clean-llvm$(1) $(Q)$(MAKE) clean-llvm$(1)
@$$(call E, make: done cleaning llvm) @$$(call E, make: done cleaning llvm)
touch $$@ touch -r $$@.start_time $$@ && rm $$@.start_time
ifeq ($$(CFG_ENABLE_LLVM_STATIC_STDCPP),1) ifeq ($$(CFG_ENABLE_LLVM_STATIC_STDCPP),1)
LLVM_STDCPP_LOCATION_$(1) = $$(shell $$(CC_$(1)) $$(CFG_GCCISH_CFLAGS_$(1)) \ LLVM_STDCPP_RUSTFLAGS_$(1) = -L "$$(dir $$(shell $$(CC_$(1)) $$(CFG_GCCISH_CFLAGS_$(1)) \
-print-file-name=libstdc++.a) -print-file-name=libstdc++.a))"
else else
LLVM_STDCPP_LOCATION_$(1) = LLVM_STDCPP_RUSTFLAGS_$(1) =
endif endif

View File

@ -18,7 +18,7 @@ CFG_RELEASE_NUM=1.0.0
# An optional number to put after the label, e.g. '.2' -> '-beta.2' # An optional number to put after the label, e.g. '.2' -> '-beta.2'
# NB Make sure it starts with a dot to conform to semver pre-release # NB Make sure it starts with a dot to conform to semver pre-release
# versions (section 9) # versions (section 9)
CFG_PRERELEASE_VERSION=.2 CFG_PRERELEASE_VERSION=
CFG_FILENAME_EXTRA=4e7c5e5c CFG_FILENAME_EXTRA=4e7c5e5c
@ -30,8 +30,8 @@ CFG_PACKAGE_VERS=$(CFG_RELEASE_NUM)
CFG_DISABLE_UNSTABLE_FEATURES=1 CFG_DISABLE_UNSTABLE_FEATURES=1
endif endif
ifeq ($(CFG_RELEASE_CHANNEL),beta) ifeq ($(CFG_RELEASE_CHANNEL),beta)
CFG_RELEASE=$(CFG_RELEASE_NUM)-alpha$(CFG_PRERELEASE_VERSION) CFG_RELEASE=$(CFG_RELEASE_NUM)-beta$(CFG_PRERELEASE_VERSION)
CFG_PACKAGE_VERS=$(CFG_RELEASE_NUM)-alpha$(CFG_PRERELEASE_VERSION) CFG_PACKAGE_VERS=$(CFG_RELEASE_NUM)-beta$(CFG_PRERELEASE_VERSION)
CFG_DISABLE_UNSTABLE_FEATURES=1 CFG_DISABLE_UNSTABLE_FEATURES=1
endif endif
ifeq ($(CFG_RELEASE_CHANNEL),nightly) ifeq ($(CFG_RELEASE_CHANNEL),nightly)
@ -130,7 +130,7 @@ ifdef CFG_DISABLE_DEBUG
CFG_RUSTC_FLAGS += --cfg ndebug CFG_RUSTC_FLAGS += --cfg ndebug
else else
$(info cfg: enabling more debugging (CFG_ENABLE_DEBUG)) $(info cfg: enabling more debugging (CFG_ENABLE_DEBUG))
CFG_RUSTC_FLAGS += --cfg debug CFG_RUSTC_FLAGS += --cfg debug -C debug-assertions=on
endif endif
ifdef SAVE_TEMPS ifdef SAVE_TEMPS
@ -290,6 +290,7 @@ LLVM_VERSION_$(1)=$$(shell "$$(LLVM_CONFIG_$(1))" --version)
LLVM_BINDIR_$(1)=$$(shell "$$(LLVM_CONFIG_$(1))" --bindir) LLVM_BINDIR_$(1)=$$(shell "$$(LLVM_CONFIG_$(1))" --bindir)
LLVM_INCDIR_$(1)=$$(shell "$$(LLVM_CONFIG_$(1))" --includedir) LLVM_INCDIR_$(1)=$$(shell "$$(LLVM_CONFIG_$(1))" --includedir)
LLVM_LIBDIR_$(1)=$$(shell "$$(LLVM_CONFIG_$(1))" --libdir) LLVM_LIBDIR_$(1)=$$(shell "$$(LLVM_CONFIG_$(1))" --libdir)
LLVM_LIBDIR_RUSTFLAGS_$(1)=-L "$$(LLVM_LIBDIR_$(1))"
LLVM_LIBS_$(1)=$$(shell "$$(LLVM_CONFIG_$(1))" --libs $$(LLVM_COMPONENTS)) LLVM_LIBS_$(1)=$$(shell "$$(LLVM_CONFIG_$(1))" --libs $$(LLVM_COMPONENTS))
LLVM_LDFLAGS_$(1)=$$(shell "$$(LLVM_CONFIG_$(1))" --ldflags) LLVM_LDFLAGS_$(1)=$$(shell "$$(LLVM_CONFIG_$(1))" --ldflags)
# On FreeBSD, it may search wrong headers (that are for pre-installed LLVM), # On FreeBSD, it may search wrong headers (that are for pre-installed LLVM),

View File

@ -179,11 +179,19 @@ define CFG_MAKE_TOOLCHAIN
ifeq ($$(findstring $(HOST_$(1)),arm aarch64 mips mipsel powerpc),) ifeq ($$(findstring $(HOST_$(1)),arm aarch64 mips mipsel powerpc),)
# On Bitrig, we need the relocation model to be PIC for everything
ifeq (,$(filter $(OSTYPE_$(1)),bitrig))
LLVM_MC_RELOCATION_MODEL="pic"
else
LLVM_MC_RELOCATION_MODEL="default"
endif
# We're using llvm-mc as our assembler because it supports # We're using llvm-mc as our assembler because it supports
# .cfi pseudo-ops on mac # .cfi pseudo-ops on mac
CFG_ASSEMBLE_$(1)=$$(CPP_$(1)) -E $$(CFG_DEPEND_FLAGS) $$(2) | \ CFG_ASSEMBLE_$(1)=$$(CPP_$(1)) -E $$(CFG_DEPEND_FLAGS) $$(2) | \
$$(LLVM_MC_$$(CFG_BUILD)) \ $$(LLVM_MC_$$(CFG_BUILD)) \
-assemble \ -assemble \
-relocation-model=$$(LLVM_MC_RELOCATION_MODEL) \
-filetype=obj \ -filetype=obj \
-triple=$(1) \ -triple=$(1) \
-o=$$(1) -o=$$(1)

View File

@ -221,5 +221,3 @@ prepare-maybe-clean-$(1):
endef endef

View File

@ -72,9 +72,11 @@ $$(TLIB$(1)_T_$(2)_H_$(3))/stamp.$(4): CFG_COMPILER_HOST_TRIPLE = $(2)
$$(TLIB$(1)_T_$(2)_H_$(3))/stamp.$(4): \ $$(TLIB$(1)_T_$(2)_H_$(3))/stamp.$(4): \
$$(CRATEFILE_$(4)) \ $$(CRATEFILE_$(4)) \
$$(CRATE_FULLDEPS_$(1)_T_$(2)_H_$(3)_$(4)) \ $$(CRATE_FULLDEPS_$(1)_T_$(2)_H_$(3)_$(4)) \
$$(LLVM_CONFIG_$(2)) \
$$(TSREQ$(1)_T_$(2)_H_$(3)) \ $$(TSREQ$(1)_T_$(2)_H_$(3)) \
| $$(TLIB$(1)_T_$(2)_H_$(3))/ | $$(TLIB$(1)_T_$(2)_H_$(3))/
@$$(call E, rustc: $$(@D)/lib$(4)) @$$(call E, rustc: $$(@D)/lib$(4))
@touch $$@.start_time
$$(call REMOVE_ALL_OLD_GLOB_MATCHES, \ $$(call REMOVE_ALL_OLD_GLOB_MATCHES, \
$$(dir $$@)$$(call CFG_LIB_GLOB_$(2),$(4))) $$(dir $$@)$$(call CFG_LIB_GLOB_$(2),$(4)))
$$(call REMOVE_ALL_OLD_GLOB_MATCHES, \ $$(call REMOVE_ALL_OLD_GLOB_MATCHES, \
@ -83,13 +85,13 @@ $$(TLIB$(1)_T_$(2)_H_$(3))/stamp.$(4): \
$$(subst @,,$$(STAGE$(1)_T_$(2)_H_$(3))) \ $$(subst @,,$$(STAGE$(1)_T_$(2)_H_$(3))) \
$$(RUST_LIB_FLAGS_ST$(1)) \ $$(RUST_LIB_FLAGS_ST$(1)) \
-L "$$(RT_OUTPUT_DIR_$(2))" \ -L "$$(RT_OUTPUT_DIR_$(2))" \
-L "$$(LLVM_LIBDIR_$(2))" \ $$(LLVM_LIBDIR_RUSTFLAGS_$(2)) \
-L "$$(dir $$(LLVM_STDCPP_LOCATION_$(2)))" \ $$(LLVM_STDCPP_RUSTFLAGS_$(2)) \
$$(RUSTFLAGS_$(4)) \ $$(RUSTFLAGS_$(4)) \
--out-dir $$(@D) \ --out-dir $$(@D) \
-C extra-filename=-$$(CFG_FILENAME_EXTRA) \ -C extra-filename=-$$(CFG_FILENAME_EXTRA) \
$$< $$<
@touch $$@ @touch -r $$@.start_time $$@ && rm $$@.start_time
$$(call LIST_ALL_OLD_GLOB_MATCHES, \ $$(call LIST_ALL_OLD_GLOB_MATCHES, \
$$(dir $$@)$$(call CFG_LIB_GLOB_$(2),$(4))) $$(dir $$@)$$(call CFG_LIB_GLOB_$(2),$(4)))
$$(call LIST_ALL_OLD_GLOB_MATCHES, \ $$(call LIST_ALL_OLD_GLOB_MATCHES, \
@ -130,7 +132,7 @@ endef
# on $$(TSREQ$(1)_T_$(2)_H_$(3)), to ensure that no products will be # on $$(TSREQ$(1)_T_$(2)_H_$(3)), to ensure that no products will be
# put into the target area until after the get-snapshot.py script has # put into the target area until after the get-snapshot.py script has
# had its chance to clean it out; otherwise the other products will be # had its chance to clean it out; otherwise the other products will be
# inadvertantly included in the clean out. # inadvertently included in the clean out.
SNAPSHOT_RUSTC_POST_CLEANUP=$(HBIN0_H_$(CFG_BUILD))/rustc$(X_$(CFG_BUILD)) SNAPSHOT_RUSTC_POST_CLEANUP=$(HBIN0_H_$(CFG_BUILD))/rustc$(X_$(CFG_BUILD))
define TARGET_HOST_RULES define TARGET_HOST_RULES

View File

@ -19,9 +19,12 @@
DEPS_coretest := DEPS_coretest :=
$(eval $(call RUST_CRATE,coretest)) $(eval $(call RUST_CRATE,coretest))
TEST_TARGET_CRATES = $(filter-out core unicode,$(TARGET_CRATES)) coretest DEPS_collectionstest :=
$(eval $(call RUST_CRATE,collectionstest))
TEST_TARGET_CRATES = $(filter-out core unicode,$(TARGET_CRATES)) collectionstest coretest
TEST_DOC_CRATES = $(DOC_CRATES) TEST_DOC_CRATES = $(DOC_CRATES)
TEST_HOST_CRATES = $(filter-out rustc_typeck rustc_borrowck rustc_resolve rustc_trans,\ TEST_HOST_CRATES = $(filter-out rustc_typeck rustc_borrowck rustc_resolve rustc_trans rustc_lint,\
$(HOST_CRATES)) $(HOST_CRATES))
TEST_CRATES = $(TEST_TARGET_CRATES) $(TEST_HOST_CRATES) TEST_CRATES = $(TEST_TARGET_CRATES) $(TEST_HOST_CRATES)
@ -163,7 +166,7 @@ $(foreach file,$(wildcard $(S)src/doc/trpl/*.md), \
###################################################################### ######################################################################
# The main testing target. Tests lots of stuff. # The main testing target. Tests lots of stuff.
check: cleantmptestlogs cleantestlibs all check-stage2 tidy check: check-sanitycheck cleantmptestlogs cleantestlibs all check-stage2 tidy
$(Q)$(CFG_PYTHON) $(S)src/etc/check-summary.py tmp/*.log $(Q)$(CFG_PYTHON) $(S)src/etc/check-summary.py tmp/*.log
# As above but don't bother running tidy. # As above but don't bother running tidy.
@ -190,6 +193,11 @@ check-docs: cleantestlibs cleantmptestlogs check-stage2-docs
# Not run as part of the normal test suite, but tested by bors on checkin. # Not run as part of the normal test suite, but tested by bors on checkin.
check-secondary: check-build-compiletest check-build-lexer-verifier check-lexer check-pretty check-secondary: check-build-compiletest check-build-lexer-verifier check-lexer check-pretty
.PHONY: check-sanitycheck
check-sanitycheck:
$(Q)$(CFG_PYTHON) $(S)src/etc/check-sanitycheck.py
# check + check-secondary. # check + check-secondary.
# #
# Issue #17883: build check-secondary first so hidden dependencies in # Issue #17883: build check-secondary first so hidden dependencies in
@ -372,7 +380,7 @@ $(3)/stage$(1)/test/$(4)test-$(2)$$(X_$(2)): \
$(Q)CFG_LLVM_LINKAGE_FILE=$$(LLVM_LINKAGE_PATH_$(3)) \ $(Q)CFG_LLVM_LINKAGE_FILE=$$(LLVM_LINKAGE_PATH_$(3)) \
$$(subst @,,$$(STAGE$(1)_T_$(2)_H_$(3))) -o $$@ $$< --test \ $$(subst @,,$$(STAGE$(1)_T_$(2)_H_$(3))) -o $$@ $$< --test \
-L "$$(RT_OUTPUT_DIR_$(2))" \ -L "$$(RT_OUTPUT_DIR_$(2))" \
-L "$$(LLVM_LIBDIR_$(2))" \ $$(LLVM_LIBDIR_RUSTFLAGS_$(2)) \
$$(RUSTFLAGS_$(4)) $$(RUSTFLAGS_$(4))
endef endef
@ -389,10 +397,11 @@ check-stage$(1)-T-$(2)-H-$(3)-$(4)-exec: $$(call TEST_OK_FILE,$(1),$(2),$(3),$(4
$$(call TEST_OK_FILE,$(1),$(2),$(3),$(4)): \ $$(call TEST_OK_FILE,$(1),$(2),$(3),$(4)): \
$(3)/stage$(1)/test/$(4)test-$(2)$$(X_$(2)) $(3)/stage$(1)/test/$(4)test-$(2)$$(X_$(2))
@$$(call E, run: $$<) @$$(call E, run: $$<)
$$(Q)touch $$@.start_time
$$(Q)$$(call CFG_RUN_TEST_$(2),$$<,$(1),$(2),$(3)) $$(TESTARGS) \ $$(Q)$$(call CFG_RUN_TEST_$(2),$$<,$(1),$(2),$(3)) $$(TESTARGS) \
--logfile $$(call TEST_LOG_FILE,$(1),$(2),$(3),$(4)) \ --logfile $$(call TEST_LOG_FILE,$(1),$(2),$(3),$(4)) \
$$(call CRATE_TEST_EXTRA_ARGS,$(1),$(2),$(3),$(4)) \ $$(call CRATE_TEST_EXTRA_ARGS,$(1),$(2),$(3),$(4)) \
&& touch $$@ && touch -r $$@.start_time $$@ && rm $$@.start_time
endef endef
define DEF_TEST_CRATE_RULES_android define DEF_TEST_CRATE_RULES_android
@ -401,6 +410,7 @@ check-stage$(1)-T-$(2)-H-$(3)-$(4)-exec: $$(call TEST_OK_FILE,$(1),$(2),$(3),$(4
$$(call TEST_OK_FILE,$(1),$(2),$(3),$(4)): \ $$(call TEST_OK_FILE,$(1),$(2),$(3),$(4)): \
$(3)/stage$(1)/test/$(4)test-$(2)$$(X_$(2)) $(3)/stage$(1)/test/$(4)test-$(2)$$(X_$(2))
@$$(call E, run: $$< via adb) @$$(call E, run: $$< via adb)
$$(Q)touch $$@.start_time
$$(Q)$(CFG_ADB) push $$< $(CFG_ADB_TEST_DIR) $$(Q)$(CFG_ADB) push $$< $(CFG_ADB_TEST_DIR)
$$(Q)$(CFG_ADB) shell '(cd $(CFG_ADB_TEST_DIR); LD_LIBRARY_PATH=./$(2) \ $$(Q)$(CFG_ADB) shell '(cd $(CFG_ADB_TEST_DIR); LD_LIBRARY_PATH=./$(2) \
./$$(notdir $$<) \ ./$$(notdir $$<) \
@ -414,7 +424,7 @@ $$(call TEST_OK_FILE,$(1),$(2),$(3),$(4)): \
@if grep -q "result: ok" tmp/check-stage$(1)-T-$(2)-H-$(3)-$(4).tmp; \ @if grep -q "result: ok" tmp/check-stage$(1)-T-$(2)-H-$(3)-$(4).tmp; \
then \ then \
rm tmp/check-stage$(1)-T-$(2)-H-$(3)-$(4).tmp; \ rm tmp/check-stage$(1)-T-$(2)-H-$(3)-$(4).tmp; \
touch $$@; \ touch -r $$@.start_time $$@ && rm $$@.start_time; \
else \ else \
rm tmp/check-stage$(1)-T-$(2)-H-$(3)-$(4).tmp; \ rm tmp/check-stage$(1)-T-$(2)-H-$(3)-$(4).tmp; \
exit 101; \ exit 101; \
@ -564,6 +574,11 @@ ifeq ($(CFG_OSTYPE),apple-darwin)
CTEST_DISABLE_debuginfo-gdb = "gdb on darwin needs root" CTEST_DISABLE_debuginfo-gdb = "gdb on darwin needs root"
endif endif
ifeq ($(findstring android, $(CFG_TARGET)), android)
CTEST_DISABLE_debuginfo-gdb =
CTEST_DISABLE_debuginfo-lldb = "lldb tests are disabled on android"
endif
# CTEST_DISABLE_NONSELFHOST_$(TEST_GROUP), if set, will cause that # CTEST_DISABLE_NONSELFHOST_$(TEST_GROUP), if set, will cause that
# test group to be disabled *unless* the target is able to build a # test group to be disabled *unless* the target is able to build a
# compiler (i.e. when the target triple is in the set of of host # compiler (i.e. when the target triple is in the set of of host
@ -588,7 +603,7 @@ TEST_SREQ$(1)_T_$(2)_H_$(3) = \
# The tests select when to use debug configuration on their own; # The tests select when to use debug configuration on their own;
# remove directive, if present, from CFG_RUSTC_FLAGS (issue #7898). # remove directive, if present, from CFG_RUSTC_FLAGS (issue #7898).
CTEST_RUSTC_FLAGS := $$(subst --cfg ndebug,,$$(CFG_RUSTC_FLAGS)) CTEST_RUSTC_FLAGS := $$(subst -C debug-assertions,,$$(subst -C debug-assertions=on,,$$(CFG_RUSTC_FLAGS)))
# The tests cannot be optimized while the rest of the compiler is optimized, so # The tests cannot be optimized while the rest of the compiler is optimized, so
# filter out the optimization (if any) from rustc and then figure out if we need # filter out the optimization (if any) from rustc and then figure out if we need
@ -690,10 +705,11 @@ $$(call TEST_OK_FILE,$(1),$(2),$(3),$(4)): \
$$(TEST_SREQ$(1)_T_$(2)_H_$(3)) \ $$(TEST_SREQ$(1)_T_$(2)_H_$(3)) \
$$(CTEST_DEPS_$(4)_$(1)-T-$(2)-H-$(3)) $$(CTEST_DEPS_$(4)_$(1)-T-$(2)-H-$(3))
@$$(call E, run $(4) [$(2)]: $$<) @$$(call E, run $(4) [$(2)]: $$<)
$$(Q)touch $$@.start_time
$$(Q)$$(call CFG_RUN_CTEST_$(2),$(1),$$<,$(3)) \ $$(Q)$$(call CFG_RUN_CTEST_$(2),$(1),$$<,$(3)) \
$$(CTEST_ARGS$(1)-T-$(2)-H-$(3)-$(4)) \ $$(CTEST_ARGS$(1)-T-$(2)-H-$(3)-$(4)) \
--logfile $$(call TEST_LOG_FILE,$(1),$(2),$(3),$(4)) \ --logfile $$(call TEST_LOG_FILE,$(1),$(2),$(3),$(4)) \
&& touch $$@ && touch -r $$@.start_time $$@ && rm $$@.start_time
else else
@ -750,10 +766,11 @@ $$(call TEST_OK_FILE,$(1),$(2),$(3),$(4)): \
$$(PRETTY_DEPS_$(4)) \ $$(PRETTY_DEPS_$(4)) \
$$(PRETTY_DEPS$(1)_H_$(3)_$(4)) $$(PRETTY_DEPS$(1)_H_$(3)_$(4))
@$$(call E, run pretty-rpass [$(2)]: $$<) @$$(call E, run pretty-rpass [$(2)]: $$<)
$$(Q)touch $$@.start_time
$$(Q)$$(call CFG_RUN_CTEST_$(2),$(1),$$<,$(3)) \ $$(Q)$$(call CFG_RUN_CTEST_$(2),$(1),$$<,$(3)) \
$$(PRETTY_ARGS$(1)-T-$(2)-H-$(3)-$(4)) \ $$(PRETTY_ARGS$(1)-T-$(2)-H-$(3)-$(4)) \
--logfile $$(call TEST_LOG_FILE,$(1),$(2),$(3),$(4)) \ --logfile $$(call TEST_LOG_FILE,$(1),$(2),$(3),$(4)) \
&& touch $$@ && touch -r $$@.start_time $$@ && rm $$@.start_time
endef endef
@ -799,8 +816,10 @@ endif
ifeq ($(2),$$(CFG_BUILD)) ifeq ($(2),$$(CFG_BUILD))
$$(call TEST_OK_FILE,$(1),$(2),$(3),doc-$(4)): $$(DOCTESTDEP_$(1)_$(2)_$(3)_$(4)) $$(call TEST_OK_FILE,$(1),$(2),$(3),doc-$(4)): $$(DOCTESTDEP_$(1)_$(2)_$(3)_$(4))
@$$(call E, run doc-$(4) [$(2)]) @$$(call E, run doc-$(4) [$(2)])
$$(Q)touch $$@.start_time
$$(Q)$$(RUSTDOC_$(1)_T_$(2)_H_$(3)) --cfg dox --test $$< \ $$(Q)$$(RUSTDOC_$(1)_T_$(2)_H_$(3)) --cfg dox --test $$< \
--test-args "$$(TESTARGS)" && touch $$@ --test-args "$$(TESTARGS)" && \
touch -r $$@.start_time $$@ && rm $$@.start_time
else else
$$(call TEST_OK_FILE,$(1),$(2),$(3),doc-$(4)): $$(call TEST_OK_FILE,$(1),$(2),$(3),doc-$(4)):
touch $$@ touch $$@
@ -835,9 +854,11 @@ check-stage$(1)-T-$(2)-H-$(3)-doc-crate-$(4)-exec: \
ifeq ($(2),$$(CFG_BUILD)) ifeq ($(2),$$(CFG_BUILD))
$$(call TEST_OK_FILE,$(1),$(2),$(3),doc-crate-$(4)): $$(CRATEDOCTESTDEP_$(1)_$(2)_$(3)_$(4)) $$(call TEST_OK_FILE,$(1),$(2),$(3),doc-crate-$(4)): $$(CRATEDOCTESTDEP_$(1)_$(2)_$(3)_$(4))
@$$(call E, run doc-crate-$(4) [$(2)]) @$$(call E, run doc-crate-$(4) [$(2)])
$$(Q)touch $$@.start_time
$$(Q)CFG_LLVM_LINKAGE_FILE=$$(LLVM_LINKAGE_PATH_$(3)) \ $$(Q)CFG_LLVM_LINKAGE_FILE=$$(LLVM_LINKAGE_PATH_$(3)) \
$$(RUSTDOC_$(1)_T_$(2)_H_$(3)) --test --cfg dox \ $$(RUSTDOC_$(1)_T_$(2)_H_$(3)) --test --cfg dox \
$$(CRATEFILE_$(4)) --test-args "$$(TESTARGS)" && touch $$@ $$(CRATEFILE_$(4)) --test-args "$$(TESTARGS)" && \
touch -r $$@.start_time $$@ && rm $$@.start_time
else else
$$(call TEST_OK_FILE,$(1),$(2),$(3),doc-crate-$(4)): $$(call TEST_OK_FILE,$(1),$(2),$(3),doc-crate-$(4)):
touch $$@ touch $$@
@ -984,6 +1005,7 @@ $(3)/test/run-make/%-$(1)-T-$(2)-H-$(3).ok: \
$$(CSREQ$(1)_T_$(2)_H_$(3)) $$(CSREQ$(1)_T_$(2)_H_$(3))
@rm -rf $(3)/test/run-make/$$* @rm -rf $(3)/test/run-make/$$*
@mkdir -p $(3)/test/run-make/$$* @mkdir -p $(3)/test/run-make/$$*
$$(Q)touch $$@.start_time
$$(Q)$$(CFG_PYTHON) $(S)src/etc/maketest.py $$(dir $$<) \ $$(Q)$$(CFG_PYTHON) $(S)src/etc/maketest.py $$(dir $$<) \
$$(MAKE) \ $$(MAKE) \
$$(HBIN$(1)_H_$(3))/rustc$$(X_$(3)) \ $$(HBIN$(1)_H_$(3))/rustc$$(X_$(3)) \
@ -996,7 +1018,7 @@ $(3)/test/run-make/%-$(1)-T-$(2)-H-$(3).ok: \
"$$(LD_LIBRARY_PATH_ENV_TARGETDIR$(1)_T_$(2)_H_$(3))" \ "$$(LD_LIBRARY_PATH_ENV_TARGETDIR$(1)_T_$(2)_H_$(3))" \
$(1) \ $(1) \
$$(S) $$(S)
@touch $$@ @touch -r $$@.start_time $$@ && rm $$@.start_time
else else
# FIXME #11094 - The above rule doesn't work right for multiple targets # FIXME #11094 - The above rule doesn't work right for multiple targets
check-stage$(1)-T-$(2)-H-$(3)-rmake-exec: check-stage$(1)-T-$(2)-H-$(3)-rmake-exec:

View File

@ -17,4 +17,3 @@ else
endif endif
S := $(CFG_SRC_DIR) S := $(CFG_SRC_DIR)

View File

@ -11,6 +11,7 @@ pub use self::Mode::*;
use std::fmt; use std::fmt;
use std::str::FromStr; use std::str::FromStr;
use std::path::PathBuf;
#[derive(Clone, Copy, PartialEq, Debug)] #[derive(Clone, Copy, PartialEq, Debug)]
pub enum Mode { pub enum Mode {
@ -68,13 +69,13 @@ pub struct Config {
pub run_lib_path: String, pub run_lib_path: String,
// The rustc executable // The rustc executable
pub rustc_path: Path, pub rustc_path: PathBuf,
// The clang executable // The clang executable
pub clang_path: Option<Path>, pub clang_path: Option<PathBuf>,
// The llvm binaries path // The llvm binaries path
pub llvm_bin_path: Option<Path>, pub llvm_bin_path: Option<PathBuf>,
// The valgrind path // The valgrind path
pub valgrind_path: Option<String>, pub valgrind_path: Option<String>,
@ -84,13 +85,13 @@ pub struct Config {
pub force_valgrind: bool, pub force_valgrind: bool,
// The directory containing the tests to run // The directory containing the tests to run
pub src_base: Path, pub src_base: PathBuf,
// The directory where programs should be built // The directory where programs should be built
pub build_base: Path, pub build_base: PathBuf,
// Directory for auxiliary libraries // Directory for auxiliary libraries
pub aux_base: Path, pub aux_base: PathBuf,
// The name of the stage being built (stage1, etc) // The name of the stage being built (stage1, etc)
pub stage_id: String, pub stage_id: String,
@ -105,7 +106,7 @@ pub struct Config {
pub filter: Option<String>, pub filter: Option<String>,
// Write out a parseable log of tests that were run // Write out a parseable log of tests that were run
pub logfile: Option<Path>, pub logfile: Option<PathBuf>,
// A command line to prefix program execution with, // A command line to prefix program execution with,
// for running under valgrind // for running under valgrind
@ -133,7 +134,7 @@ pub struct Config {
pub lldb_version: Option<String>, pub lldb_version: Option<String>,
// Path to the android tools // Path to the android tools
pub android_cross_path: Path, pub android_cross_path: PathBuf,
// Extra parameter to run adb on arm-linux-androideabi // Extra parameter to run adb on arm-linux-androideabi
pub adb_path: String, pub adb_path: String,

View File

@ -12,16 +12,13 @@
#![feature(box_syntax)] #![feature(box_syntax)]
#![feature(collections)] #![feature(collections)]
#![feature(int_uint)]
#![feature(old_io)] #![feature(old_io)]
#![feature(old_path)]
#![feature(rustc_private)] #![feature(rustc_private)]
#![feature(unboxed_closures)] #![feature(unboxed_closures)]
#![feature(std_misc)] #![feature(std_misc)]
#![feature(test)] #![feature(test)]
#![feature(unicode)] #![feature(path_ext)]
#![feature(env)] #![feature(str_char)]
#![feature(core)]
#![deny(warnings)] #![deny(warnings)]
@ -32,9 +29,8 @@ extern crate getopts;
extern crate log; extern crate log;
use std::env; use std::env;
use std::old_io; use std::fs;
use std::old_io::fs; use std::path::{Path, PathBuf};
use std::thunk::Thunk;
use getopts::{optopt, optflag, reqopt}; use getopts::{optopt, optflag, reqopt};
use common::Config; use common::Config;
use common::{Pretty, DebugInfoGdb, DebugInfoLldb, Codegen}; use common::{Pretty, DebugInfoGdb, DebugInfoLldb, Codegen};
@ -115,9 +111,9 @@ pub fn parse_config(args: Vec<String> ) -> Config {
panic!() panic!()
} }
fn opt_path(m: &getopts::Matches, nm: &str) -> Path { fn opt_path(m: &getopts::Matches, nm: &str) -> PathBuf {
match m.opt_str(nm) { match m.opt_str(nm) {
Some(s) => Path::new(s), Some(s) => PathBuf::from(&s),
None => panic!("no option (=path) found for {}", nm), None => panic!("no option (=path) found for {}", nm),
} }
} }
@ -132,10 +128,10 @@ pub fn parse_config(args: Vec<String> ) -> Config {
compile_lib_path: matches.opt_str("compile-lib-path").unwrap(), compile_lib_path: matches.opt_str("compile-lib-path").unwrap(),
run_lib_path: matches.opt_str("run-lib-path").unwrap(), run_lib_path: matches.opt_str("run-lib-path").unwrap(),
rustc_path: opt_path(matches, "rustc-path"), rustc_path: opt_path(matches, "rustc-path"),
clang_path: matches.opt_str("clang-path").map(|s| Path::new(s)), clang_path: matches.opt_str("clang-path").map(|s| PathBuf::from(&s)),
valgrind_path: matches.opt_str("valgrind-path"), valgrind_path: matches.opt_str("valgrind-path"),
force_valgrind: matches.opt_present("force-valgrind"), force_valgrind: matches.opt_present("force-valgrind"),
llvm_bin_path: matches.opt_str("llvm-bin-path").map(|s| Path::new(s)), llvm_bin_path: matches.opt_str("llvm-bin-path").map(|s| PathBuf::from(&s)),
src_base: opt_path(matches, "src-base"), src_base: opt_path(matches, "src-base"),
build_base: opt_path(matches, "build-base"), build_base: opt_path(matches, "build-base"),
aux_base: opt_path(matches, "aux-base"), aux_base: opt_path(matches, "aux-base"),
@ -143,7 +139,7 @@ pub fn parse_config(args: Vec<String> ) -> Config {
mode: matches.opt_str("mode").unwrap().parse().ok().expect("invalid mode"), mode: matches.opt_str("mode").unwrap().parse().ok().expect("invalid mode"),
run_ignored: matches.opt_present("ignored"), run_ignored: matches.opt_present("ignored"),
filter: filter, filter: filter,
logfile: matches.opt_str("logfile").map(|s| Path::new(s)), logfile: matches.opt_str("logfile").map(|s| PathBuf::from(&s)),
runtool: matches.opt_str("runtool"), runtool: matches.opt_str("runtool"),
host_rustcflags: matches.opt_str("host-rustcflags"), host_rustcflags: matches.opt_str("host-rustcflags"),
target_rustcflags: matches.opt_str("target-rustcflags"), target_rustcflags: matches.opt_str("target-rustcflags"),
@ -226,7 +222,7 @@ pub fn run_tests(config: &Config) {
// android debug-info test uses remote debugger // android debug-info test uses remote debugger
// so, we test 1 task at once. // so, we test 1 task at once.
// also trying to isolate problems with adb_run_wrapper.sh ilooping // also trying to isolate problems with adb_run_wrapper.sh ilooping
env::set_var("RUST_TEST_TASKS","1"); env::set_var("RUST_TEST_THREADS","1");
} }
match config.mode { match config.mode {
@ -234,7 +230,7 @@ pub fn run_tests(config: &Config) {
// Some older versions of LLDB seem to have problems with multiple // Some older versions of LLDB seem to have problems with multiple
// instances running in parallel, so only run one test task at a // instances running in parallel, so only run one test task at a
// time. // time.
env::set_var("RUST_TEST_TASKS", "1"); env::set_var("RUST_TEST_THREADS", "1");
} }
_ => { /* proceed */ } _ => { /* proceed */ }
} }
@ -244,7 +240,11 @@ pub fn run_tests(config: &Config) {
// sadly osx needs some file descriptor limits raised for running tests in // sadly osx needs some file descriptor limits raised for running tests in
// parallel (especially when we have lots and lots of child processes). // parallel (especially when we have lots and lots of child processes).
// For context, see #8904 // For context, see #8904
old_io::test::raise_fd_limit(); #[allow(deprecated)]
fn raise_fd_limit() {
std::old_io::test::raise_fd_limit();
}
raise_fd_limit();
// Prevent issue #21352 UAC blocking .exe containing 'patch' etc. on Windows // Prevent issue #21352 UAC blocking .exe containing 'patch' etc. on Windows
// If #11207 is resolved (adding manifest to .exe) this becomes unnecessary // If #11207 is resolved (adding manifest to .exe) this becomes unnecessary
env::set_var("__COMPAT_LAYER", "RunAsInvoker"); env::set_var("__COMPAT_LAYER", "RunAsInvoker");
@ -268,7 +268,7 @@ pub fn test_opts(config: &Config) -> test::TestOpts {
logfile: config.logfile.clone(), logfile: config.logfile.clone(),
run_tests: true, run_tests: true,
run_benchmarks: true, run_benchmarks: true,
nocapture: false, nocapture: env::var("RUST_TEST_NOCAPTURE").is_ok(),
color: test::AutoColor, color: test::AutoColor,
} }
} }
@ -277,9 +277,9 @@ pub fn make_tests(config: &Config) -> Vec<test::TestDescAndFn> {
debug!("making tests from {:?}", debug!("making tests from {:?}",
config.src_base.display()); config.src_base.display());
let mut tests = Vec::new(); let mut tests = Vec::new();
let dirs = fs::readdir(&config.src_base).unwrap(); let dirs = fs::read_dir(&config.src_base).unwrap();
for file in &dirs { for file in dirs {
let file = file.clone(); let file = file.unwrap().path();
debug!("inspecting file {:?}", file.display()); debug!("inspecting file {:?}", file.display());
if is_test(config, &file) { if is_test(config, &file) {
let t = make_test(config, &file, || { let t = make_test(config, &file, || {
@ -302,7 +302,7 @@ pub fn is_test(config: &Config, testfile: &Path) -> bool {
_ => vec!(".rc".to_string(), ".rs".to_string()) _ => vec!(".rc".to_string(), ".rs".to_string())
}; };
let invalid_prefixes = vec!(".".to_string(), "#".to_string(), "~".to_string()); let invalid_prefixes = vec!(".".to_string(), "#".to_string(), "~".to_string());
let name = testfile.filename_str().unwrap(); let name = testfile.file_name().unwrap().to_str().unwrap();
let mut valid = false; let mut valid = false;
@ -328,7 +328,7 @@ pub fn make_test<F>(config: &Config, testfile: &Path, f: F) -> test::TestDescAnd
desc: test::TestDesc { desc: test::TestDesc {
name: make_test_name(config, testfile), name: make_test_name(config, testfile),
ignore: header::is_test_ignored(config, testfile), ignore: header::is_test_ignored(config, testfile),
should_fail: test::ShouldFail::No, should_panic: test::ShouldPanic::No,
}, },
testfn: f(), testfn: f(),
} }
@ -338,9 +338,9 @@ pub fn make_test_name(config: &Config, testfile: &Path) -> test::TestName {
// Try to elide redundant long paths // Try to elide redundant long paths
fn shorten(path: &Path) -> String { fn shorten(path: &Path) -> String {
let filename = path.filename_str(); let filename = path.file_name().unwrap().to_str();
let p = path.dir_path(); let p = path.parent().unwrap();
let dir = p.filename_str(); let dir = p.file_name().unwrap().to_str();
format!("{}/{}", dir.unwrap_or(""), filename.unwrap_or("")) format!("{}/{}", dir.unwrap_or(""), filename.unwrap_or(""))
} }
@ -349,19 +349,17 @@ pub fn make_test_name(config: &Config, testfile: &Path) -> test::TestName {
pub fn make_test_closure(config: &Config, testfile: &Path) -> test::TestFn { pub fn make_test_closure(config: &Config, testfile: &Path) -> test::TestFn {
let config = (*config).clone(); let config = (*config).clone();
// FIXME (#9639): This needs to handle non-utf8 paths let testfile = testfile.to_path_buf();
let testfile = testfile.as_str().unwrap().to_string(); test::DynTestFn(Box::new(move || {
test::DynTestFn(Thunk::new(move || { runtest::run(config, &testfile)
runtest::run(config, testfile)
})) }))
} }
pub fn make_metrics_test_closure(config: &Config, testfile: &Path) -> test::TestFn { pub fn make_metrics_test_closure(config: &Config, testfile: &Path) -> test::TestFn {
let config = (*config).clone(); let config = (*config).clone();
// FIXME (#9639): This needs to handle non-utf8 paths let testfile = testfile.to_path_buf();
let testfile = testfile.as_str().unwrap().to_string();
test::DynMetricFn(box move |mm: &mut test::MetricMap| { test::DynMetricFn(box move |mm: &mut test::MetricMap| {
runtest::run_metrics(config, testfile, mm) runtest::run_metrics(config, &testfile, mm)
}) })
} }

View File

@ -9,16 +9,19 @@
// except according to those terms. // except according to those terms.
use self::WhichLine::*; use self::WhichLine::*;
use std::old_io::{BufferedReader, File}; use std::fs::File;
use std::io::BufReader;
use std::io::prelude::*;
use std::path::Path;
pub struct ExpectedError { pub struct ExpectedError {
pub line: uint, pub line: usize,
pub kind: String, pub kind: String,
pub msg: String, pub msg: String,
} }
#[derive(PartialEq, Debug)] #[derive(PartialEq, Debug)]
enum WhichLine { ThisLine, FollowPrevious(uint), AdjustBackward(uint) } enum WhichLine { ThisLine, FollowPrevious(usize), AdjustBackward(usize) }
/// Looks for either "//~| KIND MESSAGE" or "//~^^... KIND MESSAGE" /// Looks for either "//~| KIND MESSAGE" or "//~^^... KIND MESSAGE"
/// The former is a "follow" that inherits its target from the preceding line; /// The former is a "follow" that inherits its target from the preceding line;
@ -29,7 +32,7 @@ enum WhichLine { ThisLine, FollowPrevious(uint), AdjustBackward(uint) }
/// //~| ERROR message two for that same line. /// //~| ERROR message two for that same line.
// Load any test directives embedded in the file // Load any test directives embedded in the file
pub fn load_errors(testfile: &Path) -> Vec<ExpectedError> { pub fn load_errors(testfile: &Path) -> Vec<ExpectedError> {
let mut rdr = BufferedReader::new(File::open(testfile).unwrap()); let rdr = BufReader::new(File::open(testfile).unwrap());
// `last_nonfollow_error` tracks the most recently seen // `last_nonfollow_error` tracks the most recently seen
// line with an error template that did not use the // line with an error template that did not use the
@ -55,10 +58,10 @@ pub fn load_errors(testfile: &Path) -> Vec<ExpectedError> {
}).collect() }).collect()
} }
fn parse_expected(last_nonfollow_error: Option<uint>, fn parse_expected(last_nonfollow_error: Option<usize>,
line_num: uint, line_num: usize,
line: &str) -> Option<(WhichLine, ExpectedError)> { line: &str) -> Option<(WhichLine, ExpectedError)> {
let start = match line.find_str("//~") { Some(i) => i, None => return None }; let start = match line.find("//~") { Some(i) => i, None => return None };
let (follow, adjusts) = if line.char_at(start + 3) == '|' { let (follow, adjusts) = if line.char_at(start + 3) == '|' {
(true, 0) (true, 0)
} else { } else {
@ -68,7 +71,7 @@ fn parse_expected(last_nonfollow_error: Option<uint>,
let letters = line[kind_start..].chars(); let letters = line[kind_start..].chars();
let kind = letters.skip_while(|c| c.is_whitespace()) let kind = letters.skip_while(|c| c.is_whitespace())
.take_while(|c| !c.is_whitespace()) .take_while(|c| !c.is_whitespace())
.map(|c| c.to_lowercase()) .flat_map(|c| c.to_lowercase())
.collect::<String>(); .collect::<String>();
let letters = line[kind_start..].chars(); let letters = line[kind_start..].chars();
let msg = letters.skip_while(|c| c.is_whitespace()) let msg = letters.skip_while(|c| c.is_whitespace())

View File

@ -8,6 +8,12 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use std::env;
use std::fs::File;
use std::io::BufReader;
use std::io::prelude::*;
use std::path::{Path, PathBuf};
use common::Config; use common::Config;
use common; use common;
use util; use util;
@ -21,7 +27,7 @@ pub struct TestProps {
pub run_flags: Option<String>, pub run_flags: Option<String>,
// If present, the name of a file that this test should match when // If present, the name of a file that this test should match when
// pretty-printed // pretty-printed
pub pp_exact: Option<Path>, pub pp_exact: Option<PathBuf>,
// Modules from aux directory that should be compiled // Modules from aux directory that should be compiled
pub aux_builds: Vec<String> , pub aux_builds: Vec<String> ,
// Environment settings to use during execution // Environment settings to use during execution
@ -34,8 +40,8 @@ pub struct TestProps {
pub check_stdout: bool, pub check_stdout: bool,
// Don't force a --crate-type=dylib flag on the command line // Don't force a --crate-type=dylib flag on the command line
pub no_prefer_dynamic: bool, pub no_prefer_dynamic: bool,
// Don't run --pretty expanded when running pretty printing tests // Run --pretty expanded when running pretty printing tests
pub no_pretty_expanded: bool, pub pretty_expanded: bool,
// Which pretty mode are we testing with, default to 'normal' // Which pretty mode are we testing with, default to 'normal'
pub pretty_mode: String, pub pretty_mode: String,
// Only compare pretty output and don't try compiling // Only compare pretty output and don't try compiling
@ -56,11 +62,11 @@ pub fn load_props(testfile: &Path) -> TestProps {
let mut force_host = false; let mut force_host = false;
let mut check_stdout = false; let mut check_stdout = false;
let mut no_prefer_dynamic = false; let mut no_prefer_dynamic = false;
let mut no_pretty_expanded = false; let mut pretty_expanded = false;
let mut pretty_mode = None; let mut pretty_mode = None;
let mut pretty_compare_only = false; let mut pretty_compare_only = false;
let mut forbid_output = Vec::new(); let mut forbid_output = Vec::new();
iter_header(testfile, |ln| { iter_header(testfile, &mut |ln| {
match parse_error_pattern(ln) { match parse_error_pattern(ln) {
Some(ep) => error_patterns.push(ep), Some(ep) => error_patterns.push(ep),
None => () None => ()
@ -90,8 +96,8 @@ pub fn load_props(testfile: &Path) -> TestProps {
no_prefer_dynamic = parse_no_prefer_dynamic(ln); no_prefer_dynamic = parse_no_prefer_dynamic(ln);
} }
if !no_pretty_expanded { if !pretty_expanded {
no_pretty_expanded = parse_no_pretty_expanded(ln); pretty_expanded = parse_pretty_expanded(ln);
} }
if pretty_mode.is_none() { if pretty_mode.is_none() {
@ -125,6 +131,16 @@ pub fn load_props(testfile: &Path) -> TestProps {
true true
}); });
for key in vec!["RUST_TEST_NOCAPTURE", "RUST_TEST_THREADS"] {
match env::var(key) {
Ok(val) =>
if exec_env.iter().find(|&&(ref x, _)| *x == key.to_string()).is_none() {
exec_env.push((key.to_string(), val))
},
Err(..) => {}
}
}
TestProps { TestProps {
error_patterns: error_patterns, error_patterns: error_patterns,
compile_flags: compile_flags, compile_flags: compile_flags,
@ -136,7 +152,7 @@ pub fn load_props(testfile: &Path) -> TestProps {
force_host: force_host, force_host: force_host,
check_stdout: check_stdout, check_stdout: check_stdout,
no_prefer_dynamic: no_prefer_dynamic, no_prefer_dynamic: no_prefer_dynamic,
no_pretty_expanded: no_pretty_expanded, pretty_expanded: pretty_expanded,
pretty_mode: pretty_mode.unwrap_or("normal".to_string()), pretty_mode: pretty_mode.unwrap_or("normal".to_string()),
pretty_compare_only: pretty_compare_only, pretty_compare_only: pretty_compare_only,
forbid_output: forbid_output, forbid_output: forbid_output,
@ -147,6 +163,9 @@ pub fn is_test_ignored(config: &Config, testfile: &Path) -> bool {
fn ignore_target(config: &Config) -> String { fn ignore_target(config: &Config) -> String {
format!("ignore-{}", util::get_os(&config.target)) format!("ignore-{}", util::get_os(&config.target))
} }
fn ignore_architecture(config: &Config) -> String {
format!("ignore-{}", util::get_arch(&config.target))
}
fn ignore_stage(config: &Config) -> String { fn ignore_stage(config: &Config) -> String {
format!("ignore-{}", format!("ignore-{}",
config.stage_id.split('-').next().unwrap()) config.stage_id.split('-').next().unwrap())
@ -207,9 +226,10 @@ pub fn is_test_ignored(config: &Config, testfile: &Path) -> bool {
} }
} }
let val = iter_header(testfile, |ln| { let val = iter_header(testfile, &mut |ln| {
!parse_name_directive(ln, "ignore-test") && !parse_name_directive(ln, "ignore-test") &&
!parse_name_directive(ln, &ignore_target(config)) && !parse_name_directive(ln, &ignore_target(config)) &&
!parse_name_directive(ln, &ignore_architecture(config)) &&
!parse_name_directive(ln, &ignore_stage(config)) && !parse_name_directive(ln, &ignore_stage(config)) &&
!(config.mode == common::Pretty && parse_name_directive(ln, "ignore-pretty")) && !(config.mode == common::Pretty && parse_name_directive(ln, "ignore-pretty")) &&
!(config.target != config.host && parse_name_directive(ln, "ignore-cross-compile")) && !(config.target != config.host && parse_name_directive(ln, "ignore-cross-compile")) &&
@ -220,12 +240,8 @@ pub fn is_test_ignored(config: &Config, testfile: &Path) -> bool {
!val !val
} }
fn iter_header<F>(testfile: &Path, mut it: F) -> bool where fn iter_header(testfile: &Path, it: &mut FnMut(&str) -> bool) -> bool {
F: FnMut(&str) -> bool, let rdr = BufReader::new(File::open(testfile).unwrap());
{
use std::old_io::{BufferedReader, File};
let mut rdr = BufferedReader::new(File::open(testfile).unwrap());
for ln in rdr.lines() { for ln in rdr.lines() {
// Assume that any directives will be found before the first // Assume that any directives will be found before the first
// module or function. This doesn't seem to be an optimization // module or function. This doesn't seem to be an optimization
@ -279,8 +295,8 @@ fn parse_no_prefer_dynamic(line: &str) -> bool {
parse_name_directive(line, "no-prefer-dynamic") parse_name_directive(line, "no-prefer-dynamic")
} }
fn parse_no_pretty_expanded(line: &str) -> bool { fn parse_pretty_expanded(line: &str) -> bool {
parse_name_directive(line, "no-pretty-expanded") parse_name_directive(line, "pretty-expanded")
} }
fn parse_pretty_mode(line: &str) -> Option<String> { fn parse_pretty_mode(line: &str) -> Option<String> {
@ -295,7 +311,7 @@ fn parse_exec_env(line: &str) -> Option<(String, String)> {
parse_name_value_directive(line, "exec-env").map(|nv| { parse_name_value_directive(line, "exec-env").map(|nv| {
// nv is either FOO or FOO=BAR // nv is either FOO or FOO=BAR
let mut strs: Vec<String> = nv let mut strs: Vec<String> = nv
.splitn(1, '=') .splitn(2, '=')
.map(|s| s.to_string()) .map(|s| s.to_string())
.collect(); .collect();
@ -310,12 +326,12 @@ fn parse_exec_env(line: &str) -> Option<(String, String)> {
}) })
} }
fn parse_pp_exact(line: &str, testfile: &Path) -> Option<Path> { fn parse_pp_exact(line: &str, testfile: &Path) -> Option<PathBuf> {
match parse_name_value_directive(line, "pp-exact") { match parse_name_value_directive(line, "pp-exact") {
Some(s) => Some(Path::new(s)), Some(s) => Some(PathBuf::from(&s)),
None => { None => {
if parse_name_directive(line, "pp-exact") { if parse_name_directive(line, "pp-exact") {
testfile.filename().map(|s| Path::new(s)) testfile.file_name().map(|s| PathBuf::from(s))
} else { } else {
None None
} }
@ -324,13 +340,14 @@ fn parse_pp_exact(line: &str, testfile: &Path) -> Option<Path> {
} }
fn parse_name_directive(line: &str, directive: &str) -> bool { fn parse_name_directive(line: &str, directive: &str) -> bool {
line.contains(directive) // This 'no-' rule is a quick hack to allow pretty-expanded and no-pretty-expanded to coexist
line.contains(directive) && !line.contains(&("no-".to_string() + directive))
} }
pub fn parse_name_value_directive(line: &str, directive: &str) pub fn parse_name_value_directive(line: &str, directive: &str)
-> Option<String> { -> Option<String> {
let keycolon = format!("{}:", directive); let keycolon = format!("{}:", directive);
match line.find_str(&keycolon) { match line.find(&keycolon) {
Some(colon) => { Some(colon) => {
let value = line[(colon + keycolon.len()) .. line.len()].to_string(); let value = line[(colon + keycolon.len()) .. line.len()].to_string();
debug!("{}: {}", directive, value); debug!("{}: {}", directive, value);
@ -340,7 +357,7 @@ pub fn parse_name_value_directive(line: &str, directive: &str)
} }
} }
pub fn gdb_version_to_int(version_string: &str) -> int { pub fn gdb_version_to_int(version_string: &str) -> isize {
let error_string = format!( let error_string = format!(
"Encountered GDB version string with unexpected format: {}", "Encountered GDB version string with unexpected format: {}",
version_string); version_string);
@ -352,17 +369,17 @@ pub fn gdb_version_to_int(version_string: &str) -> int {
panic!("{}", error_string); panic!("{}", error_string);
} }
let major: int = components[0].parse().ok().expect(&error_string); let major: isize = components[0].parse().ok().expect(&error_string);
let minor: int = components[1].parse().ok().expect(&error_string); let minor: isize = components[1].parse().ok().expect(&error_string);
return major * 1000 + minor; return major * 1000 + minor;
} }
pub fn lldb_version_to_int(version_string: &str) -> int { pub fn lldb_version_to_int(version_string: &str) -> isize {
let error_string = format!( let error_string = format!(
"Encountered LLDB version string with unexpected format: {}", "Encountered LLDB version string with unexpected format: {}",
version_string); version_string);
let error_string = error_string; let error_string = error_string;
let major: int = version_string.parse().ok().expect(&error_string); let major: isize = version_string.parse().ok().expect(&error_string);
return major; return major;
} }

View File

@ -8,27 +8,29 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use std::old_io::process::{ProcessExit, Command, Process, ProcessOutput};
use std::dynamic_lib::DynamicLibrary; use std::dynamic_lib::DynamicLibrary;
use std::io::prelude::*;
use std::path::PathBuf;
use std::process::{ExitStatus, Command, Child, Output, Stdio};
fn add_target_env(cmd: &mut Command, lib_path: &str, aux_path: Option<&str>) { fn add_target_env(cmd: &mut Command, lib_path: &str, aux_path: Option<&str>) {
// Need to be sure to put both the lib_path and the aux path in the dylib // Need to be sure to put both the lib_path and the aux path in the dylib
// search path for the child. // search path for the child.
let mut path = DynamicLibrary::search_path(); let mut path = DynamicLibrary::search_path();
match aux_path { match aux_path {
Some(p) => path.insert(0, Path::new(p)), Some(p) => path.insert(0, PathBuf::from(p)),
None => {} None => {}
} }
path.insert(0, Path::new(lib_path)); path.insert(0, PathBuf::from(lib_path));
// Add the new dylib search path var // Add the new dylib search path var
let var = DynamicLibrary::envvar(); let var = DynamicLibrary::envvar();
let newpath = DynamicLibrary::create_path(&path); let newpath = DynamicLibrary::create_path(&path);
let newpath = String::from_utf8(newpath).unwrap(); let newpath = newpath.to_str().unwrap().to_string();
cmd.env(var.to_string(), newpath); cmd.env(var, &newpath);
} }
pub struct Result {pub status: ProcessExit, pub out: String, pub err: String} pub struct Result {pub status: ExitStatus, pub out: String, pub err: String}
pub fn run(lib_path: &str, pub fn run(lib_path: &str,
prog: &str, prog: &str,
@ -38,10 +40,13 @@ pub fn run(lib_path: &str,
input: Option<String>) -> Option<Result> { input: Option<String>) -> Option<Result> {
let mut cmd = Command::new(prog); let mut cmd = Command::new(prog);
cmd.args(args); cmd.args(args)
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.stderr(Stdio::piped());
add_target_env(&mut cmd, lib_path, aux_path); add_target_env(&mut cmd, lib_path, aux_path);
for (key, val) in env { for (key, val) in env {
cmd.env(key, val); cmd.env(&key, &val);
} }
match cmd.spawn() { match cmd.spawn() {
@ -49,13 +54,13 @@ pub fn run(lib_path: &str,
if let Some(input) = input { if let Some(input) = input {
process.stdin.as_mut().unwrap().write_all(input.as_bytes()).unwrap(); process.stdin.as_mut().unwrap().write_all(input.as_bytes()).unwrap();
} }
let ProcessOutput { status, output, error } = let Output { status, stdout, stderr } =
process.wait_with_output().unwrap(); process.wait_with_output().unwrap();
Some(Result { Some(Result {
status: status, status: status,
out: String::from_utf8(output).unwrap(), out: String::from_utf8(stdout).unwrap(),
err: String::from_utf8(error).unwrap() err: String::from_utf8(stderr).unwrap()
}) })
}, },
Err(..) => None Err(..) => None
@ -67,13 +72,16 @@ pub fn run_background(lib_path: &str,
aux_path: Option<&str>, aux_path: Option<&str>,
args: &[String], args: &[String],
env: Vec<(String, String)> , env: Vec<(String, String)> ,
input: Option<String>) -> Option<Process> { input: Option<String>) -> Option<Child> {
let mut cmd = Command::new(prog); let mut cmd = Command::new(prog);
cmd.args(args); cmd.args(args)
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.stderr(Stdio::piped());
add_target_env(&mut cmd, lib_path, aux_path); add_target_env(&mut cmd, lib_path, aux_path);
for (key, val) in env { for (key, val) in env {
cmd.env(key, val); cmd.env(&key, &val);
} }
match cmd.spawn() { match cmd.spawn() {

View File

@ -11,35 +11,28 @@
use self::TargetLocation::*; use self::TargetLocation::*;
use common::Config; use common::Config;
use common::{CompileFail, ParseFail, Pretty, RunFail, RunPass, RunPassValgrind, DebugInfoGdb}; use common::{CompileFail, ParseFail, Pretty, RunFail, RunPass, RunPassValgrind};
use common::{Codegen, DebugInfoLldb}; use common::{Codegen, DebugInfoLldb, DebugInfoGdb};
use errors; use errors;
use header::TestProps; use header::TestProps;
use header; use header;
use procsrv; use procsrv;
use util::logv; use util::logv;
#[cfg(target_os = "windows")]
use util;
#[cfg(target_os = "windows")]
use std::ascii::AsciiExt;
use std::old_io::File;
use std::old_io::fs::PathExtensions;
use std::old_io::fs;
use std::old_io::net::tcp;
use std::old_io::process::ProcessExit;
use std::old_io::process;
use std::old_io::timer;
use std::old_io;
use std::env; use std::env;
use std::fmt;
use std::fs::{self, File};
use std::io::BufReader;
use std::io::prelude::*;
use std::iter::repeat; use std::iter::repeat;
use std::net::TcpStream;
use std::path::{Path, PathBuf};
use std::process::{Command, Output, ExitStatus};
use std::str; use std::str;
use std::string::String;
use std::thread;
use std::time::Duration; use std::time::Duration;
use test::MetricMap; use test::MetricMap;
pub fn run(config: Config, testfile: String) { pub fn run(config: Config, testfile: &Path) {
match &*config.target { match &*config.target {
"arm-linux-androideabi" | "aarch64-linux-android" => { "arm-linux-androideabi" | "aarch64-linux-android" => {
@ -55,12 +48,11 @@ pub fn run(config: Config, testfile: String) {
run_metrics(config, testfile, &mut _mm); run_metrics(config, testfile, &mut _mm);
} }
pub fn run_metrics(config: Config, testfile: String, mm: &mut MetricMap) { pub fn run_metrics(config: Config, testfile: &Path, mm: &mut MetricMap) {
if config.verbose { if config.verbose {
// We're going to be dumping a lot of info. Start on a new line. // We're going to be dumping a lot of info. Start on a new line.
print!("\n\n"); print!("\n\n");
} }
let testfile = Path::new(testfile);
debug!("running {:?}", testfile.display()); debug!("running {:?}", testfile.display());
let props = header::load_props(&testfile); let props = header::load_props(&testfile);
debug!("loaded props"); debug!("loaded props");
@ -89,7 +81,7 @@ fn run_cfail_test(config: &Config, props: &TestProps, testfile: &Path) {
let proc_res = compile_test(config, props, testfile); let proc_res = compile_test(config, props, testfile);
if proc_res.status.success() { if proc_res.status.success() {
fatal_proc_rec(&format!("{} test compiled successfully!", config.mode)[], fatal_proc_rec(&format!("{} test compiled successfully!", config.mode)[..],
&proc_res); &proc_res);
} }
@ -127,8 +119,8 @@ fn run_rfail_test(config: &Config, props: &TestProps, testfile: &Path) {
}; };
// The value our Makefile configures valgrind to return on failure // The value our Makefile configures valgrind to return on failure
static VALGRIND_ERR: int = 100; const VALGRIND_ERR: i32 = 100;
if proc_res.status.matches_exit_status(VALGRIND_ERR) { if proc_res.status.code() == Some(VALGRIND_ERR) {
fatal_proc_rec("run-fail test isn't valgrind-clean!", &proc_res); fatal_proc_rec("run-fail test isn't valgrind-clean!", &proc_res);
} }
@ -139,10 +131,10 @@ fn run_rfail_test(config: &Config, props: &TestProps, testfile: &Path) {
fn check_correct_failure_status(proc_res: &ProcRes) { fn check_correct_failure_status(proc_res: &ProcRes) {
// The value the rust runtime returns on failure // The value the rust runtime returns on failure
static RUST_ERR: int = 101; const RUST_ERR: i32 = 101;
if !proc_res.status.matches_exit_status(RUST_ERR) { if proc_res.status.code() != Some(RUST_ERR) {
fatal_proc_rec( fatal_proc_rec(
&format!("failure produced the wrong error: {:?}", &format!("failure produced the wrong error: {}",
proc_res.status), proc_res.status),
proc_res); proc_res);
} }
@ -201,8 +193,8 @@ fn run_pretty_test(config: &Config, props: &TestProps, testfile: &Path) {
let rounds = let rounds =
match props.pp_exact { Some(_) => 1, None => 2 }; match props.pp_exact { Some(_) => 1, None => 2 };
let src = File::open(testfile).read_to_end().unwrap(); let mut src = String::new();
let src = String::from_utf8(src.clone()).unwrap(); File::open(testfile).unwrap().read_to_string(&mut src).unwrap();
let mut srcs = vec!(src); let mut srcs = vec!(src);
let mut round = 0; let mut round = 0;
@ -226,9 +218,10 @@ fn run_pretty_test(config: &Config, props: &TestProps, testfile: &Path) {
let mut expected = match props.pp_exact { let mut expected = match props.pp_exact {
Some(ref file) => { Some(ref file) => {
let filepath = testfile.dir_path().join(file); let filepath = testfile.parent().unwrap().join(file);
let s = File::open(&filepath).read_to_end().unwrap(); let mut s = String::new();
String::from_utf8(s).unwrap() File::open(&filepath).unwrap().read_to_string(&mut s).unwrap();
s
} }
None => { srcs[srcs.len() - 2].clone() } None => { srcs[srcs.len() - 2].clone() }
}; };
@ -252,7 +245,7 @@ fn run_pretty_test(config: &Config, props: &TestProps, testfile: &Path) {
if !proc_res.status.success() { if !proc_res.status.success() {
fatal_proc_rec("pretty-printed source does not typecheck", &proc_res); fatal_proc_rec("pretty-printed source does not typecheck", &proc_res);
} }
if props.no_pretty_expanded { return } if !props.pretty_expanded { return }
// additionally, run `--pretty expanded` and try to build it. // additionally, run `--pretty expanded` and try to build it.
let proc_res = print_source(config, props, testfile, srcs[round].clone(), "expanded"); let proc_res = print_source(config, props, testfile, srcs[round].clone(), "expanded");
@ -283,7 +276,7 @@ fn run_pretty_test(config: &Config, props: &TestProps, testfile: &Path) {
pretty_type.to_string()), pretty_type.to_string()),
props.exec_env.clone(), props.exec_env.clone(),
&config.compile_lib_path, &config.compile_lib_path,
Some(aux_dir.as_str().unwrap()), Some(aux_dir.to_str().unwrap()),
Some(src)) Some(src))
} }
@ -299,11 +292,11 @@ fn run_pretty_test(config: &Config, props: &TestProps, testfile: &Path) {
pretty_type, pretty_type,
format!("--target={}", config.target), format!("--target={}", config.target),
"-L".to_string(), "-L".to_string(),
aux_dir.as_str().unwrap().to_string()); aux_dir.to_str().unwrap().to_string());
args.extend(split_maybe_args(&config.target_rustcflags).into_iter()); args.extend(split_maybe_args(&config.target_rustcflags).into_iter());
args.extend(split_maybe_args(&props.compile_flags).into_iter()); args.extend(split_maybe_args(&props.compile_flags).into_iter());
return ProcArgs { return ProcArgs {
prog: config.rustc_path.as_str().unwrap().to_string(), prog: config.rustc_path.to_str().unwrap().to_string(),
args: args, args: args,
}; };
} }
@ -345,14 +338,14 @@ actual:\n\
"--crate-type=lib".to_string(), "--crate-type=lib".to_string(),
format!("--target={}", target), format!("--target={}", target),
"-L".to_string(), "-L".to_string(),
config.build_base.as_str().unwrap().to_string(), config.build_base.to_str().unwrap().to_string(),
"-L".to_string(), "-L".to_string(),
aux_dir.as_str().unwrap().to_string()); aux_dir.to_str().unwrap().to_string());
args.extend(split_maybe_args(&config.target_rustcflags).into_iter()); args.extend(split_maybe_args(&config.target_rustcflags).into_iter());
args.extend(split_maybe_args(&props.compile_flags).into_iter()); args.extend(split_maybe_args(&props.compile_flags).into_iter());
// FIXME (#9639): This needs to handle non-utf8 paths // FIXME (#9639): This needs to handle non-utf8 paths
return ProcArgs { return ProcArgs {
prog: config.rustc_path.as_str().unwrap().to_string(), prog: config.rustc_path.to_str().unwrap().to_string(),
args: args, args: args,
}; };
} }
@ -390,18 +383,19 @@ fn run_debuginfo_gdb_test(config: &Config, props: &TestProps, testfile: &Path) {
// write debugger script // write debugger script
let mut script_str = String::with_capacity(2048); let mut script_str = String::with_capacity(2048);
script_str.push_str("set charset UTF-8\n"); script_str.push_str("set charset UTF-8\n");
script_str.push_str(&format!("file {}\n", exe_file.as_str().unwrap())); script_str.push_str(&format!("file {}\n", exe_file.to_str().unwrap()));
script_str.push_str("target remote :5039\n"); script_str.push_str("target remote :5039\n");
script_str.push_str(&format!("set solib-search-path \ script_str.push_str(&format!("set solib-search-path \
./{}/stage2/lib/rustlib/{}/lib/\n", ./{}/stage2/lib/rustlib/{}/lib/\n",
config.host, config.target)); config.host, config.target));
for line in breakpoint_lines.iter() { for line in breakpoint_lines.iter() {
script_str.push_str(&format!("break {:?}:{}\n", script_str.push_str(&format!("break {:?}:{}\n",
testfile.filename_display(), testfile.file_name().unwrap()
*line)[]); .to_string_lossy(),
*line)[..]);
} }
script_str.push_str(&cmds); script_str.push_str(&cmds);
script_str.push_str("quit\n"); script_str.push_str("\nquit\n");
debug!("script_str = {}", script_str); debug!("script_str = {}", script_str);
dump_output_file(config, dump_output_file(config,
@ -415,7 +409,7 @@ fn run_debuginfo_gdb_test(config: &Config, props: &TestProps, testfile: &Path) {
None, None,
&[ &[
"push".to_string(), "push".to_string(),
exe_file.as_str().unwrap().to_string(), exe_file.to_str().unwrap().to_string(),
config.adb_test_dir.clone() config.adb_test_dir.clone()
], ],
vec!(("".to_string(), "".to_string())), vec!(("".to_string(), "".to_string())),
@ -440,9 +434,8 @@ fn run_debuginfo_gdb_test(config: &Config, props: &TestProps, testfile: &Path) {
if config.target.contains("aarch64") if config.target.contains("aarch64")
{"64"} else {""}, {"64"} else {""},
config.adb_test_dir.clone(), config.adb_test_dir.clone(),
str::from_utf8( exe_file.file_name().unwrap().to_str()
exe_file.filename() .unwrap());
.unwrap()).unwrap());
let mut process = procsrv::run_background("", let mut process = procsrv::run_background("",
&config.adb_path &config.adb_path
@ -458,17 +451,17 @@ fn run_debuginfo_gdb_test(config: &Config, props: &TestProps, testfile: &Path) {
.expect(&format!("failed to exec `{:?}`", config.adb_path)); .expect(&format!("failed to exec `{:?}`", config.adb_path));
loop { loop {
//waiting 1 second for gdbserver start //waiting 1 second for gdbserver start
timer::sleep(Duration::milliseconds(1000)); #[allow(deprecated)]
let result = thread::spawn(move || { fn sleep() {
tcp::TcpStream::connect("127.0.0.1:5039").unwrap(); ::std::old_io::timer::sleep(Duration::milliseconds(1000));
}).join(); }
if result.is_err() { sleep();
continue; if TcpStream::connect("127.0.0.1:5039").is_ok() {
break
} }
break;
} }
let tool_path = match config.android_cross_path.as_str() { let tool_path = match config.android_cross_path.to_str() {
Some(x) => x.to_string(), Some(x) => x.to_string(),
None => fatal("cannot find android cross path") None => fatal("cannot find android cross path")
}; };
@ -479,7 +472,7 @@ fn run_debuginfo_gdb_test(config: &Config, props: &TestProps, testfile: &Path) {
vec!("-quiet".to_string(), vec!("-quiet".to_string(),
"-batch".to_string(), "-batch".to_string(),
"-nx".to_string(), "-nx".to_string(),
format!("-command={}", debugger_script.as_str().unwrap())); format!("-command={}", debugger_script.to_str().unwrap()));
let mut gdb_path = tool_path; let mut gdb_path = tool_path;
gdb_path.push_str(&format!("/bin/{}-gdb", config.target)); gdb_path.push_str(&format!("/bin/{}-gdb", config.target));
@ -503,12 +496,12 @@ fn run_debuginfo_gdb_test(config: &Config, props: &TestProps, testfile: &Path) {
}; };
debugger_run_result = ProcRes { debugger_run_result = ProcRes {
status: status, status: Status::Normal(status),
stdout: out, stdout: out,
stderr: err, stderr: err,
cmdline: cmdline cmdline: cmdline
}; };
if process.signal_kill().is_err() { if process.kill().is_err() {
println!("Adb process is already finished."); println!("Adb process is already finished.");
} }
} }
@ -518,7 +511,7 @@ fn run_debuginfo_gdb_test(config: &Config, props: &TestProps, testfile: &Path) {
.expect("Could not find Rust source root"); .expect("Could not find Rust source root");
let rust_pp_module_rel_path = Path::new("./src/etc"); let rust_pp_module_rel_path = Path::new("./src/etc");
let rust_pp_module_abs_path = rust_src_root.join(rust_pp_module_rel_path) let rust_pp_module_abs_path = rust_src_root.join(rust_pp_module_rel_path)
.as_str() .to_str()
.unwrap() .unwrap()
.to_string(); .to_string();
// write debugger script // write debugger script
@ -538,7 +531,7 @@ fn run_debuginfo_gdb_test(config: &Config, props: &TestProps, testfile: &Path) {
// GDB's script auto loading safe path // GDB's script auto loading safe path
script_str.push_str( script_str.push_str(
&format!("add-auto-load-safe-path {}\n", &format!("add-auto-load-safe-path {}\n",
rust_pp_module_abs_path.replace("\\", "\\\\")) rust_pp_module_abs_path.replace(r"\", r"\\"))
); );
} }
} }
@ -553,21 +546,24 @@ fn run_debuginfo_gdb_test(config: &Config, props: &TestProps, testfile: &Path) {
script_str.push_str("set print pretty off\n"); script_str.push_str("set print pretty off\n");
// Add the pretty printer directory to GDB's source-file search path // Add the pretty printer directory to GDB's source-file search path
script_str.push_str(&format!("directory {}\n", rust_pp_module_abs_path)[]); script_str.push_str(&format!("directory {}\n",
rust_pp_module_abs_path));
// Load the target executable // Load the target executable
script_str.push_str(&format!("file {}\n", script_str.push_str(&format!("file {}\n",
exe_file.as_str().unwrap().replace("\\", "\\\\"))[]); exe_file.to_str().unwrap()
.replace(r"\", r"\\")));
// Add line breakpoints // Add line breakpoints
for line in &breakpoint_lines { for line in &breakpoint_lines {
script_str.push_str(&format!("break '{}':{}\n", script_str.push_str(&format!("break '{}':{}\n",
testfile.filename_display(), testfile.file_name().unwrap()
*line)[]); .to_string_lossy(),
*line));
} }
script_str.push_str(&cmds); script_str.push_str(&cmds);
script_str.push_str("quit\n"); script_str.push_str("\nquit\n");
debug!("script_str = {}", script_str); debug!("script_str = {}", script_str);
dump_output_file(config, dump_output_file(config,
@ -576,13 +572,8 @@ fn run_debuginfo_gdb_test(config: &Config, props: &TestProps, testfile: &Path) {
"debugger.script"); "debugger.script");
// run debugger script with gdb // run debugger script with gdb
#[cfg(windows)] fn debugger() -> &'static str {
fn debugger() -> String { if cfg!(windows) {"gdb.exe"} else {"gdb"}
"gdb.exe".to_string()
}
#[cfg(unix)]
fn debugger() -> String {
"gdb".to_string()
} }
let debugger_script = make_out_name(config, testfile, "debugger.script"); let debugger_script = make_out_name(config, testfile, "debugger.script");
@ -592,10 +583,10 @@ fn run_debuginfo_gdb_test(config: &Config, props: &TestProps, testfile: &Path) {
vec!("-quiet".to_string(), vec!("-quiet".to_string(),
"-batch".to_string(), "-batch".to_string(),
"-nx".to_string(), "-nx".to_string(),
format!("-command={}", debugger_script.as_str().unwrap())); format!("-command={}", debugger_script.to_str().unwrap()));
let proc_args = ProcArgs { let proc_args = ProcArgs {
prog: debugger(), prog: debugger().to_string(),
args: debugger_opts, args: debugger_opts,
}; };
@ -618,7 +609,7 @@ fn run_debuginfo_gdb_test(config: &Config, props: &TestProps, testfile: &Path) {
check_debugger_output(&debugger_run_result, &check_lines); check_debugger_output(&debugger_run_result, &check_lines);
} }
fn find_rust_src_root(config: &Config) -> Option<Path> { fn find_rust_src_root(config: &Config) -> Option<PathBuf> {
let mut path = config.src_base.clone(); let mut path = config.src_base.clone();
let path_postfix = Path::new("src/etc/lldb_batchmode.py"); let path_postfix = Path::new("src/etc/lldb_batchmode.py");
@ -632,8 +623,6 @@ fn find_rust_src_root(config: &Config) -> Option<Path> {
} }
fn run_debuginfo_lldb_test(config: &Config, props: &TestProps, testfile: &Path) { fn run_debuginfo_lldb_test(config: &Config, props: &TestProps, testfile: &Path) {
use std::old_io::process::{Command, ProcessOutput};
if config.lldb_python_dir.is_none() { if config.lldb_python_dir.is_none() {
fatal("Can't run LLDB test because LLDB's python path is not set."); fatal("Can't run LLDB test because LLDB's python path is not set.");
} }
@ -685,11 +674,12 @@ fn run_debuginfo_lldb_test(config: &Config, props: &TestProps, testfile: &Path)
.expect("Could not find Rust source root"); .expect("Could not find Rust source root");
let rust_pp_module_rel_path = Path::new("./src/etc/lldb_rust_formatters.py"); let rust_pp_module_rel_path = Path::new("./src/etc/lldb_rust_formatters.py");
let rust_pp_module_abs_path = rust_src_root.join(rust_pp_module_rel_path) let rust_pp_module_abs_path = rust_src_root.join(rust_pp_module_rel_path)
.as_str() .to_str()
.unwrap() .unwrap()
.to_string(); .to_string();
script_str.push_str(&format!("command script import {}\n", &rust_pp_module_abs_path[..])[]); script_str.push_str(&format!("command script import {}\n",
&rust_pp_module_abs_path[..])[..]);
script_str.push_str("type summary add --no-value "); script_str.push_str("type summary add --no-value ");
script_str.push_str("--python-function lldb_rust_formatters.print_val "); script_str.push_str("--python-function lldb_rust_formatters.print_val ");
script_str.push_str("-x \".*\" --category Rust\n"); script_str.push_str("-x \".*\" --category Rust\n");
@ -707,7 +697,7 @@ fn run_debuginfo_lldb_test(config: &Config, props: &TestProps, testfile: &Path)
} }
// Finally, quit the debugger // Finally, quit the debugger
script_str.push_str("quit\n"); script_str.push_str("\nquit\n");
// Write the script into a file // Write the script into a file
debug!("script_str = {}", script_str); debug!("script_str = {}", script_str);
@ -735,22 +725,19 @@ fn run_debuginfo_lldb_test(config: &Config, props: &TestProps, testfile: &Path)
rust_src_root: &Path) rust_src_root: &Path)
-> ProcRes { -> ProcRes {
// Prepare the lldb_batchmode which executes the debugger script // Prepare the lldb_batchmode which executes the debugger script
let lldb_script_path = rust_src_root.join(Path::new("./src/etc/lldb_batchmode.py")); let lldb_script_path = rust_src_root.join("src/etc/lldb_batchmode.py");
let mut cmd = Command::new("python"); let mut cmd = Command::new("python");
cmd.arg(lldb_script_path) cmd.arg(&lldb_script_path)
.arg(test_executable) .arg(test_executable)
.arg(debugger_script) .arg(debugger_script)
.env_set_all(&[("PYTHONPATH", config.lldb_python_dir.clone().unwrap())]); .env("PYTHONPATH", config.lldb_python_dir.as_ref().unwrap());
let (status, out, err) = match cmd.spawn() {
Ok(process) => {
let ProcessOutput { status, output, error } =
process.wait_with_output().unwrap();
let (status, out, err) = match cmd.output() {
Ok(Output { status, stdout, stderr }) => {
(status, (status,
String::from_utf8(output).unwrap(), String::from_utf8(stdout).unwrap(),
String::from_utf8(error).unwrap()) String::from_utf8(stderr).unwrap())
}, },
Err(e) => { Err(e) => {
fatal(&format!("Failed to setup Python process for \ fatal(&format!("Failed to setup Python process for \
@ -760,7 +747,7 @@ fn run_debuginfo_lldb_test(config: &Config, props: &TestProps, testfile: &Path)
dump_output(config, test_executable, &out, &err); dump_output(config, test_executable, &out, &err);
return ProcRes { return ProcRes {
status: status, status: Status::Normal(status),
stdout: out, stdout: out,
stderr: err, stderr: err,
cmdline: format!("{:?}", cmd) cmdline: format!("{:?}", cmd)
@ -771,13 +758,11 @@ fn run_debuginfo_lldb_test(config: &Config, props: &TestProps, testfile: &Path)
struct DebuggerCommands { struct DebuggerCommands {
commands: Vec<String>, commands: Vec<String>,
check_lines: Vec<String>, check_lines: Vec<String>,
breakpoint_lines: Vec<uint>, breakpoint_lines: Vec<usize>,
} }
fn parse_debugger_commands(file_path: &Path, debugger_prefix: &str) fn parse_debugger_commands(file_path: &Path, debugger_prefix: &str)
-> DebuggerCommands { -> DebuggerCommands {
use std::old_io::{BufferedReader, File};
let command_directive = format!("{}-command", debugger_prefix); let command_directive = format!("{}-command", debugger_prefix);
let check_directive = format!("{}-check", debugger_prefix); let check_directive = format!("{}-check", debugger_prefix);
@ -785,7 +770,7 @@ fn parse_debugger_commands(file_path: &Path, debugger_prefix: &str)
let mut commands = vec!(); let mut commands = vec!();
let mut check_lines = vec!(); let mut check_lines = vec!();
let mut counter = 1; let mut counter = 1;
let mut reader = BufferedReader::new(File::open(file_path).unwrap()); let reader = BufReader::new(File::open(file_path).unwrap());
for line in reader.lines() { for line in reader.lines() {
match line { match line {
Ok(line) => { Ok(line) => {
@ -847,7 +832,7 @@ fn check_debugger_output(debugger_run_result: &ProcRes, check_lines: &[String])
check_lines.iter().map(|s| { check_lines.iter().map(|s| {
s s
.trim() .trim()
.split_str("[...]") .split("[...]")
.map(|x| x.to_string()) .map(|x| x.to_string())
.collect() .collect()
}).collect(); }).collect();
@ -866,7 +851,7 @@ fn check_debugger_output(debugger_run_result: &ProcRes, check_lines: &[String])
None None
} }
} else { } else {
rest.find_str(frag) rest.find(frag)
}; };
match found { match found {
None => { None => {
@ -965,15 +950,16 @@ fn check_expected_errors(expected_errors: Vec<errors::ExpectedError> ,
format!("{}:{}:", testfile.display(), ee.line) format!("{}:{}:", testfile.display(), ee.line)
}).collect::<Vec<String>>(); }).collect::<Vec<String>>();
#[cfg(windows)]
fn prefix_matches(line: &str, prefix: &str) -> bool { fn prefix_matches(line: &str, prefix: &str) -> bool {
use std::ascii::AsciiExt;
// On windows just translate all '\' path separators to '/'
let line = line.replace(r"\", "/");
if cfg!(windows) {
line.to_ascii_lowercase().starts_with(&prefix.to_ascii_lowercase()) line.to_ascii_lowercase().starts_with(&prefix.to_ascii_lowercase())
} } else {
#[cfg(unix)]
fn prefix_matches( line : &str, prefix : &str ) -> bool {
line.starts_with(prefix) line.starts_with(prefix)
} }
}
// A multi-line error will have followup lines which will always // A multi-line error will have followup lines which will always
// start with one of these strings. // start with one of these strings.
@ -1050,7 +1036,7 @@ fn is_compiler_error_or_warning(line: &str) -> bool {
scan_string(line, "warning", &mut i)); scan_string(line, "warning", &mut i));
} }
fn scan_until_char(haystack: &str, needle: char, idx: &mut uint) -> bool { fn scan_until_char(haystack: &str, needle: char, idx: &mut usize) -> bool {
if *idx >= haystack.len() { if *idx >= haystack.len() {
return false; return false;
} }
@ -1062,26 +1048,26 @@ fn scan_until_char(haystack: &str, needle: char, idx: &mut uint) -> bool {
return true; return true;
} }
fn scan_char(haystack: &str, needle: char, idx: &mut uint) -> bool { fn scan_char(haystack: &str, needle: char, idx: &mut usize) -> bool {
if *idx >= haystack.len() { if *idx >= haystack.len() {
return false; return false;
} }
let range = haystack.char_range_at(*idx); let ch = haystack.char_at(*idx);
if range.ch != needle { if ch != needle {
return false; return false;
} }
*idx = range.next; *idx += ch.len_utf8();
return true; return true;
} }
fn scan_integer(haystack: &str, idx: &mut uint) -> bool { fn scan_integer(haystack: &str, idx: &mut usize) -> bool {
let mut i = *idx; let mut i = *idx;
while i < haystack.len() { while i < haystack.len() {
let range = haystack.char_range_at(i); let ch = haystack.char_at(i);
if range.ch < '0' || '9' < range.ch { if ch < '0' || '9' < ch {
break; break;
} }
i = range.next; i += ch.len_utf8();
} }
if i == *idx { if i == *idx {
return false; return false;
@ -1090,16 +1076,16 @@ fn scan_integer(haystack: &str, idx: &mut uint) -> bool {
return true; return true;
} }
fn scan_string(haystack: &str, needle: &str, idx: &mut uint) -> bool { fn scan_string(haystack: &str, needle: &str, idx: &mut usize) -> bool {
let mut haystack_i = *idx; let mut haystack_i = *idx;
let mut needle_i = 0; let mut needle_i = 0;
while needle_i < needle.len() { while needle_i < needle.len() {
if haystack_i >= haystack.len() { if haystack_i >= haystack.len() {
return false; return false;
} }
let range = haystack.char_range_at(haystack_i); let ch = haystack.char_at(haystack_i);
haystack_i = range.next; haystack_i += ch.len_utf8();
if !scan_char(needle, range.ch, &mut needle_i) { if !scan_char(needle, ch, &mut needle_i) {
return false; return false;
} }
} }
@ -1113,12 +1099,42 @@ struct ProcArgs {
} }
struct ProcRes { struct ProcRes {
status: ProcessExit, status: Status,
stdout: String, stdout: String,
stderr: String, stderr: String,
cmdline: String, cmdline: String,
} }
enum Status {
Parsed(i32),
Normal(ExitStatus),
}
impl Status {
fn code(&self) -> Option<i32> {
match *self {
Status::Parsed(i) => Some(i),
Status::Normal(ref e) => e.code(),
}
}
fn success(&self) -> bool {
match *self {
Status::Parsed(i) => i == 0,
Status::Normal(ref e) => e.success(),
}
}
}
impl fmt::Display for Status {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Status::Parsed(i) => write!(f, "exit code: {}", i),
Status::Normal(ref e) => e.fmt(f),
}
}
}
fn compile_test(config: &Config, props: &TestProps, fn compile_test(config: &Config, props: &TestProps,
testfile: &Path) -> ProcRes { testfile: &Path) -> ProcRes {
compile_test_(config, props, testfile, &[]) compile_test_(config, props, testfile, &[])
@ -1133,7 +1149,7 @@ fn compile_test_(config: &Config, props: &TestProps,
let aux_dir = aux_output_dir_name(config, testfile); let aux_dir = aux_output_dir_name(config, testfile);
// FIXME (#9639): This needs to handle non-utf8 paths // FIXME (#9639): This needs to handle non-utf8 paths
let mut link_args = vec!("-L".to_string(), let mut link_args = vec!("-L".to_string(),
aux_dir.as_str().unwrap().to_string()); aux_dir.to_str().unwrap().to_string());
link_args.extend(extra_args.iter().cloned()); link_args.extend(extra_args.iter().cloned());
let args = make_compile_args(config, let args = make_compile_args(config,
props, props,
@ -1160,7 +1176,7 @@ fn exec_compiled_test(config: &Config, props: &TestProps,
make_run_args(config, props, testfile), make_run_args(config, props, testfile),
env, env,
&config.run_lib_path, &config.run_lib_path,
Some(aux_dir.as_str().unwrap()), Some(aux_dir.to_str().unwrap()),
None) None)
} }
} }
@ -1179,7 +1195,7 @@ fn compose_and_run_compiler(
let aux_dir = aux_output_dir_name(config, testfile); let aux_dir = aux_output_dir_name(config, testfile);
// FIXME (#9639): This needs to handle non-utf8 paths // FIXME (#9639): This needs to handle non-utf8 paths
let extra_link_args = vec!("-L".to_string(), aux_dir.as_str().unwrap().to_string()); let extra_link_args = vec!("-L".to_string(), aux_dir.to_str().unwrap().to_string());
for rel_ab in &props.aux_builds { for rel_ab in &props.aux_builds {
let abs_ab = config.aux_base.join(rel_ab); let abs_ab = config.aux_base.join(rel_ab);
@ -1196,7 +1212,8 @@ fn compose_and_run_compiler(
crate_type, crate_type,
|a,b| { |a,b| {
let f = make_lib_name(a, b, testfile); let f = make_lib_name(a, b, testfile);
TargetLocation::ThisDirectory(f.dir_path()) let parent = f.parent().unwrap();
TargetLocation::ThisDirectory(parent.to_path_buf())
}, },
&abs_ab); &abs_ab);
let auxres = compose_and_run(config, let auxres = compose_and_run(config,
@ -1204,7 +1221,7 @@ fn compose_and_run_compiler(
aux_args, aux_args,
Vec::new(), Vec::new(),
&config.compile_lib_path, &config.compile_lib_path,
Some(aux_dir.as_str().unwrap()), Some(aux_dir.to_str().unwrap()),
None); None);
if !auxres.status.success() { if !auxres.status.success() {
fatal_proc_rec( fatal_proc_rec(
@ -1226,13 +1243,13 @@ fn compose_and_run_compiler(
args, args,
Vec::new(), Vec::new(),
&config.compile_lib_path, &config.compile_lib_path,
Some(aux_dir.as_str().unwrap()), Some(aux_dir.to_str().unwrap()),
input) input)
} }
fn ensure_dir(path: &Path) { fn ensure_dir(path: &Path) {
if path.is_dir() { return; } if path.is_dir() { return; }
fs::mkdir(path, old_io::USER_RWX).unwrap(); fs::create_dir(path).unwrap();
} }
fn compose_and_run(config: &Config, testfile: &Path, fn compose_and_run(config: &Config, testfile: &Path,
@ -1246,8 +1263,8 @@ fn compose_and_run(config: &Config, testfile: &Path,
} }
enum TargetLocation { enum TargetLocation {
ThisFile(Path), ThisFile(PathBuf),
ThisDirectory(Path), ThisDirectory(PathBuf),
} }
fn make_compile_args<F>(config: &Config, fn make_compile_args<F>(config: &Config,
@ -1265,9 +1282,9 @@ fn make_compile_args<F>(config: &Config,
&*config.target &*config.target
}; };
// FIXME (#9639): This needs to handle non-utf8 paths // FIXME (#9639): This needs to handle non-utf8 paths
let mut args = vec!(testfile.as_str().unwrap().to_string(), let mut args = vec!(testfile.to_str().unwrap().to_string(),
"-L".to_string(), "-L".to_string(),
config.build_base.as_str().unwrap().to_string(), config.build_base.to_str().unwrap().to_string(),
format!("--target={}", target)); format!("--target={}", target));
args.push_all(&extras); args.push_all(&extras);
if !props.no_prefer_dynamic { if !props.no_prefer_dynamic {
@ -1284,7 +1301,7 @@ fn make_compile_args<F>(config: &Config,
path path
} }
}; };
args.push(path.as_str().unwrap().to_string()); args.push(path.to_str().unwrap().to_string());
if props.force_host { if props.force_host {
args.extend(split_maybe_args(&config.host_rustcflags).into_iter()); args.extend(split_maybe_args(&config.host_rustcflags).into_iter());
} else { } else {
@ -1292,24 +1309,24 @@ fn make_compile_args<F>(config: &Config,
} }
args.extend(split_maybe_args(&props.compile_flags).into_iter()); args.extend(split_maybe_args(&props.compile_flags).into_iter());
return ProcArgs { return ProcArgs {
prog: config.rustc_path.as_str().unwrap().to_string(), prog: config.rustc_path.to_str().unwrap().to_string(),
args: args, args: args,
}; };
} }
fn make_lib_name(config: &Config, auxfile: &Path, testfile: &Path) -> Path { fn make_lib_name(config: &Config, auxfile: &Path, testfile: &Path) -> PathBuf {
// what we return here is not particularly important, as it // what we return here is not particularly important, as it
// happens; rustc ignores everything except for the directory. // happens; rustc ignores everything except for the directory.
let auxname = output_testname(auxfile); let auxname = output_testname(auxfile);
aux_output_dir_name(config, testfile).join(&auxname) aux_output_dir_name(config, testfile).join(&auxname)
} }
fn make_exe_name(config: &Config, testfile: &Path) -> Path { fn make_exe_name(config: &Config, testfile: &Path) -> PathBuf {
let mut f = output_base_name(config, testfile); let mut f = output_base_name(config, testfile);
if !env::consts::EXE_SUFFIX.is_empty() { if !env::consts::EXE_SUFFIX.is_empty() {
let mut fname = f.filename().unwrap().to_vec(); let mut fname = f.file_name().unwrap().to_os_string();
fname.extend(env::consts::EXE_SUFFIX.bytes()); fname.push(env::consts::EXE_SUFFIX);
f.set_filename(fname); f.set_file_name(&fname);
} }
f f
} }
@ -1322,7 +1339,7 @@ fn make_run_args(config: &Config, props: &TestProps, testfile: &Path) ->
let exe_file = make_exe_name(config, testfile); let exe_file = make_exe_name(config, testfile);
// FIXME (#9639): This needs to handle non-utf8 paths // FIXME (#9639): This needs to handle non-utf8 paths
args.push(exe_file.as_str().unwrap().to_string()); args.push(exe_file.to_str().unwrap().to_string());
// Add the arguments in the run_flags directive // Add the arguments in the run_flags directive
args.extend(split_maybe_args(&props.run_flags).into_iter()); args.extend(split_maybe_args(&props.run_flags).into_iter());
@ -1375,22 +1392,20 @@ fn program_output(config: &Config, testfile: &Path, lib_path: &str, prog: String
input).expect(&format!("failed to exec `{}`", prog)); input).expect(&format!("failed to exec `{}`", prog));
dump_output(config, testfile, &out, &err); dump_output(config, testfile, &out, &err);
return ProcRes { return ProcRes {
status: status, status: Status::Normal(status),
stdout: out, stdout: out,
stderr: err, stderr: err,
cmdline: cmdline, cmdline: cmdline,
}; };
} }
// Linux and mac don't require adjusting the library search path
#[cfg(unix)]
fn make_cmdline(_libpath: &str, prog: &str, args: &[String]) -> String {
format!("{} {}", prog, args.connect(" "))
}
#[cfg(windows)]
fn make_cmdline(libpath: &str, prog: &str, args: &[String]) -> String { fn make_cmdline(libpath: &str, prog: &str, args: &[String]) -> String {
use util;
// Linux and mac don't require adjusting the library search path
if cfg!(unix) {
format!("{} {}", prog, args.connect(" "))
} else {
// Build the LD_LIBRARY_PATH variable as it would be seen on the command line // Build the LD_LIBRARY_PATH variable as it would be seen on the command line
// for diagnostic purposes // for diagnostic purposes
fn lib_path_cmd_prefix(path: &str) -> String { fn lib_path_cmd_prefix(path: &str) -> String {
@ -1399,6 +1414,7 @@ fn make_cmdline(libpath: &str, prog: &str, args: &[String]) -> String {
format!("{} {} {}", lib_path_cmd_prefix(libpath), prog, args.connect(" ")) format!("{} {} {}", lib_path_cmd_prefix(libpath), prog, args.connect(" "))
} }
}
fn dump_output(config: &Config, testfile: &Path, out: &str, err: &str) { fn dump_output(config: &Config, testfile: &Path, out: &str, err: &str) {
dump_output_file(config, testfile, out, "out"); dump_output_file(config, testfile, out, "out");
@ -1409,25 +1425,25 @@ fn dump_output(config: &Config, testfile: &Path, out: &str, err: &str) {
fn dump_output_file(config: &Config, testfile: &Path, fn dump_output_file(config: &Config, testfile: &Path,
out: &str, extension: &str) { out: &str, extension: &str) {
let outfile = make_out_name(config, testfile, extension); let outfile = make_out_name(config, testfile, extension);
File::create(&outfile).write_all(out.as_bytes()).unwrap(); File::create(&outfile).unwrap().write_all(out.as_bytes()).unwrap();
} }
fn make_out_name(config: &Config, testfile: &Path, extension: &str) -> Path { fn make_out_name(config: &Config, testfile: &Path, extension: &str) -> PathBuf {
output_base_name(config, testfile).with_extension(extension) output_base_name(config, testfile).with_extension(extension)
} }
fn aux_output_dir_name(config: &Config, testfile: &Path) -> Path { fn aux_output_dir_name(config: &Config, testfile: &Path) -> PathBuf {
let f = output_base_name(config, testfile); let f = output_base_name(config, testfile);
let mut fname = f.filename().unwrap().to_vec(); let mut fname = f.file_name().unwrap().to_os_string();
fname.extend("libaux".bytes()); fname.push("libaux");
f.with_filename(fname) f.with_file_name(&fname)
} }
fn output_testname(testfile: &Path) -> Path { fn output_testname(testfile: &Path) -> PathBuf {
Path::new(testfile.filestem().unwrap()) PathBuf::from(testfile.file_stem().unwrap())
} }
fn output_base_name(config: &Config, testfile: &Path) -> Path { fn output_base_name(config: &Config, testfile: &Path) -> PathBuf {
config.build_base config.build_base
.join(&output_testname(testfile)) .join(&output_testname(testfile))
.with_extension(&config.stage_id) .with_extension(&config.stage_id)
@ -1542,11 +1558,11 @@ fn _arm_exec_compiled_test(config: &Config,
Some("".to_string())) Some("".to_string()))
.expect(&format!("failed to exec `{}`", config.adb_path)); .expect(&format!("failed to exec `{}`", config.adb_path));
let mut exitcode: int = 0; let mut exitcode: i32 = 0;
for c in exitcode_out.chars() { for c in exitcode_out.chars() {
if !c.is_numeric() { break; } if !c.is_numeric() { break; }
exitcode = exitcode * 10 + match c { exitcode = exitcode * 10 + match c {
'0' ... '9' => c as int - ('0' as int), '0' ... '9' => c as i32 - ('0' as i32),
_ => 101, _ => 101,
} }
} }
@ -1587,7 +1603,7 @@ fn _arm_exec_compiled_test(config: &Config,
&stderr_out); &stderr_out);
ProcRes { ProcRes {
status: process::ProcessExit::ExitStatus(exitcode), status: Status::Parsed(exitcode),
stdout: stdout_out, stdout: stdout_out,
stderr: stderr_out, stderr: stderr_out,
cmdline: cmdline cmdline: cmdline
@ -1597,16 +1613,17 @@ fn _arm_exec_compiled_test(config: &Config,
fn _arm_push_aux_shared_library(config: &Config, testfile: &Path) { fn _arm_push_aux_shared_library(config: &Config, testfile: &Path) {
let tdir = aux_output_dir_name(config, testfile); let tdir = aux_output_dir_name(config, testfile);
let dirs = fs::readdir(&tdir).unwrap(); let dirs = fs::read_dir(&tdir).unwrap();
for file in &dirs { for file in dirs {
if file.extension_str() == Some("so") { let file = file.unwrap().path();
if file.extension().and_then(|s| s.to_str()) == Some("so") {
// FIXME (#9639): This needs to handle non-utf8 paths // FIXME (#9639): This needs to handle non-utf8 paths
let copy_result = procsrv::run("", let copy_result = procsrv::run("",
&config.adb_path, &config.adb_path,
None, None,
&[ &[
"push".to_string(), "push".to_string(),
file.as_str() file.to_str()
.unwrap() .unwrap()
.to_string(), .to_string(),
config.adb_test_dir.to_string(), config.adb_test_dir.to_string(),
@ -1627,14 +1644,14 @@ fn _arm_push_aux_shared_library(config: &Config, testfile: &Path) {
// codegen tests (vs. clang) // codegen tests (vs. clang)
fn append_suffix_to_stem(p: &Path, suffix: &str) -> Path { fn append_suffix_to_stem(p: &Path, suffix: &str) -> PathBuf {
if suffix.len() == 0 { if suffix.len() == 0 {
(*p).clone() p.to_path_buf()
} else { } else {
let mut stem = p.filestem().unwrap().to_vec(); let mut stem = p.file_stem().unwrap().to_os_string();
stem.extend("-".bytes()); stem.push("-");
stem.extend(suffix.bytes()); stem.push(suffix);
p.with_filename(stem) p.with_file_name(&stem)
} }
} }
@ -1643,7 +1660,7 @@ fn compile_test_and_save_bitcode(config: &Config, props: &TestProps,
let aux_dir = aux_output_dir_name(config, testfile); let aux_dir = aux_output_dir_name(config, testfile);
// FIXME (#9639): This needs to handle non-utf8 paths // FIXME (#9639): This needs to handle non-utf8 paths
let mut link_args = vec!("-L".to_string(), let mut link_args = vec!("-L".to_string(),
aux_dir.as_str().unwrap().to_string()); aux_dir.to_str().unwrap().to_string());
let llvm_args = vec!("--emit=llvm-bc,obj".to_string(), let llvm_args = vec!("--emit=llvm-bc,obj".to_string(),
"--crate-type=lib".to_string()); "--crate-type=lib".to_string());
link_args.extend(llvm_args.into_iter()); link_args.extend(llvm_args.into_iter());
@ -1651,7 +1668,8 @@ fn compile_test_and_save_bitcode(config: &Config, props: &TestProps,
props, props,
link_args, link_args,
|a, b| TargetLocation::ThisDirectory( |a, b| TargetLocation::ThisDirectory(
output_base_name(a, b).dir_path()), output_base_name(a, b).parent()
.unwrap().to_path_buf()),
testfile); testfile);
compose_and_run_compiler(config, props, testfile, args, None) compose_and_run_compiler(config, props, testfile, args, None)
} }
@ -1663,12 +1681,12 @@ fn compile_cc_with_clang_and_save_bitcode(config: &Config, _props: &TestProps,
let testcc = testfile.with_extension("cc"); let testcc = testfile.with_extension("cc");
let proc_args = ProcArgs { let proc_args = ProcArgs {
// FIXME (#9639): This needs to handle non-utf8 paths // FIXME (#9639): This needs to handle non-utf8 paths
prog: config.clang_path.as_ref().unwrap().as_str().unwrap().to_string(), prog: config.clang_path.as_ref().unwrap().to_str().unwrap().to_string(),
args: vec!("-c".to_string(), args: vec!("-c".to_string(),
"-emit-llvm".to_string(), "-emit-llvm".to_string(),
"-o".to_string(), "-o".to_string(),
bitcodefile.as_str().unwrap().to_string(), bitcodefile.to_str().unwrap().to_string(),
testcc.as_str().unwrap().to_string()) testcc.to_str().unwrap().to_string())
}; };
compose_and_run(config, testfile, proc_args, Vec::new(), "", None, None) compose_and_run(config, testfile, proc_args, Vec::new(), "", None, None)
} }
@ -1682,10 +1700,10 @@ fn extract_function_from_bitcode(config: &Config, _props: &TestProps,
let prog = config.llvm_bin_path.as_ref().unwrap().join("llvm-extract"); let prog = config.llvm_bin_path.as_ref().unwrap().join("llvm-extract");
let proc_args = ProcArgs { let proc_args = ProcArgs {
// FIXME (#9639): This needs to handle non-utf8 paths // FIXME (#9639): This needs to handle non-utf8 paths
prog: prog.as_str().unwrap().to_string(), prog: prog.to_str().unwrap().to_string(),
args: vec!(format!("-func={}", fname), args: vec!(format!("-func={}", fname),
format!("-o={}", extracted_bc.as_str().unwrap()), format!("-o={}", extracted_bc.to_str().unwrap()),
bitcodefile.as_str().unwrap().to_string()) bitcodefile.to_str().unwrap().to_string())
}; };
compose_and_run(config, testfile, proc_args, Vec::new(), "", None, None) compose_and_run(config, testfile, proc_args, Vec::new(), "", None, None)
} }
@ -1699,16 +1717,17 @@ fn disassemble_extract(config: &Config, _props: &TestProps,
let prog = config.llvm_bin_path.as_ref().unwrap().join("llvm-dis"); let prog = config.llvm_bin_path.as_ref().unwrap().join("llvm-dis");
let proc_args = ProcArgs { let proc_args = ProcArgs {
// FIXME (#9639): This needs to handle non-utf8 paths // FIXME (#9639): This needs to handle non-utf8 paths
prog: prog.as_str().unwrap().to_string(), prog: prog.to_str().unwrap().to_string(),
args: vec!(format!("-o={}", extracted_ll.as_str().unwrap()), args: vec!(format!("-o={}", extracted_ll.to_str().unwrap()),
extracted_bc.as_str().unwrap().to_string()) extracted_bc.to_str().unwrap().to_string())
}; };
compose_and_run(config, testfile, proc_args, Vec::new(), "", None, None) compose_and_run(config, testfile, proc_args, Vec::new(), "", None, None)
} }
fn count_extracted_lines(p: &Path) -> uint { fn count_extracted_lines(p: &Path) -> usize {
let x = File::open(&p.with_extension("ll")).read_to_end().unwrap(); let mut x = Vec::new();
File::open(&p.with_extension("ll")).unwrap().read_to_end(&mut x).unwrap();
let x = str::from_utf8(&x).unwrap(); let x = str::from_utf8(&x).unwrap();
x.lines().count() x.lines().count()
} }

View File

@ -8,22 +8,39 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use std::env;
use common::Config; use common::Config;
#[cfg(target_os = "windows")]
use std::env;
/// Conversion table from triple OS name to Rust SYSNAME /// Conversion table from triple OS name to Rust SYSNAME
static OS_TABLE: &'static [(&'static str, &'static str)] = &[ const OS_TABLE: &'static [(&'static str, &'static str)] = &[
("android", "android"),
("bitrig", "bitrig"),
("darwin", "macos"),
("dragonfly", "dragonfly"),
("freebsd", "freebsd"),
("ios", "ios"),
("linux", "linux"),
("mingw32", "windows"), ("mingw32", "windows"),
("openbsd", "openbsd"),
("win32", "windows"), ("win32", "windows"),
("windows", "windows"), ("windows", "windows"),
("darwin", "macos"), ];
("android", "android"),
("linux", "linux"), const ARCH_TABLE: &'static [(&'static str, &'static str)] = &[
("freebsd", "freebsd"), ("aarch64", "aarch64"),
("dragonfly", "dragonfly"), ("amd64", "x86_64"),
("openbsd", "openbsd"), ("arm", "arm"),
("arm64", "aarch64"),
("hexagon", "hexagon"),
("i386", "x86"),
("i686", "x86"),
("mips", "mips"),
("msp430", "msp430"),
("powerpc", "powerpc"),
("s390x", "systemz"),
("sparc", "sparc"),
("x86_64", "x86_64"),
("xcore", "xcore"),
]; ];
pub fn get_os(triple: &str) -> &'static str { pub fn get_os(triple: &str) -> &'static str {
@ -34,10 +51,17 @@ pub fn get_os(triple: &str) -> &'static str {
} }
panic!("Cannot determine OS from triple"); panic!("Cannot determine OS from triple");
} }
pub fn get_arch(triple: &str) -> &'static str {
for &(triple_arch, arch) in ARCH_TABLE {
if triple.contains(triple_arch) {
return arch
}
}
panic!("Cannot determine Architecture from triple");
}
#[cfg(target_os = "windows")]
pub fn make_new_path(path: &str) -> String { pub fn make_new_path(path: &str) -> String {
assert!(cfg!(windows));
// Windows just uses PATH as the library search path, so we have to // Windows just uses PATH as the library search path, so we have to
// maintain the current value while adding our own // maintain the current value while adding our own
match env::var(lib_path_env_var()) { match env::var(lib_path_env_var()) {
@ -48,11 +72,8 @@ pub fn make_new_path(path: &str) -> String {
} }
} }
#[cfg(target_os = "windows")]
pub fn lib_path_env_var() -> &'static str { "PATH" } pub fn lib_path_env_var() -> &'static str { "PATH" }
fn path_div() -> &'static str { ";" }
#[cfg(target_os = "windows")]
pub fn path_div() -> &'static str { ";" }
pub fn logv(config: &Config, s: String) { pub fn logv(config: &Config, s: String) {
debug!("{}", s); debug!("{}", s);

View File

@ -174,3 +174,10 @@ bindings.
See also [a long thread][alt] on renaming `let mut` to `var`. See also [a long thread][alt] on renaming `let mut` to `var`.
[alt]: https://mail.mozilla.org/pipermail/rust-dev/2014-January/008319.html [alt]: https://mail.mozilla.org/pipermail/rust-dev/2014-January/008319.html
## Why no `--x` or `x++`?
Preincrement and postincrement, while convenient, are also fairly complex. They
require knowledge of evaluation order, and often lead to subtle bugs and
undefined behavior in C and C++. `x = x + 1` or `x += 1` is only slightly
longer, but unambiguous.

View File

@ -514,7 +514,7 @@ field_expr : expr '.' ident ;
### Array expressions ### Array expressions
```antlr ```antlr
array_expr : '[' "mut" ? vec_elems? ']' ; array_expr : '[' "mut" ? array_elems? ']' ;
array_elems : [expr [',' expr]*] | [expr ',' ".." expr] ; array_elems : [expr [',' expr]*] | [expr ',' ".." expr] ;
``` ```

View File

@ -1,4 +1,4 @@
% The (old) Rust Threads and Communication Guide % The (old) Rust Threads and Communication Guide
This content has moved into This content has moved into
[the Rust Programming Language book](book/tasks.html). [the Rust Programming Language book](book/concurrency.html).

View File

@ -68,7 +68,7 @@ There are questions that are asked quite often, and so we've made FAQs for them:
* [Language Design FAQ](complement-design-faq.html) * [Language Design FAQ](complement-design-faq.html)
* [Language FAQ](complement-lang-faq.html) * [Language FAQ](complement-lang-faq.html)
* [Project FAQ](complement-project-faq.html) * [Project FAQ](complement-project-faq.html)
* [How to submit a bug report](complement-bugreport.html) * [How to submit a bug report](https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.md#bug-reports)
# The standard library # The standard library

View File

@ -140,7 +140,7 @@ right at home if you've used tools like [Bundler](http://bundler.io/),
[npm](https://www.npmjs.org/), or [pip](https://pip.pypa.io/en/latest/). [npm](https://www.npmjs.org/), or [pip](https://pip.pypa.io/en/latest/).
There's no `Makefile`s or endless `autotools` output here. (Rust's tooling does There's no `Makefile`s or endless `autotools` output here. (Rust's tooling does
[play nice with external libraries written in those [play nice with external libraries written in those
tools](http://crates.io/native-build.html), if you need to.) tools](http://doc.crates.io/build-script.html), if you need to.)
Enough about tools, let's talk code! Enough about tools, let's talk code!
@ -389,11 +389,11 @@ safe concurrent programs.
Here's an example of a concurrent Rust program: Here's an example of a concurrent Rust program:
```{rust} ```{rust}
use std::thread::Thread; use std::thread;
fn main() { fn main() {
let guards: Vec<_> = (0..10).map(|_| { let guards: Vec<_> = (0..10).map(|_| {
Thread::scoped(|| { thread::scoped(|| {
println!("Hello, world!"); println!("Hello, world!");
}) })
}).collect(); }).collect();
@ -421,44 +421,41 @@ problem.
Let's see an example. This Rust code will not compile: Let's see an example. This Rust code will not compile:
```{rust,ignore} ```{rust,ignore}
use std::thread::Thread; use std::thread;
fn main() { fn main() {
let mut numbers = vec![1, 2, 3]; let mut numbers = vec![1, 2, 3];
for i in 0..3 { let guards: Vec<_> = (0..3).map(|i| {
Thread::spawn(move || { thread::scoped(move || {
for j in 0..3 { numbers[j] += 1 } numbers[i] += 1;
}); println!("numbers[{}] is {}", i, numbers[i]);
} })
}).collect();
} }
``` ```
It gives us this error: It gives us this error:
```text ```text
6:71 error: capture of moved value: `numbers` 7:25: 10:6 error: cannot move out of captured outer variable in an `FnMut` closure
for j in 0..3 { numbers[j] += 1 } 7 thread::scoped(move || {
^~~~~~~ 8 numbers[i] += 1;
7:50 note: `numbers` moved into closure environment here 9 println!("numbers[{}] is {}", i, numbers[i]);
spawn(move || { 10 })
for j in 0..3 { numbers[j] += 1 } error: aborting due to previous error
});
6:79 error: cannot assign to immutable dereference (dereference is implicit, due to indexing)
for j in 0..3 { numbers[j] += 1 }
^~~~~~~~~~~~~~~
``` ```
It mentions that "numbers moved into closure environment". Because we This is a little confusing because there are two closures here: the one passed
declared the closure as a moving closure, and it referred to to `map`, and the one passed to `thread::scoped`. In this case, the closure for
`numbers`, the closure will try to take ownership of the vector. But `thread::scoped` is attempting to reference `numbers`, a `Vec<i32>`. This
the closure itself is created in a loop, and hence we will actually closure is a `FnOnce` closure, as thats what `thread::scoped` takes as an
create three closures, one for every iteration of the loop. This means argument. `FnOnce` closures take ownership of their environment. Thats fine,
that all three of those closures would try to own `numbers`, which is but theres one detail: because of `map`, were going to make three of these
impossible -- `numbers` must have just one owner. Rust detects this closures. And since all three try to take ownership of `numbers`, that would be
and gives us the error: we claim that `numbers` has ownership, but our a problem. Thats what it means by cannot move out of captured outer
code tries to make three owners. This may cause a safety problem, so variable: our `thread::scoped` closure wants to take ownership, and it cant,
Rust disallows it. because the closure for `map` wont let it.
What to do here? Rust has two types that helps us: `Arc<T>` and `Mutex<T>`. What to do here? Rust has two types that helps us: `Arc<T>` and `Mutex<T>`.
*Arc* stands for "atomically reference counted". In other words, an Arc will *Arc* stands for "atomically reference counted". In other words, an Arc will
@ -474,20 +471,20 @@ mutation doesn't cause a data race.
Here's what using an Arc with a Mutex looks like: Here's what using an Arc with a Mutex looks like:
```{rust} ```{rust}
use std::thread::Thread; use std::thread;
use std::sync::{Arc,Mutex}; use std::sync::{Arc,Mutex};
fn main() { fn main() {
let numbers = Arc::new(Mutex::new(vec![1, 2, 3])); let numbers = Arc::new(Mutex::new(vec![1, 2, 3]));
for i in 0..3 { let guards: Vec<_> = (0..3).map(|i| {
let number = numbers.clone(); let number = numbers.clone();
Thread::spawn(move || { thread::scoped(move || {
let mut array = number.lock().unwrap(); let mut array = number.lock().unwrap();
array[i] += 1; array[i] += 1;
println!("numbers[{}] is {}", i, array[i]); println!("numbers[{}] is {}", i, array[i]);
}); })
} }).collect();
} }
``` ```
@ -516,8 +513,10 @@ numbers[1] is 3
numbers[0] is 2 numbers[0] is 2
``` ```
Each time, we get a slightly different output, because each thread works in a Each time, we can get a slightly different output because the threads are not
different order. You may not get the same output as this sample, even. guaranteed to run in any set order. If you get the same order every time it is
because each of these threads are very small and complete too fast for their
indeterminate behavior to surface.
The important part here is that the Rust compiler was able to use ownership to The important part here is that the Rust compiler was able to use ownership to
give us assurance _at compile time_ that we weren't doing something incorrect give us assurance _at compile time_ that we weren't doing something incorrect
@ -536,16 +535,16 @@ As an example, Rust's ownership system is _entirely_ at compile time. The
safety check that makes this an error about moved values: safety check that makes this an error about moved values:
```{rust,ignore} ```{rust,ignore}
use std::thread::Thread; use std::thread;
fn main() { fn main() {
let vec = vec![1, 2, 3]; let numbers = vec![1, 2, 3];
for i in 0..3 { let guards: Vec<_> = (0..3).map(|i| {
Thread::spawn(move || { thread::scoped(move || {
println!("{}", vec[i]); println!("{}", numbers[i]);
}); })
} }).collect();
} }
``` ```
@ -569,7 +568,7 @@ while retaining safety. The answer is iterators:
```{rust} ```{rust}
let vec = vec![1, 2, 3]; let vec = vec![1, 2, 3];
for x in vec.iter() { for x in &vec {
println!("{}", x); println!("{}", x);
} }
``` ```

View File

@ -63,4 +63,3 @@ function populate_rust_search() {
populate_site_search(); populate_site_search();
populate_rust_search(); populate_rust_search();
</script> </script>

View File

@ -229,14 +229,14 @@ cases mentioned in [Number literals](#number-literals) below.
##### Characters and strings ##### Characters and strings
| | Example | Number of `#` pairs allowed | Available characters | Escapes | Equivalent to | | | Example | `#` sets | Characters | Escapes |
|---|---------|-----------------------------|----------------------|---------|---------------| |----------------------------------------------|-----------------|------------|-------------|---------------------|
| [Character](#character-literals) | `'H'` | `N/A` | All unicode | `\'` & [Byte escapes](#byte-escapes) & [Unicode escapes](#unicode-escapes) | `N/A` | | [Character](#character-literals) | `'H'` | `N/A` | All Unicode | `\'` & [Byte](#byte-escapes) & [Unicode](#unicode-escapes) |
| [String](#string-literals) | `"hello"` | `N/A` | All unicode | `\"` & [Byte escapes](#byte-escapes) & [Unicode escapes](#unicode-escapes) | `N/A` | | [String](#string-literals) | `"hello"` | `N/A` | All Unicode | `\"` & [Byte](#byte-escapes) & [Unicode](#unicode-escapes) |
| [Raw](#raw-string-literals) | `r##"hello"##` | `0...` | All unicode | `N/A` | `N/A` | | [Raw](#raw-string-literals) | `r#"hello"#` | `0...` | All Unicode | `N/A` |
| [Byte](#byte-literals) | `b'H'` | `N/A` | All ASCII | `\'` & [Byte escapes](#byte-escapes) | `u8` | | [Byte](#byte-literals) | `b'H'` | `N/A` | All ASCII | `\'` & [Byte](#byte-escapes) |
| [Byte string](#byte-string-literals) | `b"hello"` | `N/A` | All ASCII | `\"` & [Byte escapes](#byte-escapes) | `&'static [u8]` | | [Byte string](#byte-string-literals) | `b"hello"` | `N/A` | All ASCII | `\"` & [Byte](#byte-escapes) |
| [Raw byte string](#raw-byte-string-literals) | `br##"hello"##` | `0...` | All ASCII | `N/A` | `&'static [u8]` (unsure...not stated) | | [Raw byte string](#raw-byte-string-literals) | `br#"hello"#` | `0...` | All ASCII | `N/A` |
##### Byte escapes ##### Byte escapes
@ -302,7 +302,7 @@ nonzero_dec: '1' | '2' | '3' | '4'
A _character literal_ is a single Unicode character enclosed within two A _character literal_ is a single Unicode character enclosed within two
`U+0027` (single-quote) characters, with the exception of `U+0027` itself, `U+0027` (single-quote) characters, with the exception of `U+0027` itself,
which must be _escaped_ by a preceding U+005C character (`\`). which must be _escaped_ by a preceding `U+005C` character (`\`).
##### String literals ##### String literals
@ -311,6 +311,19 @@ A _string literal_ is a sequence of any Unicode characters enclosed within two
which must be _escaped_ by a preceding `U+005C` character (`\`), or a _raw which must be _escaped_ by a preceding `U+005C` character (`\`), or a _raw
string literal_. string literal_.
A multi-line string literal may be defined by terminating each line with a
`U+005C` character (`\`) immediately before the newline. This causes the
`U+005C` character, the newline, and all whitespace at the beginning of the
next line to be ignored.
```rust
let a = "foobar";
let b = "foo\
bar";
assert_eq!(a,b);
```
##### Character escapes ##### Character escapes
Some additional _escapes_ are available in either character or non-raw string Some additional _escapes_ are available in either character or non-raw string
@ -515,6 +528,9 @@ This last example is different because it is not possible to use the suffix
syntax with a floating point literal ending in a period. `2.f64` would attempt syntax with a floating point literal ending in a period. `2.f64` would attempt
to call a method named `f64` on `2`. to call a method named `f64` on `2`.
The representation semantics of floating-point numbers are described in
["Machine Types"](#machine-types).
#### Boolean literals #### Boolean literals
The two values of the boolean type are written `true` and `false`. The two values of the boolean type are written `true` and `false`.
@ -629,18 +645,7 @@ fn bar() {
A number of minor features of Rust are not central enough to have their own A number of minor features of Rust are not central enough to have their own
syntax, and yet are not implementable as functions. Instead, they are given syntax, and yet are not implementable as functions. Instead, they are given
names, and invoked through a consistent syntax: `name!(...)`. Examples include: names, and invoked through a consistent syntax: `some_extension!(...)`.
* `format!` : format data into a string
* `env!` : look up an environment variable's value at compile time
* `file!`: return the path to the file being compiled
* `stringify!` : pretty-print the Rust expression given as an argument
* `include!` : include the Rust expression in the given file
* `include_str!` : include the contents of the given file as a string
* `include_bytes!` : include the contents of the given file as a binary blob
* `error!`, `warn!`, `info!`, `debug!` : provide diagnostic information.
All of the above extensions are expressions with values.
Users of `rustc` can define new syntax extensions in two ways: Users of `rustc` can define new syntax extensions in two ways:
@ -728,23 +733,6 @@ Rust syntax is restricted in two ways:
pairs when they occur at the beginning of, or immediately after, a `$(...)*`; pairs when they occur at the beginning of, or immediately after, a `$(...)*`;
requiring a distinctive token in front can solve the problem. requiring a distinctive token in front can solve the problem.
## Syntax extensions useful for the macro author
* `log_syntax!` : print out the arguments at compile time
* `trace_macros!` : supply `true` or `false` to enable or disable macro expansion logging
* `stringify!` : turn the identifier argument into a string literal
* `concat!` : concatenates a comma-separated list of literals
* `concat_idents!` : create a new identifier by concatenating the arguments
The following attributes are used for quasiquoting in procedural macros:
* `quote_expr!`
* `quote_item!`
* `quote_pat!`
* `quote_stmt!`
* `quote_tokens!`
* `quote_ty!`
# Crates and source files # Crates and source files
Rust is a *compiled* language. Its semantics obey a *phase distinction* Rust is a *compiled* language. Its semantics obey a *phase distinction*
@ -785,8 +773,7 @@ may optionally begin with any number of `attributes` that apply to the
containing module. Attributes on the anonymous crate module define important containing module. Attributes on the anonymous crate module define important
metadata that influences the behavior of the compiler. metadata that influences the behavior of the compiler.
```{.rust} ```no_run
# #![allow(unused_attribute)]
// Crate name // Crate name
#![crate_name = "projx"] #![crate_name = "projx"]
@ -950,7 +937,7 @@ extern crate pcre;
extern crate std; // equivalent to: extern crate std as std; extern crate std; // equivalent to: extern crate std as std;
extern crate "std" as ruststd; // linking to 'std' under another name extern crate std as ruststd; // linking to 'std' under another name
``` ```
##### Use declarations ##### Use declarations
@ -989,7 +976,7 @@ Use declarations support a number of convenient shortcuts:
An example of `use` declarations: An example of `use` declarations:
``` ```
use std::iter::range_step; # #![feature(core)]
use std::option::Option::{Some, None}; use std::option::Option::{Some, None};
use std::collections::hash_map::{self, HashMap}; use std::collections::hash_map::{self, HashMap};
@ -997,9 +984,6 @@ fn foo<T>(_: T){}
fn bar(map1: HashMap<String, usize>, map2: hash_map::HashMap<String, usize>){} fn bar(map1: HashMap<String, usize>, map2: hash_map::HashMap<String, usize>){}
fn main() { fn main() {
// Equivalent to 'std::iter::range_step(0, 10, 2);'
range_step(0, 10, 2);
// Equivalent to 'foo(vec![std::option::Option::Some(1.0f64), // Equivalent to 'foo(vec![std::option::Option::Some(1.0f64),
// std::option::Option::None]);' // std::option::Option::None]);'
foo(vec![Some(1.0f64), None]); foo(vec![Some(1.0f64), None]);
@ -1049,6 +1033,7 @@ declarations.
An example of what will and will not work for `use` items: An example of what will and will not work for `use` items:
``` ```
# #![feature(core)]
# #![allow(unused_imports)] # #![allow(unused_imports)]
use foo::core::iter; // good: foo is at the root of the crate use foo::core::iter; // good: foo is at the root of the crate
use foo::baz::foobaz; // good: foo is at the root of the crate use foo::baz::foobaz; // good: foo is at the root of the crate
@ -1199,12 +1184,15 @@ the guarantee that these issues are never caused by safe code.
* Data races * Data races
* Dereferencing a null/dangling raw pointer * Dereferencing a null/dangling raw pointer
* Mutating an immutable value/reference without `UnsafeCell`
* Reads of [undef](http://llvm.org/docs/LangRef.html#undefined-values) * Reads of [undef](http://llvm.org/docs/LangRef.html#undefined-values)
(uninitialized) memory (uninitialized) memory
* Breaking the [pointer aliasing * Breaking the [pointer aliasing
rules](http://llvm.org/docs/LangRef.html#pointer-aliasing-rules) rules](http://llvm.org/docs/LangRef.html#pointer-aliasing-rules)
with raw pointers (a subset of the rules used by C) with raw pointers (a subset of the rules used by C)
* `&mut` and `&` follow LLVMs scoped [noalias] model, except if the `&T`
contains an `UnsafeCell<U>`. Unsafe code must not violate these aliasing
guarantees.
* Mutating an immutable value/reference without `UnsafeCell<U>`
* Invoking undefined behavior via compiler intrinsics: * Invoking undefined behavior via compiler intrinsics:
* Indexing outside of the bounds of an object with `std::ptr::offset` * Indexing outside of the bounds of an object with `std::ptr::offset`
(`offset` intrinsic), with (`offset` intrinsic), with
@ -1221,6 +1209,8 @@ the guarantee that these issues are never caused by safe code.
code. Rust's failure system is not compatible with exception handling in code. Rust's failure system is not compatible with exception handling in
other languages. Unwinding must be caught and handled at FFI boundaries. other languages. Unwinding must be caught and handled at FFI boundaries.
[noalias]: http://llvm.org/docs/LangRef.html#noalias
##### Behaviour not considered unsafe ##### Behaviour not considered unsafe
This is a list of behaviour not considered *unsafe* in Rust terms, but that may This is a list of behaviour not considered *unsafe* in Rust terms, but that may
@ -1233,7 +1223,7 @@ be undesired.
* Sending signals * Sending signals
* Accessing/modifying the file system * Accessing/modifying the file system
* Unsigned integer overflow (well-defined as wrapping) * Unsigned integer overflow (well-defined as wrapping)
* Signed integer overflow (well-defined as two's complement representation * Signed integer overflow (well-defined as twos complement representation
wrapping) wrapping)
#### Diverging functions #### Diverging functions
@ -1489,22 +1479,6 @@ statics:
Constants should in general be preferred over statics, unless large amounts of Constants should in general be preferred over statics, unless large amounts of
data are being stored, or single-address and mutability properties are required. data are being stored, or single-address and mutability properties are required.
```
use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT};
// Note that ATOMIC_USIZE_INIT is a *const*, but it may be used to initialize a
// static. This static can be modified, so it is not placed in read-only memory.
static COUNTER: AtomicUsize = ATOMIC_USIZE_INIT;
// This table is a candidate to be placed in read-only memory.
static TABLE: &'static [usize] = &[1, 2, 3, /* ... */];
for slot in TABLE.iter() {
println!("{}", slot);
}
COUNTER.fetch_add(1, Ordering::SeqCst);
```
#### Mutable statics #### Mutable statics
If a static item is declared with the `mut` keyword, then it is allowed to If a static item is declared with the `mut` keyword, then it is allowed to
@ -1674,7 +1648,7 @@ specific type.
Implementations are defined with the keyword `impl`. Implementations are defined with the keyword `impl`.
``` ```
# #[derive(Copy)] # #[derive(Copy, Clone)]
# struct Point {x: f64, y: f64}; # struct Point {x: f64, y: f64};
# type Surface = i32; # type Surface = i32;
# struct BoundingBox {x: f64, y: f64, width: f64, height: f64}; # struct BoundingBox {x: f64, y: f64, width: f64, height: f64};
@ -1687,6 +1661,10 @@ struct Circle {
impl Copy for Circle {} impl Copy for Circle {}
impl Clone for Circle {
fn clone(&self) -> Circle { *self }
}
impl Shape for Circle { impl Shape for Circle {
fn draw(&self, s: Surface) { do_draw_circle(s, *self); } fn draw(&self, s: Surface) { do_draw_circle(s, *self); }
fn bounding_box(&self) -> BoundingBox { fn bounding_box(&self) -> BoundingBox {
@ -1750,6 +1728,7 @@ functions, with the exception that they may not have a body and are instead
terminated by a semicolon. terminated by a semicolon.
``` ```
# #![feature(libc)]
extern crate libc; extern crate libc;
use libc::{c_char, FILE}; use libc::{c_char, FILE};
@ -1930,16 +1909,18 @@ module through the rules above. It essentially allows public access into the
re-exported item. For example, this program is valid: re-exported item. For example, this program is valid:
``` ```
pub use self::implementation as api; pub use self::implementation::api;
mod implementation { mod implementation {
pub mod api {
pub fn f() {} pub fn f() {}
} }
}
# fn main() {} # fn main() {}
``` ```
This means that any external crate referencing `implementation::f` would This means that any external crate referencing `implementation::api::f` would
receive a privacy violation, while the path `api::f` would be allowed. receive a privacy violation, while the path `api::f` would be allowed.
When re-exporting a private item, it can be thought of as allowing the "privacy When re-exporting a private item, it can be thought of as allowing the "privacy
@ -1949,7 +1930,7 @@ the namespace hierarchy as it normally would.
## Attributes ## Attributes
```{.ebnf .gram} ```{.ebnf .gram}
attribute : "#!" ? '[' meta_item ']' ; attribute : '#' '!' ? '[' meta_item ']' ;
meta_item : ident [ '=' literal meta_item : ident [ '=' literal
| '(' meta_seq ')' ] ? ; | '(' meta_seq ')' ] ? ;
meta_seq : meta_item [ ',' meta_seq ] ? ; meta_seq : meta_item [ ',' meta_seq ] ? ;
@ -2035,7 +2016,7 @@ type int8_t = i8;
item](#language-items) for more details. item](#language-items) for more details.
- `test` - indicates that this function is a test function, to only be compiled - `test` - indicates that this function is a test function, to only be compiled
in case of `--test`. in case of `--test`.
- `should_fail` - indicates that this test function should panic, inverting the success condition. - `should_panic` - indicates that this test function should panic, inverting the success condition.
- `cold` - The function is unlikely to be executed, so optimize it (and calls - `cold` - The function is unlikely to be executed, so optimize it (and calls
to it) differently. to it) differently.
@ -2162,7 +2143,7 @@ fn needs_foo_or_bar() {
// This function is only included when compiling for a unixish OS with a 32-bit // This function is only included when compiling for a unixish OS with a 32-bit
// architecture // architecture
#[cfg(all(unix, target_word_size = "32"))] #[cfg(all(unix, target_pointer_width = "32"))]
fn on_32bit_unix() { fn on_32bit_unix() {
// ... // ...
} }
@ -2188,11 +2169,11 @@ The following configurations must be defined by the implementation:
`"unix"` or `"windows"`. The value of this configuration option is defined `"unix"` or `"windows"`. The value of this configuration option is defined
as a configuration itself, like `unix` or `windows`. as a configuration itself, like `unix` or `windows`.
* `target_os = "..."`. Operating system of the target, examples include * `target_os = "..."`. Operating system of the target, examples include
`"win32"`, `"macos"`, `"linux"`, `"android"`, `"freebsd"`, `"dragonfly"` or `"win32"`, `"macos"`, `"linux"`, `"android"`, `"freebsd"`, `"dragonfly"`,
`"openbsd"`. `"bitrig"` or `"openbsd"`.
* `target_word_size = "..."`. Target word size in bits. This is set to `"32"` * `target_pointer_width = "..."`. Target pointer width in bits. This is set
for targets with 32-bit pointers, and likewise set to `"64"` for 64-bit to `"32"` for targets with 32-bit pointers, and likewise set to `"64"` for
pointers. 64-bit pointers.
* `unix`. See `target_family`. * `unix`. See `target_family`.
* `windows`. See `target_family`. * `windows`. See `target_family`.
@ -2341,18 +2322,6 @@ impl<T: PartialEq> PartialEq for Foo<T> {
} }
``` ```
Supported traits for `derive` are:
* Comparison traits: `PartialEq`, `Eq`, `PartialOrd`, `Ord`.
* Serialization: `Encodable`, `Decodable`. These require `serialize`.
* `Clone`, to create `T` from `&T` via a copy.
* `Default`, to create an empty instance of a data type.
* `FromPrimitive`, to create an instance from a numeric primitive.
* `Hash`, to iterate over the bytes in a data type.
* `Rand`, to create a random instance of a data type.
* `Debug`, to format a value using the `{:?}` formatter.
* `Copy`, for "Plain Old Data" types which can be copied by simply moving bits.
### Compiler Features ### Compiler Features
Certain aspects of Rust may be implemented in the compiler, but they're not Certain aspects of Rust may be implemented in the compiler, but they're not
@ -2373,9 +2342,13 @@ considered off, and using the features will result in a compiler error.
The currently implemented features of the reference compiler are: The currently implemented features of the reference compiler are:
* `advanced_slice_patterns` - see the [match expressions](#match-expressions) * `advanced_slice_patterns` - See the [match expressions](#match-expressions)
section for discussion; the exact semantics of section for discussion; the exact semantics of
slice patterns are subject to change. slice patterns are subject to change, so some types
are still unstable.
* `slice_patterns` - OK, actually, slice patterns are just scary and
completely unstable.
* `asm` - The `asm!` macro provides a means for inline assembly. This is often * `asm` - The `asm!` macro provides a means for inline assembly. This is often
useful, but the exact syntax for this feature along with its useful, but the exact syntax for this feature along with its
@ -2398,12 +2371,13 @@ The currently implemented features of the reference compiler are:
so that new attributes can be added in a bacwards compatible so that new attributes can be added in a bacwards compatible
manner (RFC 572). manner (RFC 572).
* `custom_derive` - Allows the use of `#[derive(Foo,Bar)]` as sugar for
`#[derive_Foo] #[derive_Bar]`, which can be user-defined syntax
extensions.
* `intrinsics` - Allows use of the "rust-intrinsics" ABI. Compiler intrinsics * `intrinsics` - Allows use of the "rust-intrinsics" ABI. Compiler intrinsics
are inherently unstable and no promise about them is made. are inherently unstable and no promise about them is made.
* `int_uint` - Allows the use of the `int` and `uint` types, which are deprecated.
Use `isize` and `usize` instead.
* `lang_items` - Allows use of the `#[lang]` attribute. Like `intrinsics`, * `lang_items` - Allows use of the `#[lang]` attribute. Like `intrinsics`,
lang items are inherently unstable and no promise about them lang items are inherently unstable and no promise about them
is made. is made.
@ -2472,6 +2446,12 @@ The currently implemented features of the reference compiler are:
* `staged_api` - Allows usage of stability markers and `#![staged_api]` in a crate * `staged_api` - Allows usage of stability markers and `#![staged_api]` in a crate
* `static_assert` - The `#[static_assert]` functionality is experimental and
unstable. The attribute can be attached to a `static` of
type `bool` and the compiler will error if the `bool` is
`false` at compile time. This version of this functionality
is unintuitive and suboptimal.
* `start` - Allows use of the `#[start]` attribute, which changes the entry point * `start` - Allows use of the `#[start]` attribute, which changes the entry point
into a Rust program. This capabiilty, especially the signature for the into a Rust program. This capabiilty, especially the signature for the
annotated function, is subject to change. annotated function, is subject to change.
@ -2518,6 +2498,14 @@ The currently implemented features of the reference compiler are:
types, e.g. as the return type of a public function. types, e.g. as the return type of a public function.
This capability may be removed in the future. This capability may be removed in the future.
* `allow_internal_unstable` - Allows `macro_rules!` macros to be tagged with the
`#[allow_internal_unstable]` attribute, designed
to allow `std` macros to call
`#[unstable]`/feature-gated functionality
internally without imposing on callers
(i.e. making them behave like function calls in
terms of encapsulation).
If a feature is promoted to a language feature, then all existing programs will If a feature is promoted to a language feature, then all existing programs will
start to receive compilation warnings about #[feature] directives which enabled start to receive compilation warnings about #[feature] directives which enabled
the new feature (because the directive is no longer necessary). However, if a the new feature (because the directive is no longer necessary). However, if a
@ -2706,7 +2694,7 @@ The following are examples of structure expressions:
``` ```
# struct Point { x: f64, y: f64 } # struct Point { x: f64, y: f64 }
# struct TuplePoint(f64, f64); # struct TuplePoint(f64, f64);
# mod game { pub struct User<'a> { pub name: &'a str, pub age: u32, pub score: uint } } # mod game { pub struct User<'a> { pub name: &'a str, pub age: u32, pub score: usize } }
# struct Cookie; fn some_fn<T>(t: T) {} # struct Cookie; fn some_fn<T>(t: T) {}
Point {x: 10.0, y: 20.0}; Point {x: 10.0, y: 20.0};
TuplePoint(10.0, 20.0); TuplePoint(10.0, 20.0);
@ -2798,7 +2786,7 @@ automatically dereferenced to make the field access possible.
### Array expressions ### Array expressions
```{.ebnf .gram} ```{.ebnf .gram}
array_expr : '[' "mut" ? vec_elems? ']' ; array_expr : '[' "mut" ? array_elems? ']' ;
array_elems : [expr [',' expr]*] | [expr ';' expr] ; array_elems : [expr [',' expr]*] | [expr ';' expr] ;
``` ```
@ -2908,10 +2896,10 @@ meaning of the operators on standard types is given here.
: Exclusive or. : Exclusive or.
Calls the `bitxor` method of the `std::ops::BitXor` trait. Calls the `bitxor` method of the `std::ops::BitXor` trait.
* `<<` * `<<`
: Logical left shift. : Left shift.
Calls the `shl` method of the `std::ops::Shl` trait. Calls the `shl` method of the `std::ops::Shl` trait.
* `>>` * `>>`
: Logical right shift. : Right shift.
Calls the `shr` method of the `std::ops::Shr` trait. Calls the `shr` method of the `std::ops::Shr` trait.
#### Lazy boolean operators #### Lazy boolean operators
@ -2958,10 +2946,6 @@ A type cast expression is denoted with the binary operator `as`.
Executing an `as` expression casts the value on the left-hand side to the type Executing an `as` expression casts the value on the left-hand side to the type
on the right-hand side. on the right-hand side.
A numeric value can be cast to any numeric type. A raw pointer value can be
cast to or from any integral type or raw pointer type. Any other cast is
unsupported and will fail to compile.
An example of an `as` expression: An example of an `as` expression:
``` ```
@ -3111,7 +3095,7 @@ ten_times(|j| println!("hello, {}", j));
### While loops ### While loops
```{.ebnf .gram} ```{.ebnf .gram}
while_expr : "while" no_struct_literal_expr '{' block '}' ; while_expr : [ lifetime ':' ] "while" no_struct_literal_expr '{' block '}' ;
``` ```
A `while` loop begins by evaluating the boolean loop conditional expression. A `while` loop begins by evaluating the boolean loop conditional expression.
@ -3176,7 +3160,7 @@ A `continue` expression is only permitted in the body of a loop.
### For expressions ### For expressions
```{.ebnf .gram} ```{.ebnf .gram}
for_expr : "for" pat "in" no_struct_literal_expr '{' block '}' ; for_expr : [ lifetime ':' ] "for" pat "in" no_struct_literal_expr '{' block '}' ;
``` ```
A `for` expression is a syntactic construct for looping over elements provided A `for` expression is a syntactic construct for looping over elements provided
@ -3280,7 +3264,7 @@ array, like `[.., 42, ..]`. If preceded by a variable name, it will bind the
corresponding slice to the variable. Example: corresponding slice to the variable. Example:
``` ```
# #![feature(advanced_slice_patterns)] # #![feature(advanced_slice_patterns, slice_patterns)]
fn is_symmetric(list: &[u32]) -> bool { fn is_symmetric(list: &[u32]) -> bool {
match list { match list {
[] | [_] => true, [] | [_] => true,
@ -3353,7 +3337,7 @@ subpattern`. For example:
#![feature(box_patterns)] #![feature(box_patterns)]
#![feature(box_syntax)] #![feature(box_syntax)]
enum List { Nil, Cons(uint, Box<List>) } enum List { Nil, Cons(u32, Box<List>) }
fn is_sorted(list: &List) -> bool { fn is_sorted(list: &List) -> bool {
match *list { match *list {
@ -3554,7 +3538,8 @@ Tuple types and values are denoted by listing the types or values of their
elements, respectively, in a parenthesized, comma-separated list. elements, respectively, in a parenthesized, comma-separated list.
Because tuple elements don't have a name, they can only be accessed by Because tuple elements don't have a name, they can only be accessed by
pattern-matching. pattern-matching or by using `N` directly as a field to access the
`N`th element.
An example of a tuple type and its use: An example of a tuple type and its use:
@ -3563,6 +3548,7 @@ type Pair<'a> = (i32, &'a str);
let p: Pair<'static> = (10, "hello"); let p: Pair<'static> = (10, "hello");
let (a, b) = p; let (a, b) = p;
assert!(b != "world"); assert!(b != "world");
assert!(p.0 == 10);
``` ```
### Array, and Slice types ### Array, and Slice types
@ -3740,9 +3726,9 @@ An example of creating and calling a closure:
```rust ```rust
let captured_var = 10; let captured_var = 10;
let closure_no_args = |&:| println!("captured_var={}", captured_var); let closure_no_args = || println!("captured_var={}", captured_var);
let closure_args = |&: arg: i32| -> i32 { let closure_args = |arg: i32| -> i32 {
println!("captured_var={}, arg={}", captured_var, arg); println!("captured_var={}, arg={}", captured_var, arg);
arg // Note lack of semicolon after 'arg' arg // Note lack of semicolon after 'arg'
}; };
@ -3835,75 +3821,27 @@ impl Printable for String {
`self` refers to the value of type `String` that is the receiver for a call to `self` refers to the value of type `String` that is the receiver for a call to
the method `make_string`. the method `make_string`.
## Type kinds # The `Copy` trait
Types in Rust are categorized into kinds, based on various properties of the Rust has a special trait, `Copy`, which when implemented changes the semantics
components of the type. The kinds are: of a value. Values whose type implements `Copy` are copied rather than moved
upon assignment.
* `Send` # The `Sized` trait
: Types of this kind can be safely sent between threads.
This kind includes scalars, boxes, procs, and
structural types containing only other owned types.
All `Send` types are `'static`.
* `Copy`
: Types of this kind consist of "Plain Old Data"
which can be copied by simply moving bits.
All values of this kind can be implicitly copied.
This kind includes scalars and immutable references,
as well as structural types containing other `Copy` types.
* `'static`
: Types of this kind do not contain any references (except for
references with the `static` lifetime, which are allowed).
This can be a useful guarantee for code
that breaks borrowing assumptions
using [`unsafe` operations](#unsafe-functions).
* `Drop`
: This is not strictly a kind,
but its presence interacts with kinds:
the `Drop` trait provides a single method `drop`
that takes no parameters,
and is run when values of the type are dropped.
Such a method is called a "destructor",
and are always executed in "top-down" order:
a value is completely destroyed
before any of the values it owns run their destructors.
Only `Send` types can implement `Drop`.
* _Default_ `Sized` is a special trait which indicates that the size of this type is known
: Types with destructors, closure environments, at compile-time.
and various other _non-first-class_ types,
are not copyable at all.
Such types can usually only be accessed through pointers,
or in some cases, moved between mutable locations.
Kinds can be supplied as _bounds_ on type parameters, like traits, in which # The `Drop` trait
case the parameter is constrained to types satisfying that kind.
By default, type parameters do not carry any assumed kind-bounds at all. When The `Drop` trait provides a destructor, to be run whenever a value of this type
instantiating a type parameter, the kind bounds on the parameter are checked to is to be destroyed.
be the same or narrower than the kind of the type that it is instantiated with.
Sending operations are not part of the Rust language, but are implemented in # Memory model
the library. Generic functions that send values bound the kind of these values
to sendable.
# Memory and concurrency models A Rust program's memory consists of a static set of *items* and a *heap*.
Immutable portions of the heap may be shared between threads, mutable portions
Rust has a memory model centered around concurrently-executing _threads_. Thus may not.
its memory model and its concurrency model are best discussed simultaneously,
as parts of each only make sense when considered from the perspective of the
other.
When reading about the memory model, keep in mind that it is partitioned in
order to support threads; and when reading about threads, keep in mind that their
isolation and communication mechanisms are only possible due to the ownership
and lifetime semantics of the memory model.
## Memory model
A Rust program's memory consists of a static set of *items*, a set of
[threads](#threads) each with its own *stack*, and a *heap*. Immutable portions of
the heap may be shared between threads, mutable portions may not.
Allocations in the stack consist of *slots*, and allocations in the heap Allocations in the stack consist of *slots*, and allocations in the heap
consist of *boxes*. consist of *boxes*.
@ -3914,10 +3852,6 @@ The _items_ of a program are those functions, modules and types that have their
value calculated at compile-time and stored uniquely in the memory image of the value calculated at compile-time and stored uniquely in the memory image of the
rust process. Items are neither dynamically allocated nor freed. rust process. Items are neither dynamically allocated nor freed.
A thread's _stack_ consists of activation frames automatically allocated on entry
to each function as the thread executes. A stack allocation is reclaimed when
control leaves the frame containing it.
The _heap_ is a general term that describes boxes. The lifetime of an The _heap_ is a general term that describes boxes. The lifetime of an
allocation in the heap depends on the lifetime of the box values pointing to allocation in the heap depends on the lifetime of the box values pointing to
it. Since box values may themselves be passed in and out of frames, or stored it. Since box values may themselves be passed in and out of frames, or stored
@ -3925,25 +3859,11 @@ in the heap, heap allocations may outlive the frame they are allocated within.
### Memory ownership ### Memory ownership
A thread owns all memory it can *safely* reach through local variables, as well
as boxes and references.
When a thread sends a value that has the `Send` trait to another thread, it loses
ownership of the value sent and can no longer refer to it. This is statically
guaranteed by the combined use of "move semantics", and the compiler-checked
_meaning_ of the `Send` trait: it is only instantiated for (transitively)
sendable kinds of data constructor and pointers, never including references.
When a stack frame is exited, its local allocations are all released, and its When a stack frame is exited, its local allocations are all released, and its
references to boxes are dropped. references to boxes are dropped.
When a thread finishes, its stack is necessarily empty and it therefore has no
references to any boxes; the remainder of its heap is immediately freed.
### Memory slots ### Memory slots
A thread's stack contains slots.
A _slot_ is a component of a stack frame, either a function parameter, a A _slot_ is a component of a stack frame, either a function parameter, a
[temporary](#lvalues,-rvalues-and-temporaries), or a local variable. [temporary](#lvalues,-rvalues-and-temporaries), or a local variable.
@ -3973,86 +3893,6 @@ state. Subsequent statements within a function may or may not initialize the
local variables. Local variables can be used only after they have been local variables. Local variables can be used only after they have been
initialized; this is enforced by the compiler. initialized; this is enforced by the compiler.
### Boxes
A _box_ is a reference to a heap allocation holding another value, which is
constructed by the prefix operator `box`. When the standard library is in use,
the type of a box is `std::owned::Box<T>`.
An example of a box type and value:
```
let x: Box<i32> = Box::new(10);
```
Box values exist in 1:1 correspondence with their heap allocation, copying a
box value makes a shallow copy of the pointer. Rust will consider a shallow
copy of a box to move ownership of the value. After a value has been moved,
the source location cannot be used unless it is reinitialized.
```
let x: Box<i32> = Box::new(10);
let y = x;
// attempting to use `x` will result in an error here
```
## Threads
Rust's primary concurrency mechanism is called a **thread**.
### Communication between threads
Rust threads are isolated and generally unable to interfere with one another's
memory directly, except through [`unsafe` code](#unsafe-functions). All
contact between threads is mediated by safe forms of ownership transfer, and data
races on memory are prohibited by the type system.
When you wish to send data between threads, the values are restricted to the
[`Send` type-kind](#type-kinds). Restricting communication interfaces to this
kind ensures that no references move between threads. Thus access to an entire
data structure can be mediated through its owning "root" value; no further
locking or copying is required to avoid data races within the substructure of
such a value.
### Thread
The _lifecycle_ of a threads consists of a finite set of states and events that
cause transitions between the states. The lifecycle states of a thread are:
* running
* blocked
* panicked
* dead
A thread begins its lifecycle &mdash; once it has been spawned &mdash; in the
*running* state. In this state it executes the statements of its entry
function, and any functions called by the entry function.
A thread may transition from the *running* state to the *blocked* state any time
it makes a blocking communication call. When the call can be completed &mdash;
when a message arrives at a sender, or a buffer opens to receive a message
&mdash; then the blocked thread will unblock and transition back to *running*.
A thread may transition to the *panicked* state at any time, due being killed by
some external event or internally, from the evaluation of a `panic!()` macro.
Once *panicking*, a thread unwinds its stack and transitions to the *dead* state.
Unwinding the stack of a thread is done by the thread itself, on its own control
stack. If a value with a destructor is freed during unwinding, the code for the
destructor is run, also on the thread's control stack. Running the destructor
code causes a temporary transition to a *running* state, and allows the
destructor code to cause any subsequent state transitions. The original thread
of unwinding and panicking thereby may suspend temporarily, and may involve
(recursive) unwinding of the stack of a failed destructor. Nonetheless, the
outermost unwinding activity will continue until the stack is unwound and the
thread transitions to the *dead* state. There is no way to "recover" from thread
panics. Once a thread has temporarily suspended its unwinding in the *panicking*
state, a panic occurring from within this destructor results in *hard* panic.
A hard panic currently results in the process aborting.
A thread in the *dead* state cannot transition to other states; it exists only to
have its termination status inspected by other threads, and/or to await
reclamation when the last reference to it drops.
# Runtime services, linkage and debugging # Runtime services, linkage and debugging
The Rust _runtime_ is a relatively compact collection of Rust code that The Rust _runtime_ is a relatively compact collection of Rust code that

View File

@ -56,6 +56,7 @@
/* General structure */ /* General structure */
body { body {
background-color: white;
margin: 0 auto; margin: 0 auto;
padding: 0 15px; padding: 0 15px;
font-family: "Source Serif Pro", Georgia, Times, "Times New Roman", serif; font-family: "Source Serif Pro", Georgia, Times, "Times New Roman", serif;

View File

@ -22,9 +22,9 @@ fn write_info(info: &Info) -> Result<(), IoError> {
let mut file = File::open_mode(&Path::new("my_best_friends.txt"), let mut file = File::open_mode(&Path::new("my_best_friends.txt"),
Open, Write); Open, Write);
// Early return on error // Early return on error
try!(file.write_line(format!("name: {}", info.name).as_slice())); try!(file.write_line(&format!("name: {}", info.name)));
try!(file.write_line(format!("age: {}", info.age).as_slice())); try!(file.write_line(&format!("age: {}", info.age)));
try!(file.write_line(format!("rating: {}", info.rating).as_slice())); try!(file.write_line(&format!("rating: {}", info.rating)));
return Ok(()); return Ok(());
} }
``` ```
@ -44,15 +44,15 @@ fn write_info(info: &Info) -> Result<(), IoError> {
let mut file = File::open_mode(&Path::new("my_best_friends.txt"), let mut file = File::open_mode(&Path::new("my_best_friends.txt"),
Open, Write); Open, Write);
// Early return on error // Early return on error
match file.write_line(format!("name: {}", info.name).as_slice()) { match file.write_line(&format!("name: {}", info.name)) {
Ok(_) => (), Ok(_) => (),
Err(e) => return Err(e) Err(e) => return Err(e)
} }
match file.write_line(format!("age: {}", info.age).as_slice()) { match file.write_line(&format!("age: {}", info.age)) {
Ok(_) => (), Ok(_) => (),
Err(e) => return Err(e) Err(e) => return Err(e)
} }
return file.write_line(format!("rating: {}", info.rating).as_slice()); return file.write_line(&format!("rating: {}", info.rating));
} }
``` ```

View File

@ -11,8 +11,7 @@ navigate through the menu on the left.
<h2 class="section-header"><a href="basic.html">Basics</a></h2> <h2 class="section-header"><a href="basic.html">Basics</a></h2>
This section is a linear introduction to the basic syntax and semantics of This section is a linear introduction to the basic syntax and semantics of
Rust. It has individual sections on each part of Rust's syntax, and culminates Rust. It has individual sections on each part of Rust's syntax.
in a small project: a guessing game.
After reading "Basics," you will have a good foundation to learn more about After reading "Basics," you will have a good foundation to learn more about
Rust, and can write very simple programs. Rust, and can write very simple programs.
@ -29,7 +28,12 @@ and will be able to understand most Rust code and write more complex programs.
In a similar fashion to "Intermediate," this section is full of individual, In a similar fashion to "Intermediate," this section is full of individual,
deep-dive chapters, which stand alone and can be read in any order. These deep-dive chapters, which stand alone and can be read in any order. These
chapters focus on the most complex features, as well as some things that chapters focus on the most complex features,
are only available in upcoming versions of Rust.
After reading "Advanced," you'll be a Rust expert! <h2 class="section-header"><a href="unstable.html">Unstable</a></h2>
In a similar fashion to "Intermediate," this section is full of individual,
deep-dive chapters, which stand alone and can be read in any order.
This chapter contains things that are only available on the nightly channel of
Rust.

View File

@ -1,6 +1,6 @@
# Summary # Summary
* [I: The Basics](basic.md) * [The Basics](basic.md)
* [Installing Rust](installing-rust.md) * [Installing Rust](installing-rust.md)
* [Hello, world!](hello-world.md) * [Hello, world!](hello-world.md)
* [Hello, Cargo!](hello-cargo.md) * [Hello, Cargo!](hello-cargo.md)
@ -13,16 +13,15 @@
* [Looping](looping.md) * [Looping](looping.md)
* [Strings](strings.md) * [Strings](strings.md)
* [Arrays, Vectors, and Slices](arrays-vectors-and-slices.md) * [Arrays, Vectors, and Slices](arrays-vectors-and-slices.md)
* [Standard Input](standard-input.md) * [Intermediate Rust](intermediate.md)
* [Guessing Game](guessing-game.md)
* [II: Intermediate Rust](intermediate.md)
* [More Strings](more-strings.md)
* [Crates and Modules](crates-and-modules.md) * [Crates and Modules](crates-and-modules.md)
* [Testing](testing.md) * [Testing](testing.md)
* [Pointers](pointers.md) * [Pointers](pointers.md)
* [Ownership](ownership.md) * [Ownership](ownership.md)
* [More Strings](more-strings.md)
* [Patterns](patterns.md) * [Patterns](patterns.md)
* [Method Syntax](method-syntax.md) * [Method Syntax](method-syntax.md)
* [Associated Types](associated-types.md)
* [Closures](closures.md) * [Closures](closures.md)
* [Iterators](iterators.md) * [Iterators](iterators.md)
* [Generics](generics.md) * [Generics](generics.md)
@ -32,10 +31,18 @@
* [Concurrency](concurrency.md) * [Concurrency](concurrency.md)
* [Error Handling](error-handling.md) * [Error Handling](error-handling.md)
* [Documentation](documentation.md) * [Documentation](documentation.md)
* [III: Advanced Topics](advanced.md) * [Advanced Topics](advanced.md)
* [FFI](ffi.md) * [FFI](ffi.md)
* [Unsafe Code](unsafe.md) * [Unsafe Code](unsafe.md)
* [Advanced Macros](advanced-macros.md) * [Advanced Macros](advanced-macros.md)
* [Unstable Rust](unstable.md)
* [Compiler Plugins](plugins.md) * [Compiler Plugins](plugins.md)
* [Inline Assembly](inline-assembly.md)
* [No stdlib](no-stdlib.md)
* [Intrinsics](intrinsics.md)
* [Lang items](lang-items.md)
* [Link args](link-args.md)
* [Benchmark Tests](benchmark-tests.md)
* [Box Syntax and Patterns](box-syntax-and-patterns.md)
* [Conclusion](conclusion.md) * [Conclusion](conclusion.md)
* [Glossary](glossary.md) * [Glossary](glossary.md)

View File

@ -6,9 +6,11 @@ off.
# Syntactic requirements # Syntactic requirements
Even when Rust code contains un-expanded macros, it can be parsed as a full Even when Rust code contains un-expanded macros, it can be parsed as a full
syntax tree. This property can be very useful for editors and other tools that [syntax tree][ast]. This property can be very useful for editors and other
process code. It also has a few consequences for the design of Rust's macro tools that process code. It also has a few consequences for the design of
system. Rust's macro system.
[ast]: glossary.html#abstract-syntax-tree
One consequence is that Rust must determine, when it parses a macro invocation, One consequence is that Rust must determine, when it parses a macro invocation,
whether the macro stands in for whether the macro stands in for
@ -192,19 +194,49 @@ To keep this system simple and correct, `#[macro_use] extern crate ...` may
only appear at the root of your crate, not inside `mod`. This ensures that only appear at the root of your crate, not inside `mod`. This ensures that
`$crate` is a single identifier. `$crate` is a single identifier.
# A final note # The deep end
Macros, as currently implemented, are not for the faint of heart. Even The introductory chapter mentioned recursive macros, but it did not give the
ordinary syntax errors can be more difficult to debug when they occur inside a full story. Recursive macros are useful for another reason: Each recursive
macro, and errors caused by parse problems in generated code can be very invocation gives you another opportunity to pattern-match the macro's
tricky. Invoking the `log_syntax!` macro can help elucidate intermediate arguments.
states, invoking `trace_macros!(true)` will automatically print those
intermediate states out, and passing the flag `--pretty expanded` as a As an extreme example, it is possible, though hardly advisable, to implement
command-line argument to the compiler will show the result of expansion. the [Bitwise Cyclic Tag](http://esolangs.org/wiki/Bitwise_Cyclic_Tag) automaton
within Rust's macro system.
```rust
macro_rules! bct {
// cmd 0: d ... => ...
(0, $($ps:tt),* ; $_d:tt)
=> (bct!($($ps),*, 0 ; ));
(0, $($ps:tt),* ; $_d:tt, $($ds:tt),*)
=> (bct!($($ps),*, 0 ; $($ds),*));
// cmd 1p: 1 ... => 1 ... p
(1, $p:tt, $($ps:tt),* ; 1)
=> (bct!($($ps),*, 1, $p ; 1, $p));
(1, $p:tt, $($ps:tt),* ; 1, $($ds:tt),*)
=> (bct!($($ps),*, 1, $p ; 1, $($ds),*, $p));
// cmd 1p: 0 ... => 0 ...
(1, $p:tt, $($ps:tt),* ; $($ds:tt),*)
=> (bct!($($ps),*, 1, $p ; $($ds),*));
// halt on empty data string
( $($ps:tt),* ; )
=> (());
}
```
Exercise: use macros to reduce duplication in the above definition of the
`bct!` macro.
# Procedural macros
If Rust's macro system can't do what you need, you may want to write a If Rust's macro system can't do what you need, you may want to write a
[compiler plugin](plugins.html) instead. Compared to `macro_rules!` [compiler plugin](plugins.html) instead. Compared to `macro_rules!`
macros, this is significantly more work, the interfaces are much less stable, macros, this is significantly more work, the interfaces are much less stable,
and the warnings about debugging apply ten-fold. In exchange you get the and bugs can be much harder to track down. In exchange you get the
flexibility of running arbitrary Rust code within the compiler. Syntax flexibility of running arbitrary Rust code within the compiler. Syntax
extension plugins are sometimes called *procedural macros* for this reason. extension plugins are sometimes called *procedural macros* for this reason.

View File

@ -60,6 +60,12 @@ let v = vec![1, 2, 3]; // v: Vec<i32>
brackets `[]` with `vec!`. Rust allows you to use either in either situation, brackets `[]` with `vec!`. Rust allows you to use either in either situation,
this is just convention.) this is just convention.)
There's an alternate form of `vec!` for repeating an initial value:
```
let v = vec![0; 10]; // ten zeroes
```
You can get the length of, iterate over, and subscript vectors just like You can get the length of, iterate over, and subscript vectors just like
arrays. In addition, (mutable) vectors can grow automatically: arrays. In addition, (mutable) vectors can grow automatically:
@ -93,7 +99,4 @@ You can also take a slice of a vector, `String`, or `&str`, because they are
backed by arrays. Slices have type `&[T]`, which we'll talk about when we cover backed by arrays. Slices have type `&[T]`, which we'll talk about when we cover
generics. generics.
We have now learned all of the most basic Rust concepts. We're ready to start We have now learned all of the most basic Rust concepts.
building ourselves a guessing game, we just need to know one last thing: how to
get input from the keyboard. You can't have a guessing game without the ability
to guess!

View File

@ -0,0 +1,202 @@
% Associated Types
Associated types are a powerful part of Rust's type system. They're related to
the idea of a 'type family', in other words, grouping multiple types together. That
description is a bit abstract, so let's dive right into an example. If you want
to write a `Graph` trait, you have two types to be generic over: the node type
and the edge type. So you might write a trait, `Graph<N, E>`, that looks like
this:
```rust
trait Graph<N, E> {
fn has_edge(&self, &N, &N) -> bool;
fn edges(&self, &N) -> Vec<E>;
// etc
}
```
While this sort of works, it ends up being awkward. For example, any function
that wants to take a `Graph` as a parameter now _also_ needs to be generic over
the `N`ode and `E`dge types too:
```rust,ignore
fn distance<N, E, G: Graph<N, E>>(graph: &G, start: &N, end: &N) -> u32 { ... }
```
Our distance calculation works regardless of our `Edge` type, so the `E` stuff in
this signature is just a distraction.
What we really want to say is that a certain `E`dge and `N`ode type come together
to form each kind of `Graph`. We can do that with associated types:
```rust
trait Graph {
type N;
type E;
fn has_edge(&self, &Self::N, &Self::N) -> bool;
fn edges(&self, &Self::N) -> Vec<Self::E>;
// etc
}
```
Now, our clients can be abstract over a given `Graph`:
```rust,ignore
fn distance<G: Graph>(graph: &G, start: &G::N, end: &G::N) -> uint { ... }
```
No need to deal with the `E`dge type here!
Let's go over all this in more detail.
## Defining associated types
Let's build that `Graph` trait. Here's the definition:
```rust
trait Graph {
type N;
type E;
fn has_edge(&self, &Self::N, &Self::N) -> bool;
fn edges(&self, &Self::N) -> Vec<Self::E>;
}
```
Simple enough. Associated types use the `type` keyword, and go inside the body
of the trait, with the functions.
These `type` declarations can have all the same thing as functions do. For example,
if we wanted our `N` type to implement `Display`, so we can print the nodes out,
we could do this:
```rust
use std::fmt;
trait Graph {
type N: fmt::Display;
type E;
fn has_edge(&self, &Self::N, &Self::N) -> bool;
fn edges(&self, &Self::N) -> Vec<Self::E>;
}
```
## Implementing associated types
Just like any trait, traits that use associated types use the `impl` keyword to
provide implementations. Here's a simple implementation of Graph:
```rust
# trait Graph {
# type N;
# type E;
# fn has_edge(&self, &Self::N, &Self::N) -> bool;
# fn edges(&self, &Self::N) -> Vec<Self::E>;
# }
struct Node;
struct Edge;
struct MyGraph;
impl Graph for MyGraph {
type N = Node;
type E = Edge;
fn has_edge(&self, n1: &Node, n2: &Node) -> bool {
true
}
fn edges(&self, n: &Node) -> Vec<Edge> {
Vec::new()
}
}
```
This silly implementation always returns `true` and an empty `Vec<Edge>`, but it
gives you an idea of how to implement this kind of thing. We first need three
`struct`s, one for the graph, one for the node, and one for the edge. If it made
more sense to use a different type, that would work as well, we're just going to
use `struct`s for all three here.
Next is the `impl` line, which is just like implementing any other trait.
From here, we use `=` to define our associated types. The name the trait uses
goes on the left of the `=`, and the concrete type we're `impl`ementing this
for goes on the right. Finally, we use the concrete types in our function
declarations.
## Trait objects with associated types
Theres one more bit of syntax we should talk about: trait objects. If you
try to create a trait object from an associated type, like this:
```rust,ignore
# trait Graph {
# type N;
# type E;
# fn has_edge(&self, &Self::N, &Self::N) -> bool;
# fn edges(&self, &Self::N) -> Vec<Self::E>;
# }
# struct Node;
# struct Edge;
# struct MyGraph;
# impl Graph for MyGraph {
# type N = Node;
# type E = Edge;
# fn has_edge(&self, n1: &Node, n2: &Node) -> bool {
# true
# }
# fn edges(&self, n: &Node) -> Vec<Edge> {
# Vec::new()
# }
# }
let graph = MyGraph;
let obj = Box::new(graph) as Box<Graph>;
```
Youll get two errors:
```text
error: the value of the associated type `E` (from the trait `main::Graph`) must
be specified [E0191]
let obj = Box::new(graph) as Box<Graph>;
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
24:44 error: the value of the associated type `N` (from the trait
`main::Graph`) must be specified [E0191]
let obj = Box::new(graph) as Box<Graph>;
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
```
We cant create a trait object like this, because we dont know the associated
types. Instead, we can write this:
```rust
# trait Graph {
# type N;
# type E;
# fn has_edge(&self, &Self::N, &Self::N) -> bool;
# fn edges(&self, &Self::N) -> Vec<Self::E>;
# }
# struct Node;
# struct Edge;
# struct MyGraph;
# impl Graph for MyGraph {
# type N = Node;
# type E = Edge;
# fn has_edge(&self, n1: &Node, n2: &Node) -> bool {
# true
# }
# fn edges(&self, n: &Node) -> Vec<Edge> {
# Vec::new()
# }
# }
let graph = MyGraph;
let obj = Box::new(graph) as Box<Graph<N=Node, E=Edge>>;
```
The `N=Node` syntax allows us to provide a concrete type, `Node`, for the `N`
type parameter. Same with `E=Edge`. If we didnt proide this constraint, we
couldnt be sure which `impl` to match this trait object to.

View File

@ -1,8 +1,7 @@
% Basics % Basics
This section is a linear introduction to the basic syntax and semantics of This section is a linear introduction to the basic syntax and semantics of
Rust. It has individual sections on each part of Rust's syntax, and cumulates Rust. It has individual sections on each part of Rust's syntax.
in a small project: a guessing game.
After reading "Basics," you will have a good foundation to learn more about After reading "Basics," you will have a good foundation to learn more about
Rust, and can write very simple programs. Rust, and can write very simple programs.

View File

@ -0,0 +1,152 @@
% Benchmark tests
Rust supports benchmark tests, which can test the performance of your
code. Let's make our `src/lib.rs` look like this (comments elided):
```{rust,ignore}
#![feature(test)]
extern crate test;
pub fn add_two(a: i32) -> i32 {
a + 2
}
#[cfg(test)]
mod tests {
use super::*;
use test::Bencher;
#[test]
fn it_works() {
assert_eq!(4, add_two(2));
}
#[bench]
fn bench_add_two(b: &mut Bencher) {
b.iter(|| add_two(2));
}
}
```
Note the `test` feature gate, which enables this unstable feature.
We've imported the `test` crate, which contains our benchmarking support.
We have a new function as well, with the `bench` attribute. Unlike regular
tests, which take no arguments, benchmark tests take a `&mut Bencher`. This
`Bencher` provides an `iter` method, which takes a closure. This closure
contains the code we'd like to benchmark.
We can run benchmark tests with `cargo bench`:
```bash
$ cargo bench
Compiling adder v0.0.1 (file:///home/steve/tmp/adder)
Running target/release/adder-91b3e234d4ed382a
running 2 tests
test tests::it_works ... ignored
test tests::bench_add_two ... bench: 1 ns/iter (+/- 0)
test result: ok. 0 passed; 0 failed; 1 ignored; 1 measured
```
Our non-benchmark test was ignored. You may have noticed that `cargo bench`
takes a bit longer than `cargo test`. This is because Rust runs our benchmark
a number of times, and then takes the average. Because we're doing so little
work in this example, we have a `1 ns/iter (+/- 0)`, but this would show
the variance if there was one.
Advice on writing benchmarks:
* Move setup code outside the `iter` loop; only put the part you want to measure inside
* Make the code do "the same thing" on each iteration; do not accumulate or change state
* Make the outer function idempotent too; the benchmark runner is likely to run
it many times
* Make the inner `iter` loop short and fast so benchmark runs are fast and the
calibrator can adjust the run-length at fine resolution
* Make the code in the `iter` loop do something simple, to assist in pinpointing
performance improvements (or regressions)
## Gotcha: optimizations
There's another tricky part to writing benchmarks: benchmarks compiled with
optimizations activated can be dramatically changed by the optimizer so that
the benchmark is no longer benchmarking what one expects. For example, the
compiler might recognize that some calculation has no external effects and
remove it entirely.
```{rust,ignore}
#![feature(test)]
extern crate test;
use test::Bencher;
#[bench]
fn bench_xor_1000_ints(b: &mut Bencher) {
b.iter(|| {
(0..1000).fold(0, |old, new| old ^ new);
});
}
```
gives the following results
```text
running 1 test
test bench_xor_1000_ints ... bench: 0 ns/iter (+/- 0)
test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured
```
The benchmarking runner offers two ways to avoid this. Either, the closure that
the `iter` method receives can return an arbitrary value which forces the
optimizer to consider the result used and ensures it cannot remove the
computation entirely. This could be done for the example above by adjusting the
`b.iter` call to
```rust
# struct X;
# impl X { fn iter<T, F>(&self, _: F) where F: FnMut() -> T {} } let b = X;
b.iter(|| {
// note lack of `;` (could also use an explicit `return`).
(0..1000).fold(0, |old, new| old ^ new)
});
```
Or, the other option is to call the generic `test::black_box` function, which
is an opaque "black box" to the optimizer and so forces it to consider any
argument as used.
```rust
#![feature(test)]
extern crate test;
# fn main() {
# struct X;
# impl X { fn iter<T, F>(&self, _: F) where F: FnMut() -> T {} } let b = X;
b.iter(|| {
let n = test::black_box(1000);
(0..n).fold(0, |a, b| a ^ b)
})
# }
```
Neither of these read or modify the value, and are very cheap for small values.
Larger values can be passed indirectly to reduce overhead (e.g.
`black_box(&huge_struct)`).
Performing either of the above changes gives the following benchmarking results
```text
running 1 test
test bench_xor_1000_ints ... bench: 131 ns/iter (+/- 3)
test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured
```
However, the optimizer can still modify a testcase in an undesirable manner
even when using either of the above.

View File

@ -0,0 +1,100 @@
% Box Syntax and Patterns
Currently the only stable way to create a `Box` is via the `Box::new` method.
Also it is not possible in stable Rust to destructure a `Box` in a match
pattern. The unstable `box` keyword can be used to both create and destructure
a `Box`. An example usage would be:
```
#![feature(box_syntax, box_patterns)]
fn main() {
let b = Some(box 5);
match b {
Some(box n) if n < 0 => {
println!("Box contains negative number {}", n);
},
Some(box n) if n >= 0 => {
println!("Box contains non-negative number {}", n);
},
None => {
println!("No box");
},
_ => unreachable!()
}
}
```
Note that these features are currently hidden behind the `box_syntax` (box
creation) and `box_patterns` (destructuring and pattern matching) gates
because the syntax may still change in the future.
# Returning Pointers
In many languages with pointers, you'd return a pointer from a function
so as to avoid copying a large data structure. For example:
```{rust}
struct BigStruct {
one: i32,
two: i32,
// etc
one_hundred: i32,
}
fn foo(x: Box<BigStruct>) -> Box<BigStruct> {
Box::new(*x)
}
fn main() {
let x = Box::new(BigStruct {
one: 1,
two: 2,
one_hundred: 100,
});
let y = foo(x);
}
```
The idea is that by passing around a box, you're only copying a pointer, rather
than the hundred `int`s that make up the `BigStruct`.
This is an antipattern in Rust. Instead, write this:
```rust
#![feature(box_syntax)]
struct BigStruct {
one: i32,
two: i32,
// etc
one_hundred: i32,
}
fn foo(x: Box<BigStruct>) -> BigStruct {
*x
}
fn main() {
let x = Box::new(BigStruct {
one: 1,
two: 2,
one_hundred: 100,
});
let y: Box<BigStruct> = box foo(x);
}
```
This gives you flexibility without sacrificing performance.
You may think that this gives us terrible performance: return a value and then
immediately box it up ?! Isn't this pattern the worst of both worlds? Rust is
smarter than that. There is no copy in this code. `main` allocates enough room
for the `box`, passes a pointer to that memory into `foo` as `x`, and then
`foo` writes the value straight into the `Box<T>`.
This is important enough that it bears repeating: pointers are not for
optimizing returning values from your code. Allow the caller to choose how they
want to use your output.

View File

@ -1,214 +1,478 @@
% Closures % Closures
So far, we've made lots of functions in Rust, but we've given them all names. Rust not only has named functions, but anonymous functions as well. Anonymous
Rust also allows us to create anonymous functions. Rust's anonymous functions that have an associated environment are called 'closures', because they
functions are called *closures*. By themselves, closures aren't all that close over an environment. Rust has a really great implementation of them, as
interesting, but when you combine them with functions that take closures as we'll see.
arguments, really powerful things are possible.
Let's make a closure: # Syntax
```{rust} Closures look like this:
let add_one = |x| { 1 + x };
println!("The sum of 5 plus 1 is {}.", add_one(5)); ```rust
let plus_one = |x: i32| x + 1;
assert_eq!(2, plus_one(1));
``` ```
We create a closure using the `|...| { ... }` syntax, and then we create a We create a binding, `plus_one`, and assign it to a closure. The closure's
binding so we can use it later. Note that we call the function using the arguments go between the pipes (`|`), and the body is an expression, in this
binding name and two parentheses, just like we would for a named function. case, `x + 1`. Remember that `{ }` is an expression, so we can have multi-line
closures too:
Let's compare syntax. The two are pretty close: ```rust
let plus_two = |x| {
let mut result: i32 = x;
```{rust} result += 1;
let add_one = |x: i32| -> i32 { 1 + x }; result += 1;
fn add_one (x: i32) -> i32 { 1 + x }
result
};
assert_eq!(4, plus_two(2));
``` ```
As you may have noticed, closures infer their argument and return types, so you You'll notice a few things about closures that are a bit different than regular
don't need to declare one. This is different from named functions, which functions defined with `fn`. The first of which is that we did not need to
default to returning unit (`()`). annotate the types of arguments the closure takes or the values it returns. We
can:
There's one big difference between a closure and named functions, and it's in ```rust
the name: a closure "closes over its environment." What does that mean? It means let plus_one = |x: i32| -> i32 { x + 1 };
this:
```{rust} assert_eq!(2, plus_one(1));
```
But we don't have to. Why is this? Basically, it was chosen for ergonomic reasons.
While specifying the full type for named functions is helpful with things like
documentation and type inference, the types of closures are rarely documented
since theyre anonymous, and they dont cause the kinds of error-at-a-distance
that inferring named function types can.
The second is that the syntax is similar, but a bit different. I've added spaces
here to make them look a little closer:
```rust
fn plus_one_v1 ( x: i32 ) -> i32 { x + 1 }
let plus_one_v2 = |x: i32 | -> i32 { x + 1 };
let plus_one_v3 = |x: i32 | x + 1 ;
```
Small differences, but they're similar in ways.
# Closures and their environment
Closures are called such because they 'close over their environment.' It
looks like this:
```rust
let num = 5;
let plus_num = |x: i32| x + num;
assert_eq!(10, plus_num(5));
```
This closure, `plus_num`, refers to a `let` binding in its scope: `num`. More
specifically, it borrows the binding. If we do something that would conflict
with that binding, we get an error. Like this one:
```rust,ignore
let mut num = 5;
let plus_num = |x: i32| x + num;
let y = &mut num;
```
Which errors with:
```text
error: cannot borrow `num` as mutable because it is also borrowed as immutable
let y = &mut num;
^~~
note: previous borrow of `num` occurs here due to use in closure; the immutable
borrow prevents subsequent moves or mutable borrows of `num` until the borrow
ends
let plus_num = |x| x + num;
^~~~~~~~~~~
note: previous borrow ends here
fn main() { fn main() {
let x: i32 = 5; let mut num = 5;
let plus_num = |x| x + num;
let printer = || { println!("x is: {}", x); }; let y = &mut num;
printer(); // prints "x is: 5"
} }
^
``` ```
The `||` syntax means this is an anonymous closure that takes no arguments. A verbose yet helpful error message! As it says, we can't take a mutable borrow
Without it, we'd just have a block of code in `{}`s. on `num` because the closure is already borrowing it. If we let the closure go
out of scope, we can:
In other words, a closure has access to variables in the scope where it's ```rust
defined. The closure borrows any variables it uses, so this will error: let mut num = 5;
{
let plus_num = |x: i32| x + num;
```{rust,ignore} } // plus_num goes out of scope, borrow of num ends
fn main() {
let mut x: i32 = 5;
let printer = || { println!("x is: {}", x); }; let y = &mut num;
x = 6; // error: cannot assign to `x` because it is borrowed
}
``` ```
## Moving closures If your closure requires it, however, Rust will take ownership and move
the environment instead:
Rust has a second type of closure, called a *moving closure*. Moving ```rust,ignore
closures are indicated using the `move` keyword (e.g., `move || x * let nums = vec![1, 2, 3];
x`). The difference between a moving closure and an ordinary closure
is that a moving closure always takes ownership of all variables that
it uses. Ordinary closures, in contrast, just create a reference into
the enclosing stack frame. Moving closures are most useful with Rust's
concurrency features, and so we'll just leave it at this for
now. We'll talk about them more in the "Threads" section of the guide.
## Accepting closures as arguments let takes_nums = || nums;
Closures are most useful as an argument to another function. Here's an example: println!("{:?}", nums);
```{rust}
fn twice<F: Fn(i32) -> i32>(x: i32, f: F) -> i32 {
f(x) + f(x)
}
fn main() {
let square = |x: i32| { x * x };
twice(5, square); // evaluates to 50
}
``` ```
Let's break the example down, starting with `main`: This gives us:
```{rust} ```text
let square = |x: i32| { x * x }; note: `nums` moved into closure environment here because it has type
`[closure(()) -> collections::vec::Vec<i32>]`, which is non-copyable
let takes_nums = || nums;
^~~~~~~
``` ```
We've seen this before. We make a closure that takes an integer, and returns `Vec<T>` has ownership over its contents, and therefore, when we refer to it
its square. in our closure, we have to take ownership of `nums`. It's the same as if we'd
passed `nums` to a function that took ownership of it.
```{rust} ## `move` closures
# fn twice<F: Fn(i32) -> i32>(x: i32, f: F) -> i32 { f(x) + f(x) }
# let square = |x: i32| { x * x }; We can force our closure to take ownership of its environment with the `move`
twice(5, square); // evaluates to 50 keyword:
```rust
let num = 5;
let owns_num = move |x: i32| x + num;
``` ```
This line is more interesting. Here, we call our function, `twice`, and we pass Now, even though the keyword is `move`, the variables follow normal move semantics.
it two arguments: an integer, `5`, and our closure, `square`. This is just like In this case, `5` implements `Copy`, and so `owns_num` takes ownership of a copy
passing any other two variable bindings to a function, but if you've never of `num`. So what's the difference?
worked with closures before, it can seem a little complex. Just think: "I'm
passing two variables: one is an i32, and one is a function."
Next, let's look at how `twice` is defined: ```rust
let mut num = 5;
```{rust,ignore} {
fn twice<F: Fn(i32) -> i32>(x: i32, f: F) -> i32 { let mut add_num = |x: i32| num += x;
add_num(5);
}
assert_eq!(10, num);
``` ```
`twice` takes two arguments, `x` and `f`. That's why we called it with two So in this case, our closure took a mutable reference to `num`, and then when
arguments. `x` is an `i32`, we've done that a ton of times. `f` is a function, we called `add_num`, it mutated the underlying value, as we'd expect. We also
though, and that function takes an `i32` and returns an `i32`. This is needed to declare `add_num` as `mut` too, because were mutating its
what the requirement `Fn(i32) -> i32` for the type parameter `F` says. environment.
Now `F` represents *any* function that takes an `i32` and returns an `i32`.
This is the most complicated function signature we've seen yet! Give it a read We also had to declare `add_num` as mut, since we will be modifying its
a few times until you can see how it works. It takes a teeny bit of practice, and environment.
then it's easy. The good news is that this kind of passing a closure around
can be very efficient. With all the type information available at compile-time
the compiler can do wonders.
Finally, `twice` returns an `i32` as well. If we change to a `move` closure, it's different:
Okay, let's look at the body of `twice`: ```rust
let mut num = 5;
```{rust} {
fn twice<F: Fn(i32) -> i32>(x: i32, f: F) -> i32 { let mut add_num = move |x: i32| num += x;
f(x) + f(x)
add_num(5);
} }
assert_eq!(5, num);
``` ```
Since our closure is named `f`, we can call it just like we called our closures We only get `5`. Rather than taking a mutable borrow out on our `num`, we took
before, and we pass in our `x` argument to each one, hence the name `twice`. ownership of a copy.
If you do the math, `(5 * 5) + (5 * 5) == 50`, so that's the output we get. Another way to think about `move` closures: they give a closure its own stack
frame. Without `move`, a closure may be tied to the stack frame that created
it, while a `move` closure is self-contained. This means that you cannot
generally return a non-`move` closure from a function, for example.
Play around with this concept until you're comfortable with it. Rust's standard But before we talk about taking and returning closures, we should talk some more
library uses lots of closures where appropriate, so you'll be using about the way that closures are implemented. As a systems language, Rust gives
this technique a lot. you tons of control over what your code does, and closures are no different.
If we didn't want to give `square` a name, we could just define it inline. # Closure implementation
This example is the same as the previous one:
```{rust} Rust's implementation of closures is a bit different than other languages. They
fn twice<F: Fn(i32) -> i32>(x: i32, f: F) -> i32 { are effectively syntax sugar for traits. You'll want to make sure to have read
f(x) + f(x) the [traits chapter][traits] before this one, as well as the chapter on [static
and dynamic dispatch][dispatch], which talks about trait objects.
[traits]: traits.html
[dispatch]: static-and-dynamic-dispatch.html
Got all that? Good.
The key to understanding how closures work under the hood is something a bit
strange: Using `()` to call a function, like `foo()`, is an overloadable
operator. From this, everything else clicks into place. In Rust, we use the
trait system to overload operators. Calling functions is no different. We have
three separate traits to overload with:
```rust
# mod foo {
pub trait Fn<Args> : FnMut<Args> {
extern "rust-call" fn call(&self, args: Args) -> Self::Output;
} }
fn main() { pub trait FnMut<Args> : FnOnce<Args> {
twice(5, |x: i32| { x * x }); // evaluates to 50 extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output;
} }
pub trait FnOnce<Args> {
type Output;
extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
}
# }
``` ```
A named function's name can be used wherever you'd use a closure. Another You'll notice a few differences between these traits, but a big one is `self`:
way of writing the previous example: `Fn` takes `&self`, `FnMut` takes `&mut self`, and `FnOnce` takes `self`. This
covers all three kinds of `self` via the usual method call syntax. But we've
split them up into three traits, rather than having a single one. This gives us
a large amount of control over what kind of closures we can take.
```{rust} The `|| {}` syntax for closures is sugar for these three traits. Rust will
fn twice<F: Fn(i32) -> i32>(x: i32, f: F) -> i32 { generate a struct for the environment, `impl` the appropriate trait, and then
f(x) + f(x) use it.
# Taking closures as arguments
Now that we know that closures are traits, we already know how to accept and
return closures: just like any other trait!
This also means that we can choose static vs dynamic dispatch as well. First,
let's write a function which takes something callable, calls it, and returns
the result:
```rust
fn call_with_one<F>(some_closure: F) -> i32
where F : Fn(i32) -> i32 {
some_closure(1)
} }
fn square(x: i32) -> i32 { x * x } let answer = call_with_one(|x| x + 2);
fn main() { assert_eq!(3, answer);
twice(5, square); // evaluates to 50
}
``` ```
Doing this is not particularly common, but it's useful every once in a while. We pass our closure, `|x| x + 2`, to `call_with_one`. It just does what it
suggests: it calls the closure, giving it `1` as an argument.
Before we move on, let us look at a function that accepts two closures. Let's examine the signature of `call_with_one` in more depth:
```{rust} ```rust
fn compose<F, G>(x: i32, f: F, g: G) -> i32 fn call_with_one<F>(some_closure: F) -> i32
where F: Fn(i32) -> i32, G: Fn(i32) -> i32 { # where F : Fn(i32) -> i32 {
g(f(x)) # some_closure(1) }
}
fn main() {
compose(5,
|n: i32| { n + 42 },
|n: i32| { n * 2 }); // evaluates to 94
}
``` ```
You might ask yourself: why do we need to introduce two type We take one parameter, and it has the type `F`. We also return a `i32`. This part
parameters `F` and `G` here? Evidently, both `f` and `g` have the isn't interesting. The next part is:
same signature: `Fn(i32) -> i32`.
That is because in Rust each closure has its own unique type. ```rust
So, not only do closures with different signatures have different types, # fn call_with_one<F>(some_closure: F) -> i32
but different closures with the *same* signature have *different* where F : Fn(i32) -> i32 {
types, as well! # some_closure(1) }
```
You can think of it this way: the behavior of a closure is part of its Because `Fn` is a trait, we can bound our generic with it. In this case, our closure
type. Therefore, using a single type parameter for both closures takes a `i32` as an argument and returns an `i32`, and so the generic bound we use
will accept the first of them, rejecting the second. The distinct is `Fn(i32) -> i32`.
type of the second closure does not allow it to be represented by the
same type parameter as that of the first. We acknowledge this, and
use two different type parameters `F` and `G`.
This also introduces the `where` clause, which lets us describe type There's one other key point here: because we're bounding a generic with a
parameters in a more flexible manner. trait, this will get monomorphized, and therefore, we'll be doing static
dispatch into the closure. That's pretty neat. In many langauges, closures are
inherently heap allocated, and will always involve dynamic dispatch. In Rust,
we can stack allocate our closure environment, and statically dispatch the
call. This happens quite often with iterators and their adapters, which often
take closures as arguments.
That's all you need to get the hang of closures! Closures are a little bit Of course, if we want dynamic dispatch, we can get that too. A trait object
strange at first, but once you're used to them, you'll miss them handles this case, as usual:
in other languages. Passing functions to other functions is
incredibly powerful, as you will see in the following chapter about iterators. ```rust
fn call_with_one(some_closure: &Fn(i32) -> i32) -> i32 {
some_closure(1)
}
let answer = call_with_one(&|x| x + 2);
assert_eq!(3, answer);
```
Now we take a trait object, a `&Fn`. And we have to make a reference
to our closure when we pass it to `call_with_one`, so we use `&||`.
# Returning closures
Its very common for functional-style code to return closures in various
situations. If you try to return a closure, you may run into an error. At
first, it may seem strange, but we'll figure it out. Here's how you'd probably
try to return a closure from a function:
```rust,ignore
fn factory() -> (Fn(i32) -> Vec<i32>) {
let vec = vec![1, 2, 3];
|n| vec.push(n)
}
let f = factory();
let answer = f(4);
assert_eq!(vec![1, 2, 3, 4], answer);
```
This gives us these long, related errors:
```text
error: the trait `core::marker::Sized` is not implemented for the type
`core::ops::Fn(i32) -> collections::vec::Vec<i32>` [E0277]
f = factory();
^
note: `core::ops::Fn(i32) -> collections::vec::Vec<i32>` does not have a
constant size known at compile-time
f = factory();
^
error: the trait `core::marker::Sized` is not implemented for the type
`core::ops::Fn(i32) -> collections::vec::Vec<i32>` [E0277]
factory() -> (Fn(i32) -> Vec<i32>) {
^~~~~~~~~~~~~~~~~~~~~
note: `core::ops::Fn(i32) -> collections::vec::Vec<i32>` does not have a constant size known at compile-time
fa ctory() -> (Fn(i32) -> Vec<i32>) {
^~~~~~~~~~~~~~~~~~~~~
```
In order to return something from a function, Rust needs to know what
size the return type is. But since `Fn` is a trait, it could be various
things of various sizes: many different types can implement `Fn`. An easy
way to give something a size is to take a reference to it, as references
have a known size. So we'd write this:
```rust,ignore
fn factory() -> &(Fn(i32) -> Vec<i32>) {
let vec = vec![1, 2, 3];
|n| vec.push(n)
}
let f = factory();
let answer = f(4);
assert_eq!(vec![1, 2, 3, 4], answer);
```
But we get another error:
```text
error: missing lifetime specifier [E0106]
fn factory() -> &(Fn(i32) -> i32) {
^~~~~~~~~~~~~~~~~
```
Right. Because we have a reference, we need to give it a lifetime. But
our `factory()` function takes no arguments, so elision doesn't kick in
here. What lifetime can we choose? `'static`:
```rust,ignore
fn factory() -> &'static (Fn(i32) -> i32) {
let num = 5;
|x| x + num
}
let f = factory();
let answer = f(1);
assert_eq!(6, answer);
```
But we get another error:
```text
error: mismatched types:
expected `&'static core::ops::Fn(i32) -> i32`,
found `[closure <anon>:7:9: 7:20]`
(expected &-ptr,
found closure) [E0308]
|x| x + num
^~~~~~~~~~~
```
This error is letting us know that we don't have a `&'static Fn(i32) -> i32`,
we have a `[closure <anon>:7:9: 7:20]`. Wait, what?
Because each closure generates its own environment `struct` and implementation
of `Fn` and friends, these types are anonymous. They exist just solely for
this closure. So Rust shows them as `closure <anon>`, rather than some
autogenerated name.
But why doesn't our closure implement `&'static Fn`? Well, as we discussed before,
closures borrow their environment. And in this case, our environment is based
on a stack-allocated `5`, the `num` variable binding. So the borrow has a lifetime
of the stack frame. So if we returned this closure, the function call would be
over, the stack frame would go away, and our closure is capturing an environment
of garbage memory!
So what to do? This _almost_ works:
```rust,ignore
fn factory() -> Box<Fn(i32) -> i32> {
let num = 5;
Box::new(|x| x + num)
}
# fn main() {
let f = factory();
let answer = f(1);
assert_eq!(6, answer);
# }
```
We use a trait object, by `Box`ing up the `Fn`. There's just one last problem:
```text
error: `num` does not live long enough
Box::new(|x| x + num)
^~~~~~~~~~~
```
We still have a reference to the parent stack frame. With one last fix, we can
make this work:
```rust
fn factory() -> Box<Fn(i32) -> i32> {
let num = 5;
Box::new(move |x| x + num)
}
# fn main() {
let f = factory();
let answer = f(1);
assert_eq!(6, answer);
# }
```
By making the inner closure a `move Fn`, we create a new stack frame for our
closure. By `Box`ing it up, we've given it a known size, and allowing it to
escape our stack frame.

View File

@ -28,7 +28,7 @@ The other kind of comment is a doc comment. Doc comments use `///` instead of
/// ///
/// * `name` - The name of the person you'd like to greet. /// * `name` - The name of the person you'd like to greet.
/// ///
/// # Example /// # Examples
/// ///
/// ```rust /// ```rust
/// let name = "Steve"; /// let name = "Steve";

View File

@ -6,8 +6,8 @@ strings, but next, let's talk about some more complicated ways of storing data.
## Tuples ## Tuples
The first compound data type we're going to talk about are called *tuples*. The first compound data type we're going to talk about is called the *tuple*.
Tuples are an ordered list of a fixed size. Like this: A tuple is an ordered list of fixed size. Like this:
```rust ```rust
let x = (1, "hello"); let x = (1, "hello");
@ -47,7 +47,7 @@ This pattern is very powerful, and we'll see it repeated more later.
There are also a few things you can do with a tuple as a whole, without There are also a few things you can do with a tuple as a whole, without
destructuring. You can assign one tuple into another, if they have the same destructuring. You can assign one tuple into another, if they have the same
contained types and arity. Tuples have the same arity when they have the same contained types and [arity]. Tuples have the same arity when they have the same
length. length.
```rust ```rust
@ -196,8 +196,9 @@ Now, we have actual names, rather than positions. Good names are important,
and with a struct, we have actual names. and with a struct, we have actual names.
There _is_ one case when a tuple struct is very useful, though, and that's a There _is_ one case when a tuple struct is very useful, though, and that's a
tuple struct with only one element. We call this a *newtype*, because it lets tuple struct with only one element. We call this the *newtype* pattern, because
you create a new type that's similar to another one: it allows you to create a new type, distinct from that of its contained value
and expressing its own semantic meaning:
```{rust} ```{rust}
struct Inches(i32); struct Inches(i32);
@ -216,7 +217,7 @@ destructuring `let`, as we discussed previously in 'tuples.' In this case, the
Finally, Rust has a "sum type", an *enum*. Enums are an incredibly useful Finally, Rust has a "sum type", an *enum*. Enums are an incredibly useful
feature of Rust, and are used throughout the standard library. An `enum` is feature of Rust, and are used throughout the standard library. An `enum` is
a type which ties a set of alternates to a specific name. For example, below a type which relates a set of alternates to a specific name. For example, below
we define `Character` to be either a `Digit` or something else. These we define `Character` to be either a `Digit` or something else. These
can be used via their fully scoped names: `Character::Other` (more about `::` can be used via their fully scoped names: `Character::Other` (more about `::`
below). below).
@ -228,8 +229,8 @@ enum Character {
} }
``` ```
An `enum` variant can be defined as most normal types. Below are some example Most normal types are allowed as the variant components of an `enum`. Here are
types have been listed which also would be allowed in an `enum`. some examples:
```rust ```rust
struct Empty; struct Empty;
@ -239,15 +240,15 @@ struct Status { Health: i32, Mana: i32, Attack: i32, Defense: i32 }
struct HeightDatabase(Vec<i32>); struct HeightDatabase(Vec<i32>);
``` ```
So you see that depending on the sub-datastructure, the `enum` variant, same as You see that, depending on its type, an `enum` variant may or may not hold data.
a struct, may or may not hold data. That is, in `Character`, `Digit` is a name In `Character`, for instance, `Digit` gives a meaningful name for an `i32`
tied to an `i32` where `Other` is just a name. However, the fact that they are value, where `Other` is only a name. However, the fact that they represent
distinct makes this very useful. distinct categories of `Character` is a very useful property.
As with structures, enums don't by default have access to operators such as As with structures, the variants of an enum by default are not comparable with
compare ( `==` and `!=`), binary operations (`*` and `+`), and order equality operators (`==`, `!=`), have no ordering (`<`, `>=`, etc.), and do not
(`<` and `>=`). As such, using the previous `Character` type, the support other binary operations such as `*` and `+`. As such, the following code
following code is invalid: is invalid for the example `Character` type:
```{rust,ignore} ```{rust,ignore}
// These assignments both succeed // These assignments both succeed
@ -265,9 +266,10 @@ let four_equals_ten = four == ten;
``` ```
This may seem rather limiting, but it's a limitation which we can overcome. This may seem rather limiting, but it's a limitation which we can overcome.
There are two ways: by implementing equality ourselves, or by using the There are two ways: by implementing equality ourselves, or by pattern matching
[`match`][match] keyword. We don't know enough about Rust to implement equality variants with [`match`][match] expressions, which you'll learn in the next
yet, but we can use the `Ordering` enum from the standard library, which does: chapter. We don't know enough about Rust to implement equality yet, but we can
use the `Ordering` enum from the standard library, which does:
``` ```
enum Ordering { enum Ordering {
@ -277,9 +279,8 @@ enum Ordering {
} }
``` ```
Because we did not define `Ordering`, we must import it (from the std Because `Ordering` has already been defined for us, we will import it with the
library) with the `use` keyword. Here's an example of how `Ordering` is `use` keyword. Here's an example of how it is used:
used:
```{rust} ```{rust}
use std::cmp::Ordering; use std::cmp::Ordering;
@ -313,17 +314,17 @@ the standard library if you need them.
Okay, let's talk about the actual code in the example. `cmp` is a function that Okay, let's talk about the actual code in the example. `cmp` is a function that
compares two things, and returns an `Ordering`. We return either compares two things, and returns an `Ordering`. We return either
`Ordering::Less`, `Ordering::Greater`, or `Ordering::Equal`, depending on if `Ordering::Less`, `Ordering::Greater`, or `Ordering::Equal`, depending on
the two values are less, greater, or equal. Note that each variant of the whether the first value is less than, greater than, or equal to the second. Note
`enum` is namespaced under the `enum` itself: it's `Ordering::Greater` not that each variant of the `enum` is namespaced under the `enum` itself: it's
`Greater`. `Ordering::Greater`, not `Greater`.
The `ordering` variable has the type `Ordering`, and so contains one of the The `ordering` variable has the type `Ordering`, and so contains one of the
three values. We then do a bunch of `if`/`else` comparisons to check which three values. We then do a bunch of `if`/`else` comparisons to check which
one it is. one it is.
This `Ordering::Greater` notation is too long. Let's use `use` to import the This `Ordering::Greater` notation is too long. Let's use another form of `use`
`enum` variants instead. This will avoid full scoping: to import the `enum` variants instead. This will avoid full scoping:
```{rust} ```{rust}
use std::cmp::Ordering::{self, Equal, Less, Greater}; use std::cmp::Ordering::{self, Equal, Less, Greater};
@ -347,16 +348,17 @@ fn main() {
``` ```
Importing variants is convenient and compact, but can also cause name conflicts, Importing variants is convenient and compact, but can also cause name conflicts,
so do this with caution. It's considered good style to rarely import variants so do this with caution. For this reason, it's normally considered better style
for this reason. to `use` an enum rather than its variants directly.
As you can see, `enum`s are quite a powerful tool for data representation, and are As you can see, `enum`s are quite a powerful tool for data representation, and
even more useful when they're [generic][generics] across types. Before we are even more useful when they're [generic][generics] across types. Before we
get to generics, though, let's talk about how to use them with pattern matching, a get to generics, though, let's talk about how to use enums with pattern
tool that will let us deconstruct this sum type (the type theory term for enums) matching, a tool that will let us deconstruct sum types (the type theory term
in a very elegant way and avoid all these messy `if`/`else`s. for enums) like `Ordering` in a very elegant way that avoids all these messy
and brittle `if`/`else`s.
[arity]: ./glossary.html#arity
[match]: ./match.html [match]: ./match.html
[game]: ./guessing-game.html#comparing-guesses
[generics]: ./generics.html [generics]: ./generics.html

View File

@ -40,14 +40,14 @@ us enforce that it can't leave the current thread.
### `Sync` ### `Sync`
The second of these two trait is called [`Sync`](../std/marker/trait.Sync.html). The second of these traits is called [`Sync`](../std/marker/trait.Sync.html).
When a type `T` implements `Sync`, it indicates to the compiler that something When a type `T` implements `Sync`, it indicates to the compiler that something
of this type has no possibility of introducing memory unsafety when used from of this type has no possibility of introducing memory unsafety when used from
multiple threads concurrently. multiple threads concurrently.
For example, sharing immutable data with an atomic reference count is For example, sharing immutable data with an atomic reference count is
threadsafe. Rust provides a type like this, `Arc<T>`, and it implements `Sync`, threadsafe. Rust provides a type like this, `Arc<T>`, and it implements `Sync`,
so that it could be safely shared between threads. so it is safe to share between threads.
These two traits allow you to use the type system to make strong guarantees These two traits allow you to use the type system to make strong guarantees
about the properties of your code under concurrency. Before we demonstrate about the properties of your code under concurrency. Before we demonstrate
@ -69,7 +69,7 @@ fn main() {
} }
``` ```
The `Thread::scoped()` method accepts a closure, which is executed in a new The `thread::scoped()` method accepts a closure, which is executed in a new
thread. It's called `scoped` because this thread returns a join guard: thread. It's called `scoped` because this thread returns a join guard:
``` ```
@ -88,6 +88,7 @@ When `guard` goes out of scope, it will block execution until the thread is
finished. If we didn't want this behaviour, we could use `thread::spawn()`: finished. If we didn't want this behaviour, we could use `thread::spawn()`:
``` ```
# #![feature(old_io, std_misc)]
use std::thread; use std::thread;
use std::old_io::timer; use std::old_io::timer;
use std::time::Duration; use std::time::Duration;
@ -146,6 +147,7 @@ As an example, here is a Rust program that would have a data race in many
languages. It will not compile: languages. It will not compile:
```ignore ```ignore
# #![feature(old_io, std_misc)]
use std::thread; use std::thread;
use std::old_io::timer; use std::old_io::timer;
use std::time::Duration; use std::time::Duration;
@ -185,6 +187,7 @@ only one person at a time can mutate what's inside. For that, we can use the
but for a different reason: but for a different reason:
```ignore ```ignore
# #![feature(old_io, std_misc)]
use std::thread; use std::thread;
use std::old_io::timer; use std::old_io::timer;
use std::time::Duration; use std::time::Duration;
@ -208,10 +211,10 @@ Here's the error:
```text ```text
<anon>:11:9: 11:22 error: the trait `core::marker::Send` is not implemented for the type `std::sync::mutex::MutexGuard<'_, collections::vec::Vec<u32>>` [E0277] <anon>:11:9: 11:22 error: the trait `core::marker::Send` is not implemented for the type `std::sync::mutex::MutexGuard<'_, collections::vec::Vec<u32>>` [E0277]
<anon>:11 Thread::spawn(move || { <anon>:11 thread::spawn(move || {
^~~~~~~~~~~~~ ^~~~~~~~~~~~~
<anon>:11:9: 11:22 note: `std::sync::mutex::MutexGuard<'_, collections::vec::Vec<u32>>` cannot be sent between threads safely <anon>:11:9: 11:22 note: `std::sync::mutex::MutexGuard<'_, collections::vec::Vec<u32>>` cannot be sent between threads safely
<anon>:11 Thread::spawn(move || { <anon>:11 thread::spawn(move || {
^~~~~~~~~~~~~ ^~~~~~~~~~~~~
``` ```
@ -223,19 +226,13 @@ method which has this signature:
fn lock(&self) -> LockResult<MutexGuard<T>> fn lock(&self) -> LockResult<MutexGuard<T>>
``` ```
If we [look at the code for MutexGuard](https://github.com/rust-lang/rust/blob/ca4b9674c26c1de07a2042cb68e6a062d7184cef/src/libstd/sync/mutex.rs#L172), we'll see Because `Send` is not implemented for `MutexGuard<T>`, we can't transfer the
this: guard across thread boundaries, which gives us our error.
```ignore
__marker: marker::NoSend,
```
Because our guard is `NoSend`, it's not `Send`. Which means we can't actually
transfer the guard across thread boundaries, which gives us our error.
We can use `Arc<T>` to fix this. Here's the working version: We can use `Arc<T>` to fix this. Here's the working version:
``` ```
# #![feature(old_io, std_misc)]
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use std::thread; use std::thread;
use std::old_io::timer; use std::old_io::timer;
@ -261,6 +258,7 @@ handle is then moved into the new thread. Let's examine the body of the
thread more closely: thread more closely:
``` ```
# #![feature(old_io, std_misc)]
# use std::sync::{Arc, Mutex}; # use std::sync::{Arc, Mutex};
# use std::thread; # use std::thread;
# use std::old_io::timer; # use std::old_io::timer;
@ -282,13 +280,15 @@ it returns an `Result<T, E>`, and because this is just an example, we `unwrap()`
it to get a reference to the data. Real code would have more robust error handling it to get a reference to the data. Real code would have more robust error handling
here. We're then free to mutate it, since we have the lock. here. We're then free to mutate it, since we have the lock.
This timer bit is a bit awkward, however. We have picked a reasonable amount of Lastly, while the threads are running, we wait on a short timer. But
time to wait, but it's entirely possible that we've picked too high, and that this is not ideal: we may have picked a reasonable amount of time to
we could be taking less time. It's also possible that we've picked too low, wait but it's more likely we'll either be waiting longer than
and that we aren't actually finishing this computation. necessary or not long enough, depending on just how much time the
threads actually take to finish computing when the program runs.
Rust's standard library provides a few more mechanisms for two threads to A more precise alternative to the timer would be to use one of the
synchronize with each other. Let's talk about one: channels. mechanisms provided by the Rust standard library for synchronizing
threads with each other. Let's talk about one of them: channels.
## Channels ## Channels
@ -329,7 +329,6 @@ While this channel is just sending a generic signal, we can send any data that
is `Send` over the channel! is `Send` over the channel!
``` ```
use std::sync::{Arc, Mutex};
use std::thread; use std::thread;
use std::sync::mpsc; use std::sync::mpsc;
@ -346,7 +345,7 @@ fn main() {
}); });
} }
rx.recv().ok().expect("Could not recieve answer"); rx.recv().ok().expect("Could not receive answer");
} }
``` ```

View File

@ -1,6 +1,6 @@
% Crates and Modules % Crates and Modules
When a project starts getting large, it's considered a good software When a project starts getting large, it's considered good software
engineering practice to split it up into a bunch of smaller pieces, and then engineering practice to split it up into a bunch of smaller pieces, and then
fit them together. It's also important to have a well-defined interface, so fit them together. It's also important to have a well-defined interface, so
that some of your functionality is private, and some is public. To facilitate that some of your functionality is private, and some is public. To facilitate
@ -12,7 +12,7 @@ Rust has two distinct terms that relate to the module system: *crate* and
*module*. A crate is synonymous with a *library* or *package* in other *module*. A crate is synonymous with a *library* or *package* in other
languages. Hence "Cargo" as the name of Rust's package management tool: you languages. Hence "Cargo" as the name of Rust's package management tool: you
ship your crates to others with Cargo. Crates can produce an executable or a ship your crates to others with Cargo. Crates can produce an executable or a
shared library, depending on the project. library, depending on the project.
Each crate has an implicit *root module* that contains the code for that crate. Each crate has an implicit *root module* that contains the code for that crate.
You can then define a tree of sub-modules under that root module. Modules allow You can then define a tree of sub-modules under that root module. Modules allow
@ -28,15 +28,15 @@ two languages for those phrases to be in. We'll use this module layout:
+---| greetings | +---| greetings |
| +-----------+ | +-----------+
+---------+ | +---------+ |
| english |---+ +---| english |---+
+---------+ | +-----------+ | +---------+ | +-----------+
| +---| farewells | | +---| farewells |
+---------+ | +-----------+ +---------+ | +-----------+
| phrases |---+ | phrases |---+
+---------+ | +-----------+ +---------+ | +-----------+
| +---| greetings | | +---| greetings |
+----------+ | +-----------+ | +----------+ | +-----------+
| japanese |---+ +---| japanese |--+
+----------+ | +----------+ |
| +-----------+ | +-----------+
+---| farewells | +---| farewells |
@ -76,25 +76,19 @@ To define each of our modules, we use the `mod` keyword. Let's make our
`src/lib.rs` look like this: `src/lib.rs` look like this:
``` ```
// in src/lib.rs
mod english { mod english {
mod greetings { mod greetings {
} }
mod farewells { mod farewells {
} }
} }
mod japanese { mod japanese {
mod greetings { mod greetings {
} }
mod farewells { mod farewells {
} }
} }
``` ```
@ -145,11 +139,7 @@ mod english;
``` ```
If we do that, Rust will expect to find either a `english.rs` file, or a If we do that, Rust will expect to find either a `english.rs` file, or a
`english/mod.rs` file with the contents of our module: `english/mod.rs` file with the contents of our module.
```{rust,ignore}
// contents of our module go here
```
Note that in these files, you don't need to re-declare the module: that's Note that in these files, you don't need to re-declare the module: that's
already been done with the initial `mod` declaration. already been done with the initial `mod` declaration.
@ -181,10 +171,7 @@ $ tree .
`src/lib.rs` is our crate root, and looks like this: `src/lib.rs` is our crate root, and looks like this:
```{rust,ignore} ```{rust,ignore}
// in src/lib.rs
mod english; mod english;
mod japanese; mod japanese;
``` ```
@ -195,10 +182,7 @@ chosen the second. Both `src/english/mod.rs` and `src/japanese/mod.rs` look
like this: like this:
```{rust,ignore} ```{rust,ignore}
// both src/english/mod.rs and src/japanese/mod.rs
mod greetings; mod greetings;
mod farewells; mod farewells;
``` ```
@ -214,8 +198,6 @@ both empty at the moment. Let's add some functions.
Put this in `src/english/greetings.rs`: Put this in `src/english/greetings.rs`:
```rust ```rust
// in src/english/greetings.rs
fn hello() -> String { fn hello() -> String {
"Hello!".to_string() "Hello!".to_string()
} }
@ -224,8 +206,6 @@ fn hello() -> String {
Put this in `src/english/farewells.rs`: Put this in `src/english/farewells.rs`:
```rust ```rust
// in src/english/farewells.rs
fn goodbye() -> String { fn goodbye() -> String {
"Goodbye.".to_string() "Goodbye.".to_string()
} }
@ -248,8 +228,6 @@ about the module system.
Put this in `src/japanese/farewells.rs`: Put this in `src/japanese/farewells.rs`:
```rust ```rust
// in src/japanese/farewells.rs
fn goodbye() -> String { fn goodbye() -> String {
"さようなら".to_string() "さようなら".to_string()
} }
@ -265,11 +243,9 @@ another crate.
We have a library crate. Let's make an executable crate that imports and uses We have a library crate. Let's make an executable crate that imports and uses
our library. our library.
Make a `src/main.rs` and put this in it: (it won't quite compile yet) Make a `src/main.rs` and put this in it (it won't quite compile yet):
```rust,ignore ```rust,ignore
// in src/main.rs
extern crate phrases; extern crate phrases;
fn main() { fn main() {
@ -320,8 +296,6 @@ keyword. Let's focus on the `english` module first, so let's reduce our `src/mai
to just this: to just this:
```{rust,ignore} ```{rust,ignore}
// in src/main.rs
extern crate phrases; extern crate phrases;
fn main() { fn main() {
@ -333,28 +307,20 @@ fn main() {
In our `src/lib.rs`, let's add `pub` to the `english` module declaration: In our `src/lib.rs`, let's add `pub` to the `english` module declaration:
```{rust,ignore} ```{rust,ignore}
// in src/lib.rs
pub mod english; pub mod english;
mod japanese; mod japanese;
``` ```
And in our `src/english/mod.rs`, let's make both `pub`: And in our `src/english/mod.rs`, let's make both `pub`:
```{rust,ignore} ```{rust,ignore}
// in src/english/mod.rs
pub mod greetings; pub mod greetings;
pub mod farewells; pub mod farewells;
``` ```
In our `src/english/greetings.rs`, let's add `pub` to our `fn` declaration: In our `src/english/greetings.rs`, let's add `pub` to our `fn` declaration:
```{rust,ignore} ```{rust,ignore}
// in src/english/greetings.rs
pub fn hello() -> String { pub fn hello() -> String {
"Hello!".to_string() "Hello!".to_string()
} }
@ -363,8 +329,6 @@ pub fn hello() -> String {
And also in `src/english/farewells.rs`: And also in `src/english/farewells.rs`:
```{rust,ignore} ```{rust,ignore}
// in src/english/farewells.rs
pub fn goodbye() -> String { pub fn goodbye() -> String {
"Goodbye.".to_string() "Goodbye.".to_string()
} }
@ -400,8 +364,6 @@ Rust has a `use` keyword, which allows us to import names into our local scope.
Let's change our `src/main.rs` to look like this: Let's change our `src/main.rs` to look like this:
```{rust,ignore} ```{rust,ignore}
// in src/main.rs
extern crate phrases; extern crate phrases;
use phrases::english::greetings; use phrases::english::greetings;
@ -430,7 +392,7 @@ fn main() {
} }
``` ```
But it is not idiomatic. This is significantly more likely to introducing a But it is not idiomatic. This is significantly more likely to introduce a
naming conflict. In our short program, it's not a big deal, but as it grows, it naming conflict. In our short program, it's not a big deal, but as it grows, it
becomes a problem. If we have conflicting names, Rust will give a compilation becomes a problem. If we have conflicting names, Rust will give a compilation
error. For example, if we made the `japanese` functions public, and tried to do error. For example, if we made the `japanese` functions public, and tried to do
@ -460,21 +422,19 @@ Could not compile `phrases`.
``` ```
If we're importing multiple names from the same module, we don't have to type it out If we're importing multiple names from the same module, we don't have to type it out
twice. Rust has a shortcut syntax for writing this: twice. Instead of this:
```{rust,ignore} ```{rust,ignore}
use phrases::english::greetings; use phrases::english::greetings;
use phrases::english::farewells; use phrases::english::farewells;
``` ```
You use curly braces: We can use this shortcut:
```{rust,ignore} ```{rust,ignore}
use phrases::english::{greetings, farewells}; use phrases::english::{greetings, farewells};
``` ```
These two declarations are equivalent, but the second is a lot less typing.
## Re-exporting with `pub use` ## Re-exporting with `pub use`
You don't just use `use` to shorten identifiers. You can also use it inside of your crate You don't just use `use` to shorten identifiers. You can also use it inside of your crate
@ -484,8 +444,6 @@ interface that may not directly map to your internal code organization.
Let's look at an example. Modify your `src/main.rs` to read like this: Let's look at an example. Modify your `src/main.rs` to read like this:
```{rust,ignore} ```{rust,ignore}
// in src/main.rs
extern crate phrases; extern crate phrases;
use phrases::english::{greetings,farewells}; use phrases::english::{greetings,farewells};
@ -503,18 +461,13 @@ fn main() {
Then, modify your `src/lib.rs` to make the `japanese` mod public: Then, modify your `src/lib.rs` to make the `japanese` mod public:
```{rust,ignore} ```{rust,ignore}
// in src/lib.rs
pub mod english; pub mod english;
pub mod japanese; pub mod japanese;
``` ```
Next, make the two functions public, first in `src/japanese/greetings.rs`: Next, make the two functions public, first in `src/japanese/greetings.rs`:
```{rust,ignore} ```{rust,ignore}
// in src/japanese/greetings.rs
pub fn hello() -> String { pub fn hello() -> String {
"こんにちは".to_string() "こんにちは".to_string()
} }
@ -523,8 +476,6 @@ pub fn hello() -> String {
And then in `src/japanese/farewells.rs`: And then in `src/japanese/farewells.rs`:
```{rust,ignore} ```{rust,ignore}
// in src/japanese/farewells.rs
pub fn goodbye() -> String { pub fn goodbye() -> String {
"さようなら".to_string() "さようなら".to_string()
} }
@ -533,13 +484,10 @@ pub fn goodbye() -> String {
Finally, modify your `src/japanese/mod.rs` to read like this: Finally, modify your `src/japanese/mod.rs` to read like this:
```{rust,ignore} ```{rust,ignore}
// in src/japanese/mod.rs
pub use self::greetings::hello; pub use self::greetings::hello;
pub use self::farewells::goodbye; pub use self::farewells::goodbye;
mod greetings; mod greetings;
mod farewells; mod farewells;
``` ```
@ -555,6 +503,18 @@ Here we have a `pub use` for each function we want to bring into the
`japanese` scope. We could alternatively use the wildcard syntax to include `japanese` scope. We could alternatively use the wildcard syntax to include
everything from `greetings` into the current scope: `pub use self::greetings::*`. everything from `greetings` into the current scope: `pub use self::greetings::*`.
What about the `self`? Well, by default, `use` declarations are absolute paths,
starting from your crate root. `self` makes that path relative to your current
place in the hierarchy instead. There's one more special form of `use`: you can
`use super::` to reach one level up the tree from your current location. Some
people like to think of `self` as `.` and `super` as `..`, from many shells'
display for the current directory and the parent directory.
Outside of `use`, paths are relative: `foo::bar()` refers to a function inside
of `foo` relative to where we are. If that's prefixed with `::`, as in
`::foo::bar()`, it refers to a different `foo`, an absolute path from your
crate root.
Also, note that we `pub use`d before we declared our `mod`s. Rust requires that Also, note that we `pub use`d before we declared our `mod`s. Rust requires that
`use` declarations go first. `use` declarations go first.

View File

@ -1,224 +1,223 @@
% Documentation % Documentation
`rustdoc` is the built-in tool for generating documentation. It integrates Documentation is an important part of any software project, and it's
with the compiler to provide accurate hyperlinking between usage of types and first-class in Rust. Let's talk about the tooling Rust gives you to
their documentation. Furthermore, by not using a separate parser, it will document your project.
never reject your valid Rust code.
# Creating Documentation ## About `rustdoc`
Documenting Rust APIs is quite simple. To document a given item, we have "doc The Rust distribution includes a tool, `rustdoc`, that generates documentation.
comments": `rustdoc` is also used by Cargo through `cargo doc`.
~~~ Documentation can be generated in two ways: from source code, and from
# #![allow(unused_attribute)] standalone Markdown files.
// the "link" crate attribute is currently required for rustdoc, but normally
// isn't needed.
#![crate_id = "universe"]
#![crate_type= "lib"]
//! Tools for dealing with universes (this is a doc comment, and is shown on ## Documenting source code
//! the crate index page. The ! makes it apply to the parent of the comment,
//! rather than what follows).
# mod workaround_the_outer_function_rustdoc_inserts { The primary way of documenting a Rust project is through annotating the source
/// Widgets are very common (this is a doc comment, and will show up on code. You can use documentation comments for this purpose:
/// Widget's documentation).
pub struct Widget {
/// All widgets have a purpose (this is a doc comment, and will show up
/// the field's documentation).
purpose: String,
/// Humans are not allowed to understand some widgets
understandable: bool
}
pub fn recalibrate() { ```rust,ignore
//! Recalibrate a pesky universe (this is also a doc comment, like above, /// Constructs a new `Rc<T>`.
//! the documentation will be applied to the *parent* item, so
//! `recalibrate`).
/* ... */
}
# }
~~~
Documentation can also be controlled via the `doc` attribute on items. This is
implicitly done by the compiler when using the above form of doc comments
(converting the slash-based comments to `#[doc]` attributes).
~~~
#[doc = "
Calculates the factorial of a number.
Given the input integer `n`, this function will calculate `n!` and return it.
"]
pub fn factorial(n: int) -> int { if n < 2 {1} else {n * factorial(n - 1)} }
# fn main() {}
~~~
The `doc` attribute can also be used to control how rustdoc emits documentation
in some cases.
```
// Rustdoc will inline documentation of a `pub use` into this crate when the
// `pub use` reaches across crates, but this behavior can also be disabled.
#[doc(no_inline)]
pub use std::option::Option;
# fn main() {}
```
Doc comments are markdown, and are currently parsed with the
[hoedown][hoedown] library. rustdoc does not yet do any fanciness such as
referencing other items inline, like javadoc's `@see`. One exception to this
is that the first paragraph will be used as the "summary" of an item in the
generated documentation:
~~~
/// A whizbang. Does stuff. (this line is the summary)
/// ///
/// Whizbangs are ... /// # Examples
struct Whizbang; ///
~~~ /// ```
/// use std::rc::Rc;
To generate the docs, run `rustdoc universe.rs`. By default, it generates a ///
directory called `doc`, with the documentation for `universe` being in /// let five = Rc::new(5);
`doc/universe/index.html`. If you are using other crates with `extern crate`, /// ```
rustdoc will even link to them when you use their types, as long as their pub fn new(value: T) -> Rc<T> {
documentation has already been generated by a previous run of rustdoc, or the // implementation goes here
crate advertises that its documentation is hosted at a given URL.
The generated output can be controlled with the `doc` crate attribute, which
is how the above advertisement works. An example from the `libstd`
documentation:
~~~
#[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/")];
~~~
The `html_root_url` is the prefix that rustdoc will apply to any references to
that crate's types etc.
rustdoc can also generate JSON, for consumption by other tools, with
`rustdoc --output-format json`, and also consume already-generated JSON with
`rustdoc --input-format json`.
rustdoc also supports personalizing the output from crates' documentation,
similar to markdown options.
- `--html-in-header FILE`: includes the contents of `FILE` at the
end of the `<head>...</head>` section.
- `--html-before-content FILE`: includes the contents of `FILE`
directly after `<body>`, before the rendered content (including the
search bar).
- `--html-after-content FILE`: includes the contents of `FILE`
after all the rendered content.
# Using the Documentation
The web pages generated by rustdoc present the same logical hierarchy that one
writes a library with. Every kind of item (function, struct, etc) has its own
color, and one can always click on a colored type to jump to its
documentation. There is a search bar at the top, which is powered by some
JavaScript and a statically-generated search index. No special web server is
required for the search.
[hoedown]: https://github.com/hoedown/hoedown
# Testing the Documentation
`rustdoc` has support for testing code examples which appear in the
documentation. This is helpful for keeping code examples up to date with the
source code.
To test documentation, the `--test` argument is passed to rustdoc:
~~~ {.sh}
rustdoc --test crate.rs
~~~
## Defining tests
Rust documentation currently uses the markdown format, and rustdoc treats all
code blocks as testable-by-default unless they carry a language tag of another
language. In order to not run a test over a block of code, the `ignore` string
can be added to the three-backtick form of markdown code block.
~~~md
```
// This is a testable code block
```
```rust{.example}
// This is rust and also testable
```
```ignore
// This is not a testable code block
```
// This is a testable code block (4-space indent)
```sh
# this is shell code and not tested
```
~~~
You can specify that the test's execution should fail with the `should_fail`
directive.
~~~md
```should_fail
// This code block is expected to generate a panic when run
```
~~~
You can specify that the code block should be compiled but not run with the
`no_run` directive.
~~~md
```no_run
// This code will be compiled but not executed
```
~~~
Lastly, you can specify that a code block be compiled as if `--test`
were passed to the compiler using the `test_harness` directive.
~~~md
```test_harness
#[test]
fn foo() {
panic!("oops! (will run & register as a failed test)")
} }
``` ```
~~~
Rustdoc also supplies some extra sugar for helping with some tedious This code generates documentation that looks [like this][rc-new]. I've left the
documentation examples. If a line is prefixed with `# `, then the line implementation out, with a regular comment in its place. That's the first thing
will not show up in the HTML documentation, but it will be used when to notice about this annotation: it uses `///`, instead of `//`. The triple slash
testing the code block (NB. the space after the `#` is required, so indicates a documentation comment.
that one can still write things like `#[derive(Eq)]`).
Documentation comments are written in Markdown.
Rust keeps track of these comments, and uses them when generating
documentation. This is important when documenting things like enums:
~~~md
``` ```
# /!\ The three following lines are comments, which are usually stripped off by /// The `Option` type. See [the module level documentation](../) for more.
# the doc-generating tool. In order to display them anyway in this particular enum Option<T> {
# case, the character following the leading '#' is not a usual space like in /// No value
# these first five lines but a non breakable one. None,
# // showing 'fib' in this documentation would just be tedious and detracts from /// Some value `T`
# // what's actually being documented. Some(T),
# fn fib(n: int) { n + 2 } }
spawn(move || { fib(200); })
``` ```
~~~
The documentation online would look like `spawn(move || { fib(200); })`, but when The above works, but this does not:
testing this code, the `fib` function will be included (so it can compile).
Rustdoc will automatically add a `main()` wrapper around your code, and in the right ```rust,ignore
place. For example: /// The `Option` type. See [the module level documentation](../) for more.
enum Option<T> {
None, /// No value
Some(T), /// Some value `T`
}
```
You'll get an error:
```text
hello.rs:4:1: 4:2 error: expected ident, found `}`
hello.rs:4 }
^
```
This [unfortunate error](https://github.com/rust-lang/rust/issues/22547) is
correct: documentation comments apply to the thing after them, and there's no
thing after that last comment.
[rc-new]: http://doc.rust-lang.org/nightly/std/rc/struct.Rc.html#method.new
### Writing documentation comments
Anyway, let's cover each part of this comment in detail:
```
/// Constructs a new `Rc<T>`.
# fn foo() {}
```
The first line of a documentation comment should be a short summary of its
functionality. One sentence. Just the basics. High level.
```
///
/// Other details about constructing `Rc<T>`s, maybe describing complicated
/// semantics, maybe additional options, all kinds of stuff.
///
# fn foo() {}
```
Our original example had just a summary line, but if we had more things to say,
we could have added more explanation in a new paragraph.
#### Special sections
```
/// # Examples
# fn foo() {}
```
Next, are special sections. These are indicated with a header, `#`. There
are three kinds of headers that are commonly used. They aren't special syntax,
just convention, for now.
```
/// # Panics
# fn foo() {}
```
Unrecoverable misuses of a function (i.e. programming errors) in Rust are
usually indicated by panics, which kill the whole current thread at the very
least. If your function has a non-trivial contract like this, that is
detected/enforced by panics, documenting it is very important.
```
/// # Failures
# fn foo() {}
```
If your function or method returns a `Result<T, E>`, then describing the
conditions under which it returns `Err(E)` is a nice thing to do. This is
slightly less important than `Panics`, because failure is encoded into the type
system, but it's still a good thing to do.
```
/// # Safety
# fn foo() {}
```
If your function is `unsafe`, you should explain which invariants the caller is
responsible for upholding.
```
/// # Examples
///
/// ```
/// use std::rc::Rc;
///
/// let five = Rc::new(5);
/// ```
# fn foo() {}
```
Third, `Examples`. Include one or more examples of using your function or
method, and your users will love you for it. These examples go inside of
code block annotations, which we'll talk about in a moment, and can have
more than one section:
```
/// # Examples
///
/// Simple `&str` patterns:
///
/// ```
/// let v: Vec<&str> = "Mary had a little lamb".split(' ').collect();
/// assert_eq!(v, vec!["Mary", "had", "a", "little", "lamb"]);
/// ```
///
/// More complex patterns with a lambda:
///
/// ```
/// let v: Vec<&str> = "abc1def2ghi".split(|c: char| c.is_numeric()).collect();
/// assert_eq!(v, vec!["abc", "def", "ghi"]);
/// ```
# fn foo() {}
```
Let's discuss the details of these code blocks.
#### Code block annotations
To write some Rust code in a comment, use the triple graves:
```
/// ```
/// println!("Hello, world");
/// ```
# fn foo() {}
```
If you want something that's not Rust code, you can add an annotation:
```
/// ```c
/// printf("Hello, world\n");
/// ```
# fn foo() {}
```
This will highlight according to whatever language you're showing off.
If you're just showing plain text, choose `text`.
It's important to choose the correct annotation here, because `rustdoc` uses it
in an interesting way: It can be used to actually test your examples, so that
they don't get out of date. If you have some C code but `rustdoc` thinks it's
Rust because you left off the annotation, `rustdoc` will complain when trying to
generate the documentation.
## Documentation as tests
Let's discuss our sample example documentation:
```
/// ```
/// println!("Hello, world");
/// ```
# fn foo() {}
```
You'll notice that you don't need a `fn main()` or anything here. `rustdoc` will
automatically add a main() wrapper around your code, and in the right place.
For example:
``` ```
/// ``` /// ```
@ -238,82 +237,326 @@ fn main() {
} }
``` ```
Here's the full algorithm: Here's the full algorithm rustdoc uses to postprocess examples:
1. Given a code block, if it does not contain `fn main`, it is wrapped in `fn main() { your_code }` 1. Any leading `#![foo]` attributes are left intact as crate attributes.
2. Given that result, if it contains no `extern crate` directives but it also 2. Some common `allow` attributes are inserted, including
contains the name of the crate being tested, then `extern crate <name>` is `unused_variables`, `unused_assignments`, `unused_mut`,
injected at the top. `unused_attributes`, and `dead_code`. Small examples often trigger
3. Some common `allow` attributes are added for documentation examples at the top. these lints.
3. If the example does not contain `extern crate`, then `extern crate
<mycrate>;` is inserted.
2. Finally, if the example does not contain `fn main`, the remainder of the
text is wrapped in `fn main() { your_code }`
## Running tests (advanced) Sometimes, this isn't enough, though. For example, all of these code samples
with `///` we've been talking about? The raw text:
Running tests often requires some special configuration to filter tests, find ```text
libraries, or try running ignored examples. The testing framework that rustdoc /// Some documentation.
uses is built on crate `test`, which is also used when you compile crates with # fn foo() {}
rustc's `--test` flag. Extra arguments can be passed to rustdoc's test harness ```
with the `--test-args` flag.
~~~console looks different than the output:
# Only run tests containing 'foo' in their name
$ rustdoc --test lib.rs --test-args 'foo'
# See what's possible when running tests ```
$ rustdoc --test lib.rs --test-args '--help' /// Some documentation.
# fn foo() {}
```
Yes, that's right: you can add lines that start with `# `, and they will
be hidden from the output, but will be used when compiling your code. You
can use this to your advantage. In this case, documentation comments need
to apply to some kind of function, so if I want to show you just a
documentation comment, I need to add a little function definition below
it. At the same time, it's just there to satisfy the compiler, so hiding
it makes the example more clear. You can use this technique to explain
longer examples in detail, while still preserving the testability of your
documentation. For example, this code:
```
let x = 5;
let y = 6;
println!("{}", x + y);
```
Here's an explanation, rendered:
First, we set `x` to five:
```
let x = 5;
# let y = 6;
# println!("{}", x + y);
```
Next, we set `y` to six:
```
# let x = 5;
let y = 6;
# println!("{}", x + y);
```
Finally, we print the sum of `x` and `y`:
```
# let x = 5;
# let y = 6;
println!("{}", x + y);
```
Here's the same explanation, in raw text:
> First, we set `x` to five:
>
> ```text
> let x = 5;
> # let y = 6;
> # println!("{}", x + y);
> ```
>
> Next, we set `y` to six:
>
> ```text
> # let x = 5;
> let y = 6;
> # println!("{}", x + y);
> ```
>
> Finally, we print the sum of `x` and `y`:
>
> ```text
> # let x = 5;
> # let y = 6;
> println!("{}", x + y);
> ```
By repeating all parts of the example, you can ensure that your example still
compiles, while only showing the parts that are relevant to that part of your
explanation.
### Documenting macros
Heres an example of documenting a macro:
```
/// Panic with a given message unless an expression evaluates to true.
///
/// # Examples
///
/// ```
/// # #[macro_use] extern crate foo;
/// # fn main() {
/// panic_unless!(1 + 1 == 2, “Math is broken.”);
/// # }
/// ```
///
/// ```should_panic
/// # #[macro_use] extern crate foo;
/// # fn main() {
/// panic_unless!(true == false, “Im broken.”);
/// # }
/// ```
#[macro_export]
macro_rules! panic_unless {
($condition:expr, $($rest:expr),+) => ({ if ! $condition { panic!($($rest),+); } });
}
# fn main() {}
```
Youll note three things: we need to add our own `extern crate` line, so that
we can add the `#[macro_use]` attribute. Second, well need to add our own
`main()` as well. Finally, a judicious use of `#` to comment out those two
things, so they dont show up in the output.
### Running documentation tests
To run the tests, either
```bash
$ rustdoc --test path/to/my/crate/root.rs
# or
$ cargo test
```
That's right, `cargo test` tests embedded documentation too.
There are a few more annotations that are useful to help `rustdoc` do the right
thing when testing your code:
```
/// ```ignore
/// fn foo() {
/// ```
# fn foo() {}
```
The `ignore` directive tells Rust to ignore your code. This is almost never
what you want, as it's the most generic. Instead, consider annotating it
with `text` if it's not code, or using `#`s to get a working example that
only shows the part you care about.
```
/// ```should_panic
/// assert!(false);
/// ```
# fn foo() {}
```
`should_panic` tells `rustdoc` that the code should compile correctly, but
not actually pass as a test.
```
/// ```no_run
/// loop {
/// println!("Hello, world");
/// }
/// ```
# fn foo() {}
```
The `no_run` attribute will compile your code, but not run it. This is
important for examples such as "Here's how to start up a network service,"
which you would want to make sure compile, but might run in an infinite loop!
### Documenting modules
Rust has another kind of doc comment, `//!`. This comment doesn't document the next item, but the enclosing item. In other words:
```
mod foo {
//! This is documentation for the `foo` module.
//!
//! # Examples
// ...
}
```
This is where you'll see `//!` used most often: for module documentation. If
you have a module in `foo.rs`, you'll often open its code and see this:
```
//! A module for using `foo`s.
//!
//! The `foo` module contains a lot of useful functionality blah blah blah
```
### Documentation comment style
Check out [RFC 505][rfc505] for full conventions around the style and format of
documentation.
[rfc505]: https://github.com/rust-lang/rfcs/blob/master/text/0505-api-comment-conventions.md
## Other documentation
All of this behavior works in non-Rust source files too. Because comments
are written in Markdown, they're often `.md` files.
When you write documentation in Markdown files, you don't need to prefix
the documentation with comments. For example:
```
/// # Examples
///
/// ```
/// use std::rc::Rc;
///
/// let five = Rc::new(5);
/// ```
# fn foo() {}
```
is just
~~~markdown
# Examples
```
use std::rc::Rc;
let five = Rc::new(5);
```
~~~ ~~~
When testing a library, code examples will often show how functions are used, when it's in a Markdown file. There is one wrinkle though: Markdown files need
and this code often requires `use`-ing paths from the crate. To accommodate this, to have a title like this:
rustdoc will implicitly add `extern crate <crate>;` where `<crate>` is the name of
the crate being tested to the top of each code example. This means that rustdoc
must be able to find a compiled version of the library crate being tested. Extra
search paths may be added via the `-L` flag to `rustdoc`.
# Standalone Markdown files ```markdown
% The title
As well as Rust crates, rustdoc supports rendering pure Markdown files This is the example documentation.
into HTML and testing the code snippets from them. A Markdown file is ```
detected by a `.md` or `.markdown` extension.
There are 4 options to modify the output that Rustdoc creates. This `%` line needs to be the very first line of the file.
- `--markdown-css PATH`: adds a `<link rel="stylesheet">` tag pointing to `PATH`. ## `doc` attributes
- `--html-in-header FILE`: includes the contents of `FILE` at the
end of the `<head>...</head>` section.
- `--html-before-content FILE`: includes the contents of `FILE`
directly after `<body>`, before the rendered content (including the
title).
- `--html-after-content FILE`: includes the contents of `FILE`
directly before `</body>`, after all the rendered content.
All of these can be specified multiple times, and they are output in At a deeper level, documentation comments are sugar for documentation attributes:
the order in which they are specified. The first line of the file being rendered must
be the title, prefixed with `%` (e.g. this page has `% Rust
Documentation` on the first line).
Like with a Rust crate, the `--test` argument will run the code ```
examples to check they compile, and obeys any `--test-args` flags. The /// this
tests are named after the last `#` heading. # fn foo() {}
# Re-exports #[doc="this"]
# fn bar() {}
```
Rustdoc will show the documentation for a publc re-export in both places: are the same, as are these:
```{rust,ignore} ```
//! this
#![doc="/// this"]
```
You won't often see this attribute used for writing documentation, but it
can be useful when changing some options, or when writing a macro.
### Re-exports
`rustdoc` will show the documentation for a public re-export in both places:
```ignore
extern crate foo; extern crate foo;
pub use foo::bar; pub use foo::bar;
``` ```
This will create documentation for `bar` both inside the documentation for This will create documentation for bar both inside the documentation for the
the crate `foo`, as well as the documentation for your crate. It will use crate `foo`, as well as the documentation for your crate. It will use the same
the same documentation in both places. documentation in both places.
This behavior can be supressed with `no_inline`: This behavior can be suppressed with `no_inline`:
```{rust,ignore} ```ignore
extern crate foo; extern crate foo;
#[doc(no_inline)] #[doc(no_inline)]
pub use foo::bar; pub use foo::bar;
``` ```
### Controlling HTML
You can control a few aspects of the HTML that `rustdoc` generates through the
`#![doc]` version of the attribute:
```
#![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/")];
```
This sets a few different options, with a logo, favicon, and a root URL.
## Generation options
`rustdoc` also contains a few other options on the command line, for further customiziation:
- `--html-in-header FILE`: includes the contents of FILE at the end of the
`<head>...</head>` section.
- `--html-before-content FILE`: includes the contents of FILE directly after
`<body>`, before the rendered content (including the search bar).
- `--html-after-content FILE`: includes the contents of FILE after all the rendered content.

View File

@ -200,15 +200,15 @@ Because these kinds of situations are relatively rare, use panics sparingly.
# Upgrading failures to panics # Upgrading failures to panics
In certain circumstances, even though a function may fail, we may want to treat In certain circumstances, even though a function may fail, we may want to treat
it as a panic instead. For example, `io::stdin().read_line()` returns an it as a panic instead. For example, `io::stdin().read_line(&mut buffer)` returns
`IoResult<String>`, a form of `Result`, when there is an error reading the an `Result<usize>`, when there is an error reading the line. This allows us to
line. This allows us to handle and possibly recover from this sort of error. handle and possibly recover from error.
If we don't want to handle this error, and would rather just abort the program, If we don't want to handle this error, and would rather just abort the program,
we can use the `unwrap()` method: we can use the `unwrap()` method:
```{rust,ignore} ```{rust,ignore}
io::stdin().read_line().unwrap(); io::stdin().read_line(&mut buffer).unwrap();
``` ```
`unwrap()` will `panic!` if the `Option` is `None`. This basically says "Give `unwrap()` will `panic!` if the `Option` is `None`. This basically says "Give
@ -219,10 +219,83 @@ shorter. Sometimes, just crashing is appropriate.
There's another way of doing this that's a bit nicer than `unwrap()`: There's another way of doing this that's a bit nicer than `unwrap()`:
```{rust,ignore} ```{rust,ignore}
let input = io::stdin().read_line() let mut buffer = String::new();
let input = io::stdin().read_line(&mut buffer)
.ok() .ok()
.expect("Failed to read line"); .expect("Failed to read line");
``` ```
`ok()` converts the `IoResult` into an `Option`, and `expect()` does the same
`ok()` converts the `Result` into an `Option`, and `expect()` does the same
thing as `unwrap()`, but takes a message. This message is passed along to the thing as `unwrap()`, but takes a message. This message is passed along to the
underlying `panic!`, providing a better error message if the code errors. underlying `panic!`, providing a better error message if the code errors.
# Using `try!`
When writing code that calls many functions that return the `Result` type, the
error handling can be tedious. The `try!` macro hides some of the boilerplate
of propagating errors up the call stack.
It replaces this:
```rust
use std::fs::File;
use std::io;
use std::io::prelude::*;
struct Info {
name: String,
age: i32,
rating: i32,
}
fn write_info(info: &Info) -> io::Result<()> {
let mut file = File::open("my_best_friends.txt").unwrap();
if let Err(e) = writeln!(&mut file, "name: {}", info.name) {
return Err(e)
}
if let Err(e) = writeln!(&mut file, "age: {}", info.age) {
return Err(e)
}
if let Err(e) = writeln!(&mut file, "rating: {}", info.rating) {
return Err(e)
}
return Ok(());
}
```
With this:
```rust
use std::fs::File;
use std::io;
use std::io::prelude::*;
struct Info {
name: String,
age: i32,
rating: i32,
}
fn write_info(info: &Info) -> io::Result<()> {
let mut file = try!(File::open("my_best_friends.txt"));
try!(writeln!(&mut file, "name: {}", info.name));
try!(writeln!(&mut file, "age: {}", info.age));
try!(writeln!(&mut file, "rating: {}", info.rating));
return Ok(());
}
```
Wrapping an expression in `try!` will result in the unwrapped success (`Ok`)
value, unless the result is `Err`, in which case `Err` is returned early from
the enclosing function.
It's worth noting that you can only use `try!` from a function that returns a
`Result`, which means that you cannot use `try!` inside of `main()`, because
`main()` doesn't return anything.
`try!` makes use of [`FromError`](../std/error/#the-fromerror-trait) to determine
what to return in the error case.

View File

@ -12,6 +12,7 @@ The following is a minimal example of calling a foreign function which will
compile if snappy is installed: compile if snappy is installed:
```no_run ```no_run
# #![feature(libc)]
extern crate libc; extern crate libc;
use libc::size_t; use libc::size_t;
@ -45,6 +46,7 @@ keeping the binding correct at runtime.
The `extern` block can be extended to cover the entire snappy API: The `extern` block can be extended to cover the entire snappy API:
```no_run ```no_run
# #![feature(libc)]
extern crate libc; extern crate libc;
use libc::{c_int, size_t}; use libc::{c_int, size_t};
@ -80,6 +82,7 @@ length is number of elements currently contained, and the capacity is the total
the allocated memory. The length is less than or equal to the capacity. the allocated memory. The length is less than or equal to the capacity.
``` ```
# #![feature(libc)]
# extern crate libc; # extern crate libc;
# use libc::{c_int, size_t}; # use libc::{c_int, size_t};
# unsafe fn snappy_validate_compressed_buffer(_: *const u8, _: size_t) -> c_int { 0 } # unsafe fn snappy_validate_compressed_buffer(_: *const u8, _: size_t) -> c_int { 0 }
@ -104,6 +107,7 @@ required capacity to hold the compressed output. The vector can then be passed t
the true length after compression for setting the length. the true length after compression for setting the length.
``` ```
# #![feature(libc)]
# extern crate libc; # extern crate libc;
# use libc::{size_t, c_int}; # use libc::{size_t, c_int};
# unsafe fn snappy_compress(a: *const u8, b: size_t, c: *mut u8, # unsafe fn snappy_compress(a: *const u8, b: size_t, c: *mut u8,
@ -130,6 +134,7 @@ Decompression is similar, because snappy stores the uncompressed size as part of
format and `snappy_uncompressed_length` will retrieve the exact buffer size required. format and `snappy_uncompressed_length` will retrieve the exact buffer size required.
``` ```
# #![feature(libc)]
# extern crate libc; # extern crate libc;
# use libc::{size_t, c_int}; # use libc::{size_t, c_int};
# unsafe fn snappy_uncompress(compressed: *const u8, # unsafe fn snappy_uncompress(compressed: *const u8,
@ -170,6 +175,8 @@ Foreign libraries often hand off ownership of resources to the calling code.
When this occurs, we must use Rust's destructors to provide safety and guarantee When this occurs, we must use Rust's destructors to provide safety and guarantee
the release of these resources (especially in the case of panic). the release of these resources (especially in the case of panic).
For more about destructors, see the [Drop trait](../std/ops/trait.Drop.html).
# Callbacks from C code to Rust functions # Callbacks from C code to Rust functions
Some external libraries require the usage of callbacks to report back their Some external libraries require the usage of callbacks to report back their
@ -359,31 +366,6 @@ A few examples of how this model can be used are:
On OSX, frameworks behave with the same semantics as a dynamic library. On OSX, frameworks behave with the same semantics as a dynamic library.
## The `link_args` attribute
There is one other way to tell rustc how to customize linking, and that is via
the `link_args` attribute. This attribute is applied to `extern` blocks and
specifies raw flags which need to get passed to the linker when producing an
artifact. An example usage would be:
``` no_run
#![feature(link_args)]
#[link_args = "-foo -bar -baz"]
extern {}
# fn main() {}
```
Note that this feature is currently hidden behind the `feature(link_args)` gate
because this is not a sanctioned way of performing linking. Right now rustc
shells out to the system linker, so it makes sense to provide extra command line
arguments, but this will not always be the case. In the future rustc may use
LLVM directly to link native libraries in which case `link_args` will have no
meaning.
It is highly recommended to *not* use this attribute, and rather use the more
formal `#[link(...)]` attribute on `extern` blocks instead.
# Unsafe blocks # Unsafe blocks
Some operations, like dereferencing unsafe pointers or calling functions that have been marked Some operations, like dereferencing unsafe pointers or calling functions that have been marked
@ -394,7 +376,7 @@ Unsafe functions, on the other hand, advertise it to the world. An unsafe functi
this: this:
``` ```
unsafe fn kaboom(ptr: *const int) -> int { *ptr } unsafe fn kaboom(ptr: *const i32) -> i32 { *ptr }
``` ```
This function can only be called from an `unsafe` block or another `unsafe` function. This function can only be called from an `unsafe` block or another `unsafe` function.
@ -406,6 +388,7 @@ global state. In order to access these variables, you declare them in `extern`
blocks with the `static` keyword: blocks with the `static` keyword:
```no_run ```no_run
# #![feature(libc)]
extern crate libc; extern crate libc;
#[link(name = "readline")] #[link(name = "readline")]
@ -415,7 +398,7 @@ extern {
fn main() { fn main() {
println!("You have readline version {} installed.", println!("You have readline version {} installed.",
rl_readline_version as int); rl_readline_version as i32);
} }
``` ```
@ -424,6 +407,7 @@ interface. To do this, statics can be declared with `mut` so we can mutate
them. them.
```no_run ```no_run
# #![feature(libc)]
extern crate libc; extern crate libc;
use std::ffi::CString; use std::ffi::CString;
@ -456,6 +440,7 @@ calling foreign functions. Some foreign functions, most notably the Windows API,
conventions. Rust provides a way to tell the compiler which convention to use: conventions. Rust provides a way to tell the compiler which convention to use:
``` ```
# #![feature(libc)]
extern crate libc; extern crate libc;
#[cfg(all(target_os = "win32", target_arch = "x86"))] #[cfg(all(target_os = "win32", target_arch = "x86"))]
@ -543,4 +528,3 @@ The `extern` makes this function adhere to the C calling convention, as
discussed above in "[Foreign Calling discussed above in "[Foreign Calling
Conventions](ffi.html#foreign-calling-conventions)". The `no_mangle` Conventions](ffi.html#foreign-calling-conventions)". The `no_mangle`
attribute turns off Rust's name mangling, so that it is easier to link to. attribute turns off Rust's name mangling, so that it is easier to link to.

View File

@ -179,7 +179,7 @@ Because this function will cause a crash, it will never return, and so it has
the type '`!`', which is read "diverges." A diverging function can be used the type '`!`', which is read "diverges." A diverging function can be used
as any type: as any type:
```should_fail ```should_panic
# fn diverges() -> ! { # fn diverges() -> ! {
# panic!("This function never returns!"); # panic!("This function never returns!");
# } # }

View File

@ -14,3 +14,26 @@ let z = (8, 2, 6);
``` ```
In the example above `x` and `y` have arity 2. `z` has arity 3. In the example above `x` and `y` have arity 2. `z` has arity 3.
### Abstract Syntax Tree
When a compiler is compiling your program, it does a number of different
things. One of the things that it does is turn the text of your program into an
'abstract syntax tree,' or 'AST.' This tree is a representation of the
structure of your program. For example, `2 + 3` can be turned into a tree:
```text
+
/ \
2 3
```
And `2 + (3 * 4)` would look like this:
```text
+
/ \
2 *
/ \
3 4
```

View File

@ -1,893 +0,0 @@
% Guessing Game
Okay! We've got the basics of Rust down. Let's write a bigger program.
For our first project, we'll implement a classic beginner programming problem:
the guessing game. Here's how it works: Our program will generate a random
integer between one and a hundred. It will then prompt us to enter a guess.
Upon entering our guess, it will tell us if we're too low or too high. Once we
guess correctly, it will congratulate us. Sound good?
## Set up
Let's set up a new project. Go to your projects directory. Remember how we
had to create our directory structure and a `Cargo.toml` for `hello_world`? Cargo
has a command that does that for us. Let's give it a shot:
```{bash}
$ cd ~/projects
$ cargo new guessing_game --bin
$ cd guessing_game
```
We pass the name of our project to `cargo new`, and then the `--bin` flag,
since we're making a binary, rather than a library.
Check out the generated `Cargo.toml`:
```toml
[package]
name = "guessing_game"
version = "0.0.1"
authors = ["Your Name <you@example.com>"]
```
Cargo gets this information from your environment. If it's not correct, go ahead
and fix that.
Finally, Cargo generated a "Hello, world!" for us. Check out `src/main.rs`:
```{rust}
fn main() {
println!("Hello, world!")
}
```
Let's try compiling what Cargo gave us:
```{bash}
$ cargo build
Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game)
```
Excellent! Open up your `src/main.rs` again. We'll be writing all of
our code in this file. We'll talk about multiple-file projects later on in the
guide.
Before we move on, let me show you one more Cargo command: `run`. `cargo run`
is kind of like `cargo build`, but it also then runs the produced executable.
Try it out:
```bash
$ cargo run
Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game)
Running `target/guessing_game`
Hello, world!
```
Great! The `run` command comes in handy when you need to rapidly iterate on a project.
Our game is just such a project, we need to quickly test each iteration before moving on to the next one.
## Processing a Guess
Let's get to it! The first thing we need to do for our guessing game is
allow our player to input a guess. Put this in your `src/main.rs`:
```{rust,no_run}
use std::old_io;
fn main() {
println!("Guess the number!");
println!("Please input your guess.");
let input = old_io::stdin().read_line()
.ok()
.expect("Failed to read line");
println!("You guessed: {}", input);
}
```
You've seen this code before, when we talked about standard input. We
import the `std::io` module with `use`, and then our `main` function contains
our program's logic. We print a little message announcing the game, ask the
user to input a guess, get their input, and then print it out.
Because we talked about this in the section on standard I/O, I won't go into
more details here. If you need a refresher, go re-read that section.
## Generating a secret number
Next, we need to generate a secret number. To do that, we need to use Rust's
random number generation, which we haven't talked about yet. Rust includes a
bunch of interesting functions in its standard library. If you need a bit of
code, it's possible that it's already been written for you! In this case,
we do know that Rust has random number generation, but we don't know how to
use it.
Enter the docs. Rust has a page specifically to document the standard library.
You can find that page [here](../std/index.html). There's a lot of information on
that page, but the best part is the search bar. Right up at the top, there's
a box that you can enter in a search term. The search is pretty primitive
right now, but is getting better all the time. If you type "random" in that
box, the page will update to [this one](../std/index.html?search=random). The very
first result is a link to [`std::rand::random`](../std/rand/fn.random.html). If we
click on that result, we'll be taken to its documentation page.
This page shows us a few things: the type signature of the function, some
explanatory text, and then an example. Let's try to modify our code to add in the
`random` function and see what happens:
```{rust,ignore}
use std::old_io;
use std::rand;
fn main() {
println!("Guess the number!");
let secret_number = (rand::random() % 100) + 1; // secret_number: i32
println!("The secret number is: {}", secret_number);
println!("Please input your guess.");
let input = old_io::stdin().read_line()
.ok()
.expect("Failed to read line");
println!("You guessed: {}", input);
}
```
The first thing we changed was to `use std::rand`, as the docs
explained. We then added in a `let` expression to create a variable binding
named `secret_number`, and we printed out its result.
Also, you may wonder why we are using `%` on the result of `rand::random()`.
This operator is called *modulo*, and it returns the remainder of a division.
By taking the modulo of the result of `rand::random()`, we're limiting the
values to be between 0 and 99. Then, we add one to the result, making it from 1
to 100. Using modulo can give you a very, very small bias in the result, but
for this example, it is not important.
Let's try to compile this using `cargo build`:
```bash
$ cargo build
Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game)
src/main.rs:7:26: 7:34 error: the type of this value must be known in this context
src/main.rs:7 let secret_number = (rand::random() % 100) + 1;
^~~~~~~~
error: aborting due to previous error
```
It didn't work! Rust says "the type of this value must be known in this
context." What's up with that? Well, as it turns out, `rand::random()` can
generate many kinds of random values, not just integers. And in this case, Rust
isn't sure what kind of value `random()` should generate. So we have to help
it. With number literals, we can just add an `i32` onto the end to tell Rust they're
integers, but that does not work with functions. There's a different syntax,
and it looks like this:
```{rust,ignore}
rand::random::<i32>();
```
This says "please give me a random `i32` value." We can change our code to use
this hint:
```{rust,no_run}
use std::old_io;
use std::rand;
fn main() {
println!("Guess the number!");
let secret_number = (rand::random::<i32>() % 100) + 1;
println!("The secret number is: {}", secret_number);
println!("Please input your guess.");
let input = old_io::stdin().read_line()
.ok()
.expect("Failed to read line");
println!("You guessed: {}", input);
}
```
Try running our new program a few times:
```bash
$ cargo run
Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game)
Running `target/guessing_game`
Guess the number!
The secret number is: 7
Please input your guess.
4
You guessed: 4
$ ./target/guessing_game
Guess the number!
The secret number is: 83
Please input your guess.
5
You guessed: 5
$ ./target/guessing_game
Guess the number!
The secret number is: -29
Please input your guess.
42
You guessed: 42
```
Wait. Negative 29? We wanted a number between one and a hundred! We have two
options here: we can either ask `random()` to generate an unsigned integer, which
can only be positive, or we can use the `abs()` function. Let's go with the
unsigned integer approach. If we want a random positive number, we should ask for
a random positive number. Our code looks like this now:
```{rust,no_run}
use std::old_io;
use std::rand;
fn main() {
println!("Guess the number!");
let secret_number = (rand::random::<u32>() % 100) + 1;
println!("The secret number is: {}", secret_number);
println!("Please input your guess.");
let input = old_io::stdin().read_line()
.ok()
.expect("Failed to read line");
println!("You guessed: {}", input);
}
```
And trying it out:
```bash
$ cargo run
Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game)
Running `target/guessing_game`
Guess the number!
The secret number is: 57
Please input your guess.
3
You guessed: 3
```
Great! Next up: let's compare our guess to the secret guess.
## Comparing guesses
If you remember, earlier in the guide, we made a `cmp` function that compared
two numbers. Let's add that in, along with a `match` statement to compare our
guess to the secret number:
```{rust,ignore}
use std::old_io;
use std::rand;
use std::cmp::Ordering;
fn main() {
println!("Guess the number!");
let secret_number = (rand::random::<u32>() % 100) + 1;
println!("The secret number is: {}", secret_number);
println!("Please input your guess.");
let input = old_io::stdin().read_line()
.ok()
.expect("Failed to read line");
println!("You guessed: {}", input);
match cmp(input, secret_number) {
Ordering::Less => println!("Too small!"),
Ordering::Greater => println!("Too big!"),
Ordering::Equal => println!("You win!"),
}
}
fn cmp(a: i32, b: i32) -> Ordering {
if a < b { Ordering::Less }
else if a > b { Ordering::Greater }
else { Ordering::Equal }
}
```
If we try to compile, we'll get some errors:
```bash
$ cargo build
Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game)
src/main.rs:20:15: 20:20 error: mismatched types: expected `i32` but found `collections::string::String` (expected i32 but found struct collections::string::String)
src/main.rs:20 match cmp(input, secret_number) {
^~~~~
src/main.rs:20:22: 20:35 error: mismatched types: expected `i32` but found `u32` (expected i32 but found u32)
src/main.rs:20 match cmp(input, secret_number) {
^~~~~~~~~~~~~
error: aborting due to 2 previous errors
```
This often happens when writing Rust programs, and is one of Rust's greatest
strengths. You try out some code, see if it compiles, and Rust tells you that
you've done something wrong. In this case, our `cmp` function works on integers,
but we've given it unsigned integers. In this case, the fix is easy, because
we wrote the `cmp` function! Let's change it to take `u32`s:
```{rust,ignore}
use std::old_io;
use std::rand;
use std::cmp::Ordering;
fn main() {
println!("Guess the number!");
let secret_number = (rand::random::<u32>() % 100) + 1;
println!("The secret number is: {}", secret_number);
println!("Please input your guess.");
let input = old_io::stdin().read_line()
.ok()
.expect("Failed to read line");
println!("You guessed: {}", input);
match cmp(input, secret_number) {
Ordering::Less => println!("Too small!"),
Ordering::Greater => println!("Too big!"),
Ordering::Equal => println!("You win!"),
}
}
fn cmp(a: u32, b: u32) -> Ordering {
if a < b { Ordering::Less }
else if a > b { Ordering::Greater }
else { Ordering::Equal }
}
```
And try compiling again:
```bash
$ cargo build
Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game)
src/main.rs:20:15: 20:20 error: mismatched types: expected `u32` but found `collections::string::String` (expected u32 but found struct collections::string::String)
src/main.rs:20 match cmp(input, secret_number) {
^~~~~
error: aborting due to previous error
```
This error is similar to the last one: we expected to get a `u32`, but we got
a `String` instead! That's because our `input` variable is coming from the
standard input, and you can guess anything. Try it:
```bash
$ ./target/guessing_game
Guess the number!
The secret number is: 73
Please input your guess.
hello
You guessed: hello
```
Oops! Also, you'll note that we just ran our program even though it didn't compile.
This works because the older version we did successfully compile was still lying
around. Gotta be careful!
Anyway, we have a `String`, but we need a `u32`. What to do? Well, there's
a function for that:
```{rust,ignore}
let input = old_io::stdin().read_line()
.ok()
.expect("Failed to read line");
let input_num: Result<u32, _> = input.parse();
```
The `parse` function takes in a `&str` value and converts it into something.
We tell it what kind of something with a type hint. Remember our type hint with
`random()`? It looked like this:
```{rust,ignore}
rand::random::<u32>();
```
There's an alternate way of providing a hint too, and that's declaring the type
in a `let`:
```{rust,ignore}
let x: u32 = rand::random();
```
In this case, we say `x` is a `u32` 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 = "5".parse::<u32>(); // input_num: Option<u32>
let input_num: Result<u32, _> = "5".parse(); // input_num: Result<u32, <u32 as FromStr>::Err>
```
Here we're converting the `Result` returned by `parse` to an `Option` by using
the `ok` method as well. Anyway, with us now converting our input to a number,
our code looks like this:
```{rust,ignore}
use std::old_io;
use std::rand;
use std::cmp::Ordering;
fn main() {
println!("Guess the number!");
let secret_number = (rand::random::<u32>() % 100) + 1;
println!("The secret number is: {}", secret_number);
println!("Please input your guess.");
let input = old_io::stdin().read_line()
.ok()
.expect("Failed to read line");
let input_num: Result<u32, _> = input.parse();
println!("You guessed: {:?}", input_num);
match cmp(input_num, secret_number) {
Ordering::Less => println!("Too small!"),
Ordering::Greater => println!("Too big!"),
Ordering::Equal => println!("You win!"),
}
}
fn cmp(a: u32, b: u32) -> Ordering {
if a < b { Ordering::Less }
else if a > b { Ordering::Greater }
else { Ordering::Equal }
}
```
Let's try it out!
```bash
$ cargo build
Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game)
src/main.rs:22:15: 22:24 error: mismatched types: expected `u32` but found `core::option::Option<u32>` (expected u32 but found enum core::option::Option)
src/main.rs:22 match cmp(input_num, secret_number) {
^~~~~~~~~
error: aborting due to previous error
```
Oh yeah! Our `input_num` has the type `Option<u32>`, rather than `u32`. We
need to unwrap the Option. If you remember from before, `match` is a great way
to do that. Try this code:
```{rust,no_run}
use std::old_io;
use std::rand;
use std::cmp::Ordering;
fn main() {
println!("Guess the number!");
let secret_number = (rand::random::<u32>() % 100) + 1;
println!("The secret number is: {}", secret_number);
println!("Please input your guess.");
let input = old_io::stdin().read_line()
.ok()
.expect("Failed to read line");
let input_num: Result<u32, _> = input.parse();
let num = match input_num {
Ok(num) => num,
Err(_) => {
println!("Please input a number!");
return;
}
};
println!("You guessed: {}", num);
match cmp(num, secret_number) {
Ordering::Less => println!("Too small!"),
Ordering::Greater => println!("Too big!"),
Ordering::Equal => println!("You win!"),
}
}
fn cmp(a: u32, b: u32) -> Ordering {
if a < b { Ordering::Less }
else if a > b { Ordering::Greater }
else { Ordering::Equal }
}
```
We use a `match` to either give us the `u32` inside of the `Option`, or else
print an error message and return. Let's give this a shot:
```bash
$ cargo run
Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game)
Running `target/guessing_game`
Guess the number!
The secret number is: 17
Please input your guess.
5
Please input a number!
```
Uh, what? But we did!
... actually, we didn't. See, when you get a line of input from `stdin()`,
you get all the input. Including the `\n` character from you pressing Enter.
Therefore, `parse()` sees the string `"5\n"` and says "nope, that's not a
number; there's non-number stuff in there!" Luckily for us, `&str`s have an easy
method we can use defined on them: `trim()`. One small modification, and our
code looks like this:
```{rust,no_run}
use std::old_io;
use std::rand;
use std::cmp::Ordering;
fn main() {
println!("Guess the number!");
let secret_number = (rand::random::<u32>() % 100) + 1;
println!("The secret number is: {}", secret_number);
println!("Please input your guess.");
let input = old_io::stdin().read_line()
.ok()
.expect("Failed to read line");
let input_num: Result<u32, _> = input.trim().parse();
let num = match input_num {
Ok(num) => num,
Err(_) => {
println!("Please input a number!");
return;
}
};
println!("You guessed: {}", num);
match cmp(num, secret_number) {
Ordering::Less => println!("Too small!"),
Ordering::Greater => println!("Too big!"),
Ordering::Equal => println!("You win!"),
}
}
fn cmp(a: u32, b: u32) -> Ordering {
if a < b { Ordering::Less }
else if a > b { Ordering::Greater }
else { Ordering::Equal }
}
```
Let's try it!
```bash
$ cargo run
Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game)
Running `target/guessing_game`
Guess the number!
The secret number is: 58
Please input your guess.
76
You guessed: 76
Too big!
```
Nice! You can see I even added spaces before my guess, and it still figured
out that I guessed 76. Run the program a few times, and verify that guessing
the number works, as well as guessing a number too small.
The Rust compiler helped us out quite a bit there! This technique is called
"leaning on the compiler", and it's often useful when working on some code.
Let the error messages help guide you towards the correct types.
Now we've got most of the game working, but we can only make one guess. Let's
change that by adding loops!
## Looping
As we already discussed, the `loop` keyword gives us an infinite loop.
Let's add that in:
```{rust,no_run}
use std::old_io;
use std::rand;
use std::cmp::Ordering;
fn main() {
println!("Guess the number!");
let secret_number = (rand::random::<u32>() % 100) + 1;
println!("The secret number is: {}", secret_number);
loop {
println!("Please input your guess.");
let input = old_io::stdin().read_line()
.ok()
.expect("Failed to read line");
let input_num: Result<u32, _> = input.trim().parse();
let num = match input_num {
Ok(num) => num,
Err(_) => {
println!("Please input a number!");
return;
}
};
println!("You guessed: {}", num);
match cmp(num, secret_number) {
Ordering::Less => println!("Too small!"),
Ordering::Greater => println!("Too big!"),
Ordering::Equal => println!("You win!"),
}
}
}
fn cmp(a: u32, b: u32) -> Ordering {
if a < b { Ordering::Less }
else if a > b { Ordering::Greater }
else { Ordering::Equal }
}
```
And try it out. But wait, didn't we just add an infinite loop? Yup. Remember
that `return`? If we give a non-number answer, we'll `return` and quit. Observe:
```bash
$ cargo run
Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game)
Running `target/guessing_game`
Guess the number!
The secret number is: 59
Please input your guess.
45
You guessed: 45
Too small!
Please input your guess.
60
You guessed: 60
Too big!
Please input your guess.
59
You guessed: 59
You win!
Please input your guess.
quit
Please input a number!
```
Ha! `quit` actually quits. As does any other non-number input. Well, this is
suboptimal to say the least. First, let's actually quit when you win the game:
```{rust,no_run}
use std::old_io;
use std::rand;
use std::cmp::Ordering;
fn main() {
println!("Guess the number!");
let secret_number = (rand::random::<u32>() % 100) + 1;
println!("The secret number is: {}", secret_number);
loop {
println!("Please input your guess.");
let input = old_io::stdin().read_line()
.ok()
.expect("Failed to read line");
let input_num: Result<u32, _> = input.trim().parse();
let num = match input_num {
Ok(num) => num,
Err(_) => {
println!("Please input a number!");
return;
}
};
println!("You guessed: {}", num);
match cmp(num, secret_number) {
Ordering::Less => println!("Too small!"),
Ordering::Greater => println!("Too big!"),
Ordering::Equal => {
println!("You win!");
return;
},
}
}
}
fn cmp(a: u32, b: u32) -> Ordering {
if a < b { Ordering::Less }
else if a > b { Ordering::Greater }
else { Ordering::Equal }
}
```
By adding the `return` line after the `You win!`, we'll exit the program when
we win. We have just one more tweak to make: when someone inputs a non-number,
we don't want to quit, we just want to ignore it. Change that `return` to
`continue`:
```{rust,no_run}
use std::old_io;
use std::rand;
use std::cmp::Ordering;
fn main() {
println!("Guess the number!");
let secret_number = (rand::random::<u32>() % 100) + 1;
println!("The secret number is: {}", secret_number);
loop {
println!("Please input your guess.");
let input = old_io::stdin().read_line()
.ok()
.expect("Failed to read line");
let input_num: Result<u32, _> = input.trim().parse();
let num = match input_num {
Ok(num) => num,
Err(_) => {
println!("Please input a number!");
continue;
}
};
println!("You guessed: {}", num);
match cmp(num, secret_number) {
Ordering::Less => println!("Too small!"),
Ordering::Greater => println!("Too big!"),
Ordering::Equal => {
println!("You win!");
return;
},
}
}
}
fn cmp(a: u32, b: u32) -> Ordering {
if a < b { Ordering::Less }
else if a > b { Ordering::Greater }
else { Ordering::Equal }
}
```
Now we should be good! Let's try:
```bash
$ cargo run
Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game)
Running `target/guessing_game`
Guess the number!
The secret number is: 61
Please input your guess.
10
You guessed: 10
Too small!
Please input your guess.
99
You guessed: 99
Too big!
Please input your guess.
foo
Please input a number!
Please input your guess.
61
You guessed: 61
You win!
```
Awesome! With one tiny last tweak, we have finished the guessing game. Can you
think of what it is? That's right, we don't want to print out the secret number.
It was good for testing, but it kind of ruins the game. Here's our final source:
```{rust,no_run}
use std::old_io;
use std::rand;
use std::cmp::Ordering;
fn main() {
println!("Guess the number!");
let secret_number = (rand::random::<u32>() % 100) + 1;
loop {
println!("Please input your guess.");
let input = old_io::stdin().read_line()
.ok()
.expect("Failed to read line");
let input_num: Result<u32, _> = input.trim().parse();
let num = match input_num {
Ok(num) => num,
Err(_) => {
println!("Please input a number!");
continue;
}
};
println!("You guessed: {}", num);
match cmp(num, secret_number) {
Ordering::Less => println!("Too small!"),
Ordering::Greater => println!("Too big!"),
Ordering::Equal => {
println!("You win!");
return;
},
}
}
}
fn cmp(a: u32, b: u32) -> Ordering {
if a < b { Ordering::Less }
else if a > b { Ordering::Greater }
else { Ordering::Equal }
}
```
## Complete!
At this point, you have successfully built the Guessing Game! Congratulations!
You've now learned the basic syntax of Rust. All of this is relatively close to
various other programming languages you have used in the past. These
fundamental syntactical and semantic elements will form the foundation for the
rest of your Rust education.
Now that you're an expert at the basics, it's time to learn about some of
Rust's more unique features.

View File

@ -18,13 +18,15 @@ the Cargo
README](https://github.com/rust-lang/cargo#installing-cargo-from-nightlies) README](https://github.com/rust-lang/cargo#installing-cargo-from-nightlies)
for specific instructions about installing it. for specific instructions about installing it.
## Converting to Cargo
Let's convert Hello World to Cargo. Let's convert Hello World to Cargo.
To Cargo-ify our project, we need to do two things: Make a `Cargo.toml` To Cargo-ify our project, we need to do two things: Make a `Cargo.toml`
configuration file, and put our source file in the right place. Let's configuration file, and put our source file in the right place. Let's
do that part first: do that part first:
```{bash} ```bash
$ mkdir src $ mkdir src
$ mv main.rs src/main.rs $ mv main.rs src/main.rs
``` ```
@ -36,7 +38,7 @@ place for everything, and everything in its place.
Next, our configuration file: Next, our configuration file:
```{bash} ```bash
$ editor Cargo.toml $ editor Cargo.toml
``` ```
@ -73,19 +75,21 @@ well as what it is named.
Once you have this file in place, we should be ready to build! Try this: Once you have this file in place, we should be ready to build! Try this:
```{bash} ```bash
$ cargo build $ cargo build
Compiling hello_world v0.0.1 (file:///home/yourname/projects/hello_world) Compiling hello_world v0.0.1 (file:///home/yourname/projects/hello_world)
$ ./target/hello_world $ ./target/debug/hello_world
Hello, world! Hello, world!
``` ```
Bam! We build our project with `cargo build`, and run it with Bam! We build our project with `cargo build`, and run it with
`./target/hello_world`. This hasn't bought us a whole lot over our simple use `./target/debug/hello_world`. This hasn't bought us a whole lot over our simple use
of `rustc`, but think about the future: when our project has more than one of `rustc`, but think about the future: when our project has more than one
file, we would need to call `rustc` more than once, and pass it a bunch of options to file, we would need to call `rustc` more than once and pass it a bunch of options to
tell it to build everything together. With Cargo, as our project grows, we can tell it to build everything together. With Cargo, as our project grows, we can
just `cargo build` and it'll work the right way. just `cargo build`, and it'll work the right way. When your project is finally
ready for release, you can use `cargo build --release` to compile your crates with
optimizations.
You'll also notice that Cargo has created a new file: `Cargo.lock`. You'll also notice that Cargo has created a new file: `Cargo.lock`.
@ -103,6 +107,62 @@ That's it! We've successfully built `hello_world` with Cargo. Even though our
program is simple, it's using much of the real tooling that you'll use for the program is simple, it's using much of the real tooling that you'll use for the
rest of your Rust career. rest of your Rust career.
## A New Project
You don't have to go through this whole process every time you want to start a new
project! Cargo has the ability to make a bare-bones project directory in which you
can start developing right away.
To start a new project with Cargo, use `cargo new`:
```bash
$ cargo new hello_world --bin
```
We're passing `--bin` because we're making a binary program: if we
were making a library, we'd leave it off.
Let's check out what Cargo has generated for us:
```bash
$ cd hello_world
$ tree .
.
├── Cargo.toml
└── src
└── main.rs
1 directory, 2 files
```
If you don't have the `tree` command, you can probably get it from your distro's package
manager. It's not necessary, but it's certainly useful.
This is all we need to get started. First, let's check out `Cargo.toml`:
```toml
[package]
name = "hello_world"
version = "0.0.1"
authors = ["Your Name <you@example.com>"]
```
Cargo has populated this file with reasonable defaults based off the arguments you gave
it and your `git` global configuration. You may notice that Cargo has also initialized
the `hello_world` directory as a `git` repository.
Here's what's in `src/main.rs`:
```rust
fn main() {
println!("Hello, world!");
}
```
Cargo has generated a "Hello World!" for us, and you're ready to start coding! A
much more in-depth guide to Cargo can be found [here](http://doc.crates.io/guide.html).
Now that you've got the tools down, let's actually learn more about the Rust Now that you've got the tools down, let's actually learn more about the Rust
language itself. These are the basics that will serve you well through the rest language itself. These are the basics that will serve you well through the rest
of your time with Rust. of your time with Rust.

View File

@ -34,6 +34,20 @@ if x == 5 {
} }
``` ```
If there is more than one case, use an `else if`:
```rust
let x = 5;
if x == 5 {
println!("x is five!");
} else if x == 6 {
println!("x is six!");
} else {
println!("x is not five or six :(");
}
```
This is all pretty standard. However, you can also do this: This is all pretty standard. However, you can also do this:

View File

@ -0,0 +1,141 @@
% Inline Assembly
For extremely low-level manipulations and performance reasons, one
might wish to control the CPU directly. Rust supports using inline
assembly to do this via the `asm!` macro. The syntax roughly matches
that of GCC & Clang:
```ignore
asm!(assembly template
: output operands
: input operands
: clobbers
: options
);
```
Any use of `asm` is feature gated (requires `#![feature(asm)]` on the
crate to allow) and of course requires an `unsafe` block.
> **Note**: the examples here are given in x86/x86-64 assembly, but
> all platforms are supported.
## Assembly template
The `assembly template` is the only required parameter and must be a
literal string (i.e. `""`)
```
#![feature(asm)]
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
fn foo() {
unsafe {
asm!("NOP");
}
}
// other platforms
#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
fn foo() { /* ... */ }
fn main() {
// ...
foo();
// ...
}
```
(The `feature(asm)` and `#[cfg]`s are omitted from now on.)
Output operands, input operands, clobbers and options are all optional
but you must add the right number of `:` if you skip them:
```
# #![feature(asm)]
# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
# fn main() { unsafe {
asm!("xor %eax, %eax"
:
:
: "eax"
);
# } }
```
Whitespace also doesn't matter:
```
# #![feature(asm)]
# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
# fn main() { unsafe {
asm!("xor %eax, %eax" ::: "eax");
# } }
```
## Operands
Input and output operands follow the same format: `:
"constraints1"(expr1), "constraints2"(expr2), ..."`. Output operand
expressions must be mutable lvalues:
```
# #![feature(asm)]
# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
fn add(a: i32, b: i32) -> i32 {
let mut c = 0;
unsafe {
asm!("add $2, $0"
: "=r"(c)
: "0"(a), "r"(b)
);
}
c
}
# #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
# fn add(a: i32, b: i32) -> i32 { a + b }
fn main() {
assert_eq!(add(3, 14159), 14162)
}
```
## Clobbers
Some instructions modify registers which might otherwise have held
different values so we use the clobbers list to indicate to the
compiler not to assume any values loaded into those registers will
stay valid.
```
# #![feature(asm)]
# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
# fn main() { unsafe {
// Put the value 0x200 in eax
asm!("mov $$0x200, %eax" : /* no outputs */ : /* no inputs */ : "eax");
# } }
```
Input and output registers need not be listed since that information
is already communicated by the given constraints. Otherwise, any other
registers used either implicitly or explicitly should be listed.
If the assembly changes the condition code register `cc` should be
specified as one of the clobbers. Similarly, if the assembly modifies
memory, `memory` should also be specified.
## Options
The last section, `options` is specific to Rust. The format is comma
separated literal strings (i.e. `:"foo", "bar", "baz"`). It's used to
specify some extra info about the inline assembly:
Current valid options are:
1. *volatile* - specifying this is analogous to
`__asm__ __volatile__ (...)` in gcc/clang.
2. *alignstack* - certain instructions expect the stack to be
aligned a certain way (i.e. SSE) and specifying this indicates to
the compiler to insert its usual stack alignment code
3. *intel* - use intel syntax instead of the default AT&T.

View File

@ -6,14 +6,14 @@ Linux or a Mac, all you need to do is this (note that you don't need to type
in the `$`s, they just indicate the start of each command): in the `$`s, they just indicate the start of each command):
```bash ```bash
$ curl -L https://static.rust-lang.org/rustup.sh | sudo sh $ curl -sf -L https://static.rust-lang.org/rustup.sh | sudo sh
``` ```
If you're concerned about the [potential insecurity](http://curlpipesh.tumblr.com/) of using `curl | sudo sh`, If you're concerned about the [potential insecurity](http://curlpipesh.tumblr.com/) of using `curl | sudo sh`,
please keep reading and see our disclaimer below. And feel free to use a two-step version of the installation and examine our installation script: please keep reading and see our disclaimer below. And feel free to use a two-step version of the installation and examine our installation script:
```bash ```bash
$ curl -L https://static.rust-lang.org/rustup.sh -O $ curl -f -L https://static.rust-lang.org/rustup.sh -O
$ sudo sh rustup.sh $ sudo sh rustup.sh
``` ```
@ -70,14 +70,19 @@ If you've got Rust installed, you can open up a shell, and type this:
$ rustc --version $ rustc --version
``` ```
You should see some output that looks something like this: You should see the version number, commit hash, commit date and build date:
```bash ```bash
rustc 1.0.0-nightly (f11f3e7ba 2015-01-04 20:02:14 +0000) rustc 1.0.0-nightly (f11f3e7ba 2015-01-04) (built 2015-01-06)
``` ```
If you did, Rust has been installed successfully! Congrats! If you did, Rust has been installed successfully! Congrats!
This installer also installs a copy of the documentation locally, so you can
read it offline. On UNIX systems, `/usr/local/share/doc/rust` is the location.
On Windows, it's in a `share/doc` directory, inside wherever you installed Rust
to.
If not, there are a number of places where you can get help. The easiest is If not, there are a number of places where you can get help. The easiest is
[the #rust IRC channel on irc.mozilla.org](irc://irc.mozilla.org/#rust), which [the #rust IRC channel on irc.mozilla.org](irc://irc.mozilla.org/#rust), which
you can access through you can access through

View File

@ -0,0 +1,25 @@
% Intrinsics
> **Note**: intrinsics will forever have an unstable interface, it is
> recommended to use the stable interfaces of libcore rather than intrinsics
> directly.
These are imported as if they were FFI functions, with the special
`rust-intrinsic` ABI. For example, if one was in a freestanding
context, but wished to be able to `transmute` between types, and
perform efficient pointer arithmetic, one would import those functions
via a declaration like
```
# #![feature(intrinsics)]
# fn main() {}
extern "rust-intrinsic" {
fn transmute<T, U>(x: T) -> U;
fn offset<T>(dst: *const T, offset: isize) -> *const T;
}
```
As with any other FFI functions, these are always `unsafe` to call.

View File

@ -57,14 +57,13 @@ for i in 0..nums.len() {
} }
``` ```
This is strictly worse than using an actual iterator. The `.iter()` method on This is strictly worse than using an actual iterator. You can iterate over vectors
vectors returns an iterator which iterates through a reference to each element directly, so write this:
of the vector in turn. So write this:
```rust ```rust
let nums = vec![1, 2, 3]; let nums = vec![1, 2, 3];
for num in nums.iter() { for num in &nums {
println!("{}", num); println!("{}", num);
} }
``` ```
@ -86,16 +85,17 @@ see it. This code works fine too:
```rust ```rust
let nums = vec![1, 2, 3]; let nums = vec![1, 2, 3];
for num in nums.iter() { for num in &nums {
println!("{}", *num); println!("{}", *num);
} }
``` ```
Now we're explicitly dereferencing `num`. Why does `iter()` give us references? Now we're explicitly dereferencing `num`. Why does `&nums` give us
Well, if it gave us the data itself, we would have to be its owner, which would references? Firstly, because we explicitly asked it to with
involve making a copy of the data and giving us the copy. With references, `&`. Secondly, if it gave us the data itself, we would have to be its
we're just borrowing a reference to the data, and so it's just passing owner, which would involve making a copy of the data and giving us the
a reference, without needing to do the copy. copy. With references, we're just borrowing a reference to the data,
and so it's just passing a reference, without needing to do the move.
So, now that we've established that ranges are often not what you want, let's So, now that we've established that ranges are often not what you want, let's
talk about what you do want instead. talk about what you do want instead.
@ -230,9 +230,9 @@ let nums = (1..100).collect::<Vec<i32>>();
Now, `collect()` will require that the range gives it some numbers, and so Now, `collect()` will require that the range gives it some numbers, and so
it will do the work of generating the sequence. it will do the work of generating the sequence.
Ranges are one of two basic iterators that you'll see. The other is `iter()`, Ranges are one of two basic iterators that you'll see. The other is `iter()`.
which you've used before. `iter()` can turn a vector into a simple iterator `iter()` can turn a vector into a simple iterator that gives you each element
that gives you each element in turn: in turn:
```rust ```rust
let nums = [1, 2, 3]; let nums = [1, 2, 3];
@ -243,10 +243,12 @@ for num in nums.iter() {
``` ```
These two basic iterators should serve you well. There are some more These two basic iterators should serve you well. There are some more
advanced iterators, including ones that are infinite. Like `count`: advanced iterators, including ones that are infinite. Like using range syntax
and `step_by`:
```rust ```rust
std::iter::count(1, 5); # #![feature(step_by)]
(1..).step_by(5);
``` ```
This iterator counts up from one, adding five each time. It will give This iterator counts up from one, adding five each time. It will give
@ -291,10 +293,11 @@ just use `for` instead.
There are tons of interesting iterator adapters. `take(n)` will return an There are tons of interesting iterator adapters. `take(n)` will return an
iterator over the next `n` elements of the original iterator, note that this iterator over the next `n` elements of the original iterator, note that this
has no side effect on the original iterator. Let's try it out with our infinite has no side effect on the original iterator. Let's try it out with our infinite
iterator from before, `count()`: iterator from before:
```rust ```rust
for i in std::iter::count(1, 5).take(5) { # #![feature(step_by)]
for i in (1..).step_by(5).take(5) {
println!("{}", i); println!("{}", i);
} }
``` ```

View File

@ -0,0 +1,79 @@
% Lang items
> **Note**: lang items are often provided by crates in the Rust distribution,
> and lang items themselves have an unstable interface. It is recommended to use
> officially distributed crates instead of defining your own lang items.
The `rustc` compiler has certain pluggable operations, that is,
functionality that isn't hard-coded into the language, but is
implemented in libraries, with a special marker to tell the compiler
it exists. The marker is the attribute `#[lang="..."]` and there are
various different values of `...`, i.e. various different 'lang
items'.
For example, `Box` pointers require two lang items, one for allocation
and one for deallocation. A freestanding program that uses the `Box`
sugar for dynamic allocations via `malloc` and `free`:
```
#![feature(lang_items, box_syntax, start, no_std, libc)]
#![no_std]
extern crate libc;
extern {
fn abort() -> !;
}
#[lang = "owned_box"]
pub struct Box<T>(*mut T);
#[lang="exchange_malloc"]
unsafe fn allocate(size: usize, _align: usize) -> *mut u8 {
let p = libc::malloc(size as libc::size_t) as *mut u8;
// malloc failed
if p as usize == 0 {
abort();
}
p
}
#[lang="exchange_free"]
unsafe fn deallocate(ptr: *mut u8, _size: usize, _align: usize) {
libc::free(ptr as *mut libc::c_void)
}
#[start]
fn main(argc: isize, argv: *const *const u8) -> isize {
let x = box 1;
0
}
#[lang = "stack_exhausted"] extern fn stack_exhausted() {}
#[lang = "eh_personality"] extern fn eh_personality() {}
#[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} }
```
Note the use of `abort`: the `exchange_malloc` lang item is assumed to
return a valid pointer, and so needs to do the check internally.
Other features provided by lang items include:
- overloadable operators via traits: the traits corresponding to the
`==`, `<`, dereferencing (`*`) and `+` (etc.) operators are all
marked with lang items; those specific four are `eq`, `ord`,
`deref`, and `add` respectively.
- stack unwinding and general failure; the `eh_personality`, `fail`
and `fail_bounds_checks` lang items.
- the traits in `std::marker` used to indicate types of
various kinds; lang items `send`, `sync` and `copy`.
- the marker types and variance indicators found in
`std::marker`; lang items `covariant_type`,
`contravariant_lifetime`, etc.
Lang items are loaded lazily by the compiler; e.g. if one never uses
`Box` then there is no need to define functions for `exchange_malloc`
and `exchange_free`. `rustc` will emit an error when an item is needed
but not found in the current crate or any that it depends on.

25
src/doc/trpl/link-args.md Normal file
View File

@ -0,0 +1,25 @@
% Link args
There is one other way to tell rustc how to customize linking, and that is via
the `link_args` attribute. This attribute is applied to `extern` blocks and
specifies raw flags which need to get passed to the linker when producing an
artifact. An example usage would be:
``` no_run
#![feature(link_args)]
#[link_args = "-foo -bar -baz"]
extern {}
# fn main() {}
```
Note that this feature is currently hidden behind the `feature(link_args)` gate
because this is not a sanctioned way of performing linking. Right now rustc
shells out to the system linker, so it makes sense to provide extra command line
arguments, but this will not always be the case. In the future rustc may use
LLVM directly to link native libraries in which case `link_args` will have no
meaning.
It is highly recommended to *not* use this attribute, and rather use the more
formal `#[link(...)]` attribute on `extern` blocks instead.

View File

@ -123,7 +123,7 @@ We now loop forever with `loop` and use `break` to break out early.
iteration. This will only print the odd numbers: iteration. This will only print the odd numbers:
```{rust} ```{rust}
for x in 0u32..10 { for x in 0..10 {
if x % 2 == 0 { continue; } if x % 2 == 0 { continue; }
println!("{}", x); println!("{}", x);

View File

@ -37,7 +37,7 @@ number of elements.
```rust ```rust
let x: Vec<u32> = vec![1, 2, 3]; let x: Vec<u32> = vec![1, 2, 3];
# assert_eq!(&[1,2,3], &x); # assert_eq!(x, [1, 2, 3]);
``` ```
This can't be an ordinary function, because it takes any number of arguments. This can't be an ordinary function, because it takes any number of arguments.
@ -51,7 +51,7 @@ let x: Vec<u32> = {
temp_vec.push(3); temp_vec.push(3);
temp_vec temp_vec
}; };
# assert_eq!(&[1,2,3], &x); # assert_eq!(x, [1, 2, 3]);
``` ```
We can implement this shorthand, using a macro: [^actual] We can implement this shorthand, using a macro: [^actual]
@ -73,7 +73,7 @@ macro_rules! vec {
}; };
} }
# fn main() { # fn main() {
# assert_eq!(&[1,2,3], &vec![1,2,3]); # assert_eq!(vec![1,2,3], [1, 2, 3]);
# } # }
``` ```
@ -189,12 +189,10 @@ shorthand for a data type could be valid as either an expression or a pattern.
## Repetition ## Repetition
The repetition behavior can seem somewhat magical, especially when multiple The repetition operator follows two principal rules:
names are bound at multiple nested levels of repetition. The two rules to keep
in mind are:
1. the behavior of `$(...)*` is to walk through one "layer" of repetitions, for 1. `$(...)*` walks through one "layer" of repetitions, for all of the `$name`s
all of the `$name`s it contains, in lockstep, and it contains, in lockstep, and
2. each `$name` must be under at least as many `$(...)*`s as it was matched 2. each `$name` must be under at least as many `$(...)*`s as it was matched
against. If it is under more, it'll be duplicated, as appropriate. against. If it is under more, it'll be duplicated, as appropriate.
@ -226,6 +224,10 @@ That's most of the matcher syntax. These examples use `$(...)*`, which is a
more" match. Both forms optionally include a separator, which can be any token more" match. Both forms optionally include a separator, which can be any token
except `+` or `*`. except `+` or `*`.
This system is based on
"[Macro-by-Example](http://www.cs.indiana.edu/ftp/techreports/TR206.pdf)"
(PDF link).
# Hygiene # Hygiene
Some languages implement macros using simple text substitution, which leads to Some languages implement macros using simple text substitution, which leads to
@ -273,19 +275,26 @@ macro, using [a GNU C extension] to emulate Rust's expression blocks.
}) })
``` ```
This looks reasonable, but watch what happens in this example: Here's a simple use case that goes terribly wrong:
```text ```text
const char *state = "reticulating splines"; const char *state = "reticulating splines";
LOG(state); LOG(state)
``` ```
The program will likely segfault, after it tries to execute This expands to
```text ```text
const char *state = "reticulating splines";
int state = get_log_state();
if (state > 0) {
printf("log(%d): %s\n", state, state); printf("log(%d): %s\n", state, state);
}
``` ```
The second variable named `state` shadows the first one. This is a problem
because the print statement should refer to both of them.
The equivalent Rust macro has the desired behavior. The equivalent Rust macro has the desired behavior.
```rust ```rust
@ -357,6 +366,64 @@ fn main() {
[items]: ../reference.html#items [items]: ../reference.html#items
# Recursive macros
A macro's expansion can include more macro invocations, including invocations
of the very same macro being expanded. These recursive macros are useful for
processing tree-structured input, as illustrated by this (simplistic) HTML
shorthand:
```rust
# #![allow(unused_must_use)]
macro_rules! write_html {
($w:expr, ) => (());
($w:expr, $e:tt) => (write!($w, "{}", $e));
($w:expr, $tag:ident [ $($inner:tt)* ] $($rest:tt)*) => {{
write!($w, "<{}>", stringify!($tag));
write_html!($w, $($inner)*);
write!($w, "</{}>", stringify!($tag));
write_html!($w, $($rest)*);
}};
}
fn main() {
# // FIXME(#21826)
use std::fmt::Write;
let mut out = String::new();
write_html!(&mut out,
html[
head[title["Macros guide"]]
body[h1["Macros are the best!"]]
]);
assert_eq!(out,
"<html><head><title>Macros guide</title></head>\
<body><h1>Macros are the best!</h1></body></html>");
}
```
# Debugging macro code
To see the results of expanding macros, run `rustc --pretty expanded`. The
output represents a whole crate, so you can also feed it back in to `rustc`,
which will sometimes produce better error messages than the original
compilation. Note that the `--pretty expanded` output may have a different
meaning if multiple variables of the same name (but different syntax contexts)
are in play in the same scope. In this case `--pretty expanded,hygiene` will
tell you about the syntax contexts.
`rustc` provides two syntax extensions that help with macro debugging. For now,
they are unstable and require feature gates.
* `log_syntax!(...)` will print its arguments to standard output, at compile
time, and "expand" to nothing.
* `trace_macros!(true)` will enable a compiler message every time a macro is
expanded. Use `trace_macros!(false)` later in expansion to turn it off.
# Further reading # Further reading
The [advanced macros chapter][] goes into more detail about macro syntax. It The [advanced macros chapter][] goes into more detail about macro syntax. It

View File

@ -23,6 +23,7 @@ the ability to use this *method call syntax* via the `impl` keyword.
Here's how it works: Here's how it works:
```{rust} ```{rust}
# #![feature(core)]
struct Circle { struct Circle {
x: f64, x: f64,
y: f64, y: f64,
@ -45,12 +46,35 @@ This will print `12.566371`.
We've made a struct that represents a circle. We then write an `impl` block, We've made a struct that represents a circle. We then write an `impl` block,
and inside it, define a method, `area`. Methods take a special first and inside it, define a method, `area`. Methods take a special first
parameter, `&self`. There are three variants: `self`, `&self`, and `&mut self`. parameter, of which there are three variants: `self`, `&self`, and `&mut self`.
You can think of this first parameter as being the `x` in `x.foo()`. The three You can think of this first parameter as being the `x` in `x.foo()`. The three
variants correspond to the three kinds of thing `x` could be: `self` if it's variants correspond to the three kinds of thing `x` could be: `self` if it's
just a value on the stack, `&self` if it's a reference, and `&mut self` if it's just a value on the stack, `&self` if it's a reference, and `&mut self` if it's
a mutable reference. We should default to using `&self`, as it's the most a mutable reference. We should default to using `&self`, as you should prefer
common. borrowing over taking ownership, as well as taking immutable references
over mutable ones. Here's an example of all three variants:
```rust
struct Circle {
x: f64,
y: f64,
radius: f64,
}
impl Circle {
fn reference(&self) {
println!("taking self by reference!");
}
fn mutable_reference(&mut self) {
println!("taking self by mutable reference!");
}
fn takes_ownership(self) {
println!("taking ownership of self!");
}
}
```
Finally, as you may remember, the value of the area of a circle is `π*r²`. Finally, as you may remember, the value of the area of a circle is `π*r²`.
Because we took the `&self` parameter to `area`, we can use it just like any Because we took the `&self` parameter to `area`, we can use it just like any
@ -65,6 +89,7 @@ original example, `foo.bar().baz()`? This is called 'method chaining', and we
can do it by returning `self`. can do it by returning `self`.
``` ```
# #![feature(core)]
struct Circle { struct Circle {
x: f64, x: f64,
y: f64, y: f64,
@ -76,8 +101,8 @@ impl Circle {
std::f64::consts::PI * (self.radius * self.radius) std::f64::consts::PI * (self.radius * self.radius)
} }
fn grow(&self) -> Circle { fn grow(&self, increment: f64) -> Circle {
Circle { x: self.x, y: self.y, radius: (self.radius * 10.0) } Circle { x: self.x, y: self.y, radius: self.radius + increment }
} }
} }
@ -85,7 +110,7 @@ fn main() {
let c = Circle { x: 0.0, y: 0.0, radius: 2.0 }; let c = Circle { x: 0.0, y: 0.0, radius: 2.0 };
println!("{}", c.area()); println!("{}", c.area());
let d = c.grow().area(); let d = c.grow(2.0).area();
println!("{}", d); println!("{}", d);
} }
``` ```
@ -100,7 +125,7 @@ fn grow(&self) -> Circle {
``` ```
We just say we're returning a `Circle`. With this method, we can grow a new We just say we're returning a `Circle`. With this method, we can grow a new
circle with an area that's 100 times larger than the old one. circle to any arbitrary size.
## Static methods ## Static methods
@ -142,6 +167,7 @@ have method overloading, named arguments, or variable arguments. We employ
the builder pattern instead. It looks like this: the builder pattern instead. It looks like this:
``` ```
# #![feature(core)]
struct Circle { struct Circle {
x: f64, x: f64,
y: f64, y: f64,
@ -155,17 +181,23 @@ impl Circle {
} }
struct CircleBuilder { struct CircleBuilder {
coordinate: f64, x: f64,
y: f64,
radius: f64, radius: f64,
} }
impl CircleBuilder { impl CircleBuilder {
fn new() -> CircleBuilder { fn new() -> CircleBuilder {
CircleBuilder { coordinate: 0.0, radius: 0.0, } CircleBuilder { x: 0.0, y: 0.0, radius: 0.0, }
} }
fn coordinate(&mut self, coordinate: f64) -> &mut CircleBuilder { fn x(&mut self, coordinate: f64) -> &mut CircleBuilder {
self.coordinate = coordinate; self.x = coordinate;
self
}
fn y(&mut self, coordinate: f64) -> &mut CircleBuilder {
self.x = coordinate;
self self
} }
@ -175,18 +207,20 @@ impl CircleBuilder {
} }
fn finalize(&self) -> Circle { fn finalize(&self) -> Circle {
Circle { x: self.coordinate, y: self.coordinate, radius: self.radius } Circle { x: self.x, y: self.y, radius: self.radius }
} }
} }
fn main() { fn main() {
let c = CircleBuilder::new() let c = CircleBuilder::new()
.coordinate(10.0) .x(1.0)
.radius(5.0) .y(2.0)
.radius(2.0)
.finalize(); .finalize();
println!("area: {}", c.area()); println!("area: {}", c.area());
println!("x: {}", c.x);
println!("y: {}", c.y);
} }
``` ```

View File

@ -12,7 +12,7 @@ Additionally, strings are not null-terminated and can contain null bytes.
Rust has two main types of strings: `&str` and `String`. Rust has two main types of strings: `&str` and `String`.
# &str # `&str`
The first kind is a `&str`. This is pronounced a 'string slice'. The first kind is a `&str`. This is pronounced a 'string slice'.
String literals are of the type `&str`: String literals are of the type `&str`:
@ -36,10 +36,40 @@ Like vector slices, string slices are simply a pointer plus a length. This
means that they're a 'view' into an already-allocated string, such as a means that they're a 'view' into an already-allocated string, such as a
string literal or a `String`. string literal or a `String`.
# String ## `str`
A `String` is a heap-allocated string. This string is growable, and is also You may occasionally see references to a `str` type, without the `&`. While
guaranteed to be UTF-8. this type does exist, its not something you want to use yourself. Sometimes,
people confuse `str` for `String`, and write this:
```rust
struct S {
s: str,
}
```
This leads to ugly errors:
```text
error: the trait `core::marker::Sized` is not implemented for the type `str` [E0277]
note: `str` does not have a constant size known at compile-time
```
Instead, this `struct` should be
```rust
struct S {
s: String,
}
```
So lets talk about `String`s.
# `String`
A `String` is a heap-allocated string. This string is growable, and is
also guaranteed to be UTF-8. `String`s are commonly created by
converting from a string slice using the `to_string` method.
``` ```
let mut s = "Hello".to_string(); let mut s = "Hello".to_string();
@ -49,7 +79,7 @@ s.push_str(", world.");
println!("{}", s); println!("{}", s);
``` ```
You can coerce a `String` into a `&str` by dereferencing it: A reference to a `String` will automatically coerce to a string slice:
``` ```
fn takes_slice(slice: &str) { fn takes_slice(slice: &str) {
@ -58,7 +88,7 @@ fn takes_slice(slice: &str) {
fn main() { fn main() {
let s = "Hello".to_string(); let s = "Hello".to_string();
takes_slice(&*s); takes_slice(&s);
} }
``` ```
@ -99,7 +129,7 @@ need, and it can make your lifetimes more complex.
To write a function that's generic over types of strings, use `&str`. To write a function that's generic over types of strings, use `&str`.
``` ```
fn some_string_length(x: &str) -> uint { fn some_string_length(x: &str) -> usize {
x.len() x.len()
} }
@ -147,6 +177,7 @@ Rust provides iterators for each of these situations:
Usually, the `graphemes()` method on `&str` is what you want: Usually, the `graphemes()` method on `&str` is what you want:
``` ```
# #![feature(unicode)]
let s = "u͔n͈̰̎i̙̮͚̦c͚̉o̼̩̰͗d͔̆̓ͥé"; let s = "u͔n͈̰̎i̙̮͚̦c͚̉o̼̩̰͗d͔̆̓ͥé";
for l in s.graphemes(true) { for l in s.graphemes(true) {
@ -277,7 +308,18 @@ This will print:
Many more bytes than graphemes! Many more bytes than graphemes!
# Other Documentation # `Deref` coercions
* [the `&str` API documentation](../std/str/index.html) References to `String`s will automatically coerce into `&str`s. Like this:
* [the `String` API documentation](../std/string/index.html)
```
fn hello(s: &str) {
println!("Hello, {}!", s);
}
let slice = "Steve";
let string = "Steve".to_string();
hello(slice);
hello(&string);
```

168
src/doc/trpl/no-stdlib.md Normal file
View File

@ -0,0 +1,168 @@
% No stdlib
By default, `std` is linked to every Rust crate. In some contexts,
this is undesirable, and can be avoided with the `#![no_std]`
attribute attached to the crate.
```ignore
// a minimal library
#![crate_type="lib"]
#![feature(no_std)]
#![no_std]
# // fn main() {} tricked you, rustdoc!
```
Obviously there's more to life than just libraries: one can use
`#[no_std]` with an executable, controlling the entry point is
possible in two ways: the `#[start]` attribute, or overriding the
default shim for the C `main` function with your own.
The function marked `#[start]` is passed the command line parameters
in the same format as C:
```
#![feature(lang_items, start, no_std, libc)]
#![no_std]
// Pull in the system libc library for what crt0.o likely requires
extern crate libc;
// Entry point for this program
#[start]
fn start(_argc: isize, _argv: *const *const u8) -> isize {
0
}
// These functions and traits are used by the compiler, but not
// for a bare-bones hello world. These are normally
// provided by libstd.
#[lang = "stack_exhausted"] extern fn stack_exhausted() {}
#[lang = "eh_personality"] extern fn eh_personality() {}
#[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} }
# // fn main() {} tricked you, rustdoc!
```
To override the compiler-inserted `main` shim, one has to disable it
with `#![no_main]` and then create the appropriate symbol with the
correct ABI and the correct name, which requires overriding the
compiler's name mangling too:
```ignore
#![feature(no_std)]
#![no_std]
#![no_main]
#![feature(lang_items, start)]
extern crate libc;
#[no_mangle] // ensure that this symbol is called `main` in the output
pub extern fn main(argc: i32, argv: *const *const u8) -> i32 {
0
}
#[lang = "stack_exhausted"] extern fn stack_exhausted() {}
#[lang = "eh_personality"] extern fn eh_personality() {}
#[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} }
# // fn main() {} tricked you, rustdoc!
```
The compiler currently makes a few assumptions about symbols which are available
in the executable to call. Normally these functions are provided by the standard
library, but without it you must define your own.
The first of these three functions, `stack_exhausted`, is invoked whenever stack
overflow is detected. This function has a number of restrictions about how it
can be called and what it must do, but if the stack limit register is not being
maintained then a thread always has an "infinite stack" and this function
shouldn't get triggered.
The second of these three functions, `eh_personality`, is used by the
failure mechanisms of the compiler. This is often mapped to GCC's
personality function (see the
[libstd implementation](../std/rt/unwind/index.html) for more
information), but crates which do not trigger a panic can be assured
that this function is never called. The final function, `panic_fmt`, is
also used by the failure mechanisms of the compiler.
## Using libcore
> **Note**: the core library's structure is unstable, and it is recommended to
> use the standard library instead wherever possible.
With the above techniques, we've got a bare-metal executable running some Rust
code. There is a good deal of functionality provided by the standard library,
however, that is necessary to be productive in Rust. If the standard library is
not sufficient, then [libcore](../core/index.html) is designed to be used
instead.
The core library has very few dependencies and is much more portable than the
standard library itself. Additionally, the core library has most of the
necessary functionality for writing idiomatic and effective Rust code.
As an example, here is a program that will calculate the dot product of two
vectors provided from C, using idiomatic Rust practices.
```
#![feature(lang_items, start, no_std, core, libc)]
#![no_std]
# extern crate libc;
extern crate core;
use core::prelude::*;
use core::mem;
#[no_mangle]
pub extern fn dot_product(a: *const u32, a_len: u32,
b: *const u32, b_len: u32) -> u32 {
use core::raw::Slice;
// Convert the provided arrays into Rust slices.
// The core::raw module guarantees that the Slice
// structure has the same memory layout as a &[T]
// slice.
//
// This is an unsafe operation because the compiler
// cannot tell the pointers are valid.
let (a_slice, b_slice): (&[u32], &[u32]) = unsafe {
mem::transmute((
Slice { data: a, len: a_len as usize },
Slice { data: b, len: b_len as usize },
))
};
// Iterate over the slices, collecting the result
let mut ret = 0;
for (i, j) in a_slice.iter().zip(b_slice.iter()) {
ret += (*i) * (*j);
}
return ret;
}
#[lang = "panic_fmt"]
extern fn panic_fmt(args: &core::fmt::Arguments,
file: &str,
line: u32) -> ! {
loop {}
}
#[lang = "stack_exhausted"] extern fn stack_exhausted() {}
#[lang = "eh_personality"] extern fn eh_personality() {}
# #[start] fn start(argc: isize, argv: *const *const u8) -> isize { 0 }
# fn main() {}
```
Note that there is one extra lang item here which differs from the examples
above, `panic_fmt`. This must be defined by consumers of libcore because the
core library declares panics, but it does not define it. The `panic_fmt`
lang item is this crate's definition of panic, and it must be guaranteed to
never return.
As can be seen in this example, the core library is intended to provide the
power of Rust in all circumstances, regardless of platform requirements. Further
libraries, such as liballoc, add functionality to libcore which make other
platform-specific assumptions, but continue to be more portable than the
standard library itself.

View File

@ -472,10 +472,15 @@ thread-safe counterpart of `Rc<T>`.
## Lifetime Elision ## Lifetime Elision
Earlier, we mentioned *lifetime elision*, a feature of Rust which allows you to Rust supports powerful local type inference in function bodies, but its
not write lifetime annotations in certain circumstances. All references have a forbidden in item signatures to allow reasoning about the types just based in
lifetime, and so if you elide a lifetime (like `&T` instead of `&'a T`), Rust the item signature alone. However, for ergonomic reasons a very restricted
will do three things to determine what those lifetimes should be. secondary inference algorithm called “lifetime elision” applies in function
signatures. It infers only based on the signature components themselves and not
based on the body of the function, only infers lifetime parameters, and does
this with only three easily memorizable and unambiguous rules. This makes
lifetime elision a shorthand for writing an item signature, while not hiding
away the actual types involved as full local inference would if applied to it.
When talking about lifetime elision, we use the term *input lifetime* and When talking about lifetime elision, we use the term *input lifetime* and
*output lifetime*. An *input lifetime* is a lifetime associated with a parameter *output lifetime*. An *input lifetime* is a lifetime associated with a parameter
@ -513,8 +518,8 @@ Otherwise, it is an error to elide an output lifetime.
### Examples ### Examples
Here are some examples of functions with elided lifetimes, and the version of Here are some examples of functions with elided lifetimes. We've paired each
what the elided lifetimes are expand to: example of an elided lifetime with its expanded form.
```{rust,ignore} ```{rust,ignore}
fn print(s: &str); // elided fn print(s: &str); // elided

View File

@ -177,6 +177,7 @@ match origin {
If you want to match against a slice or array, you can use `&`: If you want to match against a slice or array, you can use `&`:
```{rust} ```{rust}
# #![feature(slice_patterns)]
fn main() { fn main() {
let v = vec!["match_this", "1"]; let v = vec!["match_this", "1"];

View File

@ -1,29 +1,5 @@
% Compiler Plugins % Compiler Plugins
<div class="unstable-feature">
<p>
<b>Warning:</b> Plugins are an advanced, unstable feature! For many details,
the only available documentation is the <a
href="../syntax/index.html"><code>libsyntax</code></a> and <a
href="../rustc/index.html"><code>librustc</code></a> API docs, or even the source
code itself. These internal compiler APIs are also subject to change at any
time.
</p>
<p>
For defining new syntax it is often much easier to use Rust's <a
href="macros.html">built-in macro system</a>.
</p>
<p style="margin-bottom: 0">
The code in this document uses language features not covered in the Rust
Guide. See the <a href="../reference.html">Reference Manual</a> for more
information.
</p>
</div>
# Introduction # Introduction
`rustc` can load compiler plugins, which are user-provided libraries that `rustc` can load compiler plugins, which are user-provided libraries that
@ -63,7 +39,7 @@ that implements Roman numeral integer literals.
```ignore ```ignore
#![crate_type="dylib"] #![crate_type="dylib"]
#![feature(plugin_registrar)] #![feature(plugin_registrar, rustc_private)]
extern crate syntax; extern crate syntax;
extern crate rustc; extern crate rustc;
@ -71,8 +47,8 @@ extern crate rustc;
use syntax::codemap::Span; use syntax::codemap::Span;
use syntax::parse::token; use syntax::parse::token;
use syntax::ast::{TokenTree, TtToken}; use syntax::ast::{TokenTree, TtToken};
use syntax::ext::base::{ExtCtxt, MacResult, DummyResult, MacExpr}; use syntax::ext::base::{ExtCtxt, MacResult, DummyResult, MacEager};
use syntax::ext::build::AstBuilder; // trait for expr_uint use syntax::ext::build::AstBuilder; // trait for expr_usize
use rustc::plugin::Registry; use rustc::plugin::Registry;
fn expand_rn(cx: &mut ExtCtxt, sp: Span, args: &[TokenTree]) fn expand_rn(cx: &mut ExtCtxt, sp: Span, args: &[TokenTree])
@ -92,13 +68,13 @@ fn expand_rn(cx: &mut ExtCtxt, sp: Span, args: &[TokenTree])
} }
}; };
let mut text = &text; let mut text = &*text;
let mut total = 0; let mut total = 0;
while !text.is_empty() { while !text.is_empty() {
match NUMERALS.iter().find(|&&(rn, _)| text.starts_with(rn)) { match NUMERALS.iter().find(|&&(rn, _)| text.starts_with(rn)) {
Some(&(rn, val)) => { Some(&(rn, val)) => {
total += val; total += val;
text = text.slice_from(rn.len()); text = &text[rn.len()..];
} }
None => { None => {
cx.span_err(sp, "invalid Roman numeral"); cx.span_err(sp, "invalid Roman numeral");
@ -107,7 +83,7 @@ fn expand_rn(cx: &mut ExtCtxt, sp: Span, args: &[TokenTree])
} }
} }
MacExpr::new(cx.expr_uint(sp, total)) MacEager::expr(cx.expr_u32(sp, total))
} }
#[plugin_registrar] #[plugin_registrar]
@ -146,14 +122,7 @@ a more involved macro example, see
## Tips and tricks ## Tips and tricks
To see the results of expanding syntax extensions, run Some of the [macro debugging tips](macros.html#debugging-macro-code) are applicable.
`rustc --pretty expanded`. The output represents a whole crate, so you
can also feed it back in to `rustc`, which will sometimes produce better
error messages than the original compilation. Note that the
`--pretty expanded` output may have a different meaning if multiple
variables of the same name (but different syntax contexts) are in play
in the same scope. In this case `--pretty expanded,hygiene` will tell
you about the syntax contexts.
You can use [`syntax::parse`](../syntax/parse/index.html) to turn token trees into You can use [`syntax::parse`](../syntax/parse/index.html) to turn token trees into
higher-level syntax elements like expressions: higher-level syntax elements like expressions:
@ -184,8 +153,13 @@ and return
[`DummyResult`](../syntax/ext/base/struct.DummyResult.html), [`DummyResult`](../syntax/ext/base/struct.DummyResult.html),
so that the compiler can continue and find further errors. so that the compiler can continue and find further errors.
To print syntax fragments for debugging, you can use
[`span_note`](../syntax/ext/base/struct.ExtCtxt.html#method.span_note) together
with
[`syntax::print::pprust::*_to_string`](http://doc.rust-lang.org/syntax/print/pprust/index.html#functions).
The example above produced an integer literal using The example above produced an integer literal using
[`AstBuilder::expr_uint`](../syntax/ext/build/trait.AstBuilder.html#tymethod.expr_uint). [`AstBuilder::expr_usize`](../syntax/ext/build/trait.AstBuilder.html#tymethod.expr_usize).
As an alternative to the `AstBuilder` trait, `libsyntax` provides a set of As an alternative to the `AstBuilder` trait, `libsyntax` provides a set of
[quasiquote macros](../syntax/ext/quote/index.html). They are undocumented and [quasiquote macros](../syntax/ext/quote/index.html). They are undocumented and
very rough around the edges. However, the implementation may be a good very rough around the edges. However, the implementation may be a good

View File

@ -361,16 +361,16 @@ duration a *lifetime*. Let's try a more complex example:
```{rust} ```{rust}
fn main() { fn main() {
let x = &mut 5; let mut x = 5;
if *x < 10 { if x < 10 {
let y = &x; let y = &x;
println!("Oh no: {}", y); println!("Oh no: {}", y);
return; return;
} }
*x -= 1; x -= 1;
println!("Oh no: {}", x); println!("Oh no: {}", x);
} }
@ -382,17 +382,18 @@ mutated, and therefore, lets us pass. This wouldn't work:
```{rust,ignore} ```{rust,ignore}
fn main() { fn main() {
let x = &mut 5; let mut x = 5;
if *x < 10 { if x < 10 {
let y = &x; let y = &x;
*x -= 1;
x -= 1;
println!("Oh no: {}", y); println!("Oh no: {}", y);
return; return;
} }
*x -= 1; x -= 1;
println!("Oh no: {}", x); println!("Oh no: {}", x);
} }
@ -401,12 +402,12 @@ fn main() {
It gives this error: It gives this error:
```text ```text
test.rs:5:8: 5:10 error: cannot assign to `*x` because it is borrowed test.rs:7:9: 7:15 error: cannot assign to `x` because it is borrowed
test.rs:5 *x -= 1; test.rs:7 x -= 1;
^~ ^~~~~~
test.rs:4:16: 4:18 note: borrow of `*x` occurs here test.rs:5:18: 5:19 note: borrow of `x` occurs here
test.rs:4 let y = &x; test.rs:5 let y = &x;
^~ ^
``` ```
As you might guess, this kind of analysis is complex for a human, and therefore As you might guess, this kind of analysis is complex for a human, and therefore
@ -497,13 +498,10 @@ they go out of scope:
However, boxes do _not_ use reference counting or garbage collection. Boxes are However, boxes do _not_ use reference counting or garbage collection. Boxes are
what's called an *affine type*. This means that the Rust compiler, at compile what's called an *affine type*. This means that the Rust compiler, at compile
time, determines when the box comes into and goes out of scope, and inserts the time, determines when the box comes into and goes out of scope, and inserts the
appropriate calls there. Furthermore, boxes are a specific kind of affine type, appropriate calls there.
known as a *region*. You can read more about regions [in this paper on the
Cyclone programming
language](http://www.cs.umd.edu/projects/cyclone/papers/cyclone-regions.pdf).
You don't need to fully grok the theory of affine types or regions to grok You don't need to fully grok the theory of affine types to grok boxes, though.
boxes, though. As a rough approximation, you can treat this Rust code: As a rough approximation, you can treat this Rust code:
```{rust} ```{rust}
{ {
@ -560,43 +558,44 @@ fn main() {
In this case, Rust knows that `x` is being *borrowed* by the `add_one()` In this case, Rust knows that `x` is being *borrowed* by the `add_one()`
function, and since it's only reading the value, allows it. function, and since it's only reading the value, allows it.
We can borrow `x` multiple times, as long as it's not simultaneous: We can borrow `x` as read-only multiple times, even simultaneously:
```{rust} ```{rust}
fn add_one(x: &i32) -> i32 { fn add(x: &i32, y: &i32) -> i32 {
*x + 1 *x + *y
} }
fn main() { fn main() {
let x = Box::new(5); let x = Box::new(5);
println!("{}", add_one(&*x)); println!("{}", add(&*x, &*x));
println!("{}", add_one(&*x)); println!("{}", add(&*x, &*x));
println!("{}", add_one(&*x));
} }
``` ```
Or as long as it's not a mutable borrow. This will error: We can mutably borrow `x` multiple times, but only if x itself is mutable, and
it may not be *simultaneously* borrowed:
```{rust,ignore} ```{rust,ignore}
fn add_one(x: &mut i32) -> i32 { fn increment(x: &mut i32) {
*x + 1 *x += 1;
} }
fn main() { fn main() {
let x = Box::new(5); // If variable x is not "mut", this will not compile
let mut x = Box::new(5);
println!("{}", add_one(&*x)); // error: cannot borrow immutable dereference increment(&mut x);
// of `&`-pointer as mutable increment(&mut x);
println!("{}", x);
} }
``` ```
Notice we changed the signature of `add_one()` to request a mutable reference. Notice the signature of `increment()` requests a mutable reference.
## Best practices ## Best practices
Boxes are appropriate to use in two situations: Recursive data structures, Boxes are most appropriate to use when defining recursive data structures.
and occasionally, when returning data.
### Recursive data structures ### Recursive data structures
@ -630,14 +629,6 @@ we don't know the size, and therefore, we need to heap allocate our list.
Working with recursive or other unknown-sized data structures is the primary Working with recursive or other unknown-sized data structures is the primary
use-case for boxes. use-case for boxes.
### Returning data
This is important enough to have its own section entirely. The TL;DR is this:
you don't generally want to return pointers, even when you might in a language
like C or C++.
See [Returning Pointers](#returning-pointers) below for more.
# Rc and Arc # Rc and Arc
This part is coming soon. This part is coming soon.
@ -654,74 +645,6 @@ This part is coming soon.
This part is coming soon. This part is coming soon.
# Returning Pointers
In many languages with pointers, you'd return a pointer from a function
so as to avoid copying a large data structure. For example:
```{rust}
struct BigStruct {
one: i32,
two: i32,
// etc
one_hundred: i32,
}
fn foo(x: Box<BigStruct>) -> Box<BigStruct> {
Box::new(*x)
}
fn main() {
let x = Box::new(BigStruct {
one: 1,
two: 2,
one_hundred: 100,
});
let y = foo(x);
}
```
The idea is that by passing around a box, you're only copying a pointer, rather
than the hundred `int`s that make up the `BigStruct`.
This is an antipattern in Rust. Instead, write this:
```{rust}
struct BigStruct {
one: i32,
two: i32,
// etc
one_hundred: i32,
}
fn foo(x: Box<BigStruct>) -> BigStruct {
*x
}
fn main() {
let x = Box::new(BigStruct {
one: 1,
two: 2,
one_hundred: 100,
});
let y = Box::new(foo(x));
}
```
This gives you flexibility without sacrificing performance.
You may think that this gives us terrible performance: return a value and then
immediately box it up ?! Isn't this pattern the worst of both worlds? Rust is
smarter than that. There is no copy in this code. `main` allocates enough room
for the `box`, passes a pointer to that memory into `foo` as `x`, and then
`foo` writes the value straight into the `Box<T>`.
This is important enough that it bears repeating: pointers are not for
optimizing returning values from your code. Allow the caller to choose how they
want to use your output.
# Creating your own Pointers # Creating your own Pointers
This part is coming soon. This part is coming soon.

View File

@ -1,159 +0,0 @@
% Standard Input
Getting input from the keyboard is pretty easy, but uses some things
we haven't seen before. Here's a simple program that reads some input,
and then prints it back out:
```{rust,ignore}
fn main() {
println!("Type something!");
let input = std::old_io::stdin().read_line().ok().expect("Failed to read line");
println!("{}", input);
}
```
Let's go over these chunks, one by one:
```{rust,ignore}
std::old_io::stdin();
```
This calls a function, `stdin()`, that lives inside the `std::old_io` module. As
you can imagine, everything in `std` is provided by Rust, the 'standard
library.' We'll talk more about the module system later.
Since writing the fully qualified name all the time is annoying, we can use
the `use` statement to import it in:
```{rust}
use std::old_io::stdin;
stdin();
```
However, it's considered better practice to not import individual functions, but
to import the module, and only use one level of qualification:
```{rust}
use std::old_io;
old_io::stdin();
```
Let's update our example to use this style:
```{rust,ignore}
use std::old_io;
fn main() {
println!("Type something!");
let input = old_io::stdin().read_line().ok().expect("Failed to read line");
println!("{}", input);
}
```
Next up:
```{rust,ignore}
.read_line()
```
The `read_line()` method can be called on the result of `stdin()` to return
a full line of input. Nice and easy.
```{rust,ignore}
.ok().expect("Failed to read line");
```
Do you remember this code?
```{rust}
enum OptionalInt {
Value(i32),
Missing,
}
fn main() {
let x = OptionalInt::Value(5);
let y = OptionalInt::Missing;
match x {
OptionalInt::Value(n) => println!("x is {}", n),
OptionalInt::Missing => println!("x is missing!"),
}
match y {
OptionalInt::Value(n) => println!("y is {}", n),
OptionalInt::Missing => println!("y is missing!"),
}
}
```
We had to match each time to see if we had a value or not. In this case,
though, we _know_ that `x` has a `Value`, but `match` forces us to handle
the `missing` case. This is what we want 99% of the time, but sometimes, we
know better than the compiler.
Likewise, `read_line()` does not return a line of input. It _might_ return a
line of input, though it might also fail to do so. This could happen if our program
isn't running in a terminal, but as part of a cron job, or some other context
where there's no standard input. Because of this, `read_line` returns a type
very similar to our `OptionalInt`: an `IoResult<T>`. We haven't talked about
`IoResult<T>` yet because it is the *generic* form of our `OptionalInt`.
Until then, you can think of it as being the same thing, just for any type
not just `i32`s.
Rust provides a method on these `IoResult<T>`s called `ok()`, which does the
same thing as our `match` statement but assumes that we have a valid value.
We then call `expect()` on the result, which will terminate our program if we
don't have a valid value. In this case, if we can't get input, our program
doesn't work, so we're okay with that. In most cases, we would want to handle
the error case explicitly. `expect()` allows us to give an error message if
this crash happens.
We will cover the exact details of how all of this works later in the Guide.
For now, this gives you enough of a basic understanding to work with.
Back to the code we were working on! Here's a refresher:
```{rust,ignore}
use std::old_io;
fn main() {
println!("Type something!");
let input = old_io::stdin().read_line().ok().expect("Failed to read line");
println!("{}", input);
}
```
With long lines like this, Rust gives you some flexibility with the whitespace.
We _could_ write the example like this:
```{rust,ignore}
use std::old_io;
fn main() {
println!("Type something!");
// here, we'll show the types at each step
let input = old_io::stdin() // std::old_io::stdio::StdinReader
.read_line() // IoResult<String>
.ok() // Option<String>
.expect("Failed to read line"); // String
println!("{}", input);
}
```
Sometimes, this makes things more readable sometimes, less. Use your judgement
here.
That's all you need to get basic input from the standard input! It's not too
complicated, but there are a number of small parts.

View File

@ -79,12 +79,13 @@ fn main() {
} }
``` ```
This has some upsides: static dispatching of any method calls, allowing for This has a great upside: static dispatch allows function calls to be
inlining and hence usually higher performance. It also has some downsides: inlined because the callee is known at compile time, and inlining is
causing code bloat due to many copies of the same function existing in the the key to good optimization. Static dispatch is fast, but it comes at
binary, one for each type. a tradeoff: 'code bloat', due to many copies of the same function
existing in the binary, one for each type.
Furthermore, compilers arent perfect and may “optimise” code to become slower. Furthermore, compilers arent perfect and may “optimize” code to become slower.
For example, functions inlined too eagerly will bloat the instruction cache For example, functions inlined too eagerly will bloat the instruction cache
(cache rules everything around us). This is part of the reason that `#[inline]` (cache rules everything around us). This is part of the reason that `#[inline]`
and `#[inline(always)]` should be used carefully, and one reason why using a and `#[inline(always)]` should be used carefully, and one reason why using a
@ -92,8 +93,8 @@ dynamic dispatch is sometimes more efficient.
However, the common case is that it is more efficient to use static dispatch, However, the common case is that it is more efficient to use static dispatch,
and one can always have a thin statically-dispatched wrapper function that does and one can always have a thin statically-dispatched wrapper function that does
a dynamic, but not vice versa, meaning static calls are more flexible. The a dynamic dispatch, but not vice versa, meaning static calls are more flexible.
standard library tries to be statically dispatched where possible for this The standard library tries to be statically dispatched where possible for this
reason. reason.
## Dynamic dispatch ## Dynamic dispatch
@ -101,38 +102,11 @@ reason.
Rust provides dynamic dispatch through a feature called 'trait objects.' Trait Rust provides dynamic dispatch through a feature called 'trait objects.' Trait
objects, like `&Foo` or `Box<Foo>`, are normal values that store a value of objects, like `&Foo` or `Box<Foo>`, are normal values that store a value of
*any* type that implements the given trait, where the precise type can only be *any* type that implements the given trait, where the precise type can only be
known at runtime. The methods of the trait can be called on a trait object via known at runtime.
a special record of function pointers (created and managed by the compiler).
A function that takes a trait object is not specialised to each of the types A trait object can be obtained from a pointer to a concrete type that
that implements `Foo`: only one copy is generated, often (but not always) implements the trait by *casting* it (e.g. `&x as &Foo`) or *coercing* it
resulting in less code bloat. However, this comes at the cost of requiring (e.g. using `&x` as an argument to a function that takes `&Foo`).
slower virtual function calls, and effectively inhibiting any chance of
inlining and related optimisations from occurring.
Trait objects are both simple and complicated: their core representation and
layout is quite straight-forward, but there are some curly error messages and
surprising behaviours to discover.
### Obtaining a trait object
There's two similar ways to get a trait object value: casts and coercions. If
`T` is a type that implements a trait `Foo` (e.g. `u8` for the `Foo` above),
then the two ways to get a `Foo` trait object out of a pointer to `T` look
like:
```{rust,ignore}
let ref_to_t: &T = ...;
// `as` keyword for casting
let cast = ref_to_t as &Foo;
// using a `&T` in a place that has a known type of `&Foo` will implicitly coerce:
let coerce: &Foo = ref_to_t;
fn also_coerce(_unused: &Foo) {}
also_coerce(ref_to_t);
```
These trait object coercions and casts also work for pointers like `&mut T` to These trait object coercions and casts also work for pointers like `&mut T` to
`&mut Foo` and `Box<T>` to `Box<Foo>`, but that's all at the moment. Coercions `&mut Foo` and `Box<T>` to `Box<Foo>`, but that's all at the moment. Coercions
@ -140,13 +114,79 @@ and casts are identical.
This operation can be seen as "erasing" the compiler's knowledge about the This operation can be seen as "erasing" the compiler's knowledge about the
specific type of the pointer, and hence trait objects are sometimes referred to specific type of the pointer, and hence trait objects are sometimes referred to
"type erasure". as "type erasure".
Coming back to the example above, we can use the same trait to perform dynamic
dispatch with trait objects by casting:
```rust
# trait Foo { fn method(&self) -> String; }
# impl Foo for u8 { fn method(&self) -> String { format!("u8: {}", *self) } }
# impl Foo for String { fn method(&self) -> String { format!("string: {}", *self) } }
fn do_something(x: &Foo) {
x.method();
}
fn main() {
let x = 5u8;
do_something(&x as &Foo);
}
```
or by coercing:
```rust
# trait Foo { fn method(&self) -> String; }
# impl Foo for u8 { fn method(&self) -> String { format!("u8: {}", *self) } }
# impl Foo for String { fn method(&self) -> String { format!("string: {}", *self) } }
fn do_something(x: &Foo) {
x.method();
}
fn main() {
let x = "Hello".to_string();
do_something(&x);
}
```
A function that takes a trait object is not specialized to each of the types
that implements `Foo`: only one copy is generated, often (but not always)
resulting in less code bloat. However, this comes at the cost of requiring
slower virtual function calls, and effectively inhibiting any chance of
inlining and related optimisations from occurring.
### Why pointers?
Rust does not put things behind a pointer by default, unlike many managed
languages, so types can have different sizes. Knowing the size of the value at
compile time is important for things like passing it as an argument to a
function, moving it about on the stack and allocating (and deallocating) space
on the heap to store it.
For `Foo`, we would need to have a value that could be at least either a
`String` (24 bytes) or a `u8` (1 byte), as well as any other type for which
dependent crates may implement `Foo` (any number of bytes at all). There's no
way to guarantee that this last point can work if the values are stored without
a pointer, because those other types can be arbitrarily large.
Putting the value behind a pointer means the size of the value is not relevant
when we are tossing a trait object around, only the size of the pointer itself.
### Representation ### Representation
The methods of the trait can be called on a trait object via a special record
of function pointers traditionally called a 'vtable' (created and managed by
the compiler).
Trait objects are both simple and complicated: their core representation and
layout is quite straight-forward, but there are some curly error messages and
surprising behaviors to discover.
Let's start simple, with the runtime representation of a trait object. The Let's start simple, with the runtime representation of a trait object. The
`std::raw` module contains structs with layouts that are the same as the `std::raw` module contains structs with layouts that are the same as the
complicated build-in types, [including trait objects][stdraw]: complicated built-in types, [including trait objects][stdraw]:
```rust ```rust
# mod foo { # mod foo {
@ -223,14 +263,14 @@ static Foo_for_String_vtable: FooVtable = FooVtable {
The `destructor` field in each vtable points to a function that will clean up The `destructor` field in each vtable points to a function that will clean up
any resources of the vtable's type, for `u8` it is trivial, but for `String` it any resources of the vtable's type, for `u8` it is trivial, but for `String` it
will free the memory. This is necessary for owning trait objects like will free the memory. This is necessary for owning trait objects like
`Box<Foo>`, which need to clean-up both the `Box` allocation and as well as the `Box<Foo>`, which need to clean-up both the `Box` allocation as well as the
internal type when they go out of scope. The `size` and `align` fields store internal type when they go out of scope. The `size` and `align` fields store
the size of the erased type, and its alignment requirements; these are the size of the erased type, and its alignment requirements; these are
essentially unused at the moment since the information is embedded in the essentially unused at the moment since the information is embedded in the
destructor, but will be used in future, as trait objects are progressively made destructor, but will be used in the future, as trait objects are progressively
more flexible. made more flexible.
Suppose we've got some values that implement `Foo`, the explicit form of Suppose we've got some values that implement `Foo`, then the explicit form of
construction and use of `Foo` trait objects might look a bit like (ignoring the construction and use of `Foo` trait objects might look a bit like (ignoring the
type mismatches: they're all just pointers anyway): type mismatches: they're all just pointers anyway):
@ -264,23 +304,3 @@ let y = TraitObject {
If `b` or `y` were owning trait objects (`Box<Foo>`), there would be a If `b` or `y` were owning trait objects (`Box<Foo>`), there would be a
`(b.vtable.destructor)(b.data)` (respectively `y`) call when they went out of `(b.vtable.destructor)(b.data)` (respectively `y`) call when they went out of
scope. scope.
### Why pointers?
The use of language like "fat pointer" implies that a trait object is
always a pointer of some form, but why?
Rust does not put things behind a pointer by default, unlike many managed
languages, so types can have different sizes. Knowing the size of the value at
compile time is important for things like passing it as an argument to a
function, moving it about on the stack and allocating (and deallocating) space
on the heap to store it.
For `Foo`, we would need to have a value that could be at least either a
`String` (24 bytes) or a `u8` (1 byte), as well as any other type for which
dependent crates may implement `Foo` (any number of bytes at all). There's no
way to guarantee that this last point can work if the values are stored without
a pointer, because those other types can be arbitrarily large.
Putting the value behind a pointer means the size of the value is not relevant
when we are tossing a trait object around, only the size of the pointer itself.

View File

@ -25,8 +25,10 @@ compiled program, and exists for the entire duration it runs. The `string`
binding is a reference to this statically allocated string. String slices binding is a reference to this statically allocated string. String slices
have a fixed size, and cannot be mutated. have a fixed size, and cannot be mutated.
A `String`, on the other hand, is an in-memory string. This string is A `String`, on the other hand, is a heap-allocated string. This string
growable, and is also guaranteed to be UTF-8. is growable, and is also guaranteed to be UTF-8. `String`s are
commonly created by converting from a string slice using the
`to_string` method.
```{rust} ```{rust}
let mut s = "Hello".to_string(); // mut s: String let mut s = "Hello".to_string(); // mut s: String

View File

@ -129,11 +129,11 @@ $ echo $?
This is useful if you want to integrate `cargo test` into other tooling. This is useful if you want to integrate `cargo test` into other tooling.
We can invert our test's failure with another attribute: `should_fail`: We can invert our test's failure with another attribute: `should_panic`:
```rust ```rust
#[test] #[test]
#[should_fail] #[should_panic]
fn it_works() { fn it_works() {
assert!(false); assert!(false);
} }
@ -163,13 +163,13 @@ equality:
```rust ```rust
#[test] #[test]
#[should_fail] #[should_panic]
fn it_works() { fn it_works() {
assert_eq!("Hello", "world"); assert_eq!("Hello", "world");
} }
``` ```
Does this test pass or fail? Because of the `should_fail` attribute, it Does this test pass or fail? Because of the `should_panic` attribute, it
passes: passes:
```bash ```bash
@ -189,15 +189,15 @@ running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured
``` ```
`should_fail` tests can be fragile, as it's hard to guarantee that the test `should_panic` tests can be fragile, as it's hard to guarantee that the test
didn't fail for an unexpected reason. To help with this, an optional `expected` didn't fail for an unexpected reason. To help with this, an optional `expected`
parameter can be added to the `should_fail` attribute. The test harness will parameter can be added to the `should_panic` attribute. The test harness will
make sure that the failure message contains the provided text. A safer version make sure that the failure message contains the provided text. A safer version
of the example above would be: of the example above would be:
``` ```
#[test] #[test]
#[should_fail(expected = "assertion failed")] #[should_panic(expected = "assertion failed")]
fn it_works() { fn it_works() {
assert_eq!("Hello", "world"); assert_eq!("Hello", "world");
} }
@ -231,7 +231,7 @@ pub fn add_two(a: i32) -> i32 {
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod test {
use super::add_two; use super::add_two;
#[test] #[test]
@ -241,7 +241,7 @@ mod tests {
} }
``` ```
There's a few changes here. The first is the introduction of a `mod tests` with There's a few changes here. The first is the introduction of a `mod test` with
a `cfg` attribute. The module allows us to group all of our tests together, and a `cfg` attribute. The module allows us to group all of our tests together, and
to also define helper functions if needed, that don't become a part of the rest to also define helper functions if needed, that don't become a part of the rest
of our crate. The `cfg` attribute only compiles our test code if we're of our crate. The `cfg` attribute only compiles our test code if we're
@ -260,7 +260,7 @@ pub fn add_two(a: i32) -> i32 {
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod test {
use super::*; use super::*;
#[test] #[test]
@ -430,147 +430,3 @@ documentation tests: the `_0` is generated for the module test, and `add_two_0`
for the function test. These will auto increment with names like `add_two_1` as for the function test. These will auto increment with names like `add_two_1` as
you add more examples. you add more examples.
# Benchmark tests
Rust also supports benchmark tests, which can test the performance of your
code. Let's make our `src/lib.rs` look like this (comments elided):
```{rust,ignore}
extern crate test;
pub fn add_two(a: i32) -> i32 {
a + 2
}
#[cfg(test)]
mod tests {
use super::*;
use test::Bencher;
#[test]
fn it_works() {
assert_eq!(4, add_two(2));
}
#[bench]
fn bench_add_two(b: &mut Bencher) {
b.iter(|| add_two(2));
}
}
```
We've imported the `test` crate, which contains our benchmarking support.
We have a new function as well, with the `bench` attribute. Unlike regular
tests, which take no arguments, benchmark tests take a `&mut Bencher`. This
`Bencher` provides an `iter` method, which takes a closure. This closure
contains the code we'd like to benchmark.
We can run benchmark tests with `cargo bench`:
```bash
$ cargo bench
Compiling adder v0.0.1 (file:///home/steve/tmp/adder)
Running target/release/adder-91b3e234d4ed382a
running 2 tests
test tests::it_works ... ignored
test tests::bench_add_two ... bench: 1 ns/iter (+/- 0)
test result: ok. 0 passed; 0 failed; 1 ignored; 1 measured
```
Our non-benchmark test was ignored. You may have noticed that `cargo bench`
takes a bit longer than `cargo test`. This is because Rust runs our benchmark
a number of times, and then takes the average. Because we're doing so little
work in this example, we have a `1 ns/iter (+/- 0)`, but this would show
the variance if there was one.
Advice on writing benchmarks:
* Move setup code outside the `iter` loop; only put the part you want to measure inside
* Make the code do "the same thing" on each iteration; do not accumulate or change state
* Make the outer function idempotent too; the benchmark runner is likely to run
it many times
* Make the inner `iter` loop short and fast so benchmark runs are fast and the
calibrator can adjust the run-length at fine resolution
* Make the code in the `iter` loop do something simple, to assist in pinpointing
performance improvements (or regressions)
## Gotcha: optimizations
There's another tricky part to writing benchmarks: benchmarks compiled with
optimizations activated can be dramatically changed by the optimizer so that
the benchmark is no longer benchmarking what one expects. For example, the
compiler might recognize that some calculation has no external effects and
remove it entirely.
```{rust,ignore}
extern crate test;
use test::Bencher;
#[bench]
fn bench_xor_1000_ints(b: &mut Bencher) {
b.iter(|| {
(0..1000).fold(0, |old, new| old ^ new);
});
}
```
gives the following results
```text
running 1 test
test bench_xor_1000_ints ... bench: 0 ns/iter (+/- 0)
test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured
```
The benchmarking runner offers two ways to avoid this. Either, the closure that
the `iter` method receives can return an arbitrary value which forces the
optimizer to consider the result used and ensures it cannot remove the
computation entirely. This could be done for the example above by adjusting the
`b.iter` call to
```rust
# struct X;
# impl X { fn iter<T, F>(&self, _: F) where F: FnMut() -> T {} } let b = X;
b.iter(|| {
// note lack of `;` (could also use an explicit `return`).
(0..1000).fold(0, |old, new| old ^ new)
});
```
Or, the other option is to call the generic `test::black_box` function, which
is an opaque "black box" to the optimizer and so forces it to consider any
argument as used.
```rust
extern crate test;
# fn main() {
# struct X;
# impl X { fn iter<T, F>(&self, _: F) where F: FnMut() -> T {} } let b = X;
b.iter(|| {
let n = test::black_box(1000);
(0..n).fold(0, |a, b| a ^ b)
})
# }
```
Neither of these read or modify the value, and are very cheap for small values.
Larger values can be passed indirectly to reduce overhead (e.g.
`black_box(&huge_struct)`).
Performing either of the above changes gives the following benchmarking results
```text
running 1 test
test bench_xor_1000_ints ... bench: 131 ns/iter (+/- 3)
test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured
```
However, the optimizer can still modify a testcase in an undesirable manner
even when using either of the above.

View File

@ -0,0 +1,91 @@
% Tracing Macros
The `trace_macros` feature allows you to use a special feature: tracing macro
invocations.
In the advanced macros chapter, we defined a `bct` macro:
```rust
macro_rules! bct {
// cmd 0: d ... => ...
(0, $($ps:tt),* ; $_d:tt)
=> (bct!($($ps),*, 0 ; ));
(0, $($ps:tt),* ; $_d:tt, $($ds:tt),*)
=> (bct!($($ps),*, 0 ; $($ds),*));
// cmd 1p: 1 ... => 1 ... p
(1, $p:tt, $($ps:tt),* ; 1)
=> (bct!($($ps),*, 1, $p ; 1, $p));
(1, $p:tt, $($ps:tt),* ; 1, $($ds:tt),*)
=> (bct!($($ps),*, 1, $p ; 1, $($ds),*, $p));
// cmd 1p: 0 ... => 0 ...
(1, $p:tt, $($ps:tt),* ; $($ds:tt),*)
=> (bct!($($ps),*, 1, $p ; $($ds),*));
// halt on empty data string
( $($ps:tt),* ; )
=> (());
}
```
This is pretty complex! we can see the output
```rust,ignore
#![feature(trace_macros)]
macro_rules! bct {
// cmd 0: d ... => ...
(0, $($ps:tt),* ; $_d:tt)
=> (bct!($($ps),*, 0 ; ));
(0, $($ps:tt),* ; $_d:tt, $($ds:tt),*)
=> (bct!($($ps),*, 0 ; $($ds),*));
// cmd 1p: 1 ... => 1 ... p
(1, $p:tt, $($ps:tt),* ; 1)
=> (bct!($($ps),*, 1, $p ; 1, $p));
(1, $p:tt, $($ps:tt),* ; 1, $($ds:tt),*)
=> (bct!($($ps),*, 1, $p ; 1, $($ds),*, $p));
// cmd 1p: 0 ... => 0 ...
(1, $p:tt, $($ps:tt),* ; $($ds:tt),*)
=> (bct!($($ps),*, 1, $p ; $($ds),*));
// halt on empty data string
( $($ps:tt),* ; )
=> (());
}
fn main() {
trace_macros!(true);
bct!(0, 0, 1, 1, 1 ; 1, 0, 1);
}
```
This will print out a wall of text:
```text
bct! { 0 , 0 , 1 , 1 , 1 ; 1 , 0 , 1 }
bct! { 0 , 1 , 1 , 1 , 0 ; 0 , 1 }
bct! { 1 , 1 , 1 , 0 , 0 ; 1 }
bct! { 1 , 0 , 0 , 1 , 1 ; 1 , 1 }
bct! { 0 , 1 , 1 , 1 , 0 ; 1 , 1 , 0 }
bct! { 1 , 1 , 1 , 0 , 0 ; 1 , 0 }
bct! { 1 , 0 , 0 , 1 , 1 ; 1 , 0 , 1 }
bct! { 0 , 1 , 1 , 1 , 0 ; 1 , 0 , 1 , 0 }
bct! { 1 , 1 , 1 , 0 , 0 ; 0 , 1 , 0 }
bct! { 1 , 0 , 0 , 1 , 1 ; 0 , 1 , 0 }
bct! { 0 , 1 , 1 , 1 , 0 ; 0 , 1 , 0 }
```
And eventually, error:
```text
18:45 error: recursion limit reached while expanding the macro `bct`
=> (bct!($($ps),*, 1, $p ; $($ds),*));
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
```
The `trace_macros!` call is what produces this output, showing how we match
each time.

View File

@ -4,6 +4,7 @@ Do you remember the `impl` keyword, used to call a function with method
syntax? syntax?
```{rust} ```{rust}
# #![feature(core)]
struct Circle { struct Circle {
x: f64, x: f64,
y: f64, y: f64,
@ -21,6 +22,7 @@ Traits are similar, except that we define a trait with just the method
signature, then implement the trait for that struct. Like this: signature, then implement the trait for that struct. Like this:
```{rust} ```{rust}
# #![feature(core)]
struct Circle { struct Circle {
x: f64, x: f64,
y: f64, y: f64,
@ -84,6 +86,7 @@ which implements `HasArea` will have an `.area()` method.
Here's an extended example of how this works: Here's an extended example of how this works:
```{rust} ```{rust}
# #![feature(core)]
trait HasArea { trait HasArea {
fn area(&self) -> f64; fn area(&self) -> f64;
} }
@ -225,6 +228,7 @@ If we add a `use` line right above `main` and make the right things public,
everything is fine: everything is fine:
```{rust} ```{rust}
# #![feature(core)]
use shapes::HasArea; use shapes::HasArea;
mod shapes { mod shapes {
@ -273,6 +277,29 @@ One last thing about traits: generic functions with a trait bound use
dispatched. What's that mean? Check out the chapter on [static and dynamic dispatched. What's that mean? Check out the chapter on [static and dynamic
dispatch](static-and-dynamic-dispatch.html) for more. dispatch](static-and-dynamic-dispatch.html) for more.
## Multiple trait bounds
Youve seen that you can bound a generic type parameter with a trait:
```rust
fn foo<T: Clone>(x: T) {
x.clone();
}
```
If you need more than one bound, you can use `+`:
```rust
use std::fmt::Debug;
fn foo<T: Clone + Debug>(x: T) {
x.clone();
println!("{:?}", x);
}
```
`T` now needs to be both `Clone` as well as `Debug`.
## Where clause ## Where clause
Writing functions with only a few generic types and a small number of trait Writing functions with only a few generic types and a small number of trait
@ -408,6 +435,7 @@ but instead, we found a floating-point variable. We need a different bound. `Flo
to the rescue: to the rescue:
``` ```
# #![feature(std_misc)]
use std::num::Float; use std::num::Float;
fn inverse<T: Float>(x: T) -> Result<T, String> { fn inverse<T: Float>(x: T) -> Result<T, String> {
@ -423,6 +451,7 @@ from the `Float` trait. Both `f32` and `f64` implement `Float`, so our function
works just fine: works just fine:
``` ```
# #![feature(std_misc)]
# use std::num::Float; # use std::num::Float;
# fn inverse<T: Float>(x: T) -> Result<T, String> { # fn inverse<T: Float>(x: T) -> Result<T, String> {
# if x == Float::zero() { return Err("x cannot be zero!".to_string()) } # if x == Float::zero() { return Err("x cannot be zero!".to_string()) }
@ -435,3 +464,46 @@ println!("the inverse of {} is {:?}", 2.0f64, inverse(2.0f64));
println!("the inverse of {} is {:?}", 0.0f32, inverse(0.0f32)); println!("the inverse of {} is {:?}", 0.0f32, inverse(0.0f32));
println!("the inverse of {} is {:?}", 0.0f64, inverse(0.0f64)); println!("the inverse of {} is {:?}", 0.0f64, inverse(0.0f64));
``` ```
## Default methods
There's one last feature of traits we should cover: default methods. It's
easiest just to show an example:
```rust
trait Foo {
fn bar(&self);
fn baz(&self) { println!("We called baz."); }
}
```
Implementors of the `Foo` trait need to implement `bar()`, but they don't
need to implement `baz()`. They'll get this default behavior. They can
override the default if they so choose:
```rust
# trait Foo {
# fn bar(&self);
# fn baz(&self) { println!("We called baz."); }
# }
struct UseDefault;
impl Foo for UseDefault {
fn bar(&self) { println!("We called bar."); }
}
struct OverrideDefault;
impl Foo for OverrideDefault {
fn bar(&self) { println!("We called bar."); }
fn baz(&self) { println!("Override baz!"); }
}
let default = UseDefault;
default.baz(); // prints "We called baz."
let over = OverrideDefault;
over.baz(); // prints "Override baz!"
```

View File

@ -93,10 +93,6 @@ offered by the Rust language and libraries. For example, they
- are plain-old-data, that is, they don't move ownership, again unlike - are plain-old-data, that is, they don't move ownership, again unlike
`Box`, hence the Rust compiler cannot protect against bugs like `Box`, hence the Rust compiler cannot protect against bugs like
use-after-free; use-after-free;
- are considered sendable (if their contents is considered sendable),
so the compiler offers no assistance with ensuring their use is
thread-safe; for example, one can concurrently access a `*mut i32`
from two threads without synchronization.
- lack any form of lifetimes, unlike `&`, and so the compiler cannot - lack any form of lifetimes, unlike `&`, and so the compiler cannot
reason about dangling pointers; and reason about dangling pointers; and
- have no guarantees about aliasing or mutability other than mutation - have no guarantees about aliasing or mutability other than mutation
@ -185,533 +181,3 @@ code:
that clean-up is always run, even when the thread panics. that clean-up is always run, even when the thread panics.
- ensure that any data stored behind a raw pointer is destroyed at the - ensure that any data stored behind a raw pointer is destroyed at the
appropriate time. appropriate time.
As an example, we give a reimplementation of owned boxes by wrapping
`malloc` and `free`. Rust's move semantics and lifetimes mean this
reimplementation is as safe as the `Box` type.
```
#![feature(unsafe_destructor)]
extern crate libc;
use libc::{c_void, size_t, malloc, free};
use std::mem;
use std::ptr;
// Define a wrapper around the handle returned by the foreign code.
// Unique<T> has the same semantics as Box<T>
pub struct Unique<T> {
// It contains a single raw, mutable pointer to the object in question.
ptr: *mut T
}
// Implement methods for creating and using the values in the box.
// NB: For simplicity and correctness, we require that T has kind Send
// (owned boxes relax this restriction).
impl<T: Send> Unique<T> {
pub fn new(value: T) -> Unique<T> {
unsafe {
let ptr = malloc(mem::size_of::<T>() as size_t) as *mut T;
// we *need* valid pointer.
assert!(!ptr.is_null());
// `*ptr` is uninitialized, and `*ptr = value` would
// attempt to destroy it `overwrite` moves a value into
// this memory without attempting to drop the original
// value.
ptr::write(&mut *ptr, value);
Unique{ptr: ptr}
}
}
// the 'r lifetime results in the same semantics as `&*x` with
// Box<T>
pub fn borrow<'r>(&'r self) -> &'r T {
// By construction, self.ptr is valid
unsafe { &*self.ptr }
}
// the 'r lifetime results in the same semantics as `&mut *x` with
// Box<T>
pub fn borrow_mut<'r>(&'r mut self) -> &'r mut T {
unsafe { &mut *self.ptr }
}
}
// A key ingredient for safety, we associate a destructor with
// Unique<T>, making the struct manage the raw pointer: when the
// struct goes out of scope, it will automatically free the raw pointer.
//
// NB: This is an unsafe destructor, because rustc will not normally
// allow destructors to be associated with parameterized types, due to
// bad interaction with managed boxes. (With the Send restriction,
// we don't have this problem.) Note that the `#[unsafe_destructor]`
// feature gate is required to use unsafe destructors.
#[unsafe_destructor]
impl<T: Send> Drop for Unique<T> {
fn drop(&mut self) {
unsafe {
// Copy the object out from the pointer onto the stack,
// where it is covered by normal Rust destructor semantics
// and cleans itself up, if necessary
ptr::read(self.ptr);
// clean-up our allocation
free(self.ptr as *mut c_void)
}
}
}
// A comparison between the built-in `Box` and this reimplementation
fn main() {
{
let mut x = Box::new(5);
*x = 10;
} // `x` is freed here
{
let mut y = Unique::new(5);
*y.borrow_mut() = 10;
} // `y` is freed here
}
```
Notably, the only way to construct a `Unique` is via the `new`
function, and this function ensures that the internal pointer is valid
and hidden in the private field. The two `borrow` methods are safe
because the compiler statically guarantees that objects are never used
before creation or after destruction (unless you use some `unsafe`
code...).
# Inline assembly
For extremely low-level manipulations and performance reasons, one
might wish to control the CPU directly. Rust supports using inline
assembly to do this via the `asm!` macro. The syntax roughly matches
that of GCC & Clang:
```ignore
asm!(assembly template
: output operands
: input operands
: clobbers
: options
);
```
Any use of `asm` is feature gated (requires `#![feature(asm)]` on the
crate to allow) and of course requires an `unsafe` block.
> **Note**: the examples here are given in x86/x86-64 assembly, but
> all platforms are supported.
## Assembly template
The `assembly template` is the only required parameter and must be a
literal string (i.e. `""`)
```
#![feature(asm)]
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
fn foo() {
unsafe {
asm!("NOP");
}
}
// other platforms
#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
fn foo() { /* ... */ }
fn main() {
// ...
foo();
// ...
}
```
(The `feature(asm)` and `#[cfg]`s are omitted from now on.)
Output operands, input operands, clobbers and options are all optional
but you must add the right number of `:` if you skip them:
```
# #![feature(asm)]
# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
# fn main() { unsafe {
asm!("xor %eax, %eax"
:
:
: "eax"
);
# } }
```
Whitespace also doesn't matter:
```
# #![feature(asm)]
# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
# fn main() { unsafe {
asm!("xor %eax, %eax" ::: "eax");
# } }
```
## Operands
Input and output operands follow the same format: `:
"constraints1"(expr1), "constraints2"(expr2), ..."`. Output operand
expressions must be mutable lvalues:
```
# #![feature(asm)]
# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
fn add(a: i32, b: i32) -> i32 {
let mut c = 0;
unsafe {
asm!("add $2, $0"
: "=r"(c)
: "0"(a), "r"(b)
);
}
c
}
# #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
# fn add(a: i32, b: i32) -> i32 { a + b }
fn main() {
assert_eq!(add(3, 14159), 14162)
}
```
## Clobbers
Some instructions modify registers which might otherwise have held
different values so we use the clobbers list to indicate to the
compiler not to assume any values loaded into those registers will
stay valid.
```
# #![feature(asm)]
# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
# fn main() { unsafe {
// Put the value 0x200 in eax
asm!("mov $$0x200, %eax" : /* no outputs */ : /* no inputs */ : "eax");
# } }
```
Input and output registers need not be listed since that information
is already communicated by the given constraints. Otherwise, any other
registers used either implicitly or explicitly should be listed.
If the assembly changes the condition code register `cc` should be
specified as one of the clobbers. Similarly, if the assembly modifies
memory, `memory` should also be specified.
## Options
The last section, `options` is specific to Rust. The format is comma
separated literal strings (i.e. `:"foo", "bar", "baz"`). It's used to
specify some extra info about the inline assembly:
Current valid options are:
1. *volatile* - specifying this is analogous to
`__asm__ __volatile__ (...)` in gcc/clang.
2. *alignstack* - certain instructions expect the stack to be
aligned a certain way (i.e. SSE) and specifying this indicates to
the compiler to insert its usual stack alignment code
3. *intel* - use intel syntax instead of the default AT&T.
# Avoiding the standard library
By default, `std` is linked to every Rust crate. In some contexts,
this is undesirable, and can be avoided with the `#![no_std]`
attribute attached to the crate.
```ignore
// a minimal library
#![crate_type="lib"]
#![feature(no_std)]
#![no_std]
# // fn main() {} tricked you, rustdoc!
```
Obviously there's more to life than just libraries: one can use
`#[no_std]` with an executable, controlling the entry point is
possible in two ways: the `#[start]` attribute, or overriding the
default shim for the C `main` function with your own.
The function marked `#[start]` is passed the command line parameters
in the same format as C:
```
#![feature(lang_items, start, no_std)]
#![no_std]
// Pull in the system libc library for what crt0.o likely requires
extern crate libc;
// Entry point for this program
#[start]
fn start(_argc: isize, _argv: *const *const u8) -> isize {
0
}
// These functions and traits are used by the compiler, but not
// for a bare-bones hello world. These are normally
// provided by libstd.
#[lang = "stack_exhausted"] extern fn stack_exhausted() {}
#[lang = "eh_personality"] extern fn eh_personality() {}
#[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} }
# // fn main() {} tricked you, rustdoc!
```
To override the compiler-inserted `main` shim, one has to disable it
with `#![no_main]` and then create the appropriate symbol with the
correct ABI and the correct name, which requires overriding the
compiler's name mangling too:
```ignore
#![feature(no_std)]
#![no_std]
#![no_main]
#![feature(lang_items, start)]
extern crate libc;
#[no_mangle] // ensure that this symbol is called `main` in the output
pub extern fn main(argc: i32, argv: *const *const u8) -> i32 {
0
}
#[lang = "stack_exhausted"] extern fn stack_exhausted() {}
#[lang = "eh_personality"] extern fn eh_personality() {}
#[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} }
# // fn main() {} tricked you, rustdoc!
```
The compiler currently makes a few assumptions about symbols which are available
in the executable to call. Normally these functions are provided by the standard
library, but without it you must define your own.
The first of these three functions, `stack_exhausted`, is invoked whenever stack
overflow is detected. This function has a number of restrictions about how it
can be called and what it must do, but if the stack limit register is not being
maintained then a thread always has an "infinite stack" and this function
shouldn't get triggered.
The second of these three functions, `eh_personality`, is used by the
failure mechanisms of the compiler. This is often mapped to GCC's
personality function (see the
[libstd implementation](../std/rt/unwind/index.html) for more
information), but crates which do not trigger a panic can be assured
that this function is never called. The final function, `panic_fmt`, is
also used by the failure mechanisms of the compiler.
## Using libcore
> **Note**: the core library's structure is unstable, and it is recommended to
> use the standard library instead wherever possible.
With the above techniques, we've got a bare-metal executable running some Rust
code. There is a good deal of functionality provided by the standard library,
however, that is necessary to be productive in Rust. If the standard library is
not sufficient, then [libcore](../core/index.html) is designed to be used
instead.
The core library has very few dependencies and is much more portable than the
standard library itself. Additionally, the core library has most of the
necessary functionality for writing idiomatic and effective Rust code.
As an example, here is a program that will calculate the dot product of two
vectors provided from C, using idiomatic Rust practices.
```
#![feature(lang_items, start, no_std)]
#![no_std]
# extern crate libc;
extern crate core;
use core::prelude::*;
use core::mem;
#[no_mangle]
pub extern fn dot_product(a: *const u32, a_len: u32,
b: *const u32, b_len: u32) -> u32 {
use core::raw::Slice;
// Convert the provided arrays into Rust slices.
// The core::raw module guarantees that the Slice
// structure has the same memory layout as a &[T]
// slice.
//
// This is an unsafe operation because the compiler
// cannot tell the pointers are valid.
let (a_slice, b_slice): (&[u32], &[u32]) = unsafe {
mem::transmute((
Slice { data: a, len: a_len as usize },
Slice { data: b, len: b_len as usize },
))
};
// Iterate over the slices, collecting the result
let mut ret = 0;
for (i, j) in a_slice.iter().zip(b_slice.iter()) {
ret += (*i) * (*j);
}
return ret;
}
#[lang = "panic_fmt"]
extern fn panic_fmt(args: &core::fmt::Arguments,
file: &str,
line: u32) -> ! {
loop {}
}
#[lang = "stack_exhausted"] extern fn stack_exhausted() {}
#[lang = "eh_personality"] extern fn eh_personality() {}
# #[start] fn start(argc: isize, argv: *const *const u8) -> isize { 0 }
# fn main() {}
```
Note that there is one extra lang item here which differs from the examples
above, `panic_fmt`. This must be defined by consumers of libcore because the
core library declares panics, but it does not define it. The `panic_fmt`
lang item is this crate's definition of panic, and it must be guaranteed to
never return.
As can be seen in this example, the core library is intended to provide the
power of Rust in all circumstances, regardless of platform requirements. Further
libraries, such as liballoc, add functionality to libcore which make other
platform-specific assumptions, but continue to be more portable than the
standard library itself.
# Interacting with the compiler internals
> **Note**: this section is specific to the `rustc` compiler; these
> parts of the language may never be fully specified and so details may
> differ wildly between implementations (and even versions of `rustc`
> itself).
>
> Furthermore, this is just an overview; the best form of
> documentation for specific instances of these features are their
> definitions and uses in `std`.
The Rust language currently has two orthogonal mechanisms for allowing
libraries to interact directly with the compiler and vice versa:
- intrinsics, functions built directly into the compiler providing
very basic low-level functionality,
- lang-items, special functions, types and traits in libraries marked
with specific `#[lang]` attributes
## Intrinsics
> **Note**: intrinsics will forever have an unstable interface, it is
> recommended to use the stable interfaces of libcore rather than intrinsics
> directly.
These are imported as if they were FFI functions, with the special
`rust-intrinsic` ABI. For example, if one was in a freestanding
context, but wished to be able to `transmute` between types, and
perform efficient pointer arithmetic, one would import those functions
via a declaration like
```
# #![feature(intrinsics)]
# fn main() {}
extern "rust-intrinsic" {
fn transmute<T, U>(x: T) -> U;
fn offset<T>(dst: *const T, offset: isize) -> *const T;
}
```
As with any other FFI functions, these are always `unsafe` to call.
## Lang items
> **Note**: lang items are often provided by crates in the Rust distribution,
> and lang items themselves have an unstable interface. It is recommended to use
> officially distributed crates instead of defining your own lang items.
The `rustc` compiler has certain pluggable operations, that is,
functionality that isn't hard-coded into the language, but is
implemented in libraries, with a special marker to tell the compiler
it exists. The marker is the attribute `#[lang="..."]` and there are
various different values of `...`, i.e. various different 'lang
items'.
For example, `Box` pointers require two lang items, one for allocation
and one for deallocation. A freestanding program that uses the `Box`
sugar for dynamic allocations via `malloc` and `free`:
```
#![feature(lang_items, box_syntax, start, no_std)]
#![no_std]
extern crate libc;
extern {
fn abort() -> !;
}
#[lang = "owned_box"]
pub struct Box<T>(*mut T);
#[lang="exchange_malloc"]
unsafe fn allocate(size: usize, _align: usize) -> *mut u8 {
let p = libc::malloc(size as libc::size_t) as *mut u8;
// malloc failed
if p as usize == 0 {
abort();
}
p
}
#[lang="exchange_free"]
unsafe fn deallocate(ptr: *mut u8, _size: usize, _align: usize) {
libc::free(ptr as *mut libc::c_void)
}
#[start]
fn main(argc: isize, argv: *const *const u8) -> isize {
let x = box 1;
0
}
#[lang = "stack_exhausted"] extern fn stack_exhausted() {}
#[lang = "eh_personality"] extern fn eh_personality() {}
#[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} }
```
Note the use of `abort`: the `exchange_malloc` lang item is assumed to
return a valid pointer, and so needs to do the check internally.
Other features provided by lang items include:
- overloadable operators via traits: the traits corresponding to the
`==`, `<`, dereferencing (`*`) and `+` (etc.) operators are all
marked with lang items; those specific four are `eq`, `ord`,
`deref`, and `add` respectively.
- stack unwinding and general failure; the `eh_personality`, `fail`
and `fail_bounds_checks` lang items.
- the traits in `std::marker` used to indicate types of
various kinds; lang items `send`, `sync` and `copy`.
- the marker types and variance indicators found in
`std::marker`; lang items `covariant_type`,
`contravariant_lifetime`, etc.
Lang items are loaded lazily by the compiler; e.g. if one never uses
`Box` then there is no need to define functions for `exchange_malloc`
and `exchange_free`. `rustc` will emit an error when an item is needed
but not found in the current crate or any that it depends on.

1
src/doc/trpl/unstable.md Normal file
View File

@ -0,0 +1 @@
% Unstable Rust

View File

@ -12,9 +12,9 @@
#![cfg_attr(rustdoc, feature(rustdoc))] #![cfg_attr(rustdoc, feature(rustdoc))]
#[cfg(rustdoc)] #[cfg(rustdoc)]
extern crate "rustdoc" as this; extern crate rustdoc as this;
#[cfg(rustc)] #[cfg(rustc)]
extern crate "rustc_driver" as this; extern crate rustc_driver as this;
fn main() { this::main() } fn main() { this::main() }

View File

@ -0,0 +1,54 @@
#!/usr/bin/env python
#
# Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
# file at the top-level directory of this distribution and at
# http://rust-lang.org/COPYRIGHT.
#
# 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.
import os
import sys
import functools
import resource
STATUS = 0
def error_unless_permitted(env_var, message):
global STATUS
if not os.getenv(env_var):
sys.stderr.write(message)
STATUS = 1
def only_on(platforms):
def decorator(func):
@functools.wraps(func)
def inner():
if any(map(lambda x: sys.platform.startswith(x), platforms)):
func()
return inner
return decorator
@only_on(('linux', 'darwin', 'freebsd', 'openbsd'))
def check_rlimit_core():
soft, hard = resource.getrlimit(resource.RLIMIT_CORE)
if soft > 0:
error_unless_permitted('ALLOW_NONZERO_RLIMIT_CORE', """\
RLIMIT_CORE is set to a nonzero value (%d). During debuginfo, the test suite
will segfault many rustc's, creating many potentially large core files.
set ALLOW_NONZERO_RLIMIT_CORE to ignore this warning
""" % (soft))
def main():
check_rlimit_core()
if __name__ == '__main__':
main()
sys.exit(STATUS)

View File

@ -242,4 +242,3 @@ print
for line in lines: for line in lines:
print "* " + line print "* " + line
print print

View File

@ -27,9 +27,18 @@ def rust_pretty_printer_lookup_function(val):
if type_code == gdb.TYPE_CODE_STRUCT: if type_code == gdb.TYPE_CODE_STRUCT:
struct_kind = classify_struct(val.type) struct_kind = classify_struct(val.type)
if struct_kind == STRUCT_KIND_SLICE:
return RustSlicePrinter(val)
if struct_kind == STRUCT_KIND_STR_SLICE: if struct_kind == STRUCT_KIND_STR_SLICE:
return RustStringSlicePrinter(val) return RustStringSlicePrinter(val)
if struct_kind == STRUCT_KIND_STD_VEC:
return RustStdVecPrinter(val)
if struct_kind == STRUCT_KIND_STD_STRING:
return RustStdStringPrinter(val)
if struct_kind == STRUCT_KIND_TUPLE: if struct_kind == STRUCT_KIND_TUPLE:
return RustTuplePrinter(val) return RustTuplePrinter(val)
@ -172,6 +181,28 @@ class RustTupleStructPrinter:
def display_hint(self): def display_hint(self):
return "array" return "array"
class RustSlicePrinter:
def __init__(self, val):
self.val = val
def display_hint(self):
return "array"
def to_string(self):
length = int(self.val["length"])
return self.val.type.tag + ("(len: %i)" % length)
def children(self):
cs = []
length = int(self.val["length"])
data_ptr = self.val["data_ptr"]
assert data_ptr.type.code == gdb.TYPE_CODE_PTR
pointee_type = data_ptr.type.target()
for index in range(0, length):
cs.append((str(index), (data_ptr + index).dereference()))
return cs
class RustStringSlicePrinter: class RustStringSlicePrinter:
def __init__(self, val): def __init__(self, val):
@ -181,6 +212,35 @@ class RustStringSlicePrinter:
slice_byte_len = self.val["length"] slice_byte_len = self.val["length"]
return '"%s"' % self.val["data_ptr"].string(encoding="utf-8", length=slice_byte_len) return '"%s"' % self.val["data_ptr"].string(encoding="utf-8", length=slice_byte_len)
class RustStdVecPrinter:
def __init__(self, val):
self.val = val
def display_hint(self):
return "array"
def to_string(self):
length = int(self.val["len"])
cap = int(self.val["cap"])
return self.val.type.tag + ("(len: %i, cap: %i)" % (length, cap))
def children(self):
cs = []
(length, data_ptr) = extract_length_and_data_ptr_from_std_vec(self.val)
pointee_type = data_ptr.type.target()
for index in range(0, length):
cs.append((str(index), (data_ptr + index).dereference()))
return cs
class RustStdStringPrinter:
def __init__(self, val):
self.val = val
def to_string(self):
(length, data_ptr) = extract_length_and_data_ptr_from_std_vec(self.val["vec"])
return '"%s"' % data_ptr.string(encoding="utf-8", length=length)
class RustCStyleEnumPrinter: class RustCStyleEnumPrinter:
def __init__(self, val): def __init__(self, val):
@ -204,19 +264,38 @@ STRUCT_KIND_TUPLE = 2
STRUCT_KIND_TUPLE_VARIANT = 3 STRUCT_KIND_TUPLE_VARIANT = 3
STRUCT_KIND_STRUCT_VARIANT = 4 STRUCT_KIND_STRUCT_VARIANT = 4
STRUCT_KIND_CSTYLE_VARIANT = 5 STRUCT_KIND_CSTYLE_VARIANT = 5
STRUCT_KIND_STR_SLICE = 6 STRUCT_KIND_SLICE = 6
STRUCT_KIND_STR_SLICE = 7
STRUCT_KIND_STD_VEC = 8
STRUCT_KIND_STD_STRING = 9
def classify_struct(type): def classify_struct(type):
# print("\nclassify_struct: tag=%s\n" % type.tag)
if type.tag == "&str": if type.tag == "&str":
return STRUCT_KIND_STR_SLICE return STRUCT_KIND_STR_SLICE
if type.tag.startswith("&[") and type.tag.endswith("]"):
return STRUCT_KIND_SLICE
fields = list(type.fields()) fields = list(type.fields())
field_count = len(fields) field_count = len(fields)
if field_count == 0: if field_count == 0:
return STRUCT_KIND_REGULAR_STRUCT return STRUCT_KIND_REGULAR_STRUCT
if (field_count == 3 and
fields[0].name == "ptr" and
fields[1].name == "len" and
fields[2].name == "cap" and
type.tag.startswith("Vec<")):
return STRUCT_KIND_STD_VEC
if (field_count == 1 and
fields[0].name == "vec" and
type.tag == "String"):
return STRUCT_KIND_STD_STRING
if fields[0].name == "RUST$ENUM$DISR": if fields[0].name == "RUST$ENUM$DISR":
if field_count == 1: if field_count == 1:
return STRUCT_KIND_CSTYLE_VARIANT return STRUCT_KIND_CSTYLE_VARIANT
@ -254,3 +333,11 @@ def get_field_at_index(val, index):
return field return field
i += 1 i += 1
return None return None
def extract_length_and_data_ptr_from_std_vec(vec_val):
length = int(vec_val["len"])
vec_ptr_val = vec_val["ptr"]
unique_ptr_val = vec_ptr_val[first_field(vec_ptr_val)]
data_ptr = unique_ptr_val[first_field(unique_ptr_val)]
assert data_ptr.type.code == gdb.TYPE_CODE_PTR
return (length, data_ptr)

View File

@ -96,6 +96,9 @@ There are a number of supported commands:
highlights for example. If you want to simply check the presence of highlights for example. If you want to simply check the presence of
given node or attribute, use an empty string (`""`) as a `PATTERN`. given node or attribute, use an empty string (`""`) as a `PATTERN`.
* `@count PATH XPATH COUNT' checks for the occurrence of given XPath
in the given file. The number of occurrences must match the given count.
All conditions can be negated with `!`. `@!has foo/type.NoSuch.html` All conditions can be negated with `!`. `@!has foo/type.NoSuch.html`
checks if the given file does not exist, for example. checks if the given file does not exist, for example.
@ -333,6 +336,11 @@ def check_tree_text(tree, path, pat, regexp):
return ret return ret
def check_tree_count(tree, path, count):
path = normalize_xpath(path)
return len(tree.findall(path)) == count
def check(target, commands): def check(target, commands):
cache = CachedFiles(target) cache = CachedFiles(target)
for c in commands: for c in commands:
@ -360,6 +368,13 @@ def check(target, commands):
raise RuntimeError('Invalid number of @{} arguments \ raise RuntimeError('Invalid number of @{} arguments \
at line {}'.format(c.cmd, c.lineno)) at line {}'.format(c.cmd, c.lineno))
elif c.cmd == 'count': # count test
if len(c.args) == 3: # @count <path> <pat> <count> = count test
ret = check_tree_count(cache.get_tree(c.args[0]), c.args[1], int(c.args[2]))
else:
raise RuntimeError('Invalid number of @{} arguments \
at line {}'.format(c.cmd, c.lineno))
elif c.cmd == 'valid-html': elif c.cmd == 'valid-html':
raise RuntimeError('Unimplemented @valid-html at line {}'.format(c.lineno)) raise RuntimeError('Unimplemented @valid-html at line {}'.format(c.lineno))

View File

@ -165,6 +165,16 @@ void posix88_consts() {
put_const(S_IWUSR, int); put_const(S_IWUSR, int);
put_const(S_IRUSR, int); put_const(S_IRUSR, int);
put_const(S_IRWXG, int);
put_const(S_IXGRP, int);
put_const(S_IWGRP, int);
put_const(S_IRGRP, int);
put_const(S_IRWXO, int);
put_const(S_IXOTH, int);
put_const(S_IWOTH, int);
put_const(S_IROTH, int);
#ifdef F_OK #ifdef F_OK
put_const(F_OK, int); put_const(F_OK, int);
#endif #endif

View File

@ -40,31 +40,12 @@ def print_struct_val(val, internal_dict):
if is_vec_slice(val): if is_vec_slice(val):
return print_vec_slice_val(val, internal_dict) return print_vec_slice_val(val, internal_dict)
elif is_std_vec(val):
return print_std_vec_val(val, internal_dict)
else: else:
return print_struct_val_starting_from(0, val, internal_dict) return print_struct_val_starting_from(0, val, internal_dict)
def print_vec_slice_val(val, internal_dict):
length = val.GetChildAtIndex(1).GetValueAsUnsigned()
data_ptr_val = val.GetChildAtIndex(0)
data_ptr_type = data_ptr_val.GetType()
assert data_ptr_type.IsPointerType()
element_type = data_ptr_type.GetPointeeType()
element_type_size = element_type.GetByteSize()
start_address = data_ptr_val.GetValueAsUnsigned()
def render_element(i):
address = start_address + i * element_type_size
element_val = val.CreateValueFromAddress(val.GetName() +
("[%s]" % i), address, element_type)
return print_val(element_val, internal_dict)
return "&[%s]" % (', '.join([render_element(i) for i in range(length)]))
def print_struct_val_starting_from(field_start_index, val, internal_dict): def print_struct_val_starting_from(field_start_index, val, internal_dict):
''' '''
Prints a struct, tuple, or tuple struct value with Rust syntax. Prints a struct, tuple, or tuple struct value with Rust syntax.
@ -100,6 +81,16 @@ def print_struct_val_starting_from(field_start_index, val, internal_dict):
this += field_name + ": " this += field_name + ": "
field_val = val.GetChildAtIndex(child_index) field_val = val.GetChildAtIndex(child_index)
if not field_val.IsValid():
field = t.GetFieldAtIndex(child_index)
# LLDB is not good at handling zero-sized values, so we have to help
# it a little
if field.GetType().GetByteSize() == 0:
return this + extract_type_name(field.GetType().GetName())
else:
return this + "<invalid value>"
return this + print_val(field_val, internal_dict) return this + print_val(field_val, internal_dict)
body = separator.join([render_child(idx) for idx in range(field_start_index, num_children)]) body = separator.join([render_child(idx) for idx in range(field_start_index, num_children)])
@ -195,6 +186,30 @@ def print_fixed_size_vec_val(val, internal_dict):
return output return output
def print_vec_slice_val(val, internal_dict):
length = val.GetChildAtIndex(1).GetValueAsUnsigned()
data_ptr_val = val.GetChildAtIndex(0)
data_ptr_type = data_ptr_val.GetType()
return "&[%s]" % print_array_of_values(val.GetName(),
data_ptr_val,
length,
internal_dict)
def print_std_vec_val(val, internal_dict):
length = val.GetChildAtIndex(1).GetValueAsUnsigned()
# Vec<> -> Unique<> -> NonZero<> -> *T
data_ptr_val = val.GetChildAtIndex(0).GetChildAtIndex(0).GetChildAtIndex(0)
data_ptr_type = data_ptr_val.GetType()
return "vec![%s]" % print_array_of_values(val.GetName(),
data_ptr_val,
length,
internal_dict)
#=-------------------------------------------------------------------------------------------------- #=--------------------------------------------------------------------------------------------------
# Helper Functions # Helper Functions
#=-------------------------------------------------------------------------------------------------- #=--------------------------------------------------------------------------------------------------
@ -243,3 +258,44 @@ def is_vec_slice(val):
type_name = extract_type_name(ty.GetName()).replace("&'static", "&").replace(" ", "") type_name = extract_type_name(ty.GetName()).replace("&'static", "&").replace(" ", "")
return type_name.startswith("&[") and type_name.endswith("]") return type_name.startswith("&[") and type_name.endswith("]")
def is_std_vec(val):
ty = val.GetType()
if ty.GetTypeClass() != lldb.eTypeClassStruct:
return False
if ty.GetNumberOfFields() != 3:
return False
if ty.GetFieldAtIndex(0).GetName() != "ptr":
return False
if ty.GetFieldAtIndex(1).GetName() != "len":
return False
if ty.GetFieldAtIndex(2).GetName() != "cap":
return False
return ty.GetName().startswith("collections::vec::Vec<")
def print_array_of_values(array_name, data_ptr_val, length, internal_dict):
'''Prints a contigous memory range, interpreting it as values of the
pointee-type of data_ptr_val.'''
data_ptr_type = data_ptr_val.GetType()
assert data_ptr_type.IsPointerType()
element_type = data_ptr_type.GetPointeeType()
element_type_size = element_type.GetByteSize()
start_address = data_ptr_val.GetValueAsUnsigned()
def render_element(i):
address = start_address + i * element_type_size
element_val = data_ptr_val.CreateValueFromAddress(array_name + ("[%s]" % i),
address,
element_type)
return print_val(element_val, internal_dict)
return ', '.join([render_element(i) for i in range(length)])

View File

@ -18,7 +18,7 @@ LIB_PREFIX=lib
OS=`uname -s` OS=`uname -s`
case $OS in case $OS in
("Linux"|"FreeBSD"|"DragonFly"|"OpenBSD") ("Linux"|"FreeBSD"|"DragonFly"|"Bitrig"|"OpenBSD")
BIN_SUF= BIN_SUF=
LIB_SUF=.so LIB_SUF=.so
;; ;;

View File

@ -57,7 +57,16 @@ else:
args.extend(components) args.extend(components)
out = run(args) out = run(args)
for lib in out.strip().replace("\n", ' ').split(' '): for lib in out.strip().replace("\n", ' ').split(' '):
lib = lib.strip()[2:] # chop of the leading '-l' if len(lib) == 0:
continue
# in some cases we get extra spaces in between libs so ignore those
if len(lib) == 1 and lib == ' ':
continue
# not all libs strictly follow -lfoo, on Bitrig, there is -pthread
if lib[0:2] == '-l':
lib = lib.strip()[2:]
elif lib[0] == '-':
lib = lib.strip()[1:]
f.write("#[link(name = \"" + lib + "\"") f.write("#[link(name = \"" + lib + "\"")
# LLVM libraries are all static libraries # LLVM libraries are all static libraries
if 'LLVM' in lib: if 'LLVM' in lib:

View File

@ -288,6 +288,7 @@ VAL_OPTIONS=""
flag uninstall "only uninstall from the installation prefix" flag uninstall "only uninstall from the installation prefix"
valopt prefix "" "set installation prefix" valopt prefix "" "set installation prefix"
valopt date "" "use the YYYY-MM-DD nightly instead of the current nightly" valopt date "" "use the YYYY-MM-DD nightly instead of the current nightly"
valopt channel "beta" "use the selected release channel [beta]"
flag save "save the downloaded nightlies to ~/.rustup" flag save "save the downloaded nightlies to ~/.rustup"
if [ $HELP -eq 1 ] if [ $HELP -eq 1 ]
@ -307,7 +308,7 @@ CFG_CPUTYPE=$(uname -m)
if [ $CFG_OSTYPE = Darwin -a $CFG_CPUTYPE = i386 ] if [ $CFG_OSTYPE = Darwin -a $CFG_CPUTYPE = i386 ]
then then
# Darwin's `uname -s` lies and always returns i386. We have to use sysctl # Darwin's `uname -m` lies and always returns i386. We have to use sysctl
# instead. # instead.
if sysctl hw.optional.x86_64 | grep -q ': 1' if sysctl hw.optional.x86_64 | grep -q ': 1'
then then
@ -335,7 +336,7 @@ case $CFG_OSTYPE in
MINGW32*) MINGW32*)
CFG_OSTYPE=pc-mingw32 CFG_OSTYPE=pc-mingw32
;; ;;
# Thad's Cygwin identifers below # Thad's Cygwin identifiers below
# Vista 32 bit # Vista 32 bit
CYGWIN_NT-6.0) CYGWIN_NT-6.0)
@ -437,7 +438,7 @@ CFG_TMP_DIR=$(mktemp -d 2>/dev/null \
|| create_tmp_dir) || create_tmp_dir)
# If we're saving nightlies and we didn't specify which one, grab the latest # If we're saving nightlies and we didn't specify which one, grab the latest
# verison from the perspective of the server. Buildbot has typically finished # version from the perspective of the server. Buildbot has typically finished
# building and uploading by ~8UTC, but we want to include a little buffer. # building and uploading by ~8UTC, but we want to include a little buffer.
# #
# FIXME It would be better to use the known most recent nightly that has been # FIXME It would be better to use the known most recent nightly that has been
@ -449,18 +450,28 @@ then
fi fi
RUST_URL="https://static.rust-lang.org/dist" RUST_URL="https://static.rust-lang.org/dist"
RUST_PACKAGE_NAME=rust-nightly case "$CFG_CHANNEL" in
RUST_PACKAGE_NAME_AND_TRIPLE="${RUST_PACKAGE_NAME}-${HOST_TRIPLE}" nightly)
RUST_TARBALL_NAME="${RUST_PACKAGE_NAME_AND_TRIPLE}.tar.gz" # add a date suffix if we want a particular nightly.
RUST_LOCAL_INSTALL_DIR="${CFG_TMP_DIR}/${RUST_PACKAGE_NAME_AND_TRIPLE}"
RUST_LOCAL_INSTALL_SCRIPT="${RUST_LOCAL_INSTALL_DIR}/install.sh"
# add a date suffix if we want a particular nighly.
if [ -n "${CFG_DATE}" ]; if [ -n "${CFG_DATE}" ];
then then
RUST_URL="${RUST_URL}/${CFG_DATE}" RUST_URL="${RUST_URL}/${CFG_DATE}"
fi fi
RUST_PACKAGE_NAME=rust-nightly
;;
beta)
RUST_PACKAGE_NAME=rust-1.0.0-beta
;;
*)
err "Currently 'beta' and 'nightly' are the only supported channels"
esac
RUST_PACKAGE_NAME_AND_TRIPLE="${RUST_PACKAGE_NAME}-${HOST_TRIPLE}"
RUST_TARBALL_NAME="${RUST_PACKAGE_NAME_AND_TRIPLE}.tar.gz"
RUST_LOCAL_INSTALL_DIR="${CFG_TMP_DIR}/${RUST_PACKAGE_NAME_AND_TRIPLE}"
RUST_LOCAL_INSTALL_SCRIPT="${RUST_LOCAL_INSTALL_DIR}/install.sh"
download_hash() { download_hash() {
msg "Downloading ${remote_sha256}" msg "Downloading ${remote_sha256}"
remote_sha256=`"${CFG_CURL}" -f "${remote_sha256}"` remote_sha256=`"${CFG_CURL}" -f "${remote_sha256}"`

View File

@ -46,13 +46,13 @@ snapshot_files = {
"winnt": ["bin/rustc.exe"], "winnt": ["bin/rustc.exe"],
"freebsd": ["bin/rustc"], "freebsd": ["bin/rustc"],
"dragonfly": ["bin/rustc"], "dragonfly": ["bin/rustc"],
"bitrig": ["bin/rustc"],
"openbsd": ["bin/rustc"], "openbsd": ["bin/rustc"],
} }
winnt_runtime_deps_32 = ["libgcc_s_dw2-1.dll", "libstdc++-6.dll"] winnt_runtime_deps_32 = ["libgcc_s_dw2-1.dll", "libstdc++-6.dll"]
winnt_runtime_deps_64 = ["libgcc_s_seh-1.dll", "libstdc++-6.dll"] winnt_runtime_deps_64 = ["libgcc_s_seh-1.dll", "libstdc++-6.dll"]
def parse_line(n, line): def parse_line(n, line):
global snapshotfile global snapshotfile
@ -101,6 +101,8 @@ def get_kernel(triple):
return "freebsd" return "freebsd"
if os_name == "dragonfly": if os_name == "dragonfly":
return "dragonfly" return "dragonfly"
if os_name == "bitrig":
return "bitrig"
if os_name == "openbsd": if os_name == "openbsd":
return "openbsd" return "openbsd"
return "linux" return "linux"

Binary file not shown.

View File

@ -70,4 +70,3 @@ consistent with the licensing of the Independent Modules.
The availability of this Exception does not imply any general The availability of this Exception does not imply any general
presumption that third-party software is unaffected by the copyleft presumption that third-party software is unaffected by the copyleft
requirements of the license of GCC. requirements of the license of GCC.

View File

@ -13,7 +13,7 @@ import fileinput
import subprocess import subprocess
import re import re
import os import os
from licenseck import * from licenseck import check_license
import snapshot import snapshot
err = 0 err = 0
@ -22,13 +22,8 @@ cr_flag = "ignore-tidy-cr"
tab_flag = "ignore-tidy-tab" tab_flag = "ignore-tidy-tab"
linelength_flag = "ignore-tidy-linelength" linelength_flag = "ignore-tidy-linelength"
# Be careful to support Python 2.4, 2.6, and 3.x here! interesting_files = ['.rs', '.py', '.js', '.sh', '.c', '.h']
config_proc = subprocess.Popen(["git", "config", "core.autocrlf"], uninteresting_files = ['miniz.c', 'jquery', 'rust_android_dummy']
stdout=subprocess.PIPE)
result = config_proc.communicate()[0]
true = "true".encode('utf8')
autocrlf = result.strip() == true if result is not None else False
def report_error_name_no(name, no, s): def report_error_name_no(name, no, s):
@ -51,6 +46,34 @@ def do_license_check(name, contents):
if not check_license(name, contents): if not check_license(name, contents):
report_error_name_no(name, 1, "incorrect license") report_error_name_no(name, 1, "incorrect license")
def update_counts(current_name):
global file_counts
global count_other_linted_files
_, ext = os.path.splitext(current_name)
if ext in interesting_files:
file_counts[ext] += 1
else:
count_other_linted_files += 1
def interesting_file(f):
if any(x in f for x in uninteresting_files):
return False
return any(os.path.splitext(f)[1] == ext for ext in interesting_files)
# Be careful to support Python 2.4, 2.6, and 3.x here!
config_proc = subprocess.Popen(["git", "config", "core.autocrlf"],
stdout=subprocess.PIPE)
result = config_proc.communicate()[0]
true = "true".encode('utf8')
autocrlf = result.strip() == true if result is not None else False
current_name = "" current_name = ""
current_contents = "" current_contents = ""
check_tab = True check_tab = True
@ -63,28 +86,16 @@ if len(sys.argv) < 2:
src_dir = sys.argv[1] src_dir = sys.argv[1]
try:
count_lines = 0 count_lines = 0
count_non_blank_lines = 0 count_non_blank_lines = 0
count_other_linted_files = 0
interesting_files = ['.rs', '.py', '.js', '.sh', '.c', '.h']
file_counts = {ext: 0 for ext in interesting_files} file_counts = {ext: 0 for ext in interesting_files}
file_counts['other'] = 0
def update_counts(current_name):
global file_counts
_, ext = os.path.splitext(current_name)
if ext in file_counts:
file_counts[ext] += 1
else:
file_counts['other'] += 1
all_paths = set() all_paths = set()
try:
for (dirpath, dirnames, filenames) in os.walk(src_dir): for (dirpath, dirnames, filenames) in os.walk(src_dir):
# Skip some third-party directories # Skip some third-party directories
skippable_dirs = { skippable_dirs = {
'src/jemalloc', 'src/jemalloc',
@ -103,14 +114,6 @@ try:
if any(d in dirpath for d in skippable_dirs): if any(d in dirpath for d in skippable_dirs):
continue continue
def interesting_file(f):
if "miniz.c" in f \
or "jquery" in f \
or "rust_android_dummy" in f:
return False
return any(os.path.splitext(f)[1] == ext for ext in interesting_files)
file_names = [os.path.join(dirpath, f) for f in filenames file_names = [os.path.join(dirpath, f) for f in filenames
if interesting_file(f) if interesting_file(f)
and not f.endswith("_gen.rs") and not f.endswith("_gen.rs")
@ -196,10 +199,11 @@ except UnicodeDecodeError as e:
report_err("UTF-8 decoding error " + str(e)) report_err("UTF-8 decoding error " + str(e))
print print
for ext in file_counts: for ext in sorted(file_counts, key=file_counts.get, reverse=True):
print "* linted " + str(file_counts[ext]) + " " + ext + " files" print "* linted {} {} files".format(file_counts[ext], ext)
print "* total lines of code: " + str(count_lines) print "* linted {} other files".format(count_other_linted_files)
print "* total non-blank lines of code: " + str(count_non_blank_lines) print "* total lines of code: {}".format(count_lines)
print "* total non-blank lines of code: {}".format(count_non_blank_lines)
print print
sys.exit(err) sys.exit(err)

View File

@ -84,8 +84,8 @@ def fetch(f):
sys.stderr.write("cannot load %s" % f) sys.stderr.write("cannot load %s" % f)
exit(1) exit(1)
def is_valid_unicode(n): def is_surrogate(n):
return 0 <= n <= 0xD7FF or 0xE000 <= n <= 0x10FFFF return 0xD800 <= n <= 0xDFFF
def load_unicode_data(f): def load_unicode_data(f):
fetch(f) fetch(f)
@ -96,19 +96,28 @@ def load_unicode_data(f):
canon_decomp = {} canon_decomp = {}
compat_decomp = {} compat_decomp = {}
udict = {};
range_start = -1;
for line in fileinput.input(f): for line in fileinput.input(f):
fields = line.split(";") data = line.split(';');
if len(fields) != 15: if len(data) != 15:
continue continue
[code, name, gencat, combine, bidi, cp = int(data[0], 16);
if is_surrogate(cp):
continue
if range_start >= 0:
for i in xrange(range_start, cp):
udict[i] = data;
range_start = -1;
if data[1].endswith(", First>"):
range_start = cp;
continue;
udict[cp] = data;
for code in udict:
[code_org, name, gencat, combine, bidi,
decomp, deci, digit, num, mirror, decomp, deci, digit, num, mirror,
old, iso, upcase, lowcase, titlecase ] = fields old, iso, upcase, lowcase, titlecase ] = udict[code];
code_org = code
code = int(code, 16)
if not is_valid_unicode(code):
continue
# generate char to char direct common and simple conversions # generate char to char direct common and simple conversions
# uppercase to lowercase # uppercase to lowercase
@ -290,11 +299,11 @@ def emit_bsearch_range_table(f):
fn bsearch_range_table(c: char, r: &'static [(char,char)]) -> bool { fn bsearch_range_table(c: char, r: &'static [(char,char)]) -> bool {
use core::cmp::Ordering::{Equal, Less, Greater}; use core::cmp::Ordering::{Equal, Less, Greater};
use core::slice::SliceExt; use core::slice::SliceExt;
r.binary_search(|&(lo,hi)| { r.binary_search_by(|&(lo,hi)| {
if lo <= c && c <= hi { Equal } if lo <= c && c <= hi { Equal }
else if hi < c { Less } else if hi < c { Less }
else { Greater } else { Greater }
}).found().is_some() }).is_ok()
}\n }\n
""") """)
@ -303,7 +312,7 @@ def emit_table(f, name, t_data, t_type = "&'static [(char, char)]", is_pub=True,
pub_string = "" pub_string = ""
if is_pub: if is_pub:
pub_string = "pub " pub_string = "pub "
f.write(" %sstatic %s: %s = &[\n" % (pub_string, name, t_type)) f.write(" %sconst %s: %s = &[\n" % (pub_string, name, t_type))
data = "" data = ""
first = True first = True
for dat in t_data: for dat in t_data:
@ -329,14 +338,14 @@ def emit_property_module(f, mod, tbl, emit_fn):
def emit_regex_module(f, cats, w_data): def emit_regex_module(f, cats, w_data):
f.write("pub mod regex {\n") f.write("pub mod regex {\n")
regex_class = "&'static [(char, char)]" regex_class = "&'static [(char, char)]"
class_table = "&'static [(&'static str, &'static %s)]" % regex_class class_table = "&'static [(&'static str, %s)]" % regex_class
emit_table(f, "UNICODE_CLASSES", cats, class_table, emit_table(f, "UNICODE_CLASSES", cats, class_table,
pfun=lambda x: "(\"%s\",&super::%s::%s_table)" % (x[0], x[1], x[0])) pfun=lambda x: "(\"%s\",super::%s::%s_table)" % (x[0], x[1], x[0]))
f.write(" pub static PERLD: &'static %s = &super::general_category::Nd_table;\n\n" f.write(" pub const PERLD: %s = super::general_category::Nd_table;\n\n"
% regex_class) % regex_class)
f.write(" pub static PERLS: &'static %s = &super::property::White_Space_table;\n\n" f.write(" pub const PERLS: %s = super::property::White_Space_table;\n\n"
% regex_class) % regex_class)
emit_table(f, "PERLW", w_data, regex_class) emit_table(f, "PERLW", w_data, regex_class)
@ -350,7 +359,7 @@ def emit_conversions_module(f, lowerupper, upperlower):
use core::slice::SliceExt; use core::slice::SliceExt;
use core::option::Option; use core::option::Option;
use core::option::Option::{Some, None}; use core::option::Option::{Some, None};
use core::slice; use core::result::Result::{Ok, Err};
pub fn to_lower(c: char) -> char { pub fn to_lower(c: char) -> char {
match bsearch_case_table(c, LuLl_table) { match bsearch_case_table(c, LuLl_table) {
@ -367,13 +376,13 @@ def emit_conversions_module(f, lowerupper, upperlower):
} }
fn bsearch_case_table(c: char, table: &'static [(char, char)]) -> Option<usize> { fn bsearch_case_table(c: char, table: &'static [(char, char)]) -> Option<usize> {
match table.binary_search(|&(key, _)| { match table.binary_search_by(|&(key, _)| {
if c == key { Equal } if c == key { Equal }
else if key < c { Less } else if key < c { Less }
else { Greater } else { Greater }
}) { }) {
slice::BinarySearchResult::Found(i) => Some(i), Ok(i) => Some(i),
slice::BinarySearchResult::NotFound(_) => None, Err(_) => None,
} }
} }
@ -386,10 +395,9 @@ def emit_conversions_module(f, lowerupper, upperlower):
def emit_grapheme_module(f, grapheme_table, grapheme_cats): def emit_grapheme_module(f, grapheme_table, grapheme_cats):
f.write("""pub mod grapheme { f.write("""pub mod grapheme {
use core::kinds::Copy;
use core::slice::SliceExt; use core::slice::SliceExt;
pub use self::GraphemeCat::*; pub use self::GraphemeCat::*;
use core::slice; use core::result::Result::{Ok, Err};
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
@ -401,16 +409,16 @@ def emit_grapheme_module(f, grapheme_table, grapheme_cats):
fn bsearch_range_value_table(c: char, r: &'static [(char, char, GraphemeCat)]) -> GraphemeCat { fn bsearch_range_value_table(c: char, r: &'static [(char, char, GraphemeCat)]) -> GraphemeCat {
use core::cmp::Ordering::{Equal, Less, Greater}; use core::cmp::Ordering::{Equal, Less, Greater};
match r.binary_search(|&(lo, hi, _)| { match r.binary_search_by(|&(lo, hi, _)| {
if lo <= c && c <= hi { Equal } if lo <= c && c <= hi { Equal }
else if hi < c { Less } else if hi < c { Less }
else { Greater } else { Greater }
}) { }) {
slice::BinarySearchResult::Found(idx) => { Ok(idx) => {
let (_, _, cat) = r[idx]; let (_, _, cat) = r[idx];
cat cat
} }
slice::BinarySearchResult::NotFound(_) => GC_Any Err(_) => GC_Any
} }
} }
@ -430,20 +438,20 @@ def emit_charwidth_module(f, width_table):
f.write(" use core::option::Option;\n") f.write(" use core::option::Option;\n")
f.write(" use core::option::Option::{Some, None};\n") f.write(" use core::option::Option::{Some, None};\n")
f.write(" use core::slice::SliceExt;\n") f.write(" use core::slice::SliceExt;\n")
f.write(" use core::slice;\n") f.write(" use core::result::Result::{Ok, Err};\n")
f.write(""" f.write("""
fn bsearch_range_value_table(c: char, is_cjk: bool, r: &'static [(char, char, u8, u8)]) -> u8 { fn bsearch_range_value_table(c: char, is_cjk: bool, r: &'static [(char, char, u8, u8)]) -> u8 {
use core::cmp::Ordering::{Equal, Less, Greater}; use core::cmp::Ordering::{Equal, Less, Greater};
match r.binary_search(|&(lo, hi, _, _)| { match r.binary_search_by(|&(lo, hi, _, _)| {
if lo <= c && c <= hi { Equal } if lo <= c && c <= hi { Equal }
else if hi < c { Less } else if hi < c { Less }
else { Greater } else { Greater }
}) { }) {
slice::BinarySearchResult::Found(idx) => { Ok(idx) => {
let (_, _, r_ncjk, r_cjk) = r[idx]; let (_, _, r_ncjk, r_cjk) = r[idx];
if is_cjk { r_cjk } else { r_ncjk } if is_cjk { r_cjk } else { r_ncjk }
} }
slice::BinarySearchResult::NotFound(_) => 1 Err(_) => 1
} }
} }
""") """)
@ -530,17 +538,17 @@ def emit_norm_module(f, canon, compat, combine, norm_props):
fn bsearch_range_value_table(c: char, r: &'static [(char, char, u8)]) -> u8 { fn bsearch_range_value_table(c: char, r: &'static [(char, char, u8)]) -> u8 {
use core::cmp::Ordering::{Equal, Less, Greater}; use core::cmp::Ordering::{Equal, Less, Greater};
use core::slice::SliceExt; use core::slice::SliceExt;
use core::slice; use core::result::Result::{Ok, Err};
match r.binary_search(|&(lo, hi, _)| { match r.binary_search_by(|&(lo, hi, _)| {
if lo <= c && c <= hi { Equal } if lo <= c && c <= hi { Equal }
else if hi < c { Less } else if hi < c { Less }
else { Greater } else { Greater }
}) { }) {
slice::BinarySearchResult::Found(idx) => { Ok(idx) => {
let (_, _, result) = r[idx]; let (_, _, result) = r[idx];
result result
} }
slice::BinarySearchResult::NotFound(_) => 0 Err(_) => 0
} }
}\n }\n
""") """)
@ -609,7 +617,7 @@ if __name__ == "__main__":
unicode_version = re.search(pattern, readme.read()).groups() unicode_version = re.search(pattern, readme.read()).groups()
rf.write(""" rf.write("""
/// The version of [Unicode](http://www.unicode.org/) /// The version of [Unicode](http://www.unicode.org/)
/// that the `UnicodeChar` and `UnicodeStrPrelude` traits are based on. /// that the unicode parts of `CharExt` and `UnicodeStrPrelude` traits are based on.
pub const UNICODE_VERSION: (u64, u64, u64) = (%s, %s, %s); pub const UNICODE_VERSION: (u64, u64, u64) = (%s, %s, %s);
""" % unicode_version) """ % unicode_version)
(canon_decomp, compat_decomp, gencats, combines, (canon_decomp, compat_decomp, gencats, combines,

View File

@ -1 +1 @@
0.12.0-5823-g522d09dfecbeca1595f25ac58c6d0178bbd21d7d 0.12.0-7693-g9854143cba679834bc4ef932858cd5303f015a0e

View File

@ -4880,6 +4880,12 @@ case "${host}" in
abi="elf" abi="elf"
$as_echo "#define JEMALLOC_PURGE_MADVISE_FREE " >>confdefs.h $as_echo "#define JEMALLOC_PURGE_MADVISE_FREE " >>confdefs.h
;;
*-*-openbsd*|*-*-bitrig*)
CFLAGS="$CFLAGS"
abi="elf"
$as_echo "#define JEMALLOC_PURGE_MADVISE_FREE " >>confdefs.h
;; ;;
*-*-linux*) *-*-linux*)
CFLAGS="$CFLAGS" CFLAGS="$CFLAGS"

View File

@ -288,6 +288,11 @@ case "${host}" in
abi="elf" abi="elf"
AC_DEFINE([JEMALLOC_PURGE_MADVISE_FREE], [ ]) AC_DEFINE([JEMALLOC_PURGE_MADVISE_FREE], [ ])
;; ;;
*-*-openbsd*|*-*-bitrig*)
CFLAGS="$CFLAGS"
abi="elf"
AC_DEFINE([JEMALLOC_PURGE_MADVISE_FREE], [ ])
;;
*-*-linux*) *-*-linux*)
CFLAGS="$CFLAGS" CFLAGS="$CFLAGS"
CPPFLAGS="$CPPFLAGS -D_GNU_SOURCE" CPPFLAGS="$CPPFLAGS -D_GNU_SOURCE"

View File

@ -33,7 +33,7 @@
//! //!
//! Sharing some immutable data between tasks: //! Sharing some immutable data between tasks:
//! //!
//! ``` //! ```no_run
//! use std::sync::Arc; //! use std::sync::Arc;
//! use std::thread; //! use std::thread;
//! //!
@ -50,7 +50,7 @@
//! //!
//! Sharing mutable data safely between tasks with a `Mutex`: //! Sharing mutable data safely between tasks with a `Mutex`:
//! //!
//! ``` //! ```no_run
//! use std::sync::{Arc, Mutex}; //! use std::sync::{Arc, Mutex};
//! use std::thread; //! use std::thread;
//! //!
@ -69,12 +69,14 @@
//! } //! }
//! ``` //! ```
use boxed::Box;
use core::prelude::*; use core::prelude::*;
use core::atomic; use core::atomic;
use core::atomic::Ordering::{Relaxed, Release, Acquire, SeqCst}; use core::atomic::Ordering::{Relaxed, Release, Acquire, SeqCst};
use core::fmt; use core::fmt;
use core::cmp::{Ordering}; use core::cmp::Ordering;
use core::default::Default; use core::default::Default;
use core::mem::{min_align_of, size_of}; use core::mem::{min_align_of, size_of};
use core::mem; use core::mem;
@ -86,13 +88,17 @@ use heap::deallocate;
/// An atomically reference counted wrapper for shared state. /// An atomically reference counted wrapper for shared state.
/// ///
/// # Example /// # Examples
/// ///
/// In this example, a large vector of floats is shared between several tasks. /// In this example, a large vector of floats is shared between several tasks.
/// With simple pipes, without `Arc`, a copy would have to be made for each /// With simple pipes, without `Arc`, a copy would have to be made for each
/// task. /// task.
/// ///
/// ```rust /// When you clone an `Arc<T>`, it will create another pointer to the data and
/// increase the reference counter.
///
/// ```
/// # #![feature(alloc, core)]
/// use std::sync::Arc; /// use std::sync::Arc;
/// use std::thread; /// use std::thread;
/// ///
@ -104,7 +110,7 @@ use heap::deallocate;
/// let child_numbers = shared_numbers.clone(); /// let child_numbers = shared_numbers.clone();
/// ///
/// thread::spawn(move || { /// thread::spawn(move || {
/// let local_numbers = child_numbers.as_slice(); /// let local_numbers = &child_numbers[..];
/// ///
/// // Work with the local numbers /// // Work with the local numbers
/// }); /// });
@ -125,8 +131,8 @@ unsafe impl<T: Sync + Send> Sync for Arc<T> { }
/// A weak pointer to an `Arc`. /// A weak pointer to an `Arc`.
/// ///
/// Weak pointers will not keep the data inside of the `Arc` alive, and can be used to break cycles /// Weak pointers will not keep the data inside of the `Arc` alive, and can be
/// between `Arc` pointers. /// used to break cycles between `Arc` pointers.
#[unsafe_no_drop_flag] #[unsafe_no_drop_flag]
#[unstable(feature = "alloc", #[unstable(feature = "alloc",
reason = "Weak pointers may not belong in this module.")] reason = "Weak pointers may not belong in this module.")]
@ -139,6 +145,13 @@ pub struct Weak<T> {
unsafe impl<T: Sync + Send> Send for Weak<T> { } unsafe impl<T: Sync + Send> Send for Weak<T> { }
unsafe impl<T: Sync + Send> Sync for Weak<T> { } unsafe impl<T: Sync + Send> Sync for Weak<T> { }
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: fmt::Debug> fmt::Debug for Weak<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "(Weak)")
}
}
struct ArcInner<T> { struct ArcInner<T> {
strong: atomic::AtomicUsize, strong: atomic::AtomicUsize,
weak: atomic::AtomicUsize, weak: atomic::AtomicUsize,
@ -163,7 +176,7 @@ impl<T> Arc<T> {
pub fn new(data: T) -> Arc<T> { pub fn new(data: T) -> Arc<T> {
// Start the weak pointer count as 1 which is the weak pointer that's // Start the weak pointer count as 1 which is the weak pointer that's
// held by all the strong pointers (kinda), see std/rc.rs for more info // held by all the strong pointers (kinda), see std/rc.rs for more info
let x = box ArcInner { let x: Box<_> = box ArcInner {
strong: atomic::AtomicUsize::new(1), strong: atomic::AtomicUsize::new(1),
weak: atomic::AtomicUsize::new(1), weak: atomic::AtomicUsize::new(1),
data: data, data: data,
@ -176,6 +189,7 @@ impl<T> Arc<T> {
/// # Examples /// # Examples
/// ///
/// ``` /// ```
/// # #![feature(alloc)]
/// use std::sync::Arc; /// use std::sync::Arc;
/// ///
/// let five = Arc::new(5); /// let five = Arc::new(5);
@ -194,12 +208,28 @@ impl<T> Arc<T> {
impl<T> Arc<T> { impl<T> Arc<T> {
#[inline] #[inline]
fn inner(&self) -> &ArcInner<T> { fn inner(&self) -> &ArcInner<T> {
// This unsafety is ok because while this arc is alive we're guaranteed that the inner // This unsafety is ok because while this arc is alive we're guaranteed
// pointer is valid. Furthermore, we know that the `ArcInner` structure itself is `Sync` // that the inner pointer is valid. Furthermore, we know that the
// because the inner data is `Sync` as well, so we're ok loaning out an immutable pointer // `ArcInner` structure itself is `Sync` because the inner data is
// to these contents. // `Sync` as well, so we're ok loaning out an immutable pointer to these
// contents.
unsafe { &**self._ptr } unsafe { &**self._ptr }
} }
// Non-inlined part of `drop`.
#[inline(never)]
unsafe fn drop_slow(&mut self) {
let ptr = *self._ptr;
// Destroy the data at this time, even though we may not free the box
// allocation itself (there may still be weak pointers lying around).
drop(ptr::read(&self.inner().data));
if self.inner().weak.fetch_sub(1, Release) == 1 {
atomic::fence(Acquire);
deallocate(ptr as *mut u8, size_of::<ArcInner<T>>(), min_align_of::<ArcInner<T>>())
}
}
} }
/// Get the number of weak references to this value. /// Get the number of weak references to this value.
@ -212,6 +242,41 @@ pub fn weak_count<T>(this: &Arc<T>) -> usize { this.inner().weak.load(SeqCst) -
#[unstable(feature = "alloc")] #[unstable(feature = "alloc")]
pub fn strong_count<T>(this: &Arc<T>) -> usize { this.inner().strong.load(SeqCst) } pub fn strong_count<T>(this: &Arc<T>) -> usize { this.inner().strong.load(SeqCst) }
/// Try accessing a mutable reference to the contents behind an unique `Arc<T>`.
///
/// The access is granted only if this is the only reference to the object.
/// Otherwise, `None` is returned.
///
/// # Examples
///
/// ```
/// # #![feature(alloc)]
/// extern crate alloc;
/// # fn main() {
/// use alloc::arc;
///
/// let mut four = arc::Arc::new(4);
///
/// arc::unique(&mut four).map(|num| *num = 5);
/// # }
/// ```
#[inline]
#[unstable(feature = "alloc")]
pub fn unique<T>(this: &mut Arc<T>) -> Option<&mut T> {
if strong_count(this) == 1 && weak_count(this) == 0 {
// This unsafety is ok because we're guaranteed that the pointer
// returned is the *only* pointer that will ever be returned to T. Our
// reference count is guaranteed to be 1 at this point, and we required
// the Arc itself to be `mut`, so we're returning the only possible
// reference to the inner data.
let inner = unsafe { &mut **this._ptr };
Some(&mut inner.data)
}else {
None
}
}
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
impl<T> Clone for Arc<T> { impl<T> Clone for Arc<T> {
/// Makes a clone of the `Arc<T>`. /// Makes a clone of the `Arc<T>`.
@ -221,6 +286,7 @@ impl<T> Clone for Arc<T> {
/// # Examples /// # Examples
/// ///
/// ``` /// ```
/// # #![feature(alloc)]
/// use std::sync::Arc; /// use std::sync::Arc;
/// ///
/// let five = Arc::new(5); /// let five = Arc::new(5);
@ -229,13 +295,15 @@ impl<T> Clone for Arc<T> {
/// ``` /// ```
#[inline] #[inline]
fn clone(&self) -> Arc<T> { fn clone(&self) -> Arc<T> {
// Using a relaxed ordering is alright here, as knowledge of the original reference // Using a relaxed ordering is alright here, as knowledge of the
// prevents other threads from erroneously deleting the object. // original reference prevents other threads from erroneously deleting
// the object.
// //
// As explained in the [Boost documentation][1], Increasing the reference counter can // As explained in the [Boost documentation][1], Increasing the
// always be done with memory_order_relaxed: New references to an object can only be formed // reference counter can always be done with memory_order_relaxed: New
// from an existing reference, and passing an existing reference from one thread to another // references to an object can only be formed from an existing
// must already provide any required synchronization. // reference, and passing an existing reference from one thread to
// another must already provide any required synchronization.
// //
// [1]: (www.boost.org/doc/libs/1_55_0/doc/html/atomic/usage_examples.html) // [1]: (www.boost.org/doc/libs/1_55_0/doc/html/atomic/usage_examples.html)
self.inner().strong.fetch_add(1, Relaxed); self.inner().strong.fetch_add(1, Relaxed);
@ -253,15 +321,16 @@ impl<T> Deref for Arc<T> {
} }
} }
impl<T: Send + Sync + Clone> Arc<T> { impl<T: Clone> Arc<T> {
/// Make a mutable reference from the given `Arc<T>`. /// Make a mutable reference from the given `Arc<T>`.
/// ///
/// This is also referred to as a copy-on-write operation because the inner data is cloned if /// This is also referred to as a copy-on-write operation because the inner
/// the reference count is greater than one. /// data is cloned if the reference count is greater than one.
/// ///
/// # Examples /// # Examples
/// ///
/// ``` /// ```
/// # #![feature(alloc)]
/// use std::sync::Arc; /// use std::sync::Arc;
/// ///
/// let mut five = Arc::new(5); /// let mut five = Arc::new(5);
@ -271,16 +340,15 @@ impl<T: Send + Sync + Clone> Arc<T> {
#[inline] #[inline]
#[unstable(feature = "alloc")] #[unstable(feature = "alloc")]
pub fn make_unique(&mut self) -> &mut T { pub fn make_unique(&mut self) -> &mut T {
// Note that we hold a strong reference, which also counts as a weak reference, so we only // Note that we hold a strong reference, which also counts as a weak
// clone if there is an additional reference of either kind. // reference, so we only clone if there is an additional reference of
// either kind.
if self.inner().strong.load(SeqCst) != 1 || if self.inner().strong.load(SeqCst) != 1 ||
self.inner().weak.load(SeqCst) != 1 { self.inner().weak.load(SeqCst) != 1 {
*self = Arc::new((**self).clone()) *self = Arc::new((**self).clone())
} }
// This unsafety is ok because we're guaranteed that the pointer returned is the *only* // As with `unique()`, the unsafety is ok because our reference was
// pointer that will ever be returned to T. Our reference count is guaranteed to be 1 at // either unique to begin with, or became one upon cloning the contents.
// this point, and we required the Arc itself to be `mut`, so we're returning the only
// possible reference to the inner data.
let inner = unsafe { &mut **self._ptr }; let inner = unsafe { &mut **self._ptr };
&mut inner.data &mut inner.data
} }
@ -288,15 +356,17 @@ impl<T: Send + Sync + Clone> Arc<T> {
#[unsafe_destructor] #[unsafe_destructor]
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
impl<T: Sync + Send> Drop for Arc<T> { impl<T> Drop for Arc<T> {
/// Drops the `Arc<T>`. /// Drops the `Arc<T>`.
/// ///
/// This will decrement the strong reference count. If the strong reference count becomes zero /// This will decrement the strong reference count. If the strong reference
/// and the only other references are `Weak<T>` ones, `drop`s the inner value. /// count becomes zero and the only other references are `Weak<T>` ones,
/// `drop`s the inner value.
/// ///
/// # Examples /// # Examples
/// ///
/// ``` /// ```
/// # #![feature(alloc)]
/// use std::sync::Arc; /// use std::sync::Arc;
/// ///
/// { /// {
@ -313,58 +383,59 @@ impl<T: Sync + Send> Drop for Arc<T> {
/// ///
/// } // implicit drop /// } // implicit drop
/// ``` /// ```
#[inline]
fn drop(&mut self) { fn drop(&mut self) {
// This structure has #[unsafe_no_drop_flag], so this drop glue may run more than once (but // This structure has #[unsafe_no_drop_flag], so this drop glue may run
// it is guaranteed to be zeroed after the first if it's run more than once) // more than once (but it is guaranteed to be zeroed after the first if
// it's run more than once)
let ptr = *self._ptr; let ptr = *self._ptr;
if ptr.is_null() { return } // if ptr.is_null() { return }
if ptr.is_null() || ptr as usize == mem::POST_DROP_USIZE { return }
// Because `fetch_sub` is already atomic, we do not need to synchronize with other threads // Because `fetch_sub` is already atomic, we do not need to synchronize
// unless we are going to delete the object. This same logic applies to the below // with other threads unless we are going to delete the object. This
// `fetch_sub` to the `weak` count. // same logic applies to the below `fetch_sub` to the `weak` count.
if self.inner().strong.fetch_sub(1, Release) != 1 { return } if self.inner().strong.fetch_sub(1, Release) != 1 { return }
// This fence is needed to prevent reordering of use of the data and deletion of the data. // This fence is needed to prevent reordering of use of the data and
// Because it is marked `Release`, the decreasing of the reference count synchronizes with // deletion of the data. Because it is marked `Release`, the decreasing
// this `Acquire` fence. This means that use of the data happens before decreasing the // of the reference count synchronizes with this `Acquire` fence. This
// reference count, which happens before this fence, which happens before the deletion of // means that use of the data happens before decreasing the reference
// the data. // count, which happens before this fence, which happens before the
// deletion of the data.
// //
// As explained in the [Boost documentation][1], // As explained in the [Boost documentation][1],
// //
// > It is important to enforce any possible access to the object in one thread (through an // > It is important to enforce any possible access to the object in one
// > existing reference) to *happen before* deleting the object in a different thread. This // > thread (through an existing reference) to *happen before* deleting
// > is achieved by a "release" operation after dropping a reference (any access to the // > the object in a different thread. This is achieved by a "release"
// > object through this reference must obviously happened before), and an "acquire" // > operation after dropping a reference (any access to the object
// > operation before deleting the object. // > through this reference must obviously happened before), and an
// > "acquire" operation before deleting the object.
// //
// [1]: (www.boost.org/doc/libs/1_55_0/doc/html/atomic/usage_examples.html) // [1]: (www.boost.org/doc/libs/1_55_0/doc/html/atomic/usage_examples.html)
atomic::fence(Acquire); atomic::fence(Acquire);
// Destroy the data at this time, even though we may not free the box allocation itself unsafe {
// (there may still be weak pointers lying around). self.drop_slow()
unsafe { drop(ptr::read(&self.inner().data)); }
if self.inner().weak.fetch_sub(1, Release) == 1 {
atomic::fence(Acquire);
unsafe { deallocate(ptr as *mut u8, size_of::<ArcInner<T>>(),
min_align_of::<ArcInner<T>>()) }
} }
} }
} }
#[unstable(feature = "alloc", #[unstable(feature = "alloc",
reason = "Weak pointers may not belong in this module.")] reason = "Weak pointers may not belong in this module.")]
impl<T: Sync + Send> Weak<T> { impl<T> Weak<T> {
/// Upgrades a weak reference to a strong reference. /// Upgrades a weak reference to a strong reference.
/// ///
/// Upgrades the `Weak<T>` reference to an `Arc<T>`, if possible. /// Upgrades the `Weak<T>` reference to an `Arc<T>`, if possible.
/// ///
/// Returns `None` if there were no strong references and the data was destroyed. /// Returns `None` if there were no strong references and the data was
/// destroyed.
/// ///
/// # Examples /// # Examples
/// ///
/// ``` /// ```
/// # #![feature(alloc)]
/// use std::sync::Arc; /// use std::sync::Arc;
/// ///
/// let five = Arc::new(5); /// let five = Arc::new(5);
@ -374,8 +445,8 @@ impl<T: Sync + Send> Weak<T> {
/// let strong_five: Option<Arc<_>> = weak_five.upgrade(); /// let strong_five: Option<Arc<_>> = weak_five.upgrade();
/// ``` /// ```
pub fn upgrade(&self) -> Option<Arc<T>> { pub fn upgrade(&self) -> Option<Arc<T>> {
// We use a CAS loop to increment the strong count instead of a fetch_add because once the // We use a CAS loop to increment the strong count instead of a
// count hits 0 is must never be above 0. // fetch_add because once the count hits 0 is must never be above 0.
let inner = self.inner(); let inner = self.inner();
loop { loop {
let n = inner.strong.load(SeqCst); let n = inner.strong.load(SeqCst);
@ -394,7 +465,7 @@ impl<T: Sync + Send> Weak<T> {
#[unstable(feature = "alloc", #[unstable(feature = "alloc",
reason = "Weak pointers may not belong in this module.")] reason = "Weak pointers may not belong in this module.")]
impl<T: Sync + Send> Clone for Weak<T> { impl<T> Clone for Weak<T> {
/// Makes a clone of the `Weak<T>`. /// Makes a clone of the `Weak<T>`.
/// ///
/// This increases the weak reference count. /// This increases the weak reference count.
@ -402,6 +473,7 @@ impl<T: Sync + Send> Clone for Weak<T> {
/// # Examples /// # Examples
/// ///
/// ``` /// ```
/// # #![feature(alloc)]
/// use std::sync::Arc; /// use std::sync::Arc;
/// ///
/// let weak_five = Arc::new(5).downgrade(); /// let weak_five = Arc::new(5).downgrade();
@ -418,7 +490,7 @@ impl<T: Sync + Send> Clone for Weak<T> {
#[unsafe_destructor] #[unsafe_destructor]
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
impl<T: Sync + Send> Drop for Weak<T> { impl<T> Drop for Weak<T> {
/// Drops the `Weak<T>`. /// Drops the `Weak<T>`.
/// ///
/// This will decrement the weak reference count. /// This will decrement the weak reference count.
@ -426,6 +498,7 @@ impl<T: Sync + Send> Drop for Weak<T> {
/// # Examples /// # Examples
/// ///
/// ``` /// ```
/// # #![feature(alloc)]
/// use std::sync::Arc; /// use std::sync::Arc;
/// ///
/// { /// {
@ -448,10 +521,11 @@ impl<T: Sync + Send> Drop for Weak<T> {
let ptr = *self._ptr; let ptr = *self._ptr;
// see comments above for why this check is here // see comments above for why this check is here
if ptr.is_null() { return } if ptr.is_null() || ptr as usize == mem::POST_DROP_USIZE { return }
// If we find out that we were the last weak pointer, then its time to deallocate the data // If we find out that we were the last weak pointer, then its time to
// entirely. See the discussion in Arc::drop() about the memory orderings // deallocate the data entirely. See the discussion in Arc::drop() about
// the memory orderings
if self.inner().weak.fetch_sub(1, Release) == 1 { if self.inner().weak.fetch_sub(1, Release) == 1 {
atomic::fence(Acquire); atomic::fence(Acquire);
unsafe { deallocate(ptr as *mut u8, size_of::<ArcInner<T>>(), unsafe { deallocate(ptr as *mut u8, size_of::<ArcInner<T>>(),
@ -598,13 +672,6 @@ impl<T: Default + Sync + Send> Default for Arc<T> {
fn default() -> Arc<T> { Arc::new(Default::default()) } fn default() -> Arc<T> { Arc::new(Default::default()) }
} }
#[cfg(stage0)]
impl<H: Hasher, T: Hash<H>> Hash<H> for Arc<T> {
fn hash(&self, state: &mut H) {
(**self).hash(state)
}
}
#[cfg(not(stage0))]
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
impl<T: Hash> Hash for Arc<T> { impl<T: Hash> Hash for Arc<T> {
fn hash<H: Hasher>(&self, state: &mut H) { fn hash<H: Hasher>(&self, state: &mut H) {
@ -624,7 +691,7 @@ mod tests {
use std::sync::atomic::Ordering::{Acquire, SeqCst}; use std::sync::atomic::Ordering::{Acquire, SeqCst};
use std::thread; use std::thread;
use std::vec::Vec; use std::vec::Vec;
use super::{Arc, Weak, weak_count, strong_count}; use super::{Arc, Weak, weak_count, strong_count, unique};
use std::sync::Mutex; use std::sync::Mutex;
struct Canary(*mut atomic::AtomicUsize); struct Canary(*mut atomic::AtomicUsize);
@ -660,6 +727,21 @@ mod tests {
assert_eq!((*arc_v)[4], 5); assert_eq!((*arc_v)[4], 5);
} }
#[test]
fn test_arc_unique() {
let mut x = Arc::new(10);
assert!(unique(&mut x).is_some());
{
let y = x.clone();
assert!(unique(&mut x).is_none());
}
{
let z = x.downgrade();
assert!(unique(&mut x).is_none());
}
assert!(unique(&mut x).is_some());
}
#[test] #[test]
fn test_cowarc_clone_make_unique() { fn test_cowarc_clone_make_unique() {
let mut cow0 = Arc::new(75); let mut cow0 = Arc::new(75);

Some files were not shown because too many files have changed in this diff Show More