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 Zotov <whitequark@whitequark.org>
Petter Remen <petter.remen@gmail.com>
Phil Dawes <pdawes@drw.com>
Phil Dawes <phil@phildawes.net>
Phil Ruffwind <rf@rufflewind.com>
Philip Munksgaard <pmunksgaard@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
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
[internals]: http://internals.rust-lang.org

View File

@ -97,12 +97,7 @@
# make check-stage1-rpass TESTNAME=my-shiny-new-test
#
# // Having trouble figuring out which test is failing? Turn off parallel tests
# make check-stage1-std RUST_TEST_TASKS=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
# make check-stage1-std RUST_TEST_THREADS=1
#
# 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
1. Make sure you have installed the dependencies:
* `g++` 4.7 or `clang++` 3.x
* `python` 2.6 or later (but not 3.x)
* GNU `make` 3.81 or later
@ -23,20 +24,25 @@ Read ["Installing Rust"] from [The Book].
2. Clone the [source] with `git`:
```sh
$ git clone https://github.com/rust-lang/rust.git
$ cd rust
```
[source]: https://github.com/rust-lang/rust
3. Build and install:
```sh
$ ./configure
$ make && make install
```
> ***Note:*** You may need to use `sudo make install` if you do not normally have
> permission to modify the destination directory. The install locations can
> be adjusted by passing a `--prefix` argument to `configure`. Various other
> options are also supported, pass `--help` for more information on them.
> ***Note:*** You may need to use `sudo make install` if you do not
> normally have permission to modify the destination directory. The
> install locations can be adjusted by passing a `--prefix` argument
> to `configure`. Various other options are also supported pass
> `--help` for more information on them.
When complete, `make install` will place several programs into
`/usr/local/bin`: `rustc`, the Rust compiler, and `rustdoc`, the
@ -47,27 +53,30 @@ Read ["Installing Rust"] from [The Book].
### 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.
2. Now from the MSYS2 terminal we want to install the mingw64 toolchain and the other
tools we need.
```bash
# choose one based on platform
2. From the MSYS2 terminal, install the `mingw64` toolchain and other required
tools.
```sh
# Choose one based on platform:
$ pacman -S mingw-w64-i686-toolchain
$ pacman -S mingw-w64-x86_64-toolchain
$ pacman -S base-devel
```
3. With that now start `mingw32_shell.bat` or `mingw64_shell.bat`
from where you installed MSYS2 (i.e. `C:\msys`). Which one you
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:
3. Run `mingw32_shell.bat` or `mingw64_shell.bat` from wherever you installed
MYSY2 (i.e. `C:\msys`), depending on whether you want 32-bit or 64-bit Rust.
4. Navigate to Rust's source code, configure and build it:
```sh
$ ./configure
$ make && make install
```
## 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
## Getting help
## Getting Help
The Rust community congregates in a few places:
* [StackOverflow] - Direct questions about using the language here.
* [users.rust-lang.org] - General discussion, broader questions.
* [Stack Overflow] - Direct questions about using the language.
* [users.rust-lang.org] - General discussion and broader questions.
* [/r/rust] - News and general discussion.
[Stack Overflow]: http://stackoverflow.com/questions/tagged/rust
@ -106,12 +115,12 @@ The Rust community congregates in a few places:
## 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
variety of channels on Mozilla's IRC network, irc.mozilla.org. The
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
[#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
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)
-------------------------------------
@ -51,7 +150,7 @@ Version 1.0.0-alpha.2 (February 2015)
* Abstract [OS-specific string types][osstr], `std::ff::{OsString,
OsStr}`, provide strings in platform-specific encodings for easier
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
creating raw pointers.

51
configure vendored
View File

@ -374,6 +374,10 @@ case $CFG_OSTYPE in
CFG_OSTYPE=unknown-dragonfly
;;
Bitrig)
CFG_OSTYPE=unknown-bitrig
;;
OpenBSD)
CFG_OSTYPE=unknown-openbsd
;;
@ -400,7 +404,7 @@ case $CFG_OSTYPE in
CFG_OSTYPE=pc-windows-gnu
;;
# Thad's Cygwin identifers below
# Thad's Cygwin identifiers below
# Vista 32 bit
CYGWIN_NT-6.0)
@ -426,6 +430,10 @@ case $CFG_OSTYPE in
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.
# 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
;;
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
;;
@ -468,11 +479,20 @@ esac
# Detect 64 bit linux systems with 32 bit userland and force 32 bit compilation
if [ $CFG_OSTYPE = unknown-linux-gnu -a $CFG_CPUTYPE = x86_64 ]
then
file -L "$SHELL" | grep -q "x86[_-]64"
# $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
CFG_CPUTYPE=i686
fi
fi
fi
DEFAULT_BUILD="${CFG_CPUTYPE}-${CFG_OSTYPE}"
@ -506,7 +526,8 @@ VAL_OPTIONS=""
opt valgrind 0 "run tests with valgrind (memcheck by default)"
opt helgrind 0 "run tests with helgrind instead of memcheck"
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-cxx 1 "build optimized C++ code"
opt optimize-llvm 1 "build optimized LLVM"
@ -693,15 +714,17 @@ probe CFG_ADB adb
if [ ! -z "$CFG_PANDOC" ]
then
PV_MAJOR_MINOR=$(pandoc --version | grep '^pandoc\(.exe\)\? ' |
# extract the first 2 version fields, ignore everything else
sed 's/pandoc\(.exe\)\? \([0-9]*\)\.\([0-9]*\).*/\2 \3/')
# Extract "MAJOR MINOR" from Pandoc's version number
PV_MAJOR_MINOR=$(pandoc --version | grep '^pandoc' |
sed -E 's/pandoc(.exe)? ([0-9]+)\.([0-9]+).*/\2 \3/')
MIN_PV_MAJOR="1"
MIN_PV_MINOR="9"
# these patterns are shell globs, *not* regexps
PV_MAJOR=${PV_MAJOR_MINOR% *}
PV_MINOR=${PV_MAJOR_MINOR#* }
if [ "$PV_MAJOR" -lt "$MIN_PV_MAJOR" ] || [ "$PV_MINOR" -lt "$MIN_PV_MINOR" ]
then
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
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" ]
then
err "either clang or gcc is required"
@ -805,11 +836,11 @@ then
LLVM_VERSION=$($LLVM_CONFIG --version)
case $LLVM_VERSION in
(3.[2-6]*)
(3.[5-6]*)
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
fi
@ -864,7 +895,7 @@ then
| cut -d ' ' -f 2)
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"
if [ -z "$CC" ]
then

View File

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

View File

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

View File

@ -54,7 +54,7 @@ TARGET_CRATES := libc std flate arena term \
log graphviz core rbml alloc \
unicode rustc_bitflags
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
CRATES := $(TARGET_CRATES) $(HOST_CRATES)
TOOLS := compiletest rustdoc rustc rustbook
@ -70,7 +70,7 @@ DEPS_graphviz := std
DEPS_syntax := std term serialize log fmt_macros arena libc
DEPS_rustc_driver := arena flate getopts graphviz libc rustc rustc_back rustc_borrowck \
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 \
log syntax serialize rustc_llvm
@ -78,12 +78,13 @@ DEPS_rustc_typeck := rustc syntax
DEPS_rustc_borrowck := rustc log graphviz syntax
DEPS_rustc_resolve := rustc log syntax
DEPS_rustc_privacy := rustc log syntax
DEPS_rustc_lint := rustc log syntax
DEPS_rustc := syntax flate arena serialize getopts rbml \
log graphviz rustc_llvm rustc_back
DEPS_rustc_llvm := native:rustllvm libc std
DEPS_rustc_back := std syntax rustc_llvm flate log libc
DEPS_rustdoc := rustc rustc_driver native:hoedown serialize getopts \
test
test rustc_lint
DEPS_rustc_bitflags := core
DEPS_flate := std native:miniz
DEPS_arena := std
@ -121,6 +122,21 @@ ONLY_RLIB_rustc_bitflags := 1
# 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, \
$(filter-out rustc_trans, \
$(filter-out rustc_typeck, \
@ -128,11 +144,15 @@ DOC_CRATES := $(filter-out rustc, \
$(filter-out rustc_resolve, \
$(filter-out rustc_driver, \
$(filter-out rustc_privacy, \
$(filter-out rustc_lint, \
$(filter-out log, \
$(filter-out getopts, \
$(filter-out syntax, $(CRATES)))))))))))
$(filter-out syntax, $(CRATES))))))))))))
#endif
#endif
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
# 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: \
$$(DEBUGGER_RUSTLIB_ETC_SCRIPTS_GDB_ABS) \
$$(DEBUGGER_BIN_SCRIPTS_GDB_ABS)
$(Q)touch $$@.start_time
$(Q)mkdir -p $$(HBIN$(1)_H_$(2))
$(Q)mkdir -p $$(HLIB$(1)_H_$(2))/rustlib/etc
$(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)touch $$@
$(Q)touch -r $$@.start_time $$@ && rm $$@.start_time
tmp/install-debugger-scripts$(1)_H_$(2)-lldb.done: \
$$(DEBUGGER_RUSTLIB_ETC_SCRIPTS_LLDB_ABS) \
$$(DEBUGGER_BIN_SCRIPTS_LLDB_ABS)
$(Q)touch $$@.start_time
$(Q)mkdir -p $$(HBIN$(1)_H_$(2))
$(Q)mkdir -p $$(HLIB$(1)_H_$(2))/rustlib/etc
$(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)touch $$@
$(Q)touch -r $$@.start_time $$@ && rm $$@.start_time
tmp/install-debugger-scripts$(1)_H_$(2)-all.done: \
$$(DEBUGGER_RUSTLIB_ETC_SCRIPTS_ALL_ABS) \
$$(DEBUGGER_BIN_SCRIPTS_ALL_ABS)
$(Q)touch $$@.start_time
$(Q)mkdir -p $$(HBIN$(1)_H_$(2))
$(Q)mkdir -p $$(HLIB$(1)_H_$(2))/rustlib/etc
$(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)touch $$@
$(Q)touch -r $$@.start_time $$@ && rm $$@.start_time
tmp/install-debugger-scripts$(1)_H_$(2)-none.done:
$(Q)touch $$@
@ -98,29 +101,32 @@ define DEF_INSTALL_DEBUGGER_SCRIPTS_TARGET
tmp/install-debugger-scripts$(1)_T_$(2)_H_$(3)-gdb.done: \
$$(DEBUGGER_RUSTLIB_ETC_SCRIPTS_GDB_ABS) \
$$(DEBUGGER_BIN_SCRIPTS_GDB_ABS)
$(Q)touch $$@.start_time
$(Q)mkdir -p $$(TBIN$(1)_T_$(2)_H_$(3))
$(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_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: \
$$(DEBUGGER_RUSTLIB_ETC_SCRIPTS_LLDB_ABS) \
$$(DEBUGGER_BIN_SCRIPTS_LLDB_ABS)
$(Q)touch $$@.start_time
$(Q)mkdir -p $$(TBIN$(1)_T_$(2)_H_$(3))
$(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_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: \
$$(DEBUGGER_RUSTLIB_ETC_SCRIPTS_ALL_ABS) \
$$(DEBUGGER_BIN_SCRIPTS_ALL_ABS)
$(Q)touch $$@.start_time
$(Q)mkdir -p $$(TBIN$(1)_T_$(2)_H_$(3))
$(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_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:
$(Q)touch $$@

View File

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

View File

@ -259,7 +259,10 @@ doc/$(1)/index.html: $$(LIB_DOC_DEP_$(1)) doc/$(1)/
endef
$(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)))
endif
ifdef 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
doc/book/index.html: $(RUSTBOOK_EXE) $(wildcard $(S)/src/doc/trpl/*.md) | doc/
@$(call E, rustbook: $@)
$(Q)rm -rf doc/book
$(Q)$(RUSTBOOK) build $(S)src/doc/trpl doc/book
style: doc/style/index.html
doc/style/index.html: $(RUSTBOOK_EXE) $(wildcard $(S)/src/doc/style/*.md) | doc/
@$(call E, rustbook: $@)
$(Q)rm -rf doc/style
$(Q)$(RUSTBOOK) build $(S)src/doc/style doc/style

View File

@ -38,15 +38,16 @@ endif
# the stamp in the source dir.
$$(LLVM_STAMP_$(1)): $(S)src/rustllvm/llvm-auto-clean-trigger
@$$(call E, make: cleaning llvm)
$(Q)touch $$@.start_time
$(Q)$(MAKE) clean-llvm$(1)
@$$(call E, make: done cleaning llvm)
touch $$@
touch -r $$@.start_time $$@ && rm $$@.start_time
ifeq ($$(CFG_ENABLE_LLVM_STATIC_STDCPP),1)
LLVM_STDCPP_LOCATION_$(1) = $$(shell $$(CC_$(1)) $$(CFG_GCCISH_CFLAGS_$(1)) \
-print-file-name=libstdc++.a)
LLVM_STDCPP_RUSTFLAGS_$(1) = -L "$$(dir $$(shell $$(CC_$(1)) $$(CFG_GCCISH_CFLAGS_$(1)) \
-print-file-name=libstdc++.a))"
else
LLVM_STDCPP_LOCATION_$(1) =
LLVM_STDCPP_RUSTFLAGS_$(1) =
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'
# NB Make sure it starts with a dot to conform to semver pre-release
# versions (section 9)
CFG_PRERELEASE_VERSION=.2
CFG_PRERELEASE_VERSION=
CFG_FILENAME_EXTRA=4e7c5e5c
@ -30,8 +30,8 @@ CFG_PACKAGE_VERS=$(CFG_RELEASE_NUM)
CFG_DISABLE_UNSTABLE_FEATURES=1
endif
ifeq ($(CFG_RELEASE_CHANNEL),beta)
CFG_RELEASE=$(CFG_RELEASE_NUM)-alpha$(CFG_PRERELEASE_VERSION)
CFG_PACKAGE_VERS=$(CFG_RELEASE_NUM)-alpha$(CFG_PRERELEASE_VERSION)
CFG_RELEASE=$(CFG_RELEASE_NUM)-beta$(CFG_PRERELEASE_VERSION)
CFG_PACKAGE_VERS=$(CFG_RELEASE_NUM)-beta$(CFG_PRERELEASE_VERSION)
CFG_DISABLE_UNSTABLE_FEATURES=1
endif
ifeq ($(CFG_RELEASE_CHANNEL),nightly)
@ -130,7 +130,7 @@ ifdef CFG_DISABLE_DEBUG
CFG_RUSTC_FLAGS += --cfg ndebug
else
$(info cfg: enabling more debugging (CFG_ENABLE_DEBUG))
CFG_RUSTC_FLAGS += --cfg debug
CFG_RUSTC_FLAGS += --cfg debug -C debug-assertions=on
endif
ifdef SAVE_TEMPS
@ -290,6 +290,7 @@ LLVM_VERSION_$(1)=$$(shell "$$(LLVM_CONFIG_$(1))" --version)
LLVM_BINDIR_$(1)=$$(shell "$$(LLVM_CONFIG_$(1))" --bindir)
LLVM_INCDIR_$(1)=$$(shell "$$(LLVM_CONFIG_$(1))" --includedir)
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_LDFLAGS_$(1)=$$(shell "$$(LLVM_CONFIG_$(1))" --ldflags)
# 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),)
# 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
# .cfi pseudo-ops on mac
CFG_ASSEMBLE_$(1)=$$(CPP_$(1)) -E $$(CFG_DEPEND_FLAGS) $$(2) | \
$$(LLVM_MC_$$(CFG_BUILD)) \
-assemble \
-relocation-model=$$(LLVM_MC_RELOCATION_MODEL) \
-filetype=obj \
-triple=$(1) \
-o=$$(1)

View File

@ -221,5 +221,3 @@ prepare-maybe-clean-$(1):
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): \
$$(CRATEFILE_$(4)) \
$$(CRATE_FULLDEPS_$(1)_T_$(2)_H_$(3)_$(4)) \
$$(LLVM_CONFIG_$(2)) \
$$(TSREQ$(1)_T_$(2)_H_$(3)) \
| $$(TLIB$(1)_T_$(2)_H_$(3))/
@$$(call E, rustc: $$(@D)/lib$(4))
@touch $$@.start_time
$$(call REMOVE_ALL_OLD_GLOB_MATCHES, \
$$(dir $$@)$$(call CFG_LIB_GLOB_$(2),$(4)))
$$(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))) \
$$(RUST_LIB_FLAGS_ST$(1)) \
-L "$$(RT_OUTPUT_DIR_$(2))" \
-L "$$(LLVM_LIBDIR_$(2))" \
-L "$$(dir $$(LLVM_STDCPP_LOCATION_$(2)))" \
$$(LLVM_LIBDIR_RUSTFLAGS_$(2)) \
$$(LLVM_STDCPP_RUSTFLAGS_$(2)) \
$$(RUSTFLAGS_$(4)) \
--out-dir $$(@D) \
-C extra-filename=-$$(CFG_FILENAME_EXTRA) \
$$<
@touch $$@
@touch -r $$@.start_time $$@ && rm $$@.start_time
$$(call LIST_ALL_OLD_GLOB_MATCHES, \
$$(dir $$@)$$(call CFG_LIB_GLOB_$(2),$(4)))
$$(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
# 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
# inadvertantly included in the clean out.
# inadvertently included in the clean out.
SNAPSHOT_RUSTC_POST_CLEANUP=$(HBIN0_H_$(CFG_BUILD))/rustc$(X_$(CFG_BUILD))
define TARGET_HOST_RULES

View File

@ -19,9 +19,12 @@
DEPS_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_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))
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.
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
# 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.
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.
#
# 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)) \
$$(subst @,,$$(STAGE$(1)_T_$(2)_H_$(3))) -o $$@ $$< --test \
-L "$$(RT_OUTPUT_DIR_$(2))" \
-L "$$(LLVM_LIBDIR_$(2))" \
$$(LLVM_LIBDIR_RUSTFLAGS_$(2)) \
$$(RUSTFLAGS_$(4))
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)): \
$(3)/stage$(1)/test/$(4)test-$(2)$$(X_$(2))
@$$(call E, run: $$<)
$$(Q)touch $$@.start_time
$$(Q)$$(call CFG_RUN_TEST_$(2),$$<,$(1),$(2),$(3)) $$(TESTARGS) \
--logfile $$(call TEST_LOG_FILE,$(1),$(2),$(3),$(4)) \
$$(call CRATE_TEST_EXTRA_ARGS,$(1),$(2),$(3),$(4)) \
&& touch $$@
&& touch -r $$@.start_time $$@ && rm $$@.start_time
endef
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)): \
$(3)/stage$(1)/test/$(4)test-$(2)$$(X_$(2))
@$$(call E, run: $$< via adb)
$$(Q)touch $$@.start_time
$$(Q)$(CFG_ADB) push $$< $(CFG_ADB_TEST_DIR)
$$(Q)$(CFG_ADB) shell '(cd $(CFG_ADB_TEST_DIR); LD_LIBRARY_PATH=./$(2) \
./$$(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; \
then \
rm tmp/check-stage$(1)-T-$(2)-H-$(3)-$(4).tmp; \
touch $$@; \
touch -r $$@.start_time $$@ && rm $$@.start_time; \
else \
rm tmp/check-stage$(1)-T-$(2)-H-$(3)-$(4).tmp; \
exit 101; \
@ -564,6 +574,11 @@ ifeq ($(CFG_OSTYPE),apple-darwin)
CTEST_DISABLE_debuginfo-gdb = "gdb on darwin needs root"
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
# 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
@ -588,7 +603,7 @@ TEST_SREQ$(1)_T_$(2)_H_$(3) = \
# The tests select when to use debug configuration on their own;
# 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
# 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)) \
$$(CTEST_DEPS_$(4)_$(1)-T-$(2)-H-$(3))
@$$(call E, run $(4) [$(2)]: $$<)
$$(Q)touch $$@.start_time
$$(Q)$$(call CFG_RUN_CTEST_$(2),$(1),$$<,$(3)) \
$$(CTEST_ARGS$(1)-T-$(2)-H-$(3)-$(4)) \
--logfile $$(call TEST_LOG_FILE,$(1),$(2),$(3),$(4)) \
&& touch $$@
&& touch -r $$@.start_time $$@ && rm $$@.start_time
else
@ -750,10 +766,11 @@ $$(call TEST_OK_FILE,$(1),$(2),$(3),$(4)): \
$$(PRETTY_DEPS_$(4)) \
$$(PRETTY_DEPS$(1)_H_$(3)_$(4))
@$$(call E, run pretty-rpass [$(2)]: $$<)
$$(Q)touch $$@.start_time
$$(Q)$$(call CFG_RUN_CTEST_$(2),$(1),$$<,$(3)) \
$$(PRETTY_ARGS$(1)-T-$(2)-H-$(3)-$(4)) \
--logfile $$(call TEST_LOG_FILE,$(1),$(2),$(3),$(4)) \
&& touch $$@
&& touch -r $$@.start_time $$@ && rm $$@.start_time
endef
@ -799,8 +816,10 @@ endif
ifeq ($(2),$$(CFG_BUILD))
$$(call TEST_OK_FILE,$(1),$(2),$(3),doc-$(4)): $$(DOCTESTDEP_$(1)_$(2)_$(3)_$(4))
@$$(call E, run doc-$(4) [$(2)])
$$(Q)touch $$@.start_time
$$(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
$$(call TEST_OK_FILE,$(1),$(2),$(3),doc-$(4)):
touch $$@
@ -835,9 +854,11 @@ check-stage$(1)-T-$(2)-H-$(3)-doc-crate-$(4)-exec: \
ifeq ($(2),$$(CFG_BUILD))
$$(call TEST_OK_FILE,$(1),$(2),$(3),doc-crate-$(4)): $$(CRATEDOCTESTDEP_$(1)_$(2)_$(3)_$(4))
@$$(call E, run doc-crate-$(4) [$(2)])
$$(Q)touch $$@.start_time
$$(Q)CFG_LLVM_LINKAGE_FILE=$$(LLVM_LINKAGE_PATH_$(3)) \
$$(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
$$(call TEST_OK_FILE,$(1),$(2),$(3),doc-crate-$(4)):
touch $$@
@ -984,6 +1005,7 @@ $(3)/test/run-make/%-$(1)-T-$(2)-H-$(3).ok: \
$$(CSREQ$(1)_T_$(2)_H_$(3))
@rm -rf $(3)/test/run-make/$$*
@mkdir -p $(3)/test/run-make/$$*
$$(Q)touch $$@.start_time
$$(Q)$$(CFG_PYTHON) $(S)src/etc/maketest.py $$(dir $$<) \
$$(MAKE) \
$$(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))" \
$(1) \
$$(S)
@touch $$@
@touch -r $$@.start_time $$@ && rm $$@.start_time
else
# FIXME #11094 - The above rule doesn't work right for multiple targets
check-stage$(1)-T-$(2)-H-$(3)-rmake-exec:

View File

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

View File

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

View File

@ -12,16 +12,13 @@
#![feature(box_syntax)]
#![feature(collections)]
#![feature(int_uint)]
#![feature(old_io)]
#![feature(old_path)]
#![feature(rustc_private)]
#![feature(unboxed_closures)]
#![feature(std_misc)]
#![feature(test)]
#![feature(unicode)]
#![feature(env)]
#![feature(core)]
#![feature(path_ext)]
#![feature(str_char)]
#![deny(warnings)]
@ -32,9 +29,8 @@ extern crate getopts;
extern crate log;
use std::env;
use std::old_io;
use std::old_io::fs;
use std::thunk::Thunk;
use std::fs;
use std::path::{Path, PathBuf};
use getopts::{optopt, optflag, reqopt};
use common::Config;
use common::{Pretty, DebugInfoGdb, DebugInfoLldb, Codegen};
@ -115,9 +111,9 @@ pub fn parse_config(args: Vec<String> ) -> Config {
panic!()
}
fn opt_path(m: &getopts::Matches, nm: &str) -> Path {
fn opt_path(m: &getopts::Matches, nm: &str) -> PathBuf {
match m.opt_str(nm) {
Some(s) => Path::new(s),
Some(s) => PathBuf::from(&s),
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(),
run_lib_path: matches.opt_str("run-lib-path").unwrap(),
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"),
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"),
build_base: opt_path(matches, "build-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"),
run_ignored: matches.opt_present("ignored"),
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"),
host_rustcflags: matches.opt_str("host-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
// so, we test 1 task at once.
// 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 {
@ -234,7 +230,7 @@ pub fn run_tests(config: &Config) {
// Some older versions of LLDB seem to have problems with multiple
// instances running in parallel, so only run one test task at a
// time.
env::set_var("RUST_TEST_TASKS", "1");
env::set_var("RUST_TEST_THREADS", "1");
}
_ => { /* proceed */ }
}
@ -244,7 +240,11 @@ pub fn run_tests(config: &Config) {
// sadly osx needs some file descriptor limits raised for running tests in
// parallel (especially when we have lots and lots of child processes).
// 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
// If #11207 is resolved (adding manifest to .exe) this becomes unnecessary
env::set_var("__COMPAT_LAYER", "RunAsInvoker");
@ -268,7 +268,7 @@ pub fn test_opts(config: &Config) -> test::TestOpts {
logfile: config.logfile.clone(),
run_tests: true,
run_benchmarks: true,
nocapture: false,
nocapture: env::var("RUST_TEST_NOCAPTURE").is_ok(),
color: test::AutoColor,
}
}
@ -277,9 +277,9 @@ pub fn make_tests(config: &Config) -> Vec<test::TestDescAndFn> {
debug!("making tests from {:?}",
config.src_base.display());
let mut tests = Vec::new();
let dirs = fs::readdir(&config.src_base).unwrap();
for file in &dirs {
let file = file.clone();
let dirs = fs::read_dir(&config.src_base).unwrap();
for file in dirs {
let file = file.unwrap().path();
debug!("inspecting file {:?}", file.display());
if is_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())
};
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;
@ -328,7 +328,7 @@ pub fn make_test<F>(config: &Config, testfile: &Path, f: F) -> test::TestDescAnd
desc: test::TestDesc {
name: make_test_name(config, testfile),
ignore: header::is_test_ignored(config, testfile),
should_fail: test::ShouldFail::No,
should_panic: test::ShouldPanic::No,
},
testfn: f(),
}
@ -338,9 +338,9 @@ pub fn make_test_name(config: &Config, testfile: &Path) -> test::TestName {
// Try to elide redundant long paths
fn shorten(path: &Path) -> String {
let filename = path.filename_str();
let p = path.dir_path();
let dir = p.filename_str();
let filename = path.file_name().unwrap().to_str();
let p = path.parent().unwrap();
let dir = p.file_name().unwrap().to_str();
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 {
let config = (*config).clone();
// FIXME (#9639): This needs to handle non-utf8 paths
let testfile = testfile.as_str().unwrap().to_string();
test::DynTestFn(Thunk::new(move || {
runtest::run(config, testfile)
let testfile = testfile.to_path_buf();
test::DynTestFn(Box::new(move || {
runtest::run(config, &testfile)
}))
}
pub fn make_metrics_test_closure(config: &Config, testfile: &Path) -> test::TestFn {
let config = (*config).clone();
// FIXME (#9639): This needs to handle non-utf8 paths
let testfile = testfile.as_str().unwrap().to_string();
let testfile = testfile.to_path_buf();
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.
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 line: uint,
pub line: usize,
pub kind: String,
pub msg: String,
}
#[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"
/// 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.
// Load any test directives embedded in the file
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
// line with an error template that did not use the
@ -55,10 +58,10 @@ pub fn load_errors(testfile: &Path) -> Vec<ExpectedError> {
}).collect()
}
fn parse_expected(last_nonfollow_error: Option<uint>,
line_num: uint,
fn parse_expected(last_nonfollow_error: Option<usize>,
line_num: usize,
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) == '|' {
(true, 0)
} else {
@ -68,7 +71,7 @@ fn parse_expected(last_nonfollow_error: Option<uint>,
let letters = line[kind_start..].chars();
let kind = letters.skip_while(|c| c.is_whitespace())
.take_while(|c| !c.is_whitespace())
.map(|c| c.to_lowercase())
.flat_map(|c| c.to_lowercase())
.collect::<String>();
let letters = line[kind_start..].chars();
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
// 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;
use util;
@ -21,7 +27,7 @@ pub struct TestProps {
pub run_flags: Option<String>,
// If present, the name of a file that this test should match when
// pretty-printed
pub pp_exact: Option<Path>,
pub pp_exact: Option<PathBuf>,
// Modules from aux directory that should be compiled
pub aux_builds: Vec<String> ,
// Environment settings to use during execution
@ -34,8 +40,8 @@ pub struct TestProps {
pub check_stdout: bool,
// Don't force a --crate-type=dylib flag on the command line
pub no_prefer_dynamic: bool,
// Don't run --pretty expanded when running pretty printing tests
pub no_pretty_expanded: bool,
// Run --pretty expanded when running pretty printing tests
pub pretty_expanded: bool,
// Which pretty mode are we testing with, default to 'normal'
pub pretty_mode: String,
// 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 check_stdout = 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_compare_only = false;
let mut forbid_output = Vec::new();
iter_header(testfile, |ln| {
iter_header(testfile, &mut |ln| {
match parse_error_pattern(ln) {
Some(ep) => error_patterns.push(ep),
None => ()
@ -90,8 +96,8 @@ pub fn load_props(testfile: &Path) -> TestProps {
no_prefer_dynamic = parse_no_prefer_dynamic(ln);
}
if !no_pretty_expanded {
no_pretty_expanded = parse_no_pretty_expanded(ln);
if !pretty_expanded {
pretty_expanded = parse_pretty_expanded(ln);
}
if pretty_mode.is_none() {
@ -125,6 +131,16 @@ pub fn load_props(testfile: &Path) -> TestProps {
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 {
error_patterns: error_patterns,
compile_flags: compile_flags,
@ -136,7 +152,7 @@ pub fn load_props(testfile: &Path) -> TestProps {
force_host: force_host,
check_stdout: check_stdout,
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_compare_only: pretty_compare_only,
forbid_output: forbid_output,
@ -147,6 +163,9 @@ pub fn is_test_ignored(config: &Config, testfile: &Path) -> bool {
fn ignore_target(config: &Config) -> String {
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 {
format!("ignore-{}",
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_target(config)) &&
!parse_name_directive(ln, &ignore_architecture(config)) &&
!parse_name_directive(ln, &ignore_stage(config)) &&
!(config.mode == common::Pretty && parse_name_directive(ln, "ignore-pretty")) &&
!(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
}
fn iter_header<F>(testfile: &Path, mut it: F) -> bool where
F: FnMut(&str) -> bool,
{
use std::old_io::{BufferedReader, File};
let mut rdr = BufferedReader::new(File::open(testfile).unwrap());
fn iter_header(testfile: &Path, it: &mut FnMut(&str) -> bool) -> bool {
let rdr = BufReader::new(File::open(testfile).unwrap());
for ln in rdr.lines() {
// Assume that any directives will be found before the first
// 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")
}
fn parse_no_pretty_expanded(line: &str) -> bool {
parse_name_directive(line, "no-pretty-expanded")
fn parse_pretty_expanded(line: &str) -> bool {
parse_name_directive(line, "pretty-expanded")
}
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| {
// nv is either FOO or FOO=BAR
let mut strs: Vec<String> = nv
.splitn(1, '=')
.splitn(2, '=')
.map(|s| s.to_string())
.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") {
Some(s) => Some(Path::new(s)),
Some(s) => Some(PathBuf::from(&s)),
None => {
if parse_name_directive(line, "pp-exact") {
testfile.filename().map(|s| Path::new(s))
testfile.file_name().map(|s| PathBuf::from(s))
} else {
None
}
@ -324,13 +340,14 @@ fn parse_pp_exact(line: &str, testfile: &Path) -> Option<Path> {
}
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)
-> Option<String> {
let keycolon = format!("{}:", directive);
match line.find_str(&keycolon) {
match line.find(&keycolon) {
Some(colon) => {
let value = line[(colon + keycolon.len()) .. line.len()].to_string();
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!(
"Encountered GDB version string with unexpected format: {}",
version_string);
@ -352,17 +369,17 @@ pub fn gdb_version_to_int(version_string: &str) -> int {
panic!("{}", error_string);
}
let major: int = components[0].parse().ok().expect(&error_string);
let minor: int = components[1].parse().ok().expect(&error_string);
let major: isize = components[0].parse().ok().expect(&error_string);
let minor: isize = components[1].parse().ok().expect(&error_string);
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!(
"Encountered LLDB version string with unexpected format: {}",
version_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;
}

View File

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

View File

@ -11,35 +11,28 @@
use self::TargetLocation::*;
use common::Config;
use common::{CompileFail, ParseFail, Pretty, RunFail, RunPass, RunPassValgrind, DebugInfoGdb};
use common::{Codegen, DebugInfoLldb};
use common::{CompileFail, ParseFail, Pretty, RunFail, RunPass, RunPassValgrind};
use common::{Codegen, DebugInfoLldb, DebugInfoGdb};
use errors;
use header::TestProps;
use header;
use procsrv;
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::fmt;
use std::fs::{self, File};
use std::io::BufReader;
use std::io::prelude::*;
use std::iter::repeat;
use std::net::TcpStream;
use std::path::{Path, PathBuf};
use std::process::{Command, Output, ExitStatus};
use std::str;
use std::string::String;
use std::thread;
use std::time::Duration;
use test::MetricMap;
pub fn run(config: Config, testfile: String) {
pub fn run(config: Config, testfile: &Path) {
match &*config.target {
"arm-linux-androideabi" | "aarch64-linux-android" => {
@ -55,12 +48,11 @@ pub fn run(config: Config, testfile: String) {
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 {
// We're going to be dumping a lot of info. Start on a new line.
print!("\n\n");
}
let testfile = Path::new(testfile);
debug!("running {:?}", testfile.display());
let props = header::load_props(&testfile);
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);
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);
}
@ -127,8 +119,8 @@ fn run_rfail_test(config: &Config, props: &TestProps, testfile: &Path) {
};
// The value our Makefile configures valgrind to return on failure
static VALGRIND_ERR: int = 100;
if proc_res.status.matches_exit_status(VALGRIND_ERR) {
const VALGRIND_ERR: i32 = 100;
if proc_res.status.code() == Some(VALGRIND_ERR) {
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) {
// The value the rust runtime returns on failure
static RUST_ERR: int = 101;
if !proc_res.status.matches_exit_status(RUST_ERR) {
const RUST_ERR: i32 = 101;
if proc_res.status.code() != Some(RUST_ERR) {
fatal_proc_rec(
&format!("failure produced the wrong error: {:?}",
&format!("failure produced the wrong error: {}",
proc_res.status),
proc_res);
}
@ -201,8 +193,8 @@ fn run_pretty_test(config: &Config, props: &TestProps, testfile: &Path) {
let rounds =
match props.pp_exact { Some(_) => 1, None => 2 };
let src = File::open(testfile).read_to_end().unwrap();
let src = String::from_utf8(src.clone()).unwrap();
let mut src = String::new();
File::open(testfile).unwrap().read_to_string(&mut src).unwrap();
let mut srcs = vec!(src);
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 {
Some(ref file) => {
let filepath = testfile.dir_path().join(file);
let s = File::open(&filepath).read_to_end().unwrap();
String::from_utf8(s).unwrap()
let filepath = testfile.parent().unwrap().join(file);
let mut s = String::new();
File::open(&filepath).unwrap().read_to_string(&mut s).unwrap();
s
}
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() {
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.
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()),
props.exec_env.clone(),
&config.compile_lib_path,
Some(aux_dir.as_str().unwrap()),
Some(aux_dir.to_str().unwrap()),
Some(src))
}
@ -299,11 +292,11 @@ fn run_pretty_test(config: &Config, props: &TestProps, testfile: &Path) {
pretty_type,
format!("--target={}", config.target),
"-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(&props.compile_flags).into_iter());
return ProcArgs {
prog: config.rustc_path.as_str().unwrap().to_string(),
prog: config.rustc_path.to_str().unwrap().to_string(),
args: args,
};
}
@ -345,14 +338,14 @@ actual:\n\
"--crate-type=lib".to_string(),
format!("--target={}", target),
"-L".to_string(),
config.build_base.as_str().unwrap().to_string(),
config.build_base.to_str().unwrap().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(&props.compile_flags).into_iter());
// FIXME (#9639): This needs to handle non-utf8 paths
return ProcArgs {
prog: config.rustc_path.as_str().unwrap().to_string(),
prog: config.rustc_path.to_str().unwrap().to_string(),
args: args,
};
}
@ -390,18 +383,19 @@ fn run_debuginfo_gdb_test(config: &Config, props: &TestProps, testfile: &Path) {
// write debugger script
let mut script_str = String::with_capacity(2048);
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(&format!("set solib-search-path \
./{}/stage2/lib/rustlib/{}/lib/\n",
config.host, config.target));
for line in breakpoint_lines.iter() {
script_str.push_str(&format!("break {:?}:{}\n",
testfile.filename_display(),
*line)[]);
testfile.file_name().unwrap()
.to_string_lossy(),
*line)[..]);
}
script_str.push_str(&cmds);
script_str.push_str("quit\n");
script_str.push_str("\nquit\n");
debug!("script_str = {}", script_str);
dump_output_file(config,
@ -415,7 +409,7 @@ fn run_debuginfo_gdb_test(config: &Config, props: &TestProps, testfile: &Path) {
None,
&[
"push".to_string(),
exe_file.as_str().unwrap().to_string(),
exe_file.to_str().unwrap().to_string(),
config.adb_test_dir.clone()
],
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")
{"64"} else {""},
config.adb_test_dir.clone(),
str::from_utf8(
exe_file.filename()
.unwrap()).unwrap());
exe_file.file_name().unwrap().to_str()
.unwrap());
let mut process = procsrv::run_background("",
&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));
loop {
//waiting 1 second for gdbserver start
timer::sleep(Duration::milliseconds(1000));
let result = thread::spawn(move || {
tcp::TcpStream::connect("127.0.0.1:5039").unwrap();
}).join();
if result.is_err() {
continue;
#[allow(deprecated)]
fn sleep() {
::std::old_io::timer::sleep(Duration::milliseconds(1000));
}
sleep();
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(),
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(),
"-batch".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;
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 {
status: status,
status: Status::Normal(status),
stdout: out,
stderr: err,
cmdline: cmdline
};
if process.signal_kill().is_err() {
if process.kill().is_err() {
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");
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)
.as_str()
.to_str()
.unwrap()
.to_string();
// 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
script_str.push_str(
&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");
// 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
script_str.push_str(&format!("file {}\n",
exe_file.as_str().unwrap().replace("\\", "\\\\"))[]);
exe_file.to_str().unwrap()
.replace(r"\", r"\\")));
// Add line breakpoints
for line in &breakpoint_lines {
script_str.push_str(&format!("break '{}':{}\n",
testfile.filename_display(),
*line)[]);
testfile.file_name().unwrap()
.to_string_lossy(),
*line));
}
script_str.push_str(&cmds);
script_str.push_str("quit\n");
script_str.push_str("\nquit\n");
debug!("script_str = {}", script_str);
dump_output_file(config,
@ -576,13 +572,8 @@ fn run_debuginfo_gdb_test(config: &Config, props: &TestProps, testfile: &Path) {
"debugger.script");
// run debugger script with gdb
#[cfg(windows)]
fn debugger() -> String {
"gdb.exe".to_string()
}
#[cfg(unix)]
fn debugger() -> String {
"gdb".to_string()
fn debugger() -> &'static str {
if cfg!(windows) {"gdb.exe"} else {"gdb"}
}
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(),
"-batch".to_string(),
"-nx".to_string(),
format!("-command={}", debugger_script.as_str().unwrap()));
format!("-command={}", debugger_script.to_str().unwrap()));
let proc_args = ProcArgs {
prog: debugger(),
prog: debugger().to_string(),
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);
}
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 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) {
use std::old_io::process::{Command, ProcessOutput};
if config.lldb_python_dir.is_none() {
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");
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)
.as_str()
.to_str()
.unwrap()
.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("--python-function lldb_rust_formatters.print_val ");
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
script_str.push_str("quit\n");
script_str.push_str("\nquit\n");
// Write the script into a file
debug!("script_str = {}", script_str);
@ -735,22 +725,19 @@ fn run_debuginfo_lldb_test(config: &Config, props: &TestProps, testfile: &Path)
rust_src_root: &Path)
-> ProcRes {
// 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");
cmd.arg(lldb_script_path)
cmd.arg(&lldb_script_path)
.arg(test_executable)
.arg(debugger_script)
.env_set_all(&[("PYTHONPATH", config.lldb_python_dir.clone().unwrap())]);
let (status, out, err) = match cmd.spawn() {
Ok(process) => {
let ProcessOutput { status, output, error } =
process.wait_with_output().unwrap();
.env("PYTHONPATH", config.lldb_python_dir.as_ref().unwrap());
let (status, out, err) = match cmd.output() {
Ok(Output { status, stdout, stderr }) => {
(status,
String::from_utf8(output).unwrap(),
String::from_utf8(error).unwrap())
String::from_utf8(stdout).unwrap(),
String::from_utf8(stderr).unwrap())
},
Err(e) => {
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);
return ProcRes {
status: status,
status: Status::Normal(status),
stdout: out,
stderr: err,
cmdline: format!("{:?}", cmd)
@ -771,13 +758,11 @@ fn run_debuginfo_lldb_test(config: &Config, props: &TestProps, testfile: &Path)
struct DebuggerCommands {
commands: Vec<String>,
check_lines: Vec<String>,
breakpoint_lines: Vec<uint>,
breakpoint_lines: Vec<usize>,
}
fn parse_debugger_commands(file_path: &Path, debugger_prefix: &str)
-> DebuggerCommands {
use std::old_io::{BufferedReader, File};
let command_directive = format!("{}-command", 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 check_lines = vec!();
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() {
match line {
Ok(line) => {
@ -847,7 +832,7 @@ fn check_debugger_output(debugger_run_result: &ProcRes, check_lines: &[String])
check_lines.iter().map(|s| {
s
.trim()
.split_str("[...]")
.split("[...]")
.map(|x| x.to_string())
.collect()
}).collect();
@ -866,7 +851,7 @@ fn check_debugger_output(debugger_run_result: &ProcRes, check_lines: &[String])
None
}
} else {
rest.find_str(frag)
rest.find(frag)
};
match found {
None => {
@ -965,15 +950,16 @@ fn check_expected_errors(expected_errors: Vec<errors::ExpectedError> ,
format!("{}:{}:", testfile.display(), ee.line)
}).collect::<Vec<String>>();
#[cfg(windows)]
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())
}
#[cfg(unix)]
fn prefix_matches( line : &str, prefix : &str ) -> bool {
} else {
line.starts_with(prefix)
}
}
// A multi-line error will have followup lines which will always
// 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));
}
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() {
return false;
}
@ -1062,26 +1048,26 @@ fn scan_until_char(haystack: &str, needle: char, idx: &mut uint) -> bool {
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() {
return false;
}
let range = haystack.char_range_at(*idx);
if range.ch != needle {
let ch = haystack.char_at(*idx);
if ch != needle {
return false;
}
*idx = range.next;
*idx += ch.len_utf8();
return true;
}
fn scan_integer(haystack: &str, idx: &mut uint) -> bool {
fn scan_integer(haystack: &str, idx: &mut usize) -> bool {
let mut i = *idx;
while i < haystack.len() {
let range = haystack.char_range_at(i);
if range.ch < '0' || '9' < range.ch {
let ch = haystack.char_at(i);
if ch < '0' || '9' < ch {
break;
}
i = range.next;
i += ch.len_utf8();
}
if i == *idx {
return false;
@ -1090,16 +1076,16 @@ fn scan_integer(haystack: &str, idx: &mut uint) -> bool {
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 needle_i = 0;
while needle_i < needle.len() {
if haystack_i >= haystack.len() {
return false;
}
let range = haystack.char_range_at(haystack_i);
haystack_i = range.next;
if !scan_char(needle, range.ch, &mut needle_i) {
let ch = haystack.char_at(haystack_i);
haystack_i += ch.len_utf8();
if !scan_char(needle, ch, &mut needle_i) {
return false;
}
}
@ -1113,12 +1099,42 @@ struct ProcArgs {
}
struct ProcRes {
status: ProcessExit,
status: Status,
stdout: String,
stderr: 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,
testfile: &Path) -> ProcRes {
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);
// FIXME (#9639): This needs to handle non-utf8 paths
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());
let args = make_compile_args(config,
props,
@ -1160,7 +1176,7 @@ fn exec_compiled_test(config: &Config, props: &TestProps,
make_run_args(config, props, testfile),
env,
&config.run_lib_path,
Some(aux_dir.as_str().unwrap()),
Some(aux_dir.to_str().unwrap()),
None)
}
}
@ -1179,7 +1195,7 @@ fn compose_and_run_compiler(
let aux_dir = aux_output_dir_name(config, testfile);
// 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 {
let abs_ab = config.aux_base.join(rel_ab);
@ -1196,7 +1212,8 @@ fn compose_and_run_compiler(
crate_type,
|a,b| {
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);
let auxres = compose_and_run(config,
@ -1204,7 +1221,7 @@ fn compose_and_run_compiler(
aux_args,
Vec::new(),
&config.compile_lib_path,
Some(aux_dir.as_str().unwrap()),
Some(aux_dir.to_str().unwrap()),
None);
if !auxres.status.success() {
fatal_proc_rec(
@ -1226,13 +1243,13 @@ fn compose_and_run_compiler(
args,
Vec::new(),
&config.compile_lib_path,
Some(aux_dir.as_str().unwrap()),
Some(aux_dir.to_str().unwrap()),
input)
}
fn ensure_dir(path: &Path) {
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,
@ -1246,8 +1263,8 @@ fn compose_and_run(config: &Config, testfile: &Path,
}
enum TargetLocation {
ThisFile(Path),
ThisDirectory(Path),
ThisFile(PathBuf),
ThisDirectory(PathBuf),
}
fn make_compile_args<F>(config: &Config,
@ -1265,9 +1282,9 @@ fn make_compile_args<F>(config: &Config,
&*config.target
};
// 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(),
config.build_base.as_str().unwrap().to_string(),
config.build_base.to_str().unwrap().to_string(),
format!("--target={}", target));
args.push_all(&extras);
if !props.no_prefer_dynamic {
@ -1284,7 +1301,7 @@ fn make_compile_args<F>(config: &Config,
path
}
};
args.push(path.as_str().unwrap().to_string());
args.push(path.to_str().unwrap().to_string());
if props.force_host {
args.extend(split_maybe_args(&config.host_rustcflags).into_iter());
} else {
@ -1292,24 +1309,24 @@ fn make_compile_args<F>(config: &Config,
}
args.extend(split_maybe_args(&props.compile_flags).into_iter());
return ProcArgs {
prog: config.rustc_path.as_str().unwrap().to_string(),
prog: config.rustc_path.to_str().unwrap().to_string(),
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
// happens; rustc ignores everything except for the directory.
let auxname = output_testname(auxfile);
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);
if !env::consts::EXE_SUFFIX.is_empty() {
let mut fname = f.filename().unwrap().to_vec();
fname.extend(env::consts::EXE_SUFFIX.bytes());
f.set_filename(fname);
let mut fname = f.file_name().unwrap().to_os_string();
fname.push(env::consts::EXE_SUFFIX);
f.set_file_name(&fname);
}
f
}
@ -1322,7 +1339,7 @@ fn make_run_args(config: &Config, props: &TestProps, testfile: &Path) ->
let exe_file = make_exe_name(config, testfile);
// 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
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));
dump_output(config, testfile, &out, &err);
return ProcRes {
status: status,
status: Status::Normal(status),
stdout: out,
stderr: err,
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 {
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
// for diagnostic purposes
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(" "))
}
}
fn dump_output(config: &Config, testfile: &Path, out: &str, err: &str) {
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,
out: &str, extension: &str) {
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)
}
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 mut fname = f.filename().unwrap().to_vec();
fname.extend("libaux".bytes());
f.with_filename(fname)
let mut fname = f.file_name().unwrap().to_os_string();
fname.push("libaux");
f.with_file_name(&fname)
}
fn output_testname(testfile: &Path) -> Path {
Path::new(testfile.filestem().unwrap())
fn output_testname(testfile: &Path) -> PathBuf {
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
.join(&output_testname(testfile))
.with_extension(&config.stage_id)
@ -1542,11 +1558,11 @@ fn _arm_exec_compiled_test(config: &Config,
Some("".to_string()))
.expect(&format!("failed to exec `{}`", config.adb_path));
let mut exitcode: int = 0;
let mut exitcode: i32 = 0;
for c in exitcode_out.chars() {
if !c.is_numeric() { break; }
exitcode = exitcode * 10 + match c {
'0' ... '9' => c as int - ('0' as int),
'0' ... '9' => c as i32 - ('0' as i32),
_ => 101,
}
}
@ -1587,7 +1603,7 @@ fn _arm_exec_compiled_test(config: &Config,
&stderr_out);
ProcRes {
status: process::ProcessExit::ExitStatus(exitcode),
status: Status::Parsed(exitcode),
stdout: stdout_out,
stderr: stderr_out,
cmdline: cmdline
@ -1597,16 +1613,17 @@ fn _arm_exec_compiled_test(config: &Config,
fn _arm_push_aux_shared_library(config: &Config, testfile: &Path) {
let tdir = aux_output_dir_name(config, testfile);
let dirs = fs::readdir(&tdir).unwrap();
for file in &dirs {
if file.extension_str() == Some("so") {
let dirs = fs::read_dir(&tdir).unwrap();
for file in dirs {
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
let copy_result = procsrv::run("",
&config.adb_path,
None,
&[
"push".to_string(),
file.as_str()
file.to_str()
.unwrap()
.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)
fn append_suffix_to_stem(p: &Path, suffix: &str) -> Path {
fn append_suffix_to_stem(p: &Path, suffix: &str) -> PathBuf {
if suffix.len() == 0 {
(*p).clone()
p.to_path_buf()
} else {
let mut stem = p.filestem().unwrap().to_vec();
stem.extend("-".bytes());
stem.extend(suffix.bytes());
p.with_filename(stem)
let mut stem = p.file_stem().unwrap().to_os_string();
stem.push("-");
stem.push(suffix);
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);
// FIXME (#9639): This needs to handle non-utf8 paths
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(),
"--crate-type=lib".to_string());
link_args.extend(llvm_args.into_iter());
@ -1651,7 +1668,8 @@ fn compile_test_and_save_bitcode(config: &Config, props: &TestProps,
props,
link_args,
|a, b| TargetLocation::ThisDirectory(
output_base_name(a, b).dir_path()),
output_base_name(a, b).parent()
.unwrap().to_path_buf()),
testfile);
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 proc_args = ProcArgs {
// 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(),
"-emit-llvm".to_string(),
"-o".to_string(),
bitcodefile.as_str().unwrap().to_string(),
testcc.as_str().unwrap().to_string())
bitcodefile.to_str().unwrap().to_string(),
testcc.to_str().unwrap().to_string())
};
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 proc_args = ProcArgs {
// 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),
format!("-o={}", extracted_bc.as_str().unwrap()),
bitcodefile.as_str().unwrap().to_string())
format!("-o={}", extracted_bc.to_str().unwrap()),
bitcodefile.to_str().unwrap().to_string())
};
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 proc_args = ProcArgs {
// FIXME (#9639): This needs to handle non-utf8 paths
prog: prog.as_str().unwrap().to_string(),
args: vec!(format!("-o={}", extracted_ll.as_str().unwrap()),
extracted_bc.as_str().unwrap().to_string())
prog: prog.to_str().unwrap().to_string(),
args: vec!(format!("-o={}", extracted_ll.to_str().unwrap()),
extracted_bc.to_str().unwrap().to_string())
};
compose_and_run(config, testfile, proc_args, Vec::new(), "", None, None)
}
fn count_extracted_lines(p: &Path) -> uint {
let x = File::open(&p.with_extension("ll")).read_to_end().unwrap();
fn count_extracted_lines(p: &Path) -> usize {
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();
x.lines().count()
}

View File

@ -8,22 +8,39 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use std::env;
use common::Config;
#[cfg(target_os = "windows")]
use std::env;
/// 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"),
("openbsd", "openbsd"),
("win32", "windows"),
("windows", "windows"),
("darwin", "macos"),
("android", "android"),
("linux", "linux"),
("freebsd", "freebsd"),
("dragonfly", "dragonfly"),
("openbsd", "openbsd"),
];
const ARCH_TABLE: &'static [(&'static str, &'static str)] = &[
("aarch64", "aarch64"),
("amd64", "x86_64"),
("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 {
@ -34,10 +51,17 @@ pub fn get_os(triple: &str) -> &'static str {
}
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 {
assert!(cfg!(windows));
// Windows just uses PATH as the library search path, so we have to
// maintain the current value while adding our own
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" }
#[cfg(target_os = "windows")]
pub fn path_div() -> &'static str { ";" }
fn path_div() -> &'static str { ";" }
pub fn logv(config: &Config, s: String) {
debug!("{}", s);

View File

@ -174,3 +174,10 @@ bindings.
See also [a long thread][alt] on renaming `let mut` to `var`.
[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
```antlr
array_expr : '[' "mut" ? vec_elems? ']' ;
array_expr : '[' "mut" ? array_elems? ']' ;
array_elems : [expr [',' expr]*] | [expr ',' ".." expr] ;
```

View File

@ -1,4 +1,4 @@
% The (old) Rust Threads and Communication Guide
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 FAQ](complement-lang-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

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/).
There's no `Makefile`s or endless `autotools` output here. (Rust's tooling does
[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!
@ -389,11 +389,11 @@ safe concurrent programs.
Here's an example of a concurrent Rust program:
```{rust}
use std::thread::Thread;
use std::thread;
fn main() {
let guards: Vec<_> = (0..10).map(|_| {
Thread::scoped(|| {
thread::scoped(|| {
println!("Hello, world!");
})
}).collect();
@ -421,44 +421,41 @@ problem.
Let's see an example. This Rust code will not compile:
```{rust,ignore}
use std::thread::Thread;
use std::thread;
fn main() {
let mut numbers = vec![1, 2, 3];
for i in 0..3 {
Thread::spawn(move || {
for j in 0..3 { numbers[j] += 1 }
});
}
let guards: Vec<_> = (0..3).map(|i| {
thread::scoped(move || {
numbers[i] += 1;
println!("numbers[{}] is {}", i, numbers[i]);
})
}).collect();
}
```
It gives us this error:
```text
6:71 error: capture of moved value: `numbers`
for j in 0..3 { numbers[j] += 1 }
^~~~~~~
7:50 note: `numbers` moved into closure environment here
spawn(move || {
for j in 0..3 { numbers[j] += 1 }
});
6:79 error: cannot assign to immutable dereference (dereference is implicit, due to indexing)
for j in 0..3 { numbers[j] += 1 }
^~~~~~~~~~~~~~~
7:25: 10:6 error: cannot move out of captured outer variable in an `FnMut` closure
7 thread::scoped(move || {
8 numbers[i] += 1;
9 println!("numbers[{}] is {}", i, numbers[i]);
10 })
error: aborting due to previous error
```
It mentions that "numbers moved into closure environment". Because we
declared the closure as a moving closure, and it referred to
`numbers`, the closure will try to take ownership of the vector. But
the closure itself is created in a loop, and hence we will actually
create three closures, one for every iteration of the loop. This means
that all three of those closures would try to own `numbers`, which is
impossible -- `numbers` must have just one owner. Rust detects this
and gives us the error: we claim that `numbers` has ownership, but our
code tries to make three owners. This may cause a safety problem, so
Rust disallows it.
This is a little confusing because there are two closures here: the one passed
to `map`, and the one passed to `thread::scoped`. In this case, the closure for
`thread::scoped` is attempting to reference `numbers`, a `Vec<i32>`. This
closure is a `FnOnce` closure, as thats what `thread::scoped` takes as an
argument. `FnOnce` closures take ownership of their environment. Thats fine,
but theres one detail: because of `map`, were going to make three of these
closures. And since all three try to take ownership of `numbers`, that would be
a problem. Thats what it means by cannot move out of captured outer
variable: our `thread::scoped` closure wants to take ownership, and it cant,
because the closure for `map` wont let it.
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
@ -474,20 +471,20 @@ mutation doesn't cause a data race.
Here's what using an Arc with a Mutex looks like:
```{rust}
use std::thread::Thread;
use std::thread;
use std::sync::{Arc,Mutex};
fn main() {
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();
Thread::spawn(move || {
thread::scoped(move || {
let mut array = number.lock().unwrap();
array[i] += 1;
println!("numbers[{}] is {}", i, array[i]);
});
}
})
}).collect();
}
```
@ -516,8 +513,10 @@ numbers[1] is 3
numbers[0] is 2
```
Each time, we get a slightly different output, because each thread works in a
different order. You may not get the same output as this sample, even.
Each time, we can get a slightly different output because the threads are not
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
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:
```{rust,ignore}
use std::thread::Thread;
use std::thread;
fn main() {
let vec = vec![1, 2, 3];
let numbers = vec![1, 2, 3];
for i in 0..3 {
Thread::spawn(move || {
println!("{}", vec[i]);
});
}
let guards: Vec<_> = (0..3).map(|i| {
thread::scoped(move || {
println!("{}", numbers[i]);
})
}).collect();
}
```
@ -569,7 +568,7 @@ while retaining safety. The answer is iterators:
```{rust}
let vec = vec![1, 2, 3];
for x in vec.iter() {
for x in &vec {
println!("{}", x);
}
```

View File

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

View File

@ -229,14 +229,14 @@ cases mentioned in [Number literals](#number-literals) below.
##### Characters and strings
| | Example | Number of `#` pairs allowed | Available characters | Escapes | Equivalent to |
|---|---------|-----------------------------|----------------------|---------|---------------|
| [Character](#character-literals) | `'H'` | `N/A` | All unicode | `\'` & [Byte escapes](#byte-escapes) & [Unicode escapes](#unicode-escapes) | `N/A` |
| [String](#string-literals) | `"hello"` | `N/A` | All unicode | `\"` & [Byte escapes](#byte-escapes) & [Unicode escapes](#unicode-escapes) | `N/A` |
| [Raw](#raw-string-literals) | `r##"hello"##` | `0...` | All unicode | `N/A` | `N/A` |
| [Byte](#byte-literals) | `b'H'` | `N/A` | All ASCII | `\'` & [Byte escapes](#byte-escapes) | `u8` |
| [Byte string](#byte-string-literals) | `b"hello"` | `N/A` | All ASCII | `\"` & [Byte escapes](#byte-escapes) | `&'static [u8]` |
| [Raw byte string](#raw-byte-string-literals) | `br##"hello"##` | `0...` | All ASCII | `N/A` | `&'static [u8]` (unsure...not stated) |
| | Example | `#` sets | Characters | Escapes |
|----------------------------------------------|-----------------|------------|-------------|---------------------|
| [Character](#character-literals) | `'H'` | `N/A` | All Unicode | `\'` & [Byte](#byte-escapes) & [Unicode](#unicode-escapes) |
| [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` |
| [Byte](#byte-literals) | `b'H'` | `N/A` | All ASCII | `\'` & [Byte](#byte-escapes) |
| [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` |
##### Byte escapes
@ -302,7 +302,7 @@ nonzero_dec: '1' | '2' | '3' | '4'
A _character literal_ is a single Unicode character enclosed within two
`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
@ -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
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
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
to call a method named `f64` on `2`.
The representation semantics of floating-point numbers are described in
["Machine Types"](#machine-types).
#### Boolean literals
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
syntax, and yet are not implementable as functions. Instead, they are given
names, and invoked through a consistent syntax: `name!(...)`. Examples include:
* `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.
names, and invoked through a consistent syntax: `some_extension!(...)`.
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 `$(...)*`;
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
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
metadata that influences the behavior of the compiler.
```{.rust}
# #![allow(unused_attribute)]
```no_run
// Crate name
#![crate_name = "projx"]
@ -950,7 +937,7 @@ extern crate pcre;
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
@ -989,7 +976,7 @@ Use declarations support a number of convenient shortcuts:
An example of `use` declarations:
```
use std::iter::range_step;
# #![feature(core)]
use std::option::Option::{Some, None};
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 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),
// std::option::Option::None]);'
foo(vec![Some(1.0f64), None]);
@ -1049,6 +1033,7 @@ declarations.
An example of what will and will not work for `use` items:
```
# #![feature(core)]
# #![allow(unused_imports)]
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
@ -1199,12 +1184,15 @@ the guarantee that these issues are never caused by safe code.
* Data races
* Dereferencing a null/dangling raw pointer
* Mutating an immutable value/reference without `UnsafeCell`
* Reads of [undef](http://llvm.org/docs/LangRef.html#undefined-values)
(uninitialized) memory
* Breaking the [pointer aliasing
rules](http://llvm.org/docs/LangRef.html#pointer-aliasing-rules)
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:
* Indexing outside of the bounds of an object with `std::ptr::offset`
(`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
other languages. Unwinding must be caught and handled at FFI boundaries.
[noalias]: http://llvm.org/docs/LangRef.html#noalias
##### Behaviour not considered unsafe
This is a list of behaviour not considered *unsafe* in Rust terms, but that may
@ -1233,7 +1223,7 @@ be undesired.
* Sending signals
* Accessing/modifying the file system
* 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)
#### Diverging functions
@ -1489,22 +1479,6 @@ statics:
Constants should in general be preferred over statics, unless large amounts of
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
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`.
```
# #[derive(Copy)]
# #[derive(Copy, Clone)]
# struct Point {x: f64, y: f64};
# type Surface = i32;
# struct BoundingBox {x: f64, y: f64, width: f64, height: f64};
@ -1687,6 +1661,10 @@ struct Circle {
impl Copy for Circle {}
impl Clone for Circle {
fn clone(&self) -> Circle { *self }
}
impl Shape for Circle {
fn draw(&self, s: Surface) { do_draw_circle(s, *self); }
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.
```
# #![feature(libc)]
extern crate libc;
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:
```
pub use self::implementation as api;
pub use self::implementation::api;
mod implementation {
pub mod api {
pub fn f() {}
}
}
# 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.
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
```{.ebnf .gram}
attribute : "#!" ? '[' meta_item ']' ;
attribute : '#' '!' ? '[' meta_item ']' ;
meta_item : ident [ '=' literal
| '(' meta_seq ')' ] ? ;
meta_seq : meta_item [ ',' meta_seq ] ? ;
@ -2035,7 +2016,7 @@ type int8_t = i8;
item](#language-items) for more details.
- `test` - indicates that this function is a test function, to only be compiled
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
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
// architecture
#[cfg(all(unix, target_word_size = "32"))]
#[cfg(all(unix, target_pointer_width = "32"))]
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
as a configuration itself, like `unix` or `windows`.
* `target_os = "..."`. Operating system of the target, examples include
`"win32"`, `"macos"`, `"linux"`, `"android"`, `"freebsd"`, `"dragonfly"` or
`"openbsd"`.
* `target_word_size = "..."`. Target word size in bits. This is set to `"32"`
for targets with 32-bit pointers, and likewise set to `"64"` for 64-bit
pointers.
`"win32"`, `"macos"`, `"linux"`, `"android"`, `"freebsd"`, `"dragonfly"`,
`"bitrig"` or `"openbsd"`.
* `target_pointer_width = "..."`. Target pointer width in bits. This is set
to `"32"` for targets with 32-bit pointers, and likewise set to `"64"` for
64-bit pointers.
* `unix`. 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
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:
* `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
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
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
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
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 are inherently unstable and no promise about them
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
* `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
into a Rust program. This capabiilty, especially the signature for the
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.
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
start to receive compilation warnings about #[feature] directives which enabled
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 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) {}
Point {x: 10.0, y: 20.0};
TuplePoint(10.0, 20.0);
@ -2798,7 +2786,7 @@ automatically dereferenced to make the field access possible.
### Array expressions
```{.ebnf .gram}
array_expr : '[' "mut" ? vec_elems? ']' ;
array_expr : '[' "mut" ? array_elems? ']' ;
array_elems : [expr [',' expr]*] | [expr ';' expr] ;
```
@ -2908,10 +2896,10 @@ meaning of the operators on standard types is given here.
: Exclusive or.
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.
* `>>`
: Logical right shift.
: Right shift.
Calls the `shr` method of the `std::ops::Shr` trait.
#### 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
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:
```
@ -3111,7 +3095,7 @@ ten_times(|j| println!("hello, {}", j));
### While loops
```{.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.
@ -3176,7 +3160,7 @@ A `continue` expression is only permitted in the body of a loop.
### For expressions
```{.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
@ -3280,7 +3264,7 @@ array, like `[.., 42, ..]`. If preceded by a variable name, it will bind the
corresponding slice to the variable. Example:
```
# #![feature(advanced_slice_patterns)]
# #![feature(advanced_slice_patterns, slice_patterns)]
fn is_symmetric(list: &[u32]) -> bool {
match list {
[] | [_] => true,
@ -3353,7 +3337,7 @@ subpattern`. For example:
#![feature(box_patterns)]
#![feature(box_syntax)]
enum List { Nil, Cons(uint, Box<List>) }
enum List { Nil, Cons(u32, Box<List>) }
fn is_sorted(list: &List) -> bool {
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.
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:
@ -3563,6 +3548,7 @@ type Pair<'a> = (i32, &'a str);
let p: Pair<'static> = (10, "hello");
let (a, b) = p;
assert!(b != "world");
assert!(p.0 == 10);
```
### Array, and Slice types
@ -3740,9 +3726,9 @@ An example of creating and calling a closure:
```rust
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);
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
the method `make_string`.
## Type kinds
# The `Copy` trait
Types in Rust are categorized into kinds, based on various properties of the
components of the type. The kinds are:
Rust has a special trait, `Copy`, which when implemented changes the semantics
of a value. Values whose type implements `Copy` are copied rather than moved
upon assignment.
* `Send`
: 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`.
# The `Sized` trait
* _Default_
: Types with destructors, closure environments,
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.
`Sized` is a special trait which indicates that the size of this type is known
at compile-time.
Kinds can be supplied as _bounds_ on type parameters, like traits, in which
case the parameter is constrained to types satisfying that kind.
# The `Drop` trait
By default, type parameters do not carry any assumed kind-bounds at all. When
instantiating a type parameter, the kind bounds on the parameter are checked to
be the same or narrower than the kind of the type that it is instantiated with.
The `Drop` trait provides a destructor, to be run whenever a value of this type
is to be destroyed.
Sending operations are not part of the Rust language, but are implemented in
the library. Generic functions that send values bound the kind of these values
to sendable.
# Memory model
# Memory and concurrency models
Rust has a memory model centered around concurrently-executing _threads_. Thus
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.
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
may not.
Allocations in the stack consist of *slots*, and allocations in the heap
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
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
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
@ -3925,25 +3859,11 @@ in the heap, heap allocations may outlive the frame they are allocated within.
### 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
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
A thread's stack contains slots.
A _slot_ is a component of a stack frame, either a function parameter, a
[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
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
The Rust _runtime_ is a relatively compact collection of Rust code that

View File

@ -56,6 +56,7 @@
/* General structure */
body {
background-color: white;
margin: 0 auto;
padding: 0 15px;
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"),
Open, Write);
// Early return on error
try!(file.write_line(format!("name: {}", info.name).as_slice()));
try!(file.write_line(format!("age: {}", info.age).as_slice()));
try!(file.write_line(format!("rating: {}", info.rating).as_slice()));
try!(file.write_line(&format!("name: {}", info.name)));
try!(file.write_line(&format!("age: {}", info.age)));
try!(file.write_line(&format!("rating: {}", info.rating)));
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"),
Open, Write);
// Early return on error
match file.write_line(format!("name: {}", info.name).as_slice()) {
match file.write_line(&format!("name: {}", info.name)) {
Ok(_) => (),
Err(e) => return Err(e)
}
match file.write_line(format!("age: {}", info.age).as_slice()) {
match file.write_line(&format!("age: {}", info.age)) {
Ok(_) => (),
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>
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
in a small project: a guessing game.
Rust. It has individual sections on each part of Rust's syntax.
After reading "Basics," you will have a good foundation to learn more about
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,
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
are only available in upcoming versions of Rust.
chapters focus on the most complex features,
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
* [I: The Basics](basic.md)
* [The Basics](basic.md)
* [Installing Rust](installing-rust.md)
* [Hello, world!](hello-world.md)
* [Hello, Cargo!](hello-cargo.md)
@ -13,16 +13,15 @@
* [Looping](looping.md)
* [Strings](strings.md)
* [Arrays, Vectors, and Slices](arrays-vectors-and-slices.md)
* [Standard Input](standard-input.md)
* [Guessing Game](guessing-game.md)
* [II: Intermediate Rust](intermediate.md)
* [More Strings](more-strings.md)
* [Intermediate Rust](intermediate.md)
* [Crates and Modules](crates-and-modules.md)
* [Testing](testing.md)
* [Pointers](pointers.md)
* [Ownership](ownership.md)
* [More Strings](more-strings.md)
* [Patterns](patterns.md)
* [Method Syntax](method-syntax.md)
* [Associated Types](associated-types.md)
* [Closures](closures.md)
* [Iterators](iterators.md)
* [Generics](generics.md)
@ -32,10 +31,18 @@
* [Concurrency](concurrency.md)
* [Error Handling](error-handling.md)
* [Documentation](documentation.md)
* [III: Advanced Topics](advanced.md)
* [Advanced Topics](advanced.md)
* [FFI](ffi.md)
* [Unsafe Code](unsafe.md)
* [Advanced Macros](advanced-macros.md)
* [Unstable Rust](unstable.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)
* [Glossary](glossary.md)

View File

@ -6,9 +6,11 @@ off.
# Syntactic requirements
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
process code. It also has a few consequences for the design of Rust's macro
system.
[syntax tree][ast]. This property can be very useful for editors and other
tools that process code. It also has a few consequences for the design of
Rust's macro system.
[ast]: glossary.html#abstract-syntax-tree
One consequence is that Rust must determine, when it parses a macro invocation,
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
`$crate` is a single identifier.
# A final note
# The deep end
Macros, as currently implemented, are not for the faint of heart. Even
ordinary syntax errors can be more difficult to debug when they occur inside a
macro, and errors caused by parse problems in generated code can be very
tricky. Invoking the `log_syntax!` macro can help elucidate intermediate
states, invoking `trace_macros!(true)` will automatically print those
intermediate states out, and passing the flag `--pretty expanded` as a
command-line argument to the compiler will show the result of expansion.
The introductory chapter mentioned recursive macros, but it did not give the
full story. Recursive macros are useful for another reason: Each recursive
invocation gives you another opportunity to pattern-match the macro's
arguments.
As an extreme example, it is possible, though hardly advisable, to implement
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
[compiler plugin](plugins.html) instead. Compared to `macro_rules!`
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
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,
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
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
generics.
We have now learned all of the most basic Rust concepts. We're ready to start
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!
We have now learned all of the most basic Rust concepts.

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
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
in a small project: a guessing game.
Rust. It has individual sections on each part of Rust's syntax.
After reading "Basics," you will have a good foundation to learn more about
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
So far, we've made lots of functions in Rust, but we've given them all names.
Rust also allows us to create anonymous functions. Rust's anonymous
functions are called *closures*. By themselves, closures aren't all that
interesting, but when you combine them with functions that take closures as
arguments, really powerful things are possible.
Rust not only has named functions, but anonymous functions as well. Anonymous
functions that have an associated environment are called 'closures', because they
close over an environment. Rust has a really great implementation of them, as
we'll see.
Let's make a closure:
# Syntax
```{rust}
let add_one = |x| { 1 + x };
Closures look like this:
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
binding so we can use it later. Note that we call the function using the
binding name and two parentheses, just like we would for a named function.
We create a binding, `plus_one`, and assign it to a closure. The closure's
arguments go between the pipes (`|`), and the body is an expression, in this
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}
let add_one = |x: i32| -> i32 { 1 + x };
fn add_one (x: i32) -> i32 { 1 + x }
result += 1;
result += 1;
result
};
assert_eq!(4, plus_two(2));
```
As you may have noticed, closures infer their argument and return types, so you
don't need to declare one. This is different from named functions, which
default to returning unit (`()`).
You'll notice a few things about closures that are a bit different than regular
functions defined with `fn`. The first of which is that we did not need to
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
the name: a closure "closes over its environment." What does that mean? It means
this:
```rust
let plus_one = |x: i32| -> i32 { x + 1 };
```{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() {
let x: i32 = 5;
let mut num = 5;
let plus_num = |x| x + num;
let printer = || { println!("x is: {}", x); };
printer(); // prints "x is: 5"
let y = &mut num;
}
^
```
The `||` syntax means this is an anonymous closure that takes no arguments.
Without it, we'd just have a block of code in `{}`s.
A verbose yet helpful error message! As it says, we can't take a mutable borrow
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
defined. The closure borrows any variables it uses, so this will error:
```rust
let mut num = 5;
{
let plus_num = |x: i32| x + num;
```{rust,ignore}
fn main() {
let mut x: i32 = 5;
} // plus_num goes out of scope, borrow of num ends
let printer = || { println!("x is: {}", x); };
x = 6; // error: cannot assign to `x` because it is borrowed
}
let y = &mut num;
```
## 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
closures are indicated using the `move` keyword (e.g., `move || x *
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.
```rust,ignore
let nums = vec![1, 2, 3];
## Accepting closures as arguments
let takes_nums = || nums;
Closures are most useful as an argument to another function. Here's an example:
```{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
}
println!("{:?}", nums);
```
Let's break the example down, starting with `main`:
This gives us:
```{rust}
let square = |x: i32| { x * x };
```text
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
its square.
`Vec<T>` has ownership over its contents, and therefore, when we refer to it
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}
# fn twice<F: Fn(i32) -> i32>(x: i32, f: F) -> i32 { f(x) + f(x) }
# let square = |x: i32| { x * x };
twice(5, square); // evaluates to 50
## `move` closures
We can force our closure to take ownership of its environment with the `move`
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
it two arguments: an integer, `5`, and our closure, `square`. This is just like
passing any other two variable bindings to a function, but if you've never
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."
Now, even though the keyword is `move`, the variables follow normal move semantics.
In this case, `5` implements `Copy`, and so `owns_num` takes ownership of a copy
of `num`. So what's the difference?
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
arguments. `x` is an `i32`, we've done that a ton of times. `f` is a function,
though, and that function takes an `i32` and returns an `i32`. This is
what the requirement `Fn(i32) -> i32` for the type parameter `F` says.
Now `F` represents *any* function that takes an `i32` and returns an `i32`.
So in this case, our closure took a mutable reference to `num`, and then when
we called `add_num`, it mutated the underlying value, as we'd expect. We also
needed to declare `add_num` as `mut` too, because were mutating its
environment.
This is the most complicated function signature we've seen yet! Give it a read
a few times until you can see how it works. It takes a teeny bit of practice, and
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.
We also had to declare `add_num` as mut, since we will be modifying its
environment.
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 {
f(x) + f(x)
{
let mut add_num = move |x: i32| num += x;
add_num(5);
}
assert_eq!(5, num);
```
Since our closure is named `f`, we can call it just like we called our closures
before, and we pass in our `x` argument to each one, hence the name `twice`.
We only get `5`. Rather than taking a mutable borrow out on our `num`, we took
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
library uses lots of closures where appropriate, so you'll be using
this technique a lot.
But before we talk about taking and returning closures, we should talk some more
about the way that closures are implemented. As a systems language, Rust gives
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.
This example is the same as the previous one:
# Closure implementation
```{rust}
fn twice<F: Fn(i32) -> i32>(x: i32, f: F) -> i32 {
f(x) + f(x)
Rust's implementation of closures is a bit different than other languages. They
are effectively syntax sugar for traits. You'll want to make sure to have read
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() {
twice(5, |x: i32| { x * x }); // evaluates to 50
pub trait FnMut<Args> : FnOnce<Args> {
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
way of writing the previous example:
You'll notice a few differences between these traits, but a big one is `self`:
`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}
fn twice<F: Fn(i32) -> i32>(x: i32, f: F) -> i32 {
f(x) + f(x)
The `|| {}` syntax for closures is sugar for these three traits. Rust will
generate a struct for the environment, `impl` the appropriate trait, and then
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() {
twice(5, square); // evaluates to 50
}
assert_eq!(3, answer);
```
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}
fn compose<F, G>(x: i32, f: F, g: G) -> i32
where F: Fn(i32) -> i32, G: Fn(i32) -> i32 {
g(f(x))
}
fn main() {
compose(5,
|n: i32| { n + 42 },
|n: i32| { n * 2 }); // evaluates to 94
}
```rust
fn call_with_one<F>(some_closure: F) -> i32
# where F : Fn(i32) -> i32 {
# some_closure(1) }
```
You might ask yourself: why do we need to introduce two type
parameters `F` and `G` here? Evidently, both `f` and `g` have the
same signature: `Fn(i32) -> i32`.
We take one parameter, and it has the type `F`. We also return a `i32`. This part
isn't interesting. The next part is:
That is because in Rust each closure has its own unique type.
So, not only do closures with different signatures have different types,
but different closures with the *same* signature have *different*
types, as well!
```rust
# fn call_with_one<F>(some_closure: F) -> i32
where F : Fn(i32) -> i32 {
# some_closure(1) }
```
You can think of it this way: the behavior of a closure is part of its
type. Therefore, using a single type parameter for both closures
will accept the first of them, rejecting the second. The distinct
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`.
Because `Fn` is a trait, we can bound our generic with it. In this case, our closure
takes a `i32` as an argument and returns an `i32`, and so the generic bound we use
is `Fn(i32) -> i32`.
This also introduces the `where` clause, which lets us describe type
parameters in a more flexible manner.
There's one other key point here: because we're bounding a generic with a
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
strange at first, but once you're used to them, you'll miss them
in other languages. Passing functions to other functions is
incredibly powerful, as you will see in the following chapter about iterators.
Of course, if we want dynamic dispatch, we can get that too. A trait object
handles this case, as usual:
```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.
///
/// # Example
/// # Examples
///
/// ```rust
/// let name = "Steve";

View File

@ -6,8 +6,8 @@ strings, but next, let's talk about some more complicated ways of storing data.
## Tuples
The first compound data type we're going to talk about are called *tuples*.
Tuples are an ordered list of a fixed size. Like this:
The first compound data type we're going to talk about is called the *tuple*.
A tuple is an ordered list of fixed size. Like this:
```rust
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
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.
```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.
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
you create a new type that's similar to another one:
tuple struct with only one element. We call this the *newtype* pattern, because
it allows you to create a new type, distinct from that of its contained value
and expressing its own semantic meaning:
```{rust}
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
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
can be used via their fully scoped names: `Character::Other` (more about `::`
below).
@ -228,8 +229,8 @@ enum Character {
}
```
An `enum` variant can be defined as most normal types. Below are some example
types have been listed which also would be allowed in an `enum`.
Most normal types are allowed as the variant components of an `enum`. Here are
some examples:
```rust
struct Empty;
@ -239,15 +240,15 @@ struct Status { Health: i32, Mana: i32, Attack: i32, Defense: i32 }
struct HeightDatabase(Vec<i32>);
```
So you see that depending on the sub-datastructure, the `enum` variant, same as
a struct, may or may not hold data. That is, in `Character`, `Digit` is a name
tied to an `i32` where `Other` is just a name. However, the fact that they are
distinct makes this very useful.
You see that, depending on its type, an `enum` variant may or may not hold data.
In `Character`, for instance, `Digit` gives a meaningful name for an `i32`
value, where `Other` is only a name. However, the fact that they represent
distinct categories of `Character` is a very useful property.
As with structures, enums don't by default have access to operators such as
compare ( `==` and `!=`), binary operations (`*` and `+`), and order
(`<` and `>=`). As such, using the previous `Character` type, the
following code is invalid:
As with structures, the variants of an enum by default are not comparable with
equality operators (`==`, `!=`), have no ordering (`<`, `>=`, etc.), and do not
support other binary operations such as `*` and `+`. As such, the following code
is invalid for the example `Character` type:
```{rust,ignore}
// 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.
There are two ways: by implementing equality ourselves, or by using the
[`match`][match] keyword. We don't know enough about Rust to implement equality
yet, but we can use the `Ordering` enum from the standard library, which does:
There are two ways: by implementing equality ourselves, or by pattern matching
variants with [`match`][match] expressions, which you'll learn in the next
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 {
@ -277,9 +279,8 @@ enum Ordering {
}
```
Because we did not define `Ordering`, we must import it (from the std
library) with the `use` keyword. Here's an example of how `Ordering` is
used:
Because `Ordering` has already been defined for us, we will import it with the
`use` keyword. Here's an example of how it is used:
```{rust}
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
compares two things, and returns an `Ordering`. We return either
`Ordering::Less`, `Ordering::Greater`, or `Ordering::Equal`, depending on if
the two values are less, greater, or equal. Note that each variant of the
`enum` is namespaced under the `enum` itself: it's `Ordering::Greater` not
`Greater`.
`Ordering::Less`, `Ordering::Greater`, or `Ordering::Equal`, depending on
whether the first value is less than, greater than, or equal to the second. Note
that each variant of the `enum` is namespaced under the `enum` itself: it's
`Ordering::Greater`, not `Greater`.
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
one it is.
This `Ordering::Greater` notation is too long. Let's use `use` to import the
`enum` variants instead. This will avoid full scoping:
This `Ordering::Greater` notation is too long. Let's use another form of `use`
to import the `enum` variants instead. This will avoid full scoping:
```{rust}
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,
so do this with caution. It's considered good style to rarely import variants
for this reason.
so do this with caution. For this reason, it's normally considered better style
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
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
tool that will let us deconstruct this sum type (the type theory term for enums)
in a very elegant way and avoid all these messy `if`/`else`s.
As you can see, `enum`s are quite a powerful tool for data representation, and
are even more useful when they're [generic][generics] across types. Before we
get to generics, though, let's talk about how to use enums with pattern
matching, a tool that will let us deconstruct sum types (the type theory term
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
[game]: ./guessing-game.html#comparing-guesses
[generics]: ./generics.html

View File

@ -40,14 +40,14 @@ us enforce that it can't leave the current thread.
### `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
of this type has no possibility of introducing memory unsafety when used from
multiple threads concurrently.
For example, sharing immutable data with an atomic reference count is
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
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:
```
@ -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()`:
```
# #![feature(old_io, std_misc)]
use std::thread;
use std::old_io::timer;
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:
```ignore
# #![feature(old_io, std_misc)]
use std::thread;
use std::old_io::timer;
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:
```ignore
# #![feature(old_io, std_misc)]
use std::thread;
use std::old_io::timer;
use std::time::Duration;
@ -208,10 +211,10 @@ Here's the error:
```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 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 Thread::spawn(move || {
<anon>:11 thread::spawn(move || {
^~~~~~~~~~~~~
```
@ -223,19 +226,13 @@ method which has this signature:
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
this:
```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.
Because `Send` is not implemented for `MutexGuard<T>`, we can't transfer the
guard across thread boundaries, which gives us our error.
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::thread;
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:
```
# #![feature(old_io, std_misc)]
# use std::sync::{Arc, Mutex};
# use std::thread;
# 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
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
time to wait, but it's entirely possible that we've picked too high, and that
we could be taking less time. It's also possible that we've picked too low,
and that we aren't actually finishing this computation.
Lastly, while the threads are running, we wait on a short timer. But
this is not ideal: we may have picked a reasonable amount of time to
wait but it's more likely we'll either be waiting longer than
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
synchronize with each other. Let's talk about one: channels.
A more precise alternative to the timer would be to use one of the
mechanisms provided by the Rust standard library for synchronizing
threads with each other. Let's talk about one of them: 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!
```
use std::sync::{Arc, Mutex};
use std::thread;
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
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
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
@ -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
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
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.
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 |
| +-----------+
+---------+ |
| english |---+
+---------+ | +-----------+
+---| english |---+
| +---------+ | +-----------+
| +---| farewells |
+---------+ | +-----------+
| phrases |---+
+---------+ | +-----------+
| +---| greetings |
+----------+ | +-----------+
| japanese |---+
| +----------+ | +-----------+
+---| japanese |--+
+----------+ |
| +-----------+
+---| 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:
```
// in src/lib.rs
mod english {
mod greetings {
}
mod farewells {
}
}
mod japanese {
mod greetings {
}
mod farewells {
}
}
```
@ -145,11 +139,7 @@ mod english;
```
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:
```{rust,ignore}
// contents of our module go here
```
`english/mod.rs` file with the contents of our module.
Note that in these files, you don't need to re-declare the module: that's
already been done with the initial `mod` declaration.
@ -181,10 +171,7 @@ $ tree .
`src/lib.rs` is our crate root, and looks like this:
```{rust,ignore}
// in src/lib.rs
mod english;
mod japanese;
```
@ -195,10 +182,7 @@ chosen the second. Both `src/english/mod.rs` and `src/japanese/mod.rs` look
like this:
```{rust,ignore}
// both src/english/mod.rs and src/japanese/mod.rs
mod greetings;
mod farewells;
```
@ -214,8 +198,6 @@ both empty at the moment. Let's add some functions.
Put this in `src/english/greetings.rs`:
```rust
// in src/english/greetings.rs
fn hello() -> String {
"Hello!".to_string()
}
@ -224,8 +206,6 @@ fn hello() -> String {
Put this in `src/english/farewells.rs`:
```rust
// in src/english/farewells.rs
fn goodbye() -> String {
"Goodbye.".to_string()
}
@ -248,8 +228,6 @@ about the module system.
Put this in `src/japanese/farewells.rs`:
```rust
// in src/japanese/farewells.rs
fn goodbye() -> String {
"さようなら".to_string()
}
@ -265,11 +243,9 @@ another crate.
We have a library crate. Let's make an executable crate that imports and uses
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
// in src/main.rs
extern crate phrases;
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:
```{rust,ignore}
// in src/main.rs
extern crate phrases;
fn main() {
@ -333,28 +307,20 @@ fn main() {
In our `src/lib.rs`, let's add `pub` to the `english` module declaration:
```{rust,ignore}
// in src/lib.rs
pub mod english;
mod japanese;
```
And in our `src/english/mod.rs`, let's make both `pub`:
```{rust,ignore}
// in src/english/mod.rs
pub mod greetings;
pub mod farewells;
```
In our `src/english/greetings.rs`, let's add `pub` to our `fn` declaration:
```{rust,ignore}
// in src/english/greetings.rs
pub fn hello() -> String {
"Hello!".to_string()
}
@ -363,8 +329,6 @@ pub fn hello() -> String {
And also in `src/english/farewells.rs`:
```{rust,ignore}
// in src/english/farewells.rs
pub fn goodbye() -> 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:
```{rust,ignore}
// in src/main.rs
extern crate phrases;
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
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
@ -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
twice. Rust has a shortcut syntax for writing this:
twice. Instead of this:
```{rust,ignore}
use phrases::english::greetings;
use phrases::english::farewells;
```
You use curly braces:
We can use this shortcut:
```{rust,ignore}
use phrases::english::{greetings, farewells};
```
These two declarations are equivalent, but the second is a lot less typing.
## Re-exporting with `pub use`
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:
```{rust,ignore}
// in src/main.rs
extern crate phrases;
use phrases::english::{greetings,farewells};
@ -503,18 +461,13 @@ fn main() {
Then, modify your `src/lib.rs` to make the `japanese` mod public:
```{rust,ignore}
// in src/lib.rs
pub mod english;
pub mod japanese;
```
Next, make the two functions public, first in `src/japanese/greetings.rs`:
```{rust,ignore}
// in src/japanese/greetings.rs
pub fn hello() -> String {
"こんにちは".to_string()
}
@ -523,8 +476,6 @@ pub fn hello() -> String {
And then in `src/japanese/farewells.rs`:
```{rust,ignore}
// in src/japanese/farewells.rs
pub fn goodbye() -> String {
"さようなら".to_string()
}
@ -533,13 +484,10 @@ pub fn goodbye() -> String {
Finally, modify your `src/japanese/mod.rs` to read like this:
```{rust,ignore}
// in src/japanese/mod.rs
pub use self::greetings::hello;
pub use self::farewells::goodbye;
mod greetings;
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
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
`use` declarations go first.

View File

@ -1,224 +1,223 @@
% Documentation
`rustdoc` is the built-in tool for generating documentation. It integrates
with the compiler to provide accurate hyperlinking between usage of types and
their documentation. Furthermore, by not using a separate parser, it will
never reject your valid Rust code.
Documentation is an important part of any software project, and it's
first-class in Rust. Let's talk about the tooling Rust gives you to
document your project.
# Creating Documentation
## About `rustdoc`
Documenting Rust APIs is quite simple. To document a given item, we have "doc
comments":
The Rust distribution includes a tool, `rustdoc`, that generates documentation.
`rustdoc` is also used by Cargo through `cargo doc`.
~~~
# #![allow(unused_attribute)]
// the "link" crate attribute is currently required for rustdoc, but normally
// isn't needed.
#![crate_id = "universe"]
#![crate_type= "lib"]
Documentation can be generated in two ways: from source code, and from
standalone Markdown files.
//! Tools for dealing with universes (this is a doc comment, and is shown on
//! the crate index page. The ! makes it apply to the parent of the comment,
//! rather than what follows).
## Documenting source code
# mod workaround_the_outer_function_rustdoc_inserts {
/// Widgets are very common (this is a doc comment, and will show up on
/// 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
}
The primary way of documenting a Rust project is through annotating the source
code. You can use documentation comments for this purpose:
pub fn recalibrate() {
//! Recalibrate a pesky universe (this is also a doc comment, like above,
//! 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)
```rust,ignore
/// Constructs a new `Rc<T>`.
///
/// Whizbangs are ...
struct Whizbang;
~~~
To generate the docs, run `rustdoc universe.rs`. By default, it generates a
directory called `doc`, with the documentation for `universe` being in
`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
documentation has already been generated by a previous run of rustdoc, or the
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)")
/// # Examples
///
/// ```
/// use std::rc::Rc;
///
/// let five = Rc::new(5);
/// ```
pub fn new(value: T) -> Rc<T> {
// implementation goes here
}
```
~~~
Rustdoc also supplies some extra sugar for helping with some tedious
documentation examples. If a line is prefixed with `# `, then the line
will not show up in the HTML documentation, but it will be used when
testing the code block (NB. the space after the `#` is required, so
that one can still write things like `#[derive(Eq)]`).
This code generates documentation that looks [like this][rc-new]. I've left the
implementation out, with a regular comment in its place. That's the first thing
to notice about this annotation: it uses `///`, instead of `//`. The triple slash
indicates a documentation comment.
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 doc-generating tool. In order to display them anyway in this particular
# case, the character following the leading '#' is not a usual space like in
# these first five lines but a non breakable one.
# // showing 'fib' in this documentation would just be tedious and detracts from
# // what's actually being documented.
# fn fib(n: int) { n + 2 }
spawn(move || { fib(200); })
/// The `Option` type. See [the module level documentation](../) for more.
enum Option<T> {
/// No value
None,
/// Some value `T`
Some(T),
}
```
~~~
The documentation online would look like `spawn(move || { fib(200); })`, but when
testing this code, the `fib` function will be included (so it can compile).
The above works, but this does not:
Rustdoc will automatically add a `main()` wrapper around your code, and in the right
place. For example:
```rust,ignore
/// 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 }`
2. Given that result, if it contains no `extern crate` directives but it also
contains the name of the crate being tested, then `extern crate <name>` is
injected at the top.
3. Some common `allow` attributes are added for documentation examples at the top.
1. Any leading `#![foo]` attributes are left intact as crate attributes.
2. Some common `allow` attributes are inserted, including
`unused_variables`, `unused_assignments`, `unused_mut`,
`unused_attributes`, and `dead_code`. Small examples often trigger
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
libraries, or try running ignored examples. The testing framework that rustdoc
uses is built on crate `test`, which is also used when you compile crates with
rustc's `--test` flag. Extra arguments can be passed to rustdoc's test harness
with the `--test-args` flag.
```text
/// Some documentation.
# fn foo() {}
```
~~~console
# Only run tests containing 'foo' in their name
$ rustdoc --test lib.rs --test-args 'foo'
looks different than the output:
# 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,
and this code often requires `use`-ing paths from the crate. To accommodate 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`.
when it's in a Markdown file. There is one wrinkle though: Markdown files need
to have a title like this:
# Standalone Markdown files
```markdown
% The title
As well as Rust crates, rustdoc supports rendering pure Markdown files
into HTML and testing the code snippets from them. A Markdown file is
detected by a `.md` or `.markdown` extension.
This is the example documentation.
```
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`.
- `--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.
## `doc` attributes
All of these can be specified multiple times, and they are output in
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).
At a deeper level, documentation comments are sugar for documentation attributes:
Like with a Rust crate, the `--test` argument will run the code
examples to check they compile, and obeys any `--test-args` flags. The
tests are named after the last `#` heading.
```
/// this
# 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;
pub use foo::bar;
```
This will create documentation for `bar` both inside the documentation for
the crate `foo`, as well as the documentation for your crate. It will use
the same documentation in both places.
This will create documentation for bar both inside the documentation for the
crate `foo`, as well as the documentation for your crate. It will use the same
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;
#[doc(no_inline)]
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
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
`IoResult<String>`, a form of `Result`, when there is an error reading the
line. This allows us to handle and possibly recover from this sort of error.
it as a panic instead. For example, `io::stdin().read_line(&mut buffer)` returns
an `Result<usize>`, when there is an error reading the line. This allows us to
handle and possibly recover from error.
If we don't want to handle this error, and would rather just abort the program,
we can use the `unwrap()` method:
```{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
@ -219,10 +219,83 @@ shorter. Sometimes, just crashing is appropriate.
There's another way of doing this that's a bit nicer than `unwrap()`:
```{rust,ignore}
let input = io::stdin().read_line()
let mut buffer = String::new();
let input = io::stdin().read_line(&mut buffer)
.ok()
.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
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:
```no_run
# #![feature(libc)]
extern crate libc;
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:
```no_run
# #![feature(libc)]
extern crate libc;
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.
```
# #![feature(libc)]
# extern crate libc;
# use libc::{c_int, size_t};
# 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.
```
# #![feature(libc)]
# extern crate libc;
# use libc::{size_t, c_int};
# 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.
```
# #![feature(libc)]
# extern crate libc;
# use libc::{size_t, c_int};
# 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
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
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.
## 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
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:
```
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.
@ -406,6 +388,7 @@ global state. In order to access these variables, you declare them in `extern`
blocks with the `static` keyword:
```no_run
# #![feature(libc)]
extern crate libc;
#[link(name = "readline")]
@ -415,7 +398,7 @@ extern {
fn main() {
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.
```no_run
# #![feature(libc)]
extern crate libc;
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:
```
# #![feature(libc)]
extern crate libc;
#[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
Conventions](ffi.html#foreign-calling-conventions)". The `no_mangle`
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
as any type:
```should_fail
```should_panic
# fn diverges() -> ! {
# 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.
### 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)
for specific instructions about installing it.
## Converting to Cargo
Let's convert Hello World to Cargo.
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
do that part first:
```{bash}
```bash
$ mkdir src
$ mv main.rs src/main.rs
```
@ -36,7 +38,7 @@ place for everything, and everything in its place.
Next, our configuration file:
```{bash}
```bash
$ 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:
```{bash}
```bash
$ cargo build
Compiling hello_world v0.0.1 (file:///home/yourname/projects/hello_world)
$ ./target/hello_world
$ ./target/debug/hello_world
Hello, world!
```
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
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
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`.
@ -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
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
language itself. These are the basics that will serve you well through the rest
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:

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):
```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`,
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
$ 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
```
@ -70,14 +70,19 @@ If you've got Rust installed, you can open up a shell, and type this:
$ 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
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!
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
[the #rust IRC channel on irc.mozilla.org](irc://irc.mozilla.org/#rust), which
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
vectors returns an iterator which iterates through a reference to each element
of the vector in turn. So write this:
This is strictly worse than using an actual iterator. You can iterate over vectors
directly, so write this:
```rust
let nums = vec![1, 2, 3];
for num in nums.iter() {
for num in &nums {
println!("{}", num);
}
```
@ -86,16 +85,17 @@ see it. This code works fine too:
```rust
let nums = vec![1, 2, 3];
for num in nums.iter() {
for num in &nums {
println!("{}", *num);
}
```
Now we're explicitly dereferencing `num`. Why does `iter()` give us references?
Well, if it gave us the data itself, we would have to be its owner, which would
involve making a copy of the data and giving us the 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 copy.
Now we're explicitly dereferencing `num`. Why does `&nums` give us
references? Firstly, because we explicitly asked it to with
`&`. Secondly, if it gave us the data itself, we would have to be its
owner, which would involve making a copy of the data and giving us the
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
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
it will do the work of generating the sequence.
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
that gives you each element in turn:
Ranges are one of two basic iterators that you'll see. The other is `iter()`.
`iter()` can turn a vector into a simple iterator that gives you each element
in turn:
```rust
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
advanced iterators, including ones that are infinite. Like `count`:
advanced iterators, including ones that are infinite. Like using range syntax
and `step_by`:
```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
@ -291,10 +293,11 @@ just use `for` instead.
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
has no side effect on the original iterator. Let's try it out with our infinite
iterator from before, `count()`:
iterator from before:
```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);
}
```

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:
```{rust}
for x in 0u32..10 {
for x in 0..10 {
if x % 2 == 0 { continue; }
println!("{}", x);

View File

@ -37,7 +37,7 @@ number of elements.
```rust
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.
@ -51,7 +51,7 @@ let x: Vec<u32> = {
temp_vec.push(3);
temp_vec
};
# assert_eq!(&[1,2,3], &x);
# assert_eq!(x, [1, 2, 3]);
```
We can implement this shorthand, using a macro: [^actual]
@ -73,7 +73,7 @@ macro_rules! vec {
};
}
# 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
The repetition behavior can seem somewhat magical, especially when multiple
names are bound at multiple nested levels of repetition. The two rules to keep
in mind are:
The repetition operator follows two principal rules:
1. the behavior of `$(...)*` is to walk through one "layer" of repetitions, for
all of the `$name`s it contains, in lockstep, and
1. `$(...)*` walks through one "layer" of repetitions, for all of the `$name`s
it contains, in lockstep, and
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.
@ -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
except `+` or `*`.
This system is based on
"[Macro-by-Example](http://www.cs.indiana.edu/ftp/techreports/TR206.pdf)"
(PDF link).
# Hygiene
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
const char *state = "reticulating splines";
LOG(state);
LOG(state)
```
The program will likely segfault, after it tries to execute
This expands to
```text
const char *state = "reticulating splines";
int state = get_log_state();
if (state > 0) {
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.
```rust
@ -357,6 +366,64 @@ fn main() {
[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
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:
```{rust}
# #![feature(core)]
struct Circle {
x: 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,
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
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
a mutable reference. We should default to using `&self`, as it's the most
common.
a mutable reference. We should default to using `&self`, as you should prefer
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²`.
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`.
```
# #![feature(core)]
struct Circle {
x: f64,
y: f64,
@ -76,8 +101,8 @@ impl Circle {
std::f64::consts::PI * (self.radius * self.radius)
}
fn grow(&self) -> Circle {
Circle { x: self.x, y: self.y, radius: (self.radius * 10.0) }
fn grow(&self, increment: f64) -> Circle {
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 };
println!("{}", c.area());
let d = c.grow().area();
let d = c.grow(2.0).area();
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
circle with an area that's 100 times larger than the old one.
circle to any arbitrary size.
## Static methods
@ -142,6 +167,7 @@ have method overloading, named arguments, or variable arguments. We employ
the builder pattern instead. It looks like this:
```
# #![feature(core)]
struct Circle {
x: f64,
y: f64,
@ -155,17 +181,23 @@ impl Circle {
}
struct CircleBuilder {
coordinate: f64,
x: f64,
y: f64,
radius: f64,
}
impl 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 {
self.coordinate = coordinate;
fn x(&mut self, coordinate: f64) -> &mut CircleBuilder {
self.x = coordinate;
self
}
fn y(&mut self, coordinate: f64) -> &mut CircleBuilder {
self.x = coordinate;
self
}
@ -175,18 +207,20 @@ impl CircleBuilder {
}
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() {
let c = CircleBuilder::new()
.coordinate(10.0)
.radius(5.0)
.x(1.0)
.y(2.0)
.radius(2.0)
.finalize();
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`.
# &str
# `&str`
The first kind is a `&str`. This is pronounced a 'string slice'.
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
string literal or a `String`.
# String
## `str`
A `String` is a heap-allocated string. This string is growable, and is also
guaranteed to be UTF-8.
You may occasionally see references to a `str` type, without the `&`. While
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();
@ -49,7 +79,7 @@ s.push_str(", world.");
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) {
@ -58,7 +88,7 @@ fn takes_slice(slice: &str) {
fn main() {
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`.
```
fn some_string_length(x: &str) -> uint {
fn some_string_length(x: &str) -> usize {
x.len()
}
@ -147,6 +177,7 @@ Rust provides iterators for each of these situations:
Usually, the `graphemes()` method on `&str` is what you want:
```
# #![feature(unicode)]
let s = "u͔n͈̰̎i̙̮͚̦c͚̉o̼̩̰͗d͔̆̓ͥé";
for l in s.graphemes(true) {
@ -277,7 +308,18 @@ This will print:
Many more bytes than graphemes!
# Other Documentation
# `Deref` coercions
* [the `&str` API documentation](../std/str/index.html)
* [the `String` API documentation](../std/string/index.html)
References to `String`s will automatically coerce into `&str`s. Like this:
```
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
Earlier, we mentioned *lifetime elision*, a feature of Rust which allows you to
not write lifetime annotations in certain circumstances. All references have a
lifetime, and so if you elide a lifetime (like `&T` instead of `&'a T`), Rust
will do three things to determine what those lifetimes should be.
Rust supports powerful local type inference in function bodies, but its
forbidden in item signatures to allow reasoning about the types just based in
the item signature alone. However, for ergonomic reasons a very restricted
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
*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
Here are some examples of functions with elided lifetimes, and the version of
what the elided lifetimes are expand to:
Here are some examples of functions with elided lifetimes. We've paired each
example of an elided lifetime with its expanded form.
```{rust,ignore}
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 `&`:
```{rust}
# #![feature(slice_patterns)]
fn main() {
let v = vec!["match_this", "1"];

View File

@ -1,29 +1,5 @@
% 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
`rustc` can load compiler plugins, which are user-provided libraries that
@ -63,7 +39,7 @@ that implements Roman numeral integer literals.
```ignore
#![crate_type="dylib"]
#![feature(plugin_registrar)]
#![feature(plugin_registrar, rustc_private)]
extern crate syntax;
extern crate rustc;
@ -71,8 +47,8 @@ extern crate rustc;
use syntax::codemap::Span;
use syntax::parse::token;
use syntax::ast::{TokenTree, TtToken};
use syntax::ext::base::{ExtCtxt, MacResult, DummyResult, MacExpr};
use syntax::ext::build::AstBuilder; // trait for expr_uint
use syntax::ext::base::{ExtCtxt, MacResult, DummyResult, MacEager};
use syntax::ext::build::AstBuilder; // trait for expr_usize
use rustc::plugin::Registry;
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;
while !text.is_empty() {
match NUMERALS.iter().find(|&&(rn, _)| text.starts_with(rn)) {
Some(&(rn, val)) => {
total += val;
text = text.slice_from(rn.len());
text = &text[rn.len()..];
}
None => {
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]
@ -146,14 +122,7 @@ a more involved macro example, see
## Tips and tricks
To see the results of expanding syntax extensions, 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.
Some of the [macro debugging tips](macros.html#debugging-macro-code) are applicable.
You can use [`syntax::parse`](../syntax/parse/index.html) to turn token trees into
higher-level syntax elements like expressions:
@ -184,8 +153,13 @@ and return
[`DummyResult`](../syntax/ext/base/struct.DummyResult.html),
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
[`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
[quasiquote macros](../syntax/ext/quote/index.html). They are undocumented and
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}
fn main() {
let x = &mut 5;
let mut x = 5;
if *x < 10 {
if x < 10 {
let y = &x;
println!("Oh no: {}", y);
return;
}
*x -= 1;
x -= 1;
println!("Oh no: {}", x);
}
@ -382,17 +382,18 @@ mutated, and therefore, lets us pass. This wouldn't work:
```{rust,ignore}
fn main() {
let x = &mut 5;
let mut x = 5;
if *x < 10 {
if x < 10 {
let y = &x;
*x -= 1;
x -= 1;
println!("Oh no: {}", y);
return;
}
*x -= 1;
x -= 1;
println!("Oh no: {}", x);
}
@ -401,12 +402,12 @@ fn main() {
It gives this error:
```text
test.rs:5:8: 5:10 error: cannot assign to `*x` because it is borrowed
test.rs:5 *x -= 1;
^~
test.rs:4:16: 4:18 note: borrow of `*x` occurs here
test.rs:4 let y = &x;
^~
test.rs:7:9: 7:15 error: cannot assign to `x` because it is borrowed
test.rs:7 x -= 1;
^~~~~~
test.rs:5:18: 5:19 note: borrow of `x` occurs here
test.rs:5 let y = &x;
^
```
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
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
appropriate calls there. Furthermore, boxes are a specific kind of affine type,
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).
appropriate calls there.
You don't need to fully grok the theory of affine types or regions to grok
boxes, though. As a rough approximation, you can treat this Rust code:
You don't need to fully grok the theory of affine types to grok boxes, though.
As a rough approximation, you can treat this Rust code:
```{rust}
{
@ -560,43 +558,44 @@ fn main() {
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.
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}
fn add_one(x: &i32) -> i32 {
*x + 1
fn add(x: &i32, y: &i32) -> i32 {
*x + *y
}
fn main() {
let x = Box::new(5);
println!("{}", add_one(&*x));
println!("{}", add_one(&*x));
println!("{}", add_one(&*x));
println!("{}", add(&*x, &*x));
println!("{}", add(&*x, &*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}
fn add_one(x: &mut i32) -> i32 {
*x + 1
fn increment(x: &mut i32) {
*x += 1;
}
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
// of `&`-pointer as mutable
increment(&mut x);
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
Boxes are appropriate to use in two situations: Recursive data structures,
and occasionally, when returning data.
Boxes are most appropriate to use when defining 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
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
This part is coming soon.
@ -654,74 +645,6 @@ 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
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
inlining and hence usually higher performance. It also has some downsides:
causing code bloat due to many copies of the same function existing in the
binary, one for each type.
This has a great upside: static dispatch allows function calls to be
inlined because the callee is known at compile time, and inlining is
the key to good optimization. Static dispatch is fast, but it comes at
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
(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
@ -92,8 +93,8 @@ dynamic dispatch is sometimes more efficient.
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
a dynamic, but not vice versa, meaning static calls are more flexible. The
standard library tries to be statically dispatched where possible for this
a dynamic dispatch, but not vice versa, meaning static calls are more flexible.
The standard library tries to be statically dispatched where possible for this
reason.
## Dynamic dispatch
@ -101,38 +102,11 @@ reason.
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
*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
a special record of function pointers (created and managed by the compiler).
known at runtime.
A function that takes a trait object is not specialised 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.
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);
```
A trait object can be obtained from a pointer to a concrete type that
implements the trait by *casting* it (e.g. `&x as &Foo`) or *coercing* it
(e.g. using `&x` as an argument to a function that takes `&Foo`).
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
@ -140,13 +114,79 @@ and casts are identical.
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
"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
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
`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
# 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
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
`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
the size of the erased type, and its alignment requirements; these are
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
more flexible.
destructor, but will be used in the future, as trait objects are progressively
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
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
`(b.vtable.destructor)(b.data)` (respectively `y`) call when they went out of
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
have a fixed size, and cannot be mutated.
A `String`, on the other hand, is an in-memory string. This string is
growable, and is also guaranteed to be UTF-8.
A `String`, on the other hand, 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.
```{rust}
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.
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
#[test]
#[should_fail]
#[should_panic]
fn it_works() {
assert!(false);
}
@ -163,13 +163,13 @@ equality:
```rust
#[test]
#[should_fail]
#[should_panic]
fn it_works() {
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:
```bash
@ -189,15 +189,15 @@ running 0 tests
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`
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
of the example above would be:
```
#[test]
#[should_fail(expected = "assertion failed")]
#[should_panic(expected = "assertion failed")]
fn it_works() {
assert_eq!("Hello", "world");
}
@ -231,7 +231,7 @@ pub fn add_two(a: i32) -> i32 {
}
#[cfg(test)]
mod tests {
mod test {
use super::add_two;
#[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
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
@ -260,7 +260,7 @@ pub fn add_two(a: i32) -> i32 {
}
#[cfg(test)]
mod tests {
mod test {
use super::*;
#[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
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?
```{rust}
# #![feature(core)]
struct Circle {
x: 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:
```{rust}
# #![feature(core)]
struct Circle {
x: f64,
y: f64,
@ -84,6 +86,7 @@ which implements `HasArea` will have an `.area()` method.
Here's an extended example of how this works:
```{rust}
# #![feature(core)]
trait HasArea {
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:
```{rust}
# #![feature(core)]
use shapes::HasArea;
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
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
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:
```
# #![feature(std_misc)]
use std::num::Float;
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:
```
# #![feature(std_misc)]
# use std::num::Float;
# fn inverse<T: Float>(x: T) -> Result<T, 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.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
`Box`, hence the Rust compiler cannot protect against bugs like
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
reason about dangling pointers; and
- 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.
- ensure that any data stored behind a raw pointer is destroyed at the
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(rustdoc)]
extern crate "rustdoc" as this;
extern crate rustdoc as this;
#[cfg(rustc)]
extern crate "rustc_driver" as this;
extern crate rustc_driver as this;
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:
print "* " + line
print

View File

@ -27,9 +27,18 @@ def rust_pretty_printer_lookup_function(val):
if type_code == gdb.TYPE_CODE_STRUCT:
struct_kind = classify_struct(val.type)
if struct_kind == STRUCT_KIND_SLICE:
return RustSlicePrinter(val)
if struct_kind == STRUCT_KIND_STR_SLICE:
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:
return RustTuplePrinter(val)
@ -172,6 +181,28 @@ class RustTupleStructPrinter:
def display_hint(self):
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:
def __init__(self, val):
@ -181,6 +212,35 @@ class RustStringSlicePrinter:
slice_byte_len = self.val["length"]
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:
def __init__(self, val):
@ -204,19 +264,38 @@ STRUCT_KIND_TUPLE = 2
STRUCT_KIND_TUPLE_VARIANT = 3
STRUCT_KIND_STRUCT_VARIANT = 4
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):
# print("\nclassify_struct: tag=%s\n" % type.tag)
if type.tag == "&str":
return STRUCT_KIND_STR_SLICE
if type.tag.startswith("&[") and type.tag.endswith("]"):
return STRUCT_KIND_SLICE
fields = list(type.fields())
field_count = len(fields)
if field_count == 0:
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 field_count == 1:
return STRUCT_KIND_CSTYLE_VARIANT
@ -254,3 +333,11 @@ def get_field_at_index(val, index):
return field
i += 1
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
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`
checks if the given file does not exist, for example.
@ -333,6 +336,11 @@ def check_tree_text(tree, path, pat, regexp):
return ret
def check_tree_count(tree, path, count):
path = normalize_xpath(path)
return len(tree.findall(path)) == count
def check(target, commands):
cache = CachedFiles(target)
for c in commands:
@ -360,6 +368,13 @@ def check(target, commands):
raise RuntimeError('Invalid number of @{} arguments \
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':
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_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
put_const(F_OK, int);
#endif

View File

@ -40,31 +40,12 @@ def print_struct_val(val, internal_dict):
if is_vec_slice(val):
return print_vec_slice_val(val, internal_dict)
elif is_std_vec(val):
return print_std_vec_val(val, internal_dict)
else:
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):
'''
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 + ": "
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)
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
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
#=--------------------------------------------------------------------------------------------------
@ -243,3 +258,44 @@ def is_vec_slice(val):
type_name = extract_type_name(ty.GetName()).replace("&'static", "&").replace(" ", "")
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`
case $OS in
("Linux"|"FreeBSD"|"DragonFly"|"OpenBSD")
("Linux"|"FreeBSD"|"DragonFly"|"Bitrig"|"OpenBSD")
BIN_SUF=
LIB_SUF=.so
;;

View File

@ -57,7 +57,16 @@ else:
args.extend(components)
out = run(args)
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 + "\"")
# LLVM libraries are all static libraries
if 'LLVM' in lib:

View File

@ -288,6 +288,7 @@ VAL_OPTIONS=""
flag uninstall "only uninstall from the installation prefix"
valopt prefix "" "set installation prefix"
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"
if [ $HELP -eq 1 ]
@ -307,7 +308,7 @@ CFG_CPUTYPE=$(uname -m)
if [ $CFG_OSTYPE = Darwin -a $CFG_CPUTYPE = i386 ]
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.
if sysctl hw.optional.x86_64 | grep -q ': 1'
then
@ -335,7 +336,7 @@ case $CFG_OSTYPE in
MINGW32*)
CFG_OSTYPE=pc-mingw32
;;
# Thad's Cygwin identifers below
# Thad's Cygwin identifiers below
# Vista 32 bit
CYGWIN_NT-6.0)
@ -437,7 +438,7 @@ CFG_TMP_DIR=$(mktemp -d 2>/dev/null \
|| create_tmp_dir)
# 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.
#
# FIXME It would be better to use the known most recent nightly that has been
@ -449,18 +450,28 @@ then
fi
RUST_URL="https://static.rust-lang.org/dist"
RUST_PACKAGE_NAME=rust-nightly
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"
# add a date suffix if we want a particular nighly.
case "$CFG_CHANNEL" in
nightly)
# add a date suffix if we want a particular nightly.
if [ -n "${CFG_DATE}" ];
then
RUST_URL="${RUST_URL}/${CFG_DATE}"
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() {
msg "Downloading ${remote_sha256}"
remote_sha256=`"${CFG_CURL}" -f "${remote_sha256}"`

View File

@ -46,13 +46,13 @@ snapshot_files = {
"winnt": ["bin/rustc.exe"],
"freebsd": ["bin/rustc"],
"dragonfly": ["bin/rustc"],
"bitrig": ["bin/rustc"],
"openbsd": ["bin/rustc"],
}
winnt_runtime_deps_32 = ["libgcc_s_dw2-1.dll", "libstdc++-6.dll"]
winnt_runtime_deps_64 = ["libgcc_s_seh-1.dll", "libstdc++-6.dll"]
def parse_line(n, line):
global snapshotfile
@ -101,6 +101,8 @@ def get_kernel(triple):
return "freebsd"
if os_name == "dragonfly":
return "dragonfly"
if os_name == "bitrig":
return "bitrig"
if os_name == "openbsd":
return "openbsd"
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
presumption that third-party software is unaffected by the copyleft
requirements of the license of GCC.

View File

@ -13,7 +13,7 @@ import fileinput
import subprocess
import re
import os
from licenseck import *
from licenseck import check_license
import snapshot
err = 0
@ -22,13 +22,8 @@ cr_flag = "ignore-tidy-cr"
tab_flag = "ignore-tidy-tab"
linelength_flag = "ignore-tidy-linelength"
# 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
interesting_files = ['.rs', '.py', '.js', '.sh', '.c', '.h']
uninteresting_files = ['miniz.c', 'jquery', 'rust_android_dummy']
def report_error_name_no(name, no, s):
@ -51,6 +46,34 @@ def do_license_check(name, contents):
if not check_license(name, contents):
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_contents = ""
check_tab = True
@ -63,28 +86,16 @@ if len(sys.argv) < 2:
src_dir = sys.argv[1]
try:
count_lines = 0
count_non_blank_lines = 0
interesting_files = ['.rs', '.py', '.js', '.sh', '.c', '.h']
count_other_linted_files = 0
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()
try:
for (dirpath, dirnames, filenames) in os.walk(src_dir):
# Skip some third-party directories
skippable_dirs = {
'src/jemalloc',
@ -103,14 +114,6 @@ try:
if any(d in dirpath for d in skippable_dirs):
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
if interesting_file(f)
and not f.endswith("_gen.rs")
@ -196,10 +199,11 @@ except UnicodeDecodeError as e:
report_err("UTF-8 decoding error " + str(e))
print
for ext in file_counts:
print "* linted " + str(file_counts[ext]) + " " + ext + " files"
print "* total lines of code: " + str(count_lines)
print "* total non-blank lines of code: " + str(count_non_blank_lines)
for ext in sorted(file_counts, key=file_counts.get, reverse=True):
print "* linted {} {} files".format(file_counts[ext], ext)
print "* linted {} other files".format(count_other_linted_files)
print "* total lines of code: {}".format(count_lines)
print "* total non-blank lines of code: {}".format(count_non_blank_lines)
print
sys.exit(err)

View File

@ -84,8 +84,8 @@ def fetch(f):
sys.stderr.write("cannot load %s" % f)
exit(1)
def is_valid_unicode(n):
return 0 <= n <= 0xD7FF or 0xE000 <= n <= 0x10FFFF
def is_surrogate(n):
return 0xD800 <= n <= 0xDFFF
def load_unicode_data(f):
fetch(f)
@ -96,19 +96,28 @@ def load_unicode_data(f):
canon_decomp = {}
compat_decomp = {}
udict = {};
range_start = -1;
for line in fileinput.input(f):
fields = line.split(";")
if len(fields) != 15:
data = line.split(';');
if len(data) != 15:
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,
old, iso, upcase, lowcase, titlecase ] = fields
code_org = code
code = int(code, 16)
if not is_valid_unicode(code):
continue
old, iso, upcase, lowcase, titlecase ] = udict[code];
# generate char to char direct common and simple conversions
# uppercase to lowercase
@ -290,11 +299,11 @@ def emit_bsearch_range_table(f):
fn bsearch_range_table(c: char, r: &'static [(char,char)]) -> bool {
use core::cmp::Ordering::{Equal, Less, Greater};
use core::slice::SliceExt;
r.binary_search(|&(lo,hi)| {
r.binary_search_by(|&(lo,hi)| {
if lo <= c && c <= hi { Equal }
else if hi < c { Less }
else { Greater }
}).found().is_some()
}).is_ok()
}\n
""")
@ -303,7 +312,7 @@ def emit_table(f, name, t_data, t_type = "&'static [(char, char)]", is_pub=True,
pub_string = ""
if is_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 = ""
first = True
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):
f.write("pub mod regex {\n")
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,
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)
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)
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::option::Option;
use core::option::Option::{Some, None};
use core::slice;
use core::result::Result::{Ok, Err};
pub fn to_lower(c: char) -> char {
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> {
match table.binary_search(|&(key, _)| {
match table.binary_search_by(|&(key, _)| {
if c == key { Equal }
else if key < c { Less }
else { Greater }
}) {
slice::BinarySearchResult::Found(i) => Some(i),
slice::BinarySearchResult::NotFound(_) => None,
Ok(i) => Some(i),
Err(_) => None,
}
}
@ -386,10 +395,9 @@ def emit_conversions_module(f, lowerupper, upperlower):
def emit_grapheme_module(f, grapheme_table, grapheme_cats):
f.write("""pub mod grapheme {
use core::kinds::Copy;
use core::slice::SliceExt;
pub use self::GraphemeCat::*;
use core::slice;
use core::result::Result::{Ok, Err};
#[allow(non_camel_case_types)]
#[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 {
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 }
else if hi < c { Less }
else { Greater }
}) {
slice::BinarySearchResult::Found(idx) => {
Ok(idx) => {
let (_, _, cat) = r[idx];
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::{Some, None};\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("""
fn bsearch_range_value_table(c: char, is_cjk: bool, r: &'static [(char, char, u8, u8)]) -> u8 {
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 }
else if hi < c { Less }
else { Greater }
}) {
slice::BinarySearchResult::Found(idx) => {
Ok(idx) => {
let (_, _, r_ncjk, r_cjk) = r[idx];
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 {
use core::cmp::Ordering::{Equal, Less, Greater};
use core::slice::SliceExt;
use core::slice;
match r.binary_search(|&(lo, hi, _)| {
use core::result::Result::{Ok, Err};
match r.binary_search_by(|&(lo, hi, _)| {
if lo <= c && c <= hi { Equal }
else if hi < c { Less }
else { Greater }
}) {
slice::BinarySearchResult::Found(idx) => {
Ok(idx) => {
let (_, _, result) = r[idx];
result
}
slice::BinarySearchResult::NotFound(_) => 0
Err(_) => 0
}
}\n
""")
@ -609,7 +617,7 @@ if __name__ == "__main__":
unicode_version = re.search(pattern, readme.read()).groups()
rf.write("""
/// 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);
""" % unicode_version)
(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"
$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*)
CFLAGS="$CFLAGS"

View File

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

View File

@ -33,7 +33,7 @@
//!
//! Sharing some immutable data between tasks:
//!
//! ```
//! ```no_run
//! use std::sync::Arc;
//! use std::thread;
//!
@ -50,7 +50,7 @@
//!
//! Sharing mutable data safely between tasks with a `Mutex`:
//!
//! ```
//! ```no_run
//! use std::sync::{Arc, Mutex};
//! use std::thread;
//!
@ -69,12 +69,14 @@
//! }
//! ```
use boxed::Box;
use core::prelude::*;
use core::atomic;
use core::atomic::Ordering::{Relaxed, Release, Acquire, SeqCst};
use core::fmt;
use core::cmp::{Ordering};
use core::cmp::Ordering;
use core::default::Default;
use core::mem::{min_align_of, size_of};
use core::mem;
@ -86,13 +88,17 @@ use heap::deallocate;
/// An atomically reference counted wrapper for shared state.
///
/// # Example
/// # Examples
///
/// 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
/// 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::thread;
///
@ -104,7 +110,7 @@ use heap::deallocate;
/// let child_numbers = shared_numbers.clone();
///
/// thread::spawn(move || {
/// let local_numbers = child_numbers.as_slice();
/// let local_numbers = &child_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`.
///
/// Weak pointers will not keep the data inside of the `Arc` alive, and can be used to break cycles
/// between `Arc` pointers.
/// Weak pointers will not keep the data inside of the `Arc` alive, and can be
/// used to break cycles between `Arc` pointers.
#[unsafe_no_drop_flag]
#[unstable(feature = "alloc",
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> 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> {
strong: atomic::AtomicUsize,
weak: atomic::AtomicUsize,
@ -163,7 +176,7 @@ impl<T> Arc<T> {
pub fn new(data: T) -> Arc<T> {
// 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
let x = box ArcInner {
let x: Box<_> = box ArcInner {
strong: atomic::AtomicUsize::new(1),
weak: atomic::AtomicUsize::new(1),
data: data,
@ -176,6 +189,7 @@ impl<T> Arc<T> {
/// # Examples
///
/// ```
/// # #![feature(alloc)]
/// use std::sync::Arc;
///
/// let five = Arc::new(5);
@ -194,12 +208,28 @@ impl<T> Arc<T> {
impl<T> Arc<T> {
#[inline]
fn inner(&self) -> &ArcInner<T> {
// This unsafety is ok because while this arc is alive we're guaranteed that the inner
// pointer is valid. Furthermore, we know that the `ArcInner` structure itself is `Sync`
// because the inner data is `Sync` as well, so we're ok loaning out an immutable pointer
// to these contents.
// This unsafety is ok because while this arc is alive we're guaranteed
// that the inner pointer is valid. Furthermore, we know that the
// `ArcInner` structure itself is `Sync` because the inner data is
// `Sync` as well, so we're ok loaning out an immutable pointer to these
// contents.
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.
@ -212,6 +242,41 @@ pub fn weak_count<T>(this: &Arc<T>) -> usize { this.inner().weak.load(SeqCst) -
#[unstable(feature = "alloc")]
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")]
impl<T> Clone for Arc<T> {
/// Makes a clone of the `Arc<T>`.
@ -221,6 +286,7 @@ impl<T> Clone for Arc<T> {
/// # Examples
///
/// ```
/// # #![feature(alloc)]
/// use std::sync::Arc;
///
/// let five = Arc::new(5);
@ -229,13 +295,15 @@ impl<T> Clone for Arc<T> {
/// ```
#[inline]
fn clone(&self) -> Arc<T> {
// Using a relaxed ordering is alright here, as knowledge of the original reference
// prevents other threads from erroneously deleting the object.
// Using a relaxed ordering is alright here, as knowledge of the
// original reference prevents other threads from erroneously deleting
// the object.
//
// As explained in the [Boost documentation][1], Increasing the reference counter can
// always be done with memory_order_relaxed: New references to an object can only be formed
// from an existing reference, and passing an existing reference from one thread to another
// must already provide any required synchronization.
// As explained in the [Boost documentation][1], Increasing the
// reference counter can always be done with memory_order_relaxed: New
// references to an object can only be formed from an existing
// 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)
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>`.
///
/// This is also referred to as a copy-on-write operation because the inner data is cloned if
/// the reference count is greater than one.
/// This is also referred to as a copy-on-write operation because the inner
/// data is cloned if the reference count is greater than one.
///
/// # Examples
///
/// ```
/// # #![feature(alloc)]
/// use std::sync::Arc;
///
/// let mut five = Arc::new(5);
@ -271,16 +340,15 @@ impl<T: Send + Sync + Clone> Arc<T> {
#[inline]
#[unstable(feature = "alloc")]
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
// clone if there is an additional reference of either kind.
// Note that we hold a strong reference, which also counts as a weak
// reference, so we only clone if there is an additional reference of
// either kind.
if self.inner().strong.load(SeqCst) != 1 ||
self.inner().weak.load(SeqCst) != 1 {
*self = Arc::new((**self).clone())
}
// 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.
// As with `unique()`, the unsafety is ok because our reference was
// either unique to begin with, or became one upon cloning the contents.
let inner = unsafe { &mut **self._ptr };
&mut inner.data
}
@ -288,15 +356,17 @@ impl<T: Send + Sync + Clone> Arc<T> {
#[unsafe_destructor]
#[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>`.
///
/// This will decrement the strong reference count. If the strong reference count becomes zero
/// and the only other references are `Weak<T>` ones, `drop`s the inner value.
/// This will decrement the strong reference count. If the strong reference
/// count becomes zero and the only other references are `Weak<T>` ones,
/// `drop`s the inner value.
///
/// # Examples
///
/// ```
/// # #![feature(alloc)]
/// use std::sync::Arc;
///
/// {
@ -313,58 +383,59 @@ impl<T: Sync + Send> Drop for Arc<T> {
///
/// } // implicit drop
/// ```
#[inline]
fn drop(&mut self) {
// This structure has #[unsafe_no_drop_flag], so this drop glue may run more than once (but
// it is guaranteed to be zeroed after the first if it's run more than once)
// This structure has #[unsafe_no_drop_flag], so this drop glue may run
// more than once (but it is guaranteed to be zeroed after the first if
// it's run more than once)
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
// unless we are going to delete the object. This same logic applies to the below
// `fetch_sub` to the `weak` count.
// Because `fetch_sub` is already atomic, we do not need to synchronize
// with other threads unless we are going to delete the object. This
// same logic applies to the below `fetch_sub` to the `weak` count.
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.
// Because it is marked `Release`, the decreasing of the reference count synchronizes with
// this `Acquire` fence. This means that use of the data happens before decreasing the
// reference count, which happens before this fence, which happens before the deletion of
// the data.
// This fence is needed to prevent reordering of use of the data and
// deletion of the data. Because it is marked `Release`, the decreasing
// of the reference count synchronizes with this `Acquire` fence. This
// means that use of the data happens before decreasing the reference
// count, which happens before this fence, which happens before the
// deletion of the data.
//
// As explained in the [Boost documentation][1],
//
// > It is important to enforce any possible access to the object in one thread (through an
// > existing reference) to *happen before* deleting the object in a different thread. This
// > is achieved by a "release" operation after dropping a reference (any access to the
// > object through this reference must obviously happened before), and an "acquire"
// > operation before deleting the object.
// > It is important to enforce any possible access to the object in one
// > thread (through an existing reference) to *happen before* deleting
// > the object in a different thread. This is achieved by a "release"
// > operation after dropping a reference (any access to 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)
atomic::fence(Acquire);
// Destroy the data at this time, even though we may not free the box allocation itself
// (there may still be weak pointers lying around).
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>>()) }
unsafe {
self.drop_slow()
}
}
}
#[unstable(feature = "alloc",
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 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
///
/// ```
/// # #![feature(alloc)]
/// use std::sync::Arc;
///
/// let five = Arc::new(5);
@ -374,8 +445,8 @@ impl<T: Sync + Send> Weak<T> {
/// let strong_five: Option<Arc<_>> = weak_five.upgrade();
/// ```
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
// count hits 0 is must never be above 0.
// We use a CAS loop to increment the strong count instead of a
// fetch_add because once the count hits 0 is must never be above 0.
let inner = self.inner();
loop {
let n = inner.strong.load(SeqCst);
@ -394,7 +465,7 @@ impl<T: Sync + Send> Weak<T> {
#[unstable(feature = "alloc",
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>`.
///
/// This increases the weak reference count.
@ -402,6 +473,7 @@ impl<T: Sync + Send> Clone for Weak<T> {
/// # Examples
///
/// ```
/// # #![feature(alloc)]
/// use std::sync::Arc;
///
/// let weak_five = Arc::new(5).downgrade();
@ -418,7 +490,7 @@ impl<T: Sync + Send> Clone for Weak<T> {
#[unsafe_destructor]
#[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>`.
///
/// This will decrement the weak reference count.
@ -426,6 +498,7 @@ impl<T: Sync + Send> Drop for Weak<T> {
/// # Examples
///
/// ```
/// # #![feature(alloc)]
/// use std::sync::Arc;
///
/// {
@ -448,10 +521,11 @@ impl<T: Sync + Send> Drop for Weak<T> {
let ptr = *self._ptr;
// 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
// entirely. See the discussion in Arc::drop() about the memory orderings
// If we find out that we were the last weak pointer, then its time to
// deallocate the data entirely. See the discussion in Arc::drop() about
// the memory orderings
if self.inner().weak.fetch_sub(1, Release) == 1 {
atomic::fence(Acquire);
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()) }
}
#[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")]
impl<T: Hash> Hash for Arc<T> {
fn hash<H: Hasher>(&self, state: &mut H) {
@ -624,7 +691,7 @@ mod tests {
use std::sync::atomic::Ordering::{Acquire, SeqCst};
use std::thread;
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;
struct Canary(*mut atomic::AtomicUsize);
@ -660,6 +727,21 @@ mod tests {
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]
fn test_cowarc_clone_make_unique() {
let mut cow0 = Arc::new(75);

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