mirror of
https://git.proxmox.com/git/rustc
synced 2025-10-18 21:49:03 +00:00
Imported Upstream version 1.0.0~beta
This commit is contained in:
parent
85aaf69fd1
commit
c34b17963d
@ -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>
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
#
|
||||
|
57
README.md
57
README.md
@ -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
|
||||
$ pacman -S mingw-w64-i686-toolchain
|
||||
$ pacman -S mingw-w64-x86_64-toolchain
|
||||
2. From the MSYS2 terminal, install the `mingw64` toolchain and other required
|
||||
tools.
|
||||
|
||||
$ pacman -S base-devel
|
||||
```
|
||||
```sh
|
||||
# Choose one based on platform:
|
||||
$ pacman -S mingw-w64-i686-toolchain
|
||||
$ pacman -S mingw-w64-x86_64-toolchain
|
||||
|
||||
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:
|
||||
$ pacman -S base-devel
|
||||
```
|
||||
|
||||
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,26 +101,26 @@ 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.
|
||||
|
||||
[StackOverflow]: http://stackoverflow.com/questions/tagged/rust
|
||||
[Stack Overflow]: http://stackoverflow.com/questions/tagged/rust
|
||||
[/r/rust]: http://reddit.com/r/rust
|
||||
[users.rust-lang.org]: http://users.rust-lang.org/
|
||||
|
||||
## 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.
|
||||
|
101
RELEASES.md
101
RELEASES.md
@ -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
51
configure
vendored
@ -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,10 +479,19 @@ 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
|
||||
|
||||
|
||||
@ -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
|
||||
|
289
man/rustc.1
289
man/rustc.1
@ -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.
|
||||
|
102
man/rustdoc.1
102
man/rustdoc.1
@ -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.
|
||||
|
26
mk/cfg/x86_64-unknown-bitrig.mk
Normal file
26
mk/cfg/x86_64-unknown-bitrig.mk
Normal 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
|
@ -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
|
||||
|
||||
|
30
mk/crates.mk
30
mk/crates.mk
@ -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.
|
||||
|
@ -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 $$@
|
||||
|
@ -53,6 +53,7 @@ PKG_FILES := \
|
||||
driver \
|
||||
etc \
|
||||
$(foreach crate,$(CRATES),lib$(crate)) \
|
||||
libcollectionstest \
|
||||
libcoretest \
|
||||
libbacktrace \
|
||||
rt \
|
||||
|
@ -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)))
|
||||
$(foreach crate,$(COMPILER_DOC_CRATES),$(eval $(call DEF_LIB_DOC,$(crate),COMPILER_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
|
||||
|
@ -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
|
||||
|
||||
|
||||
|
@ -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),
|
||||
|
@ -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)
|
||||
|
@ -221,5 +221,3 @@ prepare-maybe-clean-$(1):
|
||||
|
||||
|
||||
endef
|
||||
|
||||
|
||||
|
10
mk/target.mk
10
mk/target.mk
@ -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
|
||||
|
46
mk/tests.mk
46
mk/tests.mk
@ -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:
|
||||
|
@ -17,4 +17,3 @@ else
|
||||
endif
|
||||
|
||||
S := $(CFG_SRC_DIR)
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -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())
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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() {
|
||||
|
@ -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 => {
|
||||
@ -963,16 +948,17 @@ fn check_expected_errors(expected_errors: Vec<errors::ExpectedError> ,
|
||||
|
||||
let prefixes = expected_errors.iter().map(|ee| {
|
||||
format!("{}:{}:", testfile.display(), ee.line)
|
||||
}).collect::<Vec<String> >();
|
||||
}).collect::<Vec<String>>();
|
||||
|
||||
#[cfg(windows)]
|
||||
fn prefix_matches( line : &str, prefix : &str ) -> bool {
|
||||
fn prefix_matches(line: &str, prefix: &str) -> bool {
|
||||
use std::ascii::AsciiExt;
|
||||
// On windows just translate all '\' path separators to '/'
|
||||
let line = line.replace(r"\", "/");
|
||||
if cfg!(windows) {
|
||||
line.to_ascii_lowercase().starts_with(&prefix.to_ascii_lowercase())
|
||||
} else {
|
||||
line.starts_with(prefix)
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
fn prefix_matches( line : &str, prefix : &str ) -> bool {
|
||||
line.starts_with( prefix )
|
||||
}
|
||||
|
||||
// A multi-line error will have followup lines which will always
|
||||
@ -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 {
|
||||
@ -1398,6 +1413,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) {
|
||||
@ -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()
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
|
@ -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] ;
|
||||
```
|
||||
|
@ -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).
|
||||
|
@ -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
|
||||
|
||||
|
@ -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 that’s what `thread::scoped` takes as an
|
||||
argument. `FnOnce` closures take ownership of their environment. That’s fine,
|
||||
but there’s one detail: because of `map`, we’re going to make three of these
|
||||
closures. And since all three try to take ownership of `numbers`, that would be
|
||||
a problem. That’s what it means by ‘cannot move out of captured outer
|
||||
variable’: our `thread::scoped` closure wants to take ownership, and it can’t,
|
||||
because the closure for `map` won’t 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);
|
||||
}
|
||||
```
|
||||
|
@ -63,4 +63,3 @@ function populate_rust_search() {
|
||||
populate_site_search();
|
||||
populate_rust_search();
|
||||
</script>
|
||||
|
||||
|
@ -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 LLVM’s 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 two’s 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 — once it has been spawned — 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 —
|
||||
when a message arrives at a sender, or a buffer opens to receive a message
|
||||
— 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
|
||||
|
@ -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;
|
||||
|
@ -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));
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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)
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
202
src/doc/trpl/associated-types.md
Normal file
202
src/doc/trpl/associated-types.md
Normal 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
|
||||
|
||||
There’s 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>;
|
||||
```
|
||||
|
||||
You’ll 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 can’t create a trait object like this, because we don’t 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 didn’t proide this constraint, we
|
||||
couldn’t be sure which `impl` to match this trait object to.
|
@ -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.
|
||||
|
152
src/doc/trpl/benchmark-tests.md
Normal file
152
src/doc/trpl/benchmark-tests.md
Normal 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.
|
100
src/doc/trpl/box-syntax-and-patterns.md
Normal file
100
src/doc/trpl/box-syntax-and-patterns.md
Normal 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.
|
@ -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 they’re anonymous, and they don’t 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 we’re 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
|
||||
|
||||
It’s 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.
|
||||
|
@ -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";
|
||||
|
@ -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
|
||||
|
@ -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");
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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
|
||||
|
||||
Here’s 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, “I’m broken.”);
|
||||
/// # }
|
||||
/// ```
|
||||
#[macro_export]
|
||||
macro_rules! panic_unless {
|
||||
($condition:expr, $($rest:expr),+) => ({ if ! $condition { panic!($($rest),+); } });
|
||||
}
|
||||
# fn main() {}
|
||||
```
|
||||
|
||||
You’ll note three things: we need to add our own `extern crate` line, so that
|
||||
we can add the `#[macro_use]` attribute. Second, we’ll need to add our own
|
||||
`main()` as well. Finally, a judicious use of `#` to comment out those two
|
||||
things, so they don’t 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.
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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!");
|
||||
# }
|
||||
|
@ -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
|
||||
```
|
||||
|
@ -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.
|
@ -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.
|
||||
|
@ -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:
|
||||
|
||||
|
||||
|
141
src/doc/trpl/inline-assembly.md
Normal file
141
src/doc/trpl/inline-assembly.md
Normal 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.
|
||||
|
@ -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
|
||||
|
25
src/doc/trpl/intrinsics.md
Normal file
25
src/doc/trpl/intrinsics.md
Normal 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.
|
||||
|
@ -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);
|
||||
}
|
||||
```
|
||||
|
79
src/doc/trpl/lang-items.md
Normal file
79
src/doc/trpl/lang-items.md
Normal 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
25
src/doc/trpl/link-args.md
Normal 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.
|
||||
|
@ -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);
|
||||
|
@ -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,14 +189,12 @@ 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.
|
||||
against. If it is under more, it'll be duplicated, as appropriate.
|
||||
|
||||
This baroque macro illustrates the duplication of variables from outer
|
||||
repetition levels.
|
||||
@ -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
|
||||
printf("log(%d): %s\n", state, state);
|
||||
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
|
||||
|
@ -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);
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -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, it’s 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 let’s 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
168
src/doc/trpl/no-stdlib.md
Normal 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.
|
||||
|
@ -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 it’s
|
||||
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
|
||||
|
@ -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"];
|
||||
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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.
|
@ -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 aren’t perfect and may “optimise” code to become slower.
|
||||
Furthermore, compilers aren’t 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.
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
91
src/doc/trpl/tracing-macros.md
Normal file
91
src/doc/trpl/tracing-macros.md
Normal 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.
|
@ -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
|
||||
|
||||
You’ve 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!"
|
||||
```
|
||||
|
@ -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
1
src/doc/trpl/unstable.md
Normal file
@ -0,0 +1 @@
|
||||
% Unstable Rust
|
@ -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() }
|
||||
|
54
src/etc/check-sanitycheck.py
Normal file
54
src/etc/check-sanitycheck.py
Normal 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)
|
@ -242,4 +242,3 @@ print
|
||||
for line in lines:
|
||||
print "* " + line
|
||||
print
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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))
|
||||
|
||||
|
@ -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
|
||||
|
@ -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)])
|
||||
|
@ -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
|
||||
;;
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
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"
|
||||
|
||||
# add a date suffix if we want a particular nighly.
|
||||
if [ -n "${CFG_DATE}" ];
|
||||
then
|
||||
RUST_URL="${RUST_URL}/${CFG_DATE}"
|
||||
fi
|
||||
|
||||
download_hash() {
|
||||
msg "Downloading ${remote_sha256}"
|
||||
remote_sha256=`"${CFG_CURL}" -f "${remote_sha256}"`
|
||||
|
@ -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.
1
src/etc/third-party/COPYING.RUNTIME
vendored
1
src/etc/third-party/COPYING.RUNTIME
vendored
@ -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.
|
||||
|
||||
|
@ -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]
|
||||
|
||||
count_lines = 0
|
||||
count_non_blank_lines = 0
|
||||
count_other_linted_files = 0
|
||||
|
||||
file_counts = {ext: 0 for ext in interesting_files}
|
||||
|
||||
all_paths = set()
|
||||
|
||||
try:
|
||||
count_lines = 0
|
||||
count_non_blank_lines = 0
|
||||
|
||||
interesting_files = ['.rs', '.py', '.js', '.sh', '.c', '.h']
|
||||
|
||||
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()
|
||||
|
||||
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)
|
||||
|
@ -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,
|
||||
|
@ -1 +1 @@
|
||||
0.12.0-5823-g522d09dfecbeca1595f25ac58c6d0178bbd21d7d
|
||||
0.12.0-7693-g9854143cba679834bc4ef932858cd5303f015a0e
|
||||
|
6
src/jemalloc/configure
vendored
6
src/jemalloc/configure
vendored
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user