Manual merge of #22475 - alexcrichton:rollup, r=alexcrichton
One windows bot failed spuriously.
This commit is contained in:
commit
dfc5c0f1e8
381 changed files with 6886 additions and 3250 deletions
200
CONTRIBUTING.md
200
CONTRIBUTING.md
|
@ -1,60 +1,156 @@
|
|||
## How to submit a bug report
|
||||
# Contributing to Rust
|
||||
|
||||
If you're just reporting a bug, please see:
|
||||
Thank you for your interest in contributing to Rust! There are many ways to
|
||||
contribute, and we appreciate all of them. This document is a bit long, so here's
|
||||
links to the major sections:
|
||||
|
||||
http://doc.rust-lang.org/complement-bugreport.html
|
||||
* [Feature Requests](#feature-requests)
|
||||
* [Bug Reports](#bug-reports)
|
||||
* [Pull Requests](#pull-requests)
|
||||
* [Writing Documentation](#writing-documentation)
|
||||
* [Issue Triage](#issue-triage)
|
||||
* [Out-of-tree Contributions](#out-of-tree-contributions)
|
||||
|
||||
## Submitting an issue
|
||||
If you have questions, please make a post on [internals.rust-lang.org][internals] or
|
||||
hop on [#rust-internals][pound-rust-internals].
|
||||
|
||||
Please submit issues here for bug reports or implementation details. For feature
|
||||
requests, language changes, or major changes to the libraries, please submit an
|
||||
issue against the [RFCs repository](https://github.com/rust-lang/rfcs).
|
||||
|
||||
## Pull request procedure
|
||||
|
||||
Pull requests should be targeted at Rust's `master` branch.
|
||||
Before pushing to your Github repo and issuing the pull request,
|
||||
please do two things:
|
||||
|
||||
1. [Rebase](http://git-scm.com/book/en/Git-Branching-Rebasing) your
|
||||
local changes against the `master` branch. Resolve any conflicts
|
||||
that arise.
|
||||
|
||||
2. Run the full Rust test suite with the `make check` command. You're
|
||||
not off the hook even if you just stick to documentation; code
|
||||
examples in the docs are tested as well! Although for simple
|
||||
wording or grammar fixes, this is probably unnecessary.
|
||||
|
||||
Pull requests will be treated as "review requests", and we will give
|
||||
feedback we expect to see corrected on
|
||||
[style](http://aturon.github.io/) and
|
||||
substance before pulling. Changes contributed via pull request should
|
||||
focus on a single issue at a time, like any other. We will not accept
|
||||
pull-requests that try to "sneak" unrelated changes in.
|
||||
|
||||
Normally, all pull requests must include regression tests (see
|
||||
[Note-testsuite](https://github.com/rust-lang/rust/wiki/Note-testsuite))
|
||||
that test your change. Occasionally, a change will be very difficult
|
||||
to test for. In those cases, please include a note in your commit
|
||||
message explaining why.
|
||||
|
||||
In the licensing header at the beginning of any files you change,
|
||||
please make sure the listed date range includes the current year. For
|
||||
example, if it's 2014, and you change a Rust file that was created in
|
||||
2010, it should begin:
|
||||
|
||||
```
|
||||
// Copyright 2010-2014 The Rust Project Developers.
|
||||
```
|
||||
|
||||
# Coordination and communication
|
||||
|
||||
Get feedback from other developers on
|
||||
[internals.rust-lang.org][internals], and
|
||||
[#rust-internals][pound-rust-internals].
|
||||
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
|
||||
[coc]: http://www.rust-lang.org/conduct.html
|
||||
|
||||
For more details, please refer to
|
||||
[Note-development-policy](https://github.com/rust-lang/rust/wiki/Note-development-policy).
|
||||
## Feature Requests
|
||||
|
||||
To request a change to the way that the Rust language works, please open an
|
||||
issue in the [RFCs repository](https://github.com/rust-lang/rfcs/issues/new)
|
||||
rather than this one. New features and other significant language changes
|
||||
must go through the RFC process.
|
||||
|
||||
## Bug Reports
|
||||
|
||||
While bugs are unfortunate, they're a reality in software. We can't fix what we
|
||||
don't know about, so please report liberally. If you're not sure if something
|
||||
is a bug or not, feel free to file a bug anyway.
|
||||
|
||||
If you have the chance, before reporting a bug, please [search existing
|
||||
issues](https://github.com/rust-lang/rust/search?q=&type=Issues&utf8=%E2%9C%93),
|
||||
as it's possible that someone else has already reported your error. This doesn't
|
||||
always work, and sometimes it's hard to know what to search for, so consider this
|
||||
extra credit. We won't mind if you accidentally file a duplicate report.
|
||||
|
||||
Opening an issue is as easy as following [this
|
||||
link](https://github.com/rust-lang/rust/issues/new) and filling out the fields.
|
||||
Here's a template that you can use to file a bug, though it's not necessary to
|
||||
use it exactly:
|
||||
|
||||
<short summary of the bug>
|
||||
|
||||
I tried this code:
|
||||
|
||||
<code sample that causes the bug>
|
||||
|
||||
I expected to see this happen: <explanation>
|
||||
|
||||
Instead, this happened: <explanation>
|
||||
|
||||
## Meta
|
||||
|
||||
`rustc --version --verbose`:
|
||||
|
||||
Backtrace:
|
||||
|
||||
All three components are important: what you did, what you expected, what
|
||||
happened instead. Please include the output of `rustc --version --verbose`,
|
||||
which includes important information about what platform you're on, what
|
||||
version of Rust you're using, etc.
|
||||
|
||||
Sometimes, a backtrace is helpful, and so including that is nice. To get
|
||||
a backtrace, set the `RUST_BACKTRACE` environment variable. The easiest way
|
||||
to do this is to invoke `rustc` like this:
|
||||
|
||||
```bash
|
||||
$ RUST_BACKTRACE=1 rustc ...
|
||||
```
|
||||
|
||||
## Pull Requests
|
||||
|
||||
Pull requests are the primary mechanism we use to change Rust. GitHub itself
|
||||
has some [great documentation][pull-requests] on using the Pull Request
|
||||
feature. We use the 'fork and pull' model described there.
|
||||
|
||||
[pull-requests]: https://help.github.com/articles/using-pull-requests/
|
||||
|
||||
Please make pull requests against the `master` branch.
|
||||
|
||||
All pull requests are reviewed by another person. We have a bot,
|
||||
@rust-highfive, that will automatically assign a random person to review your request.
|
||||
|
||||
If you want to request that a specific person reviews your pull request,
|
||||
you can add an `r?` to the message. For example, Steve usually reviews
|
||||
documentation changes. So if you were to make a documentation change, add
|
||||
|
||||
r? @steveklabnik
|
||||
|
||||
to the end of the message, and @rust-highfive will assign @steveklabnik instead
|
||||
of a random person. This is entirely optional.
|
||||
|
||||
After someone has reviewed your pull request, they will leave an annotation
|
||||
on the pull request with an `r+`. It will look something like this:
|
||||
|
||||
@bors: r+ 38fe8d2
|
||||
|
||||
This tells @bors, our lovable integration bot, that your pull request has
|
||||
been approved. The PR then enters the [merge queue][merge-queue], where @bors
|
||||
will run all the tests on every platform we support. If it all works out,
|
||||
@bors will merge your code into `master` and close the pull request.
|
||||
|
||||
[merge-queue]: http://buildbot.rust-lang.org/homu/queue/rust
|
||||
|
||||
## Writing Documentation
|
||||
|
||||
Documentation improvements are very welcome. The source of `doc.rust-lang.org`
|
||||
is located in `src/doc` in the tree, and standard API documentation is generated
|
||||
from the source code itself.
|
||||
|
||||
Documentation pull requests function in the same as other pull requests, though
|
||||
you may see a slightly different form of `r+`:
|
||||
|
||||
@bors: r+ 38fe8d2 rollup
|
||||
|
||||
That additional `rollup` tells @bors that this change is eligible for a 'rollup'.
|
||||
To save @bors some work, and to get small changes through more quickly, when
|
||||
@bors attempts to merge a commit that's rollup-eligible, it will also merge
|
||||
the other rollup-eligible patches too, and they'll get tested and merged at
|
||||
the same time.
|
||||
|
||||
## Issue Triage
|
||||
|
||||
Sometimes, an issue will stay open, even though the bug has been fixed. And
|
||||
sometimes, the original bug may go stale because something has changed in the
|
||||
meantime.
|
||||
|
||||
It can be helpful to go through older bug reports and make sure that they are
|
||||
still valid. Load up an older issue, double check that it's still true, and
|
||||
leave a comment letting us know if it is or is not. The [least recently updated sort][lru] is good for finding issues like this.
|
||||
|
||||
[lru]: https://github.com/rust-lang/rust/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-asc
|
||||
|
||||
## Out-of-tree Contributions
|
||||
|
||||
There are a number of other ways to contribute to Rust that don't deal with
|
||||
this repository.
|
||||
|
||||
Answer questions in [#rust][pound-rust], or on [users.rust-lang.org][users],
|
||||
or on [StackOverflow][so].
|
||||
|
||||
Participate in the [RFC process](https://github.com/rust-lang/rfcs).
|
||||
|
||||
Find a [requested community library][community-library], build it, and publish
|
||||
it to [Crates.io](http://crates.io). Easier said than done, but very, very
|
||||
valuable!
|
||||
|
||||
[pound-rust]: http://chat.mibbit.com/?server=irc.mozilla.org&channel=%23rust
|
||||
[users]: http://users.rust-lang.org/
|
||||
[so]: http://stackoverflow.com/questions/tagged/rust
|
||||
[community-library]: https://github.com/rust-lang/rfcs/labels/A-community-library
|
||||
|
|
|
@ -18,6 +18,7 @@ Read ["Installing Rust"][install] from [The Book][trpl].
|
|||
* GNU `make` 3.81 or later
|
||||
* `curl`
|
||||
* `git`
|
||||
|
||||
2. Download and build Rust:
|
||||
|
||||
You can either download a [tarball] or build directly from the [repo].
|
||||
|
@ -97,19 +98,21 @@ There is a lot more documentation in the [wiki].
|
|||
|
||||
[wiki]: https://github.com/rust-lang/rust/wiki
|
||||
|
||||
## Getting help and getting involved
|
||||
## 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.
|
||||
* [internals.rust-lang.org] - For development of the Rust language itself.
|
||||
* [/r/rust] - News and general discussion.
|
||||
|
||||
[StackOverflow]: http://stackoverflow.com/questions/tagged/rust
|
||||
[/r/rust]: http://reddit.com/r/rust
|
||||
[users.rust-lang.org]: http://users.rust-lang.org/
|
||||
[internals.rust-lang.org]: http://internals.rust-lang.org/
|
||||
|
||||
## Contributing
|
||||
|
||||
To contribute to Rust, please see [CONTRIBUTING.md](CONTRIBUTING.md).
|
||||
|
||||
## License
|
||||
|
||||
|
|
10
mk/docs.mk
10
mk/docs.mk
|
@ -25,7 +25,7 @@
|
|||
# L10N_LANGS are the languages for which the docs have been
|
||||
# translated.
|
||||
######################################################################
|
||||
DOCS := index intro tutorial complement-bugreport \
|
||||
DOCS := index intro tutorial \
|
||||
complement-lang-faq complement-design-faq complement-project-faq \
|
||||
rustdoc reference grammar
|
||||
|
||||
|
@ -73,7 +73,7 @@ RUSTBOOK = $(RPATH_VAR2_T_$(CFG_BUILD)_H_$(CFG_BUILD)) $(RUSTBOOK_EXE)
|
|||
|
||||
D := $(S)src/doc
|
||||
|
||||
DOC_TARGETS := trpl
|
||||
DOC_TARGETS := trpl style
|
||||
COMPILER_DOC_TARGETS :=
|
||||
DOC_L10N_TARGETS :=
|
||||
|
||||
|
@ -275,3 +275,9 @@ trpl: doc/book/index.html
|
|||
doc/book/index.html: $(RUSTBOOK_EXE) $(wildcard $(S)/src/doc/trpl/*.md) | doc/
|
||||
$(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/
|
||||
$(Q)rm -rf doc/style
|
||||
$(Q)$(RUSTBOOK) build $(S)src/doc/style doc/style
|
||||
|
|
|
@ -13,8 +13,8 @@
|
|||
#![feature(box_syntax)]
|
||||
#![feature(collections)]
|
||||
#![feature(int_uint)]
|
||||
#![feature(io)]
|
||||
#![feature(path)]
|
||||
#![feature(old_io)]
|
||||
#![feature(old_path)]
|
||||
#![feature(rustc_private)]
|
||||
#![feature(unboxed_closures)]
|
||||
#![feature(std_misc)]
|
||||
|
|
|
@ -35,7 +35,7 @@ use std::env;
|
|||
use std::iter::repeat;
|
||||
use std::str;
|
||||
use std::string::String;
|
||||
use std::thread::Thread;
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
use test::MetricMap;
|
||||
|
||||
|
@ -458,7 +458,7 @@ fn run_debuginfo_gdb_test(config: &Config, props: &TestProps, testfile: &Path) {
|
|||
loop {
|
||||
//waiting 1 second for gdbserver start
|
||||
timer::sleep(Duration::milliseconds(1000));
|
||||
let result = Thread::scoped(move || {
|
||||
let result = thread::spawn(move || {
|
||||
tcp::TcpStream::connect("127.0.0.1:5039").unwrap();
|
||||
}).join();
|
||||
if result.is_err() {
|
||||
|
|
|
@ -1,61 +0,0 @@
|
|||
% How to submit a Rust bug report
|
||||
|
||||
# I think I found a bug in the compiler!
|
||||
|
||||
If you see this message: `error: internal compiler error: unexpected panic`,
|
||||
then you have definitely found a bug in the compiler. It's also possible that
|
||||
your code is not well-typed, but if you saw this message, it's still a bug in
|
||||
error reporting.
|
||||
|
||||
If you see a message about an LLVM assertion failure, then you have also
|
||||
definitely found a bug in the compiler. In both of these cases, it's not your
|
||||
fault and you should report a bug!
|
||||
|
||||
If you see a compiler error message that you think is meant for users to see,
|
||||
but it confuses you, *that's a bug too*. If it wasn't clear to you, then it's
|
||||
an error message we want to improve, so please report it so that we can try
|
||||
to make it better.
|
||||
|
||||
# How do I know the bug I found isn't a bug that already exists in the issue tracker?
|
||||
|
||||
If you don't have enough time for a search, then don't worry about that. Just submit
|
||||
the bug. If it's a duplicate, somebody will notice that and close it during triage.
|
||||
|
||||
If you have the time for it, it would be useful to type the text of the error
|
||||
message you got [into the issue tracker search box](https://github.com/rust-lang/rust/issues)
|
||||
to see if there's an existing bug that resembles your problem. If there is,
|
||||
and it's an open bug, you can comment on that issue and say you are also affected.
|
||||
This will encourage the devs to fix it. But again, don't let this stop you from
|
||||
submitting a bug. We'd rather have to do the work of closing duplicates than
|
||||
miss out on valid bug reports.
|
||||
|
||||
# What information should I include in a bug report?
|
||||
|
||||
It generally helps our diagnosis to include your specific OS (for example: Mac OS X 10.8.3,
|
||||
Windows 7, Ubuntu 12.04) and your hardware architecture (for example: i686, x86_64).
|
||||
It's also helpful to provide the exact version and host by copying the output of
|
||||
re-running the erroneous rustc command with the `--version --verbose` flags, which will
|
||||
produce something like this:
|
||||
|
||||
```text
|
||||
rustc 0.12.0 (ba4081a5a 2014-10-07 13:44:41 -0700)
|
||||
binary: rustc
|
||||
commit-hash: ba4081a5a8573875fed17545846f6f6902c8ba8d
|
||||
commit-date: 2014-10-07 13:44:41 -0700
|
||||
host: i686-apple-darwin
|
||||
release: 0.12.0
|
||||
```
|
||||
|
||||
Finally, if you can also provide a backtrace, that'd be great. You can get a
|
||||
backtrace by setting the `RUST_BACKTRACE` environment variable to `1`, like
|
||||
this:
|
||||
|
||||
```bash
|
||||
$ RUST_BACKTRACE=1 rustc ...
|
||||
```
|
||||
|
||||
# I submitted a bug, but nobody has commented on it!
|
||||
|
||||
This is sad, but does happen sometimes, since we're short-staffed. If you submit a
|
||||
bug and you haven't received a comment on it within 3 business days, it's entirely
|
||||
reasonable to ask about the status of the bug in #rust on irc.mozilla.org.
|
|
@ -2398,6 +2398,10 @@ The currently implemented features of the reference compiler are:
|
|||
ways insufficient for concatenating identifiers, and may be
|
||||
removed entirely for something more wholesome.
|
||||
|
||||
* `custom_attribute` - Allows the usage of attributes unknown to the compiler
|
||||
so that new attributes can be added in a bacwards compatible
|
||||
manner (RFC 572).
|
||||
|
||||
* `intrinsics` - Allows use of the "rust-intrinsics" ABI. Compiler intrinsics
|
||||
are inherently unstable and no promise about them is made.
|
||||
|
||||
|
@ -2458,6 +2462,9 @@ The currently implemented features of the reference compiler are:
|
|||
implemented very poorly and will likely change significantly
|
||||
with a proper implementation.
|
||||
|
||||
* `rustc_attrs` - Gates internal `#[rustc_*]` attributes which may be
|
||||
for internal use only or have meaning added to them in the future.
|
||||
|
||||
* `rustc_diagnostic_macros`- A mysterious feature, used in the implementation
|
||||
of rustc, not meant for mortals.
|
||||
|
||||
|
|
64
src/doc/style/README.md
Normal file
64
src/doc/style/README.md
Normal file
|
@ -0,0 +1,64 @@
|
|||
% Style Guidelines
|
||||
|
||||
This document collects the emerging principles, conventions, abstractions, and
|
||||
best practices for writing Rust code.
|
||||
|
||||
Since Rust is evolving at a rapid pace, these guidelines are
|
||||
preliminary. The hope is that writing them down explicitly will help
|
||||
drive discussion, consensus and adoption.
|
||||
|
||||
Whenever feasible, guidelines provide specific examples from Rust's standard
|
||||
libraries.
|
||||
|
||||
### Guideline statuses
|
||||
|
||||
Every guideline has a status:
|
||||
|
||||
* **[FIXME]**: Marks places where there is more work to be done. In
|
||||
some cases, that just means going through the RFC process.
|
||||
|
||||
* **[FIXME #NNNNN]**: Like **[FIXME]**, but links to the issue tracker.
|
||||
|
||||
* **[RFC #NNNN]**: Marks accepted guidelines, linking to the rust-lang
|
||||
RFC establishing them.
|
||||
|
||||
### Guideline stabilization
|
||||
|
||||
One purpose of these guidelines is to reach decisions on a number of
|
||||
cross-cutting API and stylistic choices. Discussion and development of
|
||||
the guidelines will happen primarily on http://discuss.rust-lang.org/,
|
||||
using the Guidelines category. Discussion can also occur on the
|
||||
[guidelines issue tracker](https://github.com/rust-lang/rust-guidelines).
|
||||
|
||||
Guidelines that are under development or discussion will be marked with the
|
||||
status **[FIXME]**, with a link to the issue tracker when appropriate.
|
||||
|
||||
Once a concrete guideline is ready to be proposed, it should be filed
|
||||
as an [FIXME: needs RFC](https://github.com/rust-lang/rfcs). If the RFC is
|
||||
accepted, the official guidelines will be updated to match, and will
|
||||
include the tag **[RFC #NNNN]** linking to the RFC document.
|
||||
|
||||
### What's in this document
|
||||
|
||||
This document is broken into four parts:
|
||||
|
||||
* **[Style](style/README.md)** provides a set of rules governing naming conventions,
|
||||
whitespace, and other stylistic issues.
|
||||
|
||||
* **[Guidelines by Rust feature](features/README.md)** places the focus on each of
|
||||
Rust's features, starting from expressions and working the way out toward
|
||||
crates, dispensing guidelines relevant to each.
|
||||
|
||||
* **Topical guidelines and patterns**. The rest of the document proceeds by
|
||||
cross-cutting topic, starting with
|
||||
[Ownership and resources](ownership/README.md).
|
||||
|
||||
* **[APIs for a changing Rust](changing/README.md)**
|
||||
discusses the forward-compatibility hazards, especially those that interact
|
||||
with the pre-1.0 library stabilization process.
|
||||
|
||||
> **[FIXME]** Add cross-references throughout this document to the tutorial,
|
||||
> reference manual, and other guides.
|
||||
|
||||
> **[FIXME]** What are some _non_-goals, _non_-principles, or _anti_-patterns that
|
||||
> we should document?
|
54
src/doc/style/SUMMARY.md
Normal file
54
src/doc/style/SUMMARY.md
Normal file
|
@ -0,0 +1,54 @@
|
|||
# Summary
|
||||
|
||||
* [Style](style/README.md)
|
||||
* [Whitespace](style/whitespace.md)
|
||||
* [Comments](style/comments.md)
|
||||
* [Braces, semicolons, commas](style/braces.md)
|
||||
* [Naming](style/naming/README.md)
|
||||
* [Ownership variants](style/naming/ownership.md)
|
||||
* [Containers/wrappers](style/naming/containers.md)
|
||||
* [Conversions](style/naming/conversions.md)
|
||||
* [Iterators](style/naming/iterators.md)
|
||||
* [Imports](style/imports.md)
|
||||
* [Organization](style/organization.md)
|
||||
* [Guidelines by Rust feature](features/README.md)
|
||||
* [Let binding](features/let.md)
|
||||
* [Pattern matching](features/match.md)
|
||||
* [Loops](features/loops.md)
|
||||
* [Functions and methods](features/functions-and-methods/README.md)
|
||||
* [Input](features/functions-and-methods/input.md)
|
||||
* [Output](features/functions-and-methods/output.md)
|
||||
* [For convenience](features/functions-and-methods/convenience.md)
|
||||
* [Types](features/types/README.md)
|
||||
* [Conversions](features/types/conversions.md)
|
||||
* [The newtype pattern](features/types/newtype.md)
|
||||
* [Traits](features/traits/README.md)
|
||||
* [For generics](features/traits/generics.md)
|
||||
* [For objects](features/traits/objects.md)
|
||||
* [For overloading](features/traits/overloading.md)
|
||||
* [For extensions](features/traits/extensions.md)
|
||||
* [For reuse](features/traits/reuse.md)
|
||||
* [Common traits](features/traits/common.md)
|
||||
* [Modules](features/modules.md)
|
||||
* [Crates](features/crates.md)
|
||||
* [Ownership and resources](ownership/README.md)
|
||||
* [Constructors](ownership/constructors.md)
|
||||
* [Builders](ownership/builders.md)
|
||||
* [Destructors](ownership/destructors.md)
|
||||
* [RAII](ownership/raii.md)
|
||||
* [Cells and smart pointers](ownership/cell-smart.md)
|
||||
* [Errors](errors/README.md)
|
||||
* [Signaling](errors/signaling.md)
|
||||
* [Handling](errors/handling.md)
|
||||
* [Propagation](errors/propagation.md)
|
||||
* [Ergonomics](errors/ergonomics.md)
|
||||
* [Safety and guarantees](safety/README.md)
|
||||
* [Using unsafe](safety/unsafe.md)
|
||||
* [Library guarantees](safety/lib-guarantees.md)
|
||||
* [Testing](testing/README.md)
|
||||
* [Unit testing](testing/unit.md)
|
||||
* [FFI, platform-specific code](platform.md)
|
||||
* [APIs for a changing Rust](changing/README.md)
|
||||
* [Pre-1.0 changes](changing/pre-1-0.md)
|
||||
* [Post-1.0 changes](changing/post-1-0.md)
|
||||
* [Timing unclear](changing/unclear.md)
|
5
src/doc/style/changing/README.md
Normal file
5
src/doc/style/changing/README.md
Normal file
|
@ -0,0 +1,5 @@
|
|||
% API design for a changing Rust
|
||||
|
||||
A number of planned Rust features will drastically affect the API design
|
||||
story. This section collects some of the biggest features with concrete examples
|
||||
of how the API will change.
|
12
src/doc/style/changing/post-1-0.md
Normal file
12
src/doc/style/changing/post-1-0.md
Normal file
|
@ -0,0 +1,12 @@
|
|||
% Post-1.0 changes
|
||||
|
||||
### Higher-kinded types
|
||||
|
||||
* A trait encompassing both `Iterable<T>` for some fixed `T` and
|
||||
`FromIterator<U>` for _all_ `U` (where HKT comes in). The train
|
||||
could provide e.g. a default `map` method producing the same kind of
|
||||
the container, but with a new type parameter.
|
||||
|
||||
* **Monadic-generic programming**? Can we add this without deprecating
|
||||
huge swaths of the API (including `Option::map`, `option::collect`,
|
||||
`result::collect`, `try!` etc.
|
17
src/doc/style/changing/pre-1-0.md
Normal file
17
src/doc/style/changing/pre-1-0.md
Normal file
|
@ -0,0 +1,17 @@
|
|||
% Pre-1.0 changes
|
||||
|
||||
### `std` facade
|
||||
|
||||
We should revisit some APIs in `libstd` now that the facade effort is complete.
|
||||
|
||||
For example, the treatment of environment variables in the new
|
||||
`Command` API is waiting on access to hashtables before being
|
||||
approved.
|
||||
|
||||
### Trait reform
|
||||
|
||||
Potential for standard conversion traits (`to`, `into`, `as`).
|
||||
|
||||
Probably many other opportunities here.
|
||||
|
||||
### Unboxed closures
|
28
src/doc/style/changing/unclear.md
Normal file
28
src/doc/style/changing/unclear.md
Normal file
|
@ -0,0 +1,28 @@
|
|||
% Changes with unclear timing
|
||||
|
||||
### Associated items
|
||||
|
||||
* Many traits that currently take type parameters should instead use associated
|
||||
types; this will _drastically_ simplify signatures in some cases.
|
||||
|
||||
* Associated constants would be useful in a few places, e.g. traits for
|
||||
numerics, traits for paths.
|
||||
|
||||
### Anonymous, unboxed return types (aka `impl Trait` types)
|
||||
|
||||
* See https://github.com/rust-lang/rfcs/pull/105
|
||||
|
||||
* Could affect API design in several places, e.g. the `Iterator` trait.
|
||||
|
||||
### Default type parameters
|
||||
|
||||
We are already using this in a few places (e.g. `HashMap`), but it's
|
||||
feature-gated.
|
||||
|
||||
### Compile-time function evaluation (CTFE)
|
||||
|
||||
https://github.com/mozilla/rust/issues/11621
|
||||
|
||||
### Improved constant folding
|
||||
|
||||
https://github.com/rust-lang/rust/issues/7834
|
3
src/doc/style/errors/README.md
Normal file
3
src/doc/style/errors/README.md
Normal file
|
@ -0,0 +1,3 @@
|
|||
% Errors
|
||||
|
||||
> **[FIXME]** Add some general text here.
|
66
src/doc/style/errors/ergonomics.md
Normal file
66
src/doc/style/errors/ergonomics.md
Normal file
|
@ -0,0 +1,66 @@
|
|||
% Ergonomic error handling
|
||||
|
||||
Error propagation with raw `Result`s can require tedious matching and
|
||||
repackaging. This tedium is largely alleviated by the `try!` macro,
|
||||
and can be completely removed (in some cases) by the "`Result`-`impl`"
|
||||
pattern.
|
||||
|
||||
### The `try!` macro
|
||||
|
||||
Prefer
|
||||
|
||||
```rust
|
||||
use std::io::{File, Open, Write, IoError};
|
||||
|
||||
struct Info {
|
||||
name: String,
|
||||
age: int,
|
||||
rating: int
|
||||
}
|
||||
|
||||
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()));
|
||||
return Ok(());
|
||||
}
|
||||
```
|
||||
|
||||
over
|
||||
|
||||
```rust
|
||||
use std::io::{File, Open, Write, IoError};
|
||||
|
||||
struct Info {
|
||||
name: String,
|
||||
age: int,
|
||||
rating: int
|
||||
}
|
||||
|
||||
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()) {
|
||||
Ok(_) => (),
|
||||
Err(e) => return Err(e)
|
||||
}
|
||||
match file.write_line(format!("age: {}", info.age).as_slice()) {
|
||||
Ok(_) => (),
|
||||
Err(e) => return Err(e)
|
||||
}
|
||||
return file.write_line(format!("rating: {}", info.rating).as_slice());
|
||||
}
|
||||
```
|
||||
|
||||
See
|
||||
[the `result` module documentation](http://static.rust-lang.org/doc/master/std/result/index.html#the-try!-macro)
|
||||
for more details.
|
||||
|
||||
### The `Result`-`impl` pattern [FIXME]
|
||||
|
||||
> **[FIXME]** Document the way that the `io` module uses trait impls
|
||||
> on `IoResult` to painlessly propagate errors.
|
7
src/doc/style/errors/handling.md
Normal file
7
src/doc/style/errors/handling.md
Normal file
|
@ -0,0 +1,7 @@
|
|||
% Handling errors
|
||||
|
||||
### Use task isolation to cope with failure. [FIXME]
|
||||
|
||||
> **[FIXME]** Explain how to isolate tasks and detect task failure for recovery.
|
||||
|
||||
### Consuming `Result` [FIXME]
|
8
src/doc/style/errors/propagation.md
Normal file
8
src/doc/style/errors/propagation.md
Normal file
|
@ -0,0 +1,8 @@
|
|||
% Propagation
|
||||
|
||||
> **[FIXME]** We need guidelines on how to layer error information up a stack of
|
||||
> abstractions.
|
||||
|
||||
### Error interoperation [FIXME]
|
||||
|
||||
> **[FIXME]** Document the `FromError` infrastructure.
|
125
src/doc/style/errors/signaling.md
Normal file
125
src/doc/style/errors/signaling.md
Normal file
|
@ -0,0 +1,125 @@
|
|||
% Signaling errors [RFC #236]
|
||||
|
||||
> The guidelines below were approved by [RFC #236](https://github.com/rust-lang/rfcs/pull/236).
|
||||
|
||||
Errors fall into one of three categories:
|
||||
|
||||
* Catastrophic errors, e.g. out-of-memory.
|
||||
* Contract violations, e.g. wrong input encoding, index out of bounds.
|
||||
* Obstructions, e.g. file not found, parse error.
|
||||
|
||||
The basic principle of the convention is that:
|
||||
|
||||
* Catastrophic errors and programming errors (bugs) can and should only be
|
||||
recovered at a *coarse grain*, i.e. a task boundary.
|
||||
* Obstructions preventing an operation should be reported at a maximally *fine
|
||||
grain* -- to the immediate invoker of the operation.
|
||||
|
||||
## Catastrophic errors
|
||||
|
||||
An error is _catastrophic_ if there is no meaningful way for the current task to
|
||||
continue after the error occurs.
|
||||
|
||||
Catastrophic errors are _extremely_ rare, especially outside of `libstd`.
|
||||
|
||||
**Canonical examples**: out of memory, stack overflow.
|
||||
|
||||
### For catastrophic errors, panic
|
||||
|
||||
For errors like stack overflow, Rust currently aborts the process, but
|
||||
could in principle panic, which (in the best case) would allow
|
||||
reporting and recovery from a supervisory task.
|
||||
|
||||
## Contract violations
|
||||
|
||||
An API may define a contract that goes beyond the type checking enforced by the
|
||||
compiler. For example, slices support an indexing operation, with the contract
|
||||
that the supplied index must be in bounds.
|
||||
|
||||
Contracts can be complex and involve more than a single function invocation. For
|
||||
example, the `RefCell` type requires that `borrow_mut` not be called until all
|
||||
existing borrows have been relinquished.
|
||||
|
||||
### For contract violations, panic
|
||||
|
||||
A contract violation is always a bug, and for bugs we follow the Erlang
|
||||
philosophy of "let it crash": we assume that software *will* have bugs, and we
|
||||
design coarse-grained task boundaries to report, and perhaps recover, from these
|
||||
bugs.
|
||||
|
||||
### Contract design
|
||||
|
||||
One subtle aspect of these guidelines is that the contract for a function is
|
||||
chosen by an API designer -- and so the designer also determines what counts as
|
||||
a violation.
|
||||
|
||||
This RFC does not attempt to give hard-and-fast rules for designing
|
||||
contracts. However, here are some rough guidelines:
|
||||
|
||||
* Prefer expressing contracts through static types whenever possible.
|
||||
|
||||
* It *must* be possible to write code that uses the API without violating the
|
||||
contract.
|
||||
|
||||
* Contracts are most justified when violations are *inarguably* bugs -- but this
|
||||
is surprisingly rare.
|
||||
|
||||
* Consider whether the API client could benefit from the contract-checking
|
||||
logic. The checks may be expensive. Or there may be useful programming
|
||||
patterns where the client does not want to check inputs before hand, but would
|
||||
rather attempt the operation and then find out whether the inputs were invalid.
|
||||
|
||||
* When a contract violation is the *only* kind of error a function may encounter
|
||||
-- i.e., there are no obstructions to its success other than "bad" inputs --
|
||||
using `Result` or `Option` instead is especially warranted. Clients can then use
|
||||
`unwrap` to assert that they have passed valid input, or re-use the error
|
||||
checking done by the API for their own purposes.
|
||||
|
||||
* When in doubt, use loose contracts and instead return a `Result` or `Option`.
|
||||
|
||||
## Obstructions
|
||||
|
||||
An operation is *obstructed* if it cannot be completed for some reason, even
|
||||
though the operation's contract has been satisfied. Obstructed operations may
|
||||
have (documented!) side effects -- they are not required to roll back after
|
||||
encountering an obstruction. However, they should leave the data structures in
|
||||
a "coherent" state (satisfying their invariants, continuing to guarantee safety,
|
||||
etc.).
|
||||
|
||||
Obstructions may involve external conditions (e.g., I/O), or they may involve
|
||||
aspects of the input that are not covered by the contract.
|
||||
|
||||
**Canonical examples**: file not found, parse error.
|
||||
|
||||
### For obstructions, use `Result`
|
||||
|
||||
The
|
||||
[`Result<T,E>` type](http://static.rust-lang.org/doc/master/std/result/index.html)
|
||||
represents either a success (yielding `T`) or failure (yielding `E`). By
|
||||
returning a `Result`, a function allows its clients to discover and react to
|
||||
obstructions in a fine-grained way.
|
||||
|
||||
#### What about `Option`?
|
||||
|
||||
The `Option` type should not be used for "obstructed" operations; it
|
||||
should only be used when a `None` return value could be considered a
|
||||
"successful" execution of the operation.
|
||||
|
||||
This is of course a somewhat subjective question, but a good litmus
|
||||
test is: would a reasonable client ever ignore the result? The
|
||||
`Result` type provides a lint that ensures the result is actually
|
||||
inspected, while `Option` does not, and this difference of behavior
|
||||
can help when deciding between the two types.
|
||||
|
||||
Another litmus test: can the operation be understood as asking a
|
||||
question (possibly with sideeffects)? Operations like `pop` on a
|
||||
vector can be viewed as asking for the contents of the first element,
|
||||
with the side effect of removing it if it exists -- with an `Option`
|
||||
return value.
|
||||
|
||||
## Do not provide both `Result` and `panic!` variants.
|
||||
|
||||
An API should not provide both `Result`-producing and `panic`king versions of an
|
||||
operation. It should provide just the `Result` version, allowing clients to use
|
||||
`try!` or `unwrap` instead as needed. This is part of the general pattern of
|
||||
cutting down on redundant variants by instead using method chaining.
|
9
src/doc/style/features/README.md
Normal file
9
src/doc/style/features/README.md
Normal file
|
@ -0,0 +1,9 @@
|
|||
% Guidelines by language feature
|
||||
|
||||
Rust provides a unique combination of language features, some new and some
|
||||
old. This section gives guidance on when and how to use Rust's features, and
|
||||
brings attention to some of the tradeoffs between different features.
|
||||
|
||||
Notably missing from this section is an in-depth discussion of Rust's pointer
|
||||
types (both built-in and in the library). The topic of pointers is discussed at
|
||||
length in a [separate section on ownership](../ownership/README.md).
|
6
src/doc/style/features/crates.md
Normal file
6
src/doc/style/features/crates.md
Normal file
|
@ -0,0 +1,6 @@
|
|||
% Crates
|
||||
|
||||
> **[FIXME]** What general guidelines should we provide for crate design?
|
||||
|
||||
> Possible topics: facades; per-crate preludes (to be imported as globs);
|
||||
> "lib.rs"
|
43
src/doc/style/features/functions-and-methods/README.md
Normal file
43
src/doc/style/features/functions-and-methods/README.md
Normal file
|
@ -0,0 +1,43 @@
|
|||
% Functions and methods
|
||||
|
||||
### Prefer methods to functions if there is a clear receiver. **[FIXME: needs RFC]**
|
||||
|
||||
Prefer
|
||||
|
||||
```rust
|
||||
impl Foo {
|
||||
pub fn frob(&self, w: widget) { ... }
|
||||
}
|
||||
```
|
||||
|
||||
over
|
||||
|
||||
```rust
|
||||
pub fn frob(foo: &Foo, w: widget) { ... }
|
||||
```
|
||||
|
||||
for any operation that is clearly associated with a particular
|
||||
type.
|
||||
|
||||
Methods have numerous advantages over functions:
|
||||
* They do not need to be imported or qualified to be used: all you
|
||||
need is a value of the appropriate type.
|
||||
* Their invocation performs autoborrowing (including mutable borrows).
|
||||
* They make it easy to answer the question "what can I do with a value
|
||||
of type `T`" (especially when using rustdoc).
|
||||
* They provide `self` notation, which is more concise and often more
|
||||
clearly conveys ownership distinctions.
|
||||
|
||||
> **[FIXME]** Revisit these guidelines with
|
||||
> [UFCS](https://github.com/nick29581/rfcs/blob/ufcs/0000-ufcs.md) and
|
||||
> conventions developing around it.
|
||||
|
||||
|
||||
|
||||
### Guidelines for inherent methods. **[FIXME]**
|
||||
|
||||
> **[FIXME]** We need guidelines for when to provide inherent methods on a type,
|
||||
> versus methods through a trait or functions.
|
||||
|
||||
> **NOTE**: Rules for method resolution around inherent methods are in flux,
|
||||
> which may impact the guidelines.
|
43
src/doc/style/features/functions-and-methods/convenience.md
Normal file
43
src/doc/style/features/functions-and-methods/convenience.md
Normal file
|
@ -0,0 +1,43 @@
|
|||
% Convenience methods
|
||||
|
||||
### Provide small, coherent sets of convenience methods. **[FIXME: needs RFC]**
|
||||
|
||||
_Convenience methods_ wrap up existing functionality in a more convenient
|
||||
way. The work done by a convenience method varies widely:
|
||||
|
||||
* _Re-providing functions as methods_. For example, the `std::path::Path` type
|
||||
provides methods like `stat` on `Path`s that simply invoke the corresponding
|
||||
function in `std::io::fs`.
|
||||
* _Skipping through conversions_. For example, the `str` type provides a
|
||||
`.len()` convenience method which is also expressible as `.as_bytes().len()`.
|
||||
Sometimes the conversion is more complex: the `str` module also provides
|
||||
`from_chars`, which encapsulates a simple use of iterators.
|
||||
* _Encapsulating common arguments_. For example, vectors of `&str`s
|
||||
provide a `connect` as well as a special case, `concat`, that is expressible
|
||||
using `connect` with a fixed separator of `""`.
|
||||
* _Providing more efficient special cases_. The `connect` and `concat` example
|
||||
also applies here: singling out `concat` as a special case allows for a more
|
||||
efficient implementation.
|
||||
|
||||
Note, however, that the `connect` method actually detects the special case
|
||||
internally and invokes `concat`. Usually, it is not necessary to add a public
|
||||
convenience method just for efficiency gains; there should also be a
|
||||
_conceptual_ reason to add it, e.g. because it is such a common special case.
|
||||
|
||||
It is tempting to add convenience methods in a one-off, haphazard way as
|
||||
common use patterns emerge. Avoid this temptation, and instead _design_ small,
|
||||
coherent sets of convenience methods that are easy to remember:
|
||||
|
||||
* _Small_: Avoid combinatorial explosions of convenience methods. For example,
|
||||
instead of adding `_str` variants of methods that provide a `str` output,
|
||||
instead ensure that the normal output type of methods is easily convertible to
|
||||
`str`.
|
||||
* _Coherent_: Look for small groups of convenience methods that make sense to
|
||||
include together. For example, the `Path` API mentioned above includes a small
|
||||
selection of the most common filesystem operations that take a `Path`
|
||||
argument. If one convenience method strongly suggests the existence of others,
|
||||
consider adding the whole group.
|
||||
* _Memorable_: It is not worth saving a few characters of typing if you have to
|
||||
look up the name of a convenience method every time you use it. Add
|
||||
convenience methods with names that are obvious and easy to remember, and add
|
||||
them for the most common or painful use cases.
|
201
src/doc/style/features/functions-and-methods/input.md
Normal file
201
src/doc/style/features/functions-and-methods/input.md
Normal file
|
@ -0,0 +1,201 @@
|
|||
% Input to functions and methods
|
||||
|
||||
### Let the client decide when to copy and where to place data. [FIXME: needs RFC]
|
||||
|
||||
#### Copying:
|
||||
|
||||
Prefer
|
||||
|
||||
```rust
|
||||
fn foo(b: Bar) {
|
||||
// use b as owned, directly
|
||||
}
|
||||
```
|
||||
|
||||
over
|
||||
|
||||
```rust
|
||||
fn foo(b: &Bar) {
|
||||
let b = b.clone();
|
||||
// use b as owned after cloning
|
||||
}
|
||||
```
|
||||
|
||||
If a function requires ownership of a value of unknown type `T`, but does not
|
||||
otherwise need to make copies, the function should take ownership of the
|
||||
argument (pass by value `T`) rather than using `.clone()`. That way, the caller
|
||||
can decide whether to relinquish ownership or to `clone`.
|
||||
|
||||
Similarly, the `Copy` trait bound should only be demanded it when absolutely
|
||||
needed, not as a way of signaling that copies should be cheap to make.
|
||||
|
||||
#### Placement:
|
||||
|
||||
Prefer
|
||||
|
||||
```rust
|
||||
fn foo(b: Bar) -> Bar { ... }
|
||||
```
|
||||
|
||||
over
|
||||
|
||||
```rust
|
||||
fn foo(b: Box<Bar>) -> Box<Bar> { ... }
|
||||
```
|
||||
|
||||
for concrete types `Bar` (as opposed to trait objects). This way, the caller can
|
||||
decide whether to place data on the stack or heap. No overhead is imposed by
|
||||
letting the caller determine the placement.
|
||||
|
||||
### Minimize assumptions about parameters. [FIXME: needs RFC]
|
||||
|
||||
The fewer assumptions a function makes about its inputs, the more widely usable
|
||||
it becomes.
|
||||
|
||||
#### Minimizing assumptions through generics:
|
||||
|
||||
Prefer
|
||||
|
||||
```rust
|
||||
fn foo<T: Iterator<int>>(c: T) { ... }
|
||||
```
|
||||
|
||||
over any of
|
||||
|
||||
```rust
|
||||
fn foo(c: &[int]) { ... }
|
||||
fn foo(c: &Vec<int>) { ... }
|
||||
fn foo(c: &SomeOtherCollection<int>) { ... }
|
||||
```
|
||||
|
||||
if the function only needs to iterate over the data.
|
||||
|
||||
More generally, consider using generics to pinpoint the assumptions a function
|
||||
needs to make about its arguments.
|
||||
|
||||
On the other hand, generics can make it more difficult to read and understand a
|
||||
function's signature. Aim for "natural" parameter types that a neither overly
|
||||
concrete nor overly abstract. See the discussion on
|
||||
[traits](../../traits/README.md) for more guidance.
|
||||
|
||||
|
||||
#### Minimizing ownership assumptions:
|
||||
|
||||
Prefer either of
|
||||
|
||||
```rust
|
||||
fn foo(b: &Bar) { ... }
|
||||
fn foo(b: &mut Bar) { ... }
|
||||
```
|
||||
|
||||
over
|
||||
|
||||
```rust
|
||||
fn foo(b: Bar) { ... }
|
||||
```
|
||||
|
||||
That is, prefer borrowing arguments rather than transferring ownership, unless
|
||||
ownership is actually needed.
|
||||
|
||||
### Prefer compound return types to out-parameters. [FIXME: needs RFC]
|
||||
|
||||
Prefer
|
||||
|
||||
```rust
|
||||
fn foo() -> (Bar, Bar)
|
||||
```
|
||||
|
||||
over
|
||||
|
||||
```rust
|
||||
fn foo(output: &mut Bar) -> Bar
|
||||
```
|
||||
|
||||
for returning multiple `Bar` values.
|
||||
|
||||
Compound return types like tuples and structs are efficiently compiled
|
||||
and do not require heap allocation. If a function needs to return
|
||||
multiple values, it should do so via one of these types.
|
||||
|
||||
The primary exception: sometimes a function is meant to modify data
|
||||
that the caller already owns, for example to re-use a buffer:
|
||||
|
||||
```rust
|
||||
fn read(&mut self, buf: &mut [u8]) -> IoResult<uint>
|
||||
```
|
||||
|
||||
(From the [Reader trait](http://static.rust-lang.org/doc/master/std/io/trait.Reader.html#tymethod.read).)
|
||||
|
||||
### Consider validating arguments, statically or dynamically. [FIXME: needs RFC]
|
||||
|
||||
_Note: this material is closely related to
|
||||
[library-level guarantees](../../safety/lib-guarantees.md)._
|
||||
|
||||
Rust APIs do _not_ generally follow the
|
||||
[robustness principle](http://en.wikipedia.org/wiki/Robustness_principle): "be
|
||||
conservative in what you send; be liberal in what you accept".
|
||||
|
||||
Instead, Rust code should _enforce_ the validity of input whenever practical.
|
||||
|
||||
Enforcement can be achieved through the following mechanisms (listed
|
||||
in order of preference).
|
||||
|
||||
#### Static enforcement:
|
||||
|
||||
Choose an argument type that rules out bad inputs.
|
||||
|
||||
For example, prefer
|
||||
|
||||
```rust
|
||||
fn foo(a: ascii::Ascii) { ... }
|
||||
```
|
||||
|
||||
over
|
||||
|
||||
```rust
|
||||
fn foo(a: u8) { ... }
|
||||
```
|
||||
|
||||
Note that
|
||||
[`ascii::Ascii`](http://static.rust-lang.org/doc/master/std/ascii/struct.Ascii.html)
|
||||
is a _wrapper_ around `u8` that guarantees the highest bit is zero; see
|
||||
[newtype patterns]() for more details on creating typesafe wrappers.
|
||||
|
||||
Static enforcement usually comes at little run-time cost: it pushes the
|
||||
costs to the boundaries (e.g. when a `u8` is first converted into an
|
||||
`Ascii`). It also catches bugs early, during compilation, rather than through
|
||||
run-time failures.
|
||||
|
||||
On the other hand, some properties are difficult or impossible to
|
||||
express using types.
|
||||
|
||||
#### Dynamic enforcement:
|
||||
|
||||
Validate the input as it is processed (or ahead of time, if necessary). Dynamic
|
||||
checking is often easier to implement than static checking, but has several
|
||||
downsides:
|
||||
|
||||
1. Runtime overhead (unless checking can be done as part of processing the input).
|
||||
2. Delayed detection of bugs.
|
||||
3. Introduces failure cases, either via `fail!` or `Result`/`Option` types (see
|
||||
the [error handling guidelines](../../errors/README.md)), which must then be
|
||||
dealt with by client code.
|
||||
|
||||
#### Dynamic enforcement with `debug_assert!`:
|
||||
|
||||
Same as dynamic enforcement, but with the possibility of easily turning off
|
||||
expensive checks for production builds.
|
||||
|
||||
#### Dynamic enforcement with opt-out:
|
||||
|
||||
Same as dynamic enforcement, but adds sibling functions that opt out of the
|
||||
checking.
|
||||
|
||||
The convention is to mark these opt-out functions with a suffix like
|
||||
`_unchecked` or by placing them in a `raw` submodule.
|
||||
|
||||
The unchecked functions can be used judiciously in cases where (1) performance
|
||||
dictates avoiding checks and (2) the client is otherwise confident that the
|
||||
inputs are valid.
|
||||
|
||||
> **[FIXME]** Should opt-out functions be marked `unsafe`?
|
56
src/doc/style/features/functions-and-methods/output.md
Normal file
56
src/doc/style/features/functions-and-methods/output.md
Normal file
|
@ -0,0 +1,56 @@
|
|||
% Output from functions and methods
|
||||
|
||||
### Don't overpromise. [FIXME]
|
||||
|
||||
> **[FIXME]** Add discussion of overly-specific return types,
|
||||
> e.g. returning a compound iterator type rather than hiding it behind
|
||||
> a use of newtype.
|
||||
|
||||
### Let clients choose what to throw away. [FIXME: needs RFC]
|
||||
|
||||
#### Return useful intermediate results:
|
||||
|
||||
Many functions that answer a question also compute interesting related data. If
|
||||
this data is potentially of interest to the client, consider exposing it in the
|
||||
API.
|
||||
|
||||
Prefer
|
||||
|
||||
```rust
|
||||
struct SearchResult {
|
||||
found: bool, // item in container?
|
||||
expected_index: uint // what would the item's index be?
|
||||
}
|
||||
|
||||
fn binary_search(&self, k: Key) -> SearchResult
|
||||
```
|
||||
or
|
||||
|
||||
```rust
|
||||
fn binary_search(&self, k: Key) -> (bool, uint)
|
||||
```
|
||||
|
||||
over
|
||||
|
||||
```rust
|
||||
fn binary_search(&self, k: Key) -> bool
|
||||
```
|
||||
|
||||
#### Yield back ownership:
|
||||
|
||||
Prefer
|
||||
|
||||
```rust
|
||||
fn from_utf8_owned(vv: Vec<u8>) -> Result<String, Vec<u8>>
|
||||
```
|
||||
|
||||
over
|
||||
|
||||
```rust
|
||||
fn from_utf8_owned(vv: Vec<u8>) -> Option<String>
|
||||
```
|
||||
|
||||
The `from_utf8_owned` function gains ownership of a vector. In the successful
|
||||
case, the function consumes its input, returning an owned string without
|
||||
allocating or copying. In the unsuccessful case, however, the function returns
|
||||
back ownership of the original slice.
|
103
src/doc/style/features/let.md
Normal file
103
src/doc/style/features/let.md
Normal file
|
@ -0,0 +1,103 @@
|
|||
% Let binding
|
||||
|
||||
### Always separately bind RAII guards. [FIXME: needs RFC]
|
||||
|
||||
Prefer
|
||||
|
||||
```rust
|
||||
fn use_mutex(m: sync::mutex::Mutex<int>) {
|
||||
let guard = m.lock();
|
||||
do_work(guard);
|
||||
drop(guard); // unlock the lock
|
||||
// do other work
|
||||
}
|
||||
```
|
||||
|
||||
over
|
||||
|
||||
```rust
|
||||
fn use_mutex(m: sync::mutex::Mutex<int>) {
|
||||
do_work(m.lock());
|
||||
// do other work
|
||||
}
|
||||
```
|
||||
|
||||
As explained in the [RAII guide](../ownership/raii.md), RAII guards are values
|
||||
that represent ownership of some resource and whose destructor releases the
|
||||
resource. Because the lifetime of guards are significant, they should always be
|
||||
explicitly `let`-bound to make the lifetime clear. Consider using an explicit
|
||||
`drop` to release the resource early.
|
||||
|
||||
### Prefer conditional expressions to deferred initialization. [FIXME: needs RFC]
|
||||
|
||||
Prefer
|
||||
|
||||
```rust
|
||||
let foo = match bar {
|
||||
Baz => 0,
|
||||
Quux => 1
|
||||
};
|
||||
```
|
||||
|
||||
over
|
||||
|
||||
```rust
|
||||
let foo;
|
||||
match bar {
|
||||
Baz => {
|
||||
foo = 0;
|
||||
}
|
||||
Quux => {
|
||||
foo = 1;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
unless the conditions for initialization are too complex to fit into a simple
|
||||
conditional expression.
|
||||
|
||||
### Use type annotations for clarification; prefer explicit generics when inference fails. [FIXME: needs RFC]
|
||||
|
||||
Prefer
|
||||
|
||||
```rust
|
||||
s.iter().map(|x| x * 2)
|
||||
.collect::<Vec<_>>()
|
||||
```
|
||||
|
||||
over
|
||||
|
||||
```rust
|
||||
let v: Vec<_> = s.iter().map(|x| x * 2)
|
||||
.collect();
|
||||
```
|
||||
|
||||
When the type of a value might be unclear to the _reader_ of the code, consider
|
||||
explicitly annotating it in a `let`.
|
||||
|
||||
On the other hand, when the type is unclear to the _compiler_, prefer to specify
|
||||
the type by explicit generics instantiation, which is usually more clear.
|
||||
|
||||
### Shadowing [FIXME]
|
||||
|
||||
> **[FIXME]** Repeatedly shadowing a binding is somewhat common in Rust code. We
|
||||
> need to articulate a guideline on when it is appropriate/useful and when not.
|
||||
|
||||
### Prefer immutable bindings. [FIXME: needs RFC]
|
||||
|
||||
Use `mut` bindings to signal the span during which a value is mutated:
|
||||
|
||||
```rust
|
||||
let mut v = Vec::new();
|
||||
// push things onto v
|
||||
let v = v;
|
||||
// use v immutably henceforth
|
||||
```
|
||||
|
||||
### Prefer to bind all `struct` or tuple fields. [FIXME: needs RFC]
|
||||
|
||||
When consuming a `struct` or tuple via a `let`, bind all of the fields rather
|
||||
than using `..` to elide the ones you don't need. The benefit is that when
|
||||
fields are added, the compiler will pinpoint all of the places where that type
|
||||
of value was consumed, which will often need to be adjusted to take the new
|
||||
field properly into account.
|
13
src/doc/style/features/loops.md
Normal file
13
src/doc/style/features/loops.md
Normal file
|
@ -0,0 +1,13 @@
|
|||
% Loops
|
||||
|
||||
### Prefer `for` to `while`. [FIXME: needs RFC]
|
||||
|
||||
A `for` loop is preferable to a `while` loop, unless the loop counts in a
|
||||
non-uniform way (making it difficult to express using `for`).
|
||||
|
||||
### Guidelines for `loop`. [FIXME]
|
||||
|
||||
> **[FIXME]** When is `loop` recommended? Some possibilities:
|
||||
> * For optimistic retry algorithms
|
||||
> * For servers
|
||||
> * To avoid mutating local variables sometimes needed to fit `while`
|
26
src/doc/style/features/match.md
Normal file
26
src/doc/style/features/match.md
Normal file
|
@ -0,0 +1,26 @@
|
|||
% Pattern matching
|
||||
|
||||
### Dereference `match` targets when possible. [FIXME: needs RFC]
|
||||
|
||||
Prefer
|
||||
|
||||
~~~~
|
||||
match *foo {
|
||||
X(...) => ...
|
||||
Y(...) => ...
|
||||
}
|
||||
~~~~
|
||||
|
||||
over
|
||||
|
||||
~~~~
|
||||
match foo {
|
||||
box X(...) => ...
|
||||
box Y(...) => ...
|
||||
}
|
||||
~~~~
|
||||
|
||||
<!-- ### Clearly indicate important scopes. **[FIXME: needs RFC]** -->
|
||||
|
||||
<!-- If it is important that the destructor for a value be executed at a specific -->
|
||||
<!-- time, clearly bind that value using a standalone `let` -->
|
133
src/doc/style/features/modules.md
Normal file
133
src/doc/style/features/modules.md
Normal file
|
@ -0,0 +1,133 @@
|
|||
% Modules
|
||||
|
||||
> **[FIXME]** What general guidelines should we provide for module design?
|
||||
|
||||
> We should discuss visibility, nesting, `mod.rs`, and any interesting patterns
|
||||
> around modules.
|
||||
|
||||
### Headers [FIXME: needs RFC]
|
||||
|
||||
Organize module headers as follows:
|
||||
1. [Imports](../style/imports.md).
|
||||
1. `mod` declarations.
|
||||
1. `pub mod` declarations.
|
||||
|
||||
### Avoid `path` directives. [FIXME: needs RFC]
|
||||
|
||||
Avoid using `#[path="..."]` directives; make the file system and
|
||||
module hierarchy match, instead.
|
||||
|
||||
### Use the module hirearchy to organize APIs into coherent sections. [FIXME]
|
||||
|
||||
> **[FIXME]** Flesh this out with examples; explain what a "coherent
|
||||
> section" is with examples.
|
||||
>
|
||||
> The module hirearchy defines both the public and internal API of your module.
|
||||
> Breaking related functionality into submodules makes it understandable to both
|
||||
> users and contributors to the module.
|
||||
|
||||
### Place modules in their own file. [FIXME: needs RFC]
|
||||
|
||||
> **[FIXME]**
|
||||
> - "<100 lines" is arbitrary, but it's a clearer recommendation
|
||||
> than "~1 page" or similar suggestions that vary by screen size, etc.
|
||||
|
||||
For all except very short modules (<100 lines) and [tests](../testing/README.md),
|
||||
place the module `foo` in a separate file, as in:
|
||||
|
||||
```rust
|
||||
pub mod foo;
|
||||
|
||||
// in foo.rs or foo/mod.rs
|
||||
pub fn bar() { println!("..."); }
|
||||
/* ... */
|
||||
```
|
||||
|
||||
rather than declaring it inline:
|
||||
|
||||
```rust
|
||||
pub mod foo {
|
||||
pub fn bar() { println!("..."); }
|
||||
/* ... */
|
||||
}
|
||||
```
|
||||
|
||||
#### Use subdirectories for modules with children. [FIXME: needs RFC]
|
||||
|
||||
For modules that themselves have submodules, place the module in a separate
|
||||
directory (e.g., `bar/mod.rs` for a module `bar`) rather than the same directory.
|
||||
|
||||
Note the structure of
|
||||
[`std::io`](http://doc.rust-lang.org/std/io/). Many of the submodules lack
|
||||
children, like
|
||||
[`io::fs`](http://doc.rust-lang.org/std/io/fs/)
|
||||
and
|
||||
[`io::stdio`](http://doc.rust-lang.org/std/io/stdio/).
|
||||
On the other hand,
|
||||
[`io::net`](http://doc.rust-lang.org/std/io/net/)
|
||||
contains submodules, so it lives in a separate directory:
|
||||
|
||||
```
|
||||
io/mod.rs
|
||||
io/extensions.rs
|
||||
io/fs.rs
|
||||
io/net/mod.rs
|
||||
io/net/addrinfo.rs
|
||||
io/net/ip.rs
|
||||
io/net/tcp.rs
|
||||
io/net/udp.rs
|
||||
io/net/unix.rs
|
||||
io/pipe.rs
|
||||
...
|
||||
```
|
||||
|
||||
While it is possible to define all of `io` within a single directory,
|
||||
mirroring the module hirearchy in the directory structure makes
|
||||
submodules of `io::net` easier to find.
|
||||
|
||||
### Consider top-level definitions or reexports. [FIXME: needs RFC]
|
||||
|
||||
For modules with submodules,
|
||||
define or [reexport](http://doc.rust-lang.org/std/io/#reexports) commonly used
|
||||
definitions at the top level:
|
||||
|
||||
* Functionality relevant to the module itself or to many of its
|
||||
children should be defined in `mod.rs`.
|
||||
* Functionality specific to a submodule should live in that
|
||||
submodule. Reexport at the top level for the most important or
|
||||
common definitions.
|
||||
|
||||
For example,
|
||||
[`IoError`](http://doc.rust-lang.org/std/io/struct.IoError.html)
|
||||
is defined in `io/mod.rs`, since it pertains to the entirety of `io`,
|
||||
while
|
||||
[`TcpStream`](http://doc.rust-lang.org/std/io/net/tcp/struct.TcpStream.html)
|
||||
is defined in `io/net/tcp.rs` and reexported in the `io` module.
|
||||
|
||||
### Use internal module hirearchies for organization. [FIXME: needs RFC]
|
||||
|
||||
> **[FIXME]**
|
||||
> - Referencing internal modules from the standard library is subject to
|
||||
> becoming outdated.
|
||||
|
||||
Internal module hirearchies (i.e., private submodules) may be used to
|
||||
hide implementation details that are not part of the module's API.
|
||||
|
||||
For example, in [`std::io`](http://doc.rust-lang.org/std/io/), `mod mem`
|
||||
provides implementations for
|
||||
[`BufReader`](http://doc.rust-lang.org/std/io/struct.BufReader.html)
|
||||
and
|
||||
[`BufWriter`](http://doc.rust-lang.org/std/io/struct.BufWriter.html),
|
||||
but these are re-exported in `io/mod.rs` at the top level of the module:
|
||||
|
||||
```rust
|
||||
// libstd/io/mod.rs
|
||||
|
||||
pub use self::mem::{MemReader, BufReader, MemWriter, BufWriter};
|
||||
/* ... */
|
||||
mod mem;
|
||||
```
|
||||
|
||||
This hides the detail that there even exists a `mod mem` in `io`, and
|
||||
helps keep code organized while offering freedom to change the
|
||||
implementation.
|
22
src/doc/style/features/traits/README.md
Normal file
22
src/doc/style/features/traits/README.md
Normal file
|
@ -0,0 +1,22 @@
|
|||
% Traits
|
||||
|
||||
Traits are probably Rust's most complex feature, supporting a wide range of use
|
||||
cases and design tradeoffs. Patterns of trait usage are still emerging.
|
||||
|
||||
### Know whether a trait will be used as an object. [FIXME: needs RFC]
|
||||
|
||||
Trait objects have some [significant limitations](objects.md): methods
|
||||
invoked through a trait object cannot use generics, and cannot use
|
||||
`Self` except in receiver position.
|
||||
|
||||
When designing a trait, decide early on whether the trait will be used
|
||||
as an [object](objects.md) or as a [bound on generics](generics.md);
|
||||
the tradeoffs are discussed in each of the linked sections.
|
||||
|
||||
If a trait is meant to be used as an object, its methods should take
|
||||
and return trait objects rather than use generics.
|
||||
|
||||
|
||||
### Default methods [FIXME]
|
||||
|
||||
> **[FIXME]** Guidelines for default methods.
|
71
src/doc/style/features/traits/common.md
Normal file
71
src/doc/style/features/traits/common.md
Normal file
|
@ -0,0 +1,71 @@
|
|||
% Common traits
|
||||
|
||||
### Eagerly implement common traits. [FIXME: needs RFC]
|
||||
|
||||
Rust's trait system does not allow _orphans_: roughly, every `impl` must live
|
||||
either in the crate that defines the trait or the implementing
|
||||
type. Consequently, crates that define new types should eagerly implement all
|
||||
applicable, common traits.
|
||||
|
||||
To see why, consider the following situation:
|
||||
|
||||
* Crate `std` defines trait `Show`.
|
||||
* Crate `url` defines type `Url`, without implementing `Show`.
|
||||
* Crate `webapp` imports from both `std` and `url`,
|
||||
|
||||
There is no way for `webapp` to add `Show` to `url`, since it defines neither.
|
||||
(Note: the newtype pattern can provide an efficient, but inconvenient
|
||||
workaround; see [newtype for views](../types/newtype.md))
|
||||
|
||||
The most important common traits to implement from `std` are:
|
||||
|
||||
```rust
|
||||
Clone, Show, Hash, Eq
|
||||
```
|
||||
|
||||
#### When safe, derive or otherwise implement `Send` and `Share`. [FIXME]
|
||||
|
||||
> **[FIXME]**. This guideline is in flux while the "opt-in" nature of
|
||||
> built-in traits is being decided. See https://github.com/rust-lang/rfcs/pull/127
|
||||
|
||||
### Prefer to derive, rather than implement. [FIXME: needs RFC]
|
||||
|
||||
Deriving saves implementation effort, makes correctness trivial, and
|
||||
automatically adapts to upstream changes.
|
||||
|
||||
### Do not overload operators in surprising ways. [FIXME: needs RFC]
|
||||
|
||||
Operators with built in syntax (`*`, `|`, and so on) can be provided for a type
|
||||
by implementing the traits in `core::ops`. These operators come with strong
|
||||
expectations: implement `Mul` only for an operation that bears some resemblance
|
||||
to multiplication (and shares the expected properties, e.g. associativity), and
|
||||
so on for the other traits.
|
||||
|
||||
### The `Drop` trait
|
||||
|
||||
The `Drop` trait is treated specially by the compiler as a way of
|
||||
associating destructors with types. See
|
||||
[the section on destructors](../../ownership/destructors.md) for
|
||||
guidance.
|
||||
|
||||
### The `Deref`/`DerefMut` traits
|
||||
|
||||
#### Use `Deref`/`DerefMut` only for smart pointers. [FIXME: needs RFC]
|
||||
|
||||
The `Deref` traits are used implicitly by the compiler in many circumstances,
|
||||
and interact with method resolution. The relevant rules are designed
|
||||
specifically to accommodate smart pointers, and so the traits should be used
|
||||
only for that purpose.
|
||||
|
||||
#### Do not fail within a `Deref`/`DerefMut` implementation. [FIXME: needs RFC]
|
||||
|
||||
Because the `Deref` traits are invoked implicitly by the compiler in sometimes
|
||||
subtle ways, failure during dereferencing can be extremely confusing. If a
|
||||
dereference might not succeed, target the `Deref` trait as a `Result` or
|
||||
`Option` type instead.
|
||||
|
||||
#### Avoid inherent methods when implementing `Deref`/`DerefMut` [FIXME: needs RFC]
|
||||
|
||||
The rules around method resolution and `Deref` are in flux, but inherent methods
|
||||
on a type implementing `Deref` are likely to shadow any methods of the referent
|
||||
with the same name.
|
7
src/doc/style/features/traits/extensions.md
Normal file
7
src/doc/style/features/traits/extensions.md
Normal file
|
@ -0,0 +1,7 @@
|
|||
% Using traits to add extension methods
|
||||
|
||||
> **[FIXME]** Elaborate.
|
||||
|
||||
### Consider using default methods rather than extension traits **[FIXME]**
|
||||
|
||||
> **[FIXME]** Elaborate.
|
68
src/doc/style/features/traits/generics.md
Normal file
68
src/doc/style/features/traits/generics.md
Normal file
|
@ -0,0 +1,68 @@
|
|||
% Using traits for bounds on generics
|
||||
|
||||
The most widespread use of traits is for writing generic functions or types. For
|
||||
example, the following signature describes a function for consuming any iterator
|
||||
yielding items of type `A` to produce a collection of `A`:
|
||||
|
||||
```rust
|
||||
fn from_iter<T: Iterator<A>>(iterator: T) -> SomeCollection<A>
|
||||
```
|
||||
|
||||
Here, the `Iterator` trait is specifies an interface that a type `T` must
|
||||
explicitly implement to be used by this generic function.
|
||||
|
||||
**Pros**:
|
||||
|
||||
* _Reusability_. Generic functions can be applied to an open-ended collection of
|
||||
types, while giving a clear contract for the functionality those types must
|
||||
provide.
|
||||
* _Static dispatch and optimization_. Each use of a generic function is
|
||||
specialized ("monomorphized") to the particular types implementing the trait
|
||||
bounds, which means that (1) invocations of trait methods are static, direct
|
||||
calls to the implementation and (2) the compiler can inline and otherwise
|
||||
optimize these calls.
|
||||
* _Inline layout_. If a `struct` and `enum` type is generic over some type
|
||||
parameter `T`, values of type `T` will be laid out _inline_ in the
|
||||
`struct`/`enum`, without any indirection.
|
||||
* _Inference_. Since the type parameters to generic functions can usually be
|
||||
inferred, generic functions can help cut down on verbosity in code where
|
||||
explicit conversions or other method calls would usually be necessary. See the
|
||||
[overloading/implicits use case](#use-case:-limited-overloading-and/or-implicit-conversions)
|
||||
below.
|
||||
* _Precise types_. Because generic give a _name_ to the specific type
|
||||
implementing a trait, it is possible to be precise about places where that
|
||||
exact type is required or produced. For example, a function
|
||||
|
||||
```rust
|
||||
fn binary<T: Trait>(x: T, y: T) -> T
|
||||
```
|
||||
|
||||
is guaranteed to consume and produce elements of exactly the same type `T`; it
|
||||
cannot be invoked with parameters of different types that both implement
|
||||
`Trait`.
|
||||
|
||||
**Cons**:
|
||||
|
||||
* _Code size_. Specializing generic functions means that the function body is
|
||||
duplicated. The increase in code size must be weighed against the performance
|
||||
benefits of static dispatch.
|
||||
* _Homogeneous types_. This is the other side of the "precise types" coin: if
|
||||
`T` is a type parameter, it stands for a _single_ actual type. So for example
|
||||
a `Vec<T>` contains elements of a single concrete type (and, indeed, the
|
||||
vector representation is specialized to lay these out in line). Sometimes
|
||||
heterogeneous collections are useful; see
|
||||
[trait objects](#use-case:-trait-objects) below.
|
||||
* _Signature verbosity_. Heavy use of generics can bloat function signatures.
|
||||
**[Ed. note]** This problem may be mitigated by some language improvements; stay tuned.
|
||||
|
||||
### Favor widespread traits. **[FIXME: needs RFC]**
|
||||
|
||||
Generic types are a form of abstraction, which entails a mental indirection: if
|
||||
a function takes an argument of type `T` bounded by `Trait`, clients must first
|
||||
think about the concrete types that implement `Trait` to understand how and when
|
||||
the function is callable.
|
||||
|
||||
To keep the cost of abstraction low, favor widely-known traits. Whenever
|
||||
possible, implement and use traits provided as part of the standard library. Do
|
||||
not introduce new traits for generics lightly; wait until there are a wide range
|
||||
of types that can implement the type.
|
49
src/doc/style/features/traits/objects.md
Normal file
49
src/doc/style/features/traits/objects.md
Normal file
|
@ -0,0 +1,49 @@
|
|||
% Using trait objects
|
||||
|
||||
> **[FIXME]** What are uses of trait objects other than heterogeneous collections?
|
||||
|
||||
Trait objects are useful primarily when _heterogeneous_ collections of objects
|
||||
need to be treated uniformly; it is the closest that Rust comes to
|
||||
object-oriented programming.
|
||||
|
||||
```rust
|
||||
struct Frame { ... }
|
||||
struct Button { ... }
|
||||
struct Label { ... }
|
||||
|
||||
trait Widget { ... }
|
||||
|
||||
impl Widget for Frame { ... }
|
||||
impl Widget for Button { ... }
|
||||
impl Widget for Label { ... }
|
||||
|
||||
impl Frame {
|
||||
fn new(contents: &[Box<Widget>]) -> Frame {
|
||||
...
|
||||
}
|
||||
}
|
||||
|
||||
fn make_gui() -> Box<Widget> {
|
||||
let b: Box<Widget> = box Button::new(...);
|
||||
let l: Box<Widget> = box Label::new(...);
|
||||
|
||||
box Frame::new([b, l]) as Box<Widget>
|
||||
}
|
||||
```
|
||||
|
||||
By using trait objects, we can set up a GUI framework with a `Frame` widget that
|
||||
contains a heterogeneous collection of children widgets.
|
||||
|
||||
**Pros**:
|
||||
|
||||
* _Heterogeneity_. When you need it, you really need it.
|
||||
* _Code size_. Unlike generics, trait objects do not generate specialized
|
||||
(monomorphized) versions of code, which can greatly reduce code size.
|
||||
|
||||
**Cons**:
|
||||
|
||||
* _No generic methods_. Trait objects cannot currently provide generic methods.
|
||||
* _Dynamic dispatch and fat pointers_. Trait objects inherently involve
|
||||
indirection and vtable dispatch, which can carry a performance penalty.
|
||||
* _No Self_. Except for the method receiver argument, methods on trait objects
|
||||
cannot use the `Self` type.
|
7
src/doc/style/features/traits/overloading.md
Normal file
7
src/doc/style/features/traits/overloading.md
Normal file
|
@ -0,0 +1,7 @@
|
|||
% Using traits for overloading
|
||||
|
||||
> **[FIXME]** Elaborate.
|
||||
|
||||
> **[FIXME]** We need to decide on guidelines for this use case. There are a few
|
||||
> patterns emerging in current Rust code, but it's not clear how widespread they
|
||||
> should be.
|
30
src/doc/style/features/traits/reuse.md
Normal file
30
src/doc/style/features/traits/reuse.md
Normal file
|
@ -0,0 +1,30 @@
|
|||
% Using traits to share implementations
|
||||
|
||||
> **[FIXME]** Elaborate.
|
||||
|
||||
> **[FIXME]** We probably want to discourage this, at least when used in a way
|
||||
> that is publicly exposed.
|
||||
|
||||
Traits that provide default implmentations for function can provide code reuse
|
||||
across types. For example, a `print` method can be defined across multiple
|
||||
types as follows:
|
||||
|
||||
``` Rust
|
||||
trait Printable {
|
||||
// Default method implementation
|
||||
fn print(&self) { println!("{:?}", *self) }
|
||||
}
|
||||
|
||||
impl Printable for int {}
|
||||
|
||||
impl Printable for String {
|
||||
fn print(&self) { println!("{}", *self) }
|
||||
}
|
||||
|
||||
impl Printable for bool {}
|
||||
|
||||
impl Printable for f32 {}
|
||||
```
|
||||
|
||||
This allows the implementation of `print` to be shared across types, yet
|
||||
overridden where needed, as seen in the `impl` for `String`.
|
68
src/doc/style/features/types/README.md
Normal file
68
src/doc/style/features/types/README.md
Normal file
|
@ -0,0 +1,68 @@
|
|||
% Data types
|
||||
|
||||
### Use custom types to imbue meaning; do not abuse `bool`, `Option` or other core types. **[FIXME: needs RFC]**
|
||||
|
||||
Prefer
|
||||
|
||||
```rust
|
||||
let w = Widget::new(Small, Round)
|
||||
```
|
||||
|
||||
over
|
||||
|
||||
```rust
|
||||
let w = Widget::new(true, false)
|
||||
```
|
||||
|
||||
Core types like `bool`, `u8` and `Option` have many possible interpretations.
|
||||
|
||||
Use custom types (whether `enum`s, `struct`, or tuples) to convey
|
||||
interpretation and invariants. In the above example,
|
||||
it is not immediately clear what `true` and `false` are conveying without
|
||||
looking up the argument names, but `Small` and `Round` are more suggestive.
|
||||
|
||||
Using custom types makes it easier to expand the
|
||||
options later on, for example by adding an `ExtraLarge` variant.
|
||||
|
||||
See [the newtype pattern](newtype.md) for a no-cost way to wrap
|
||||
existing types with a distinguished name.
|
||||
|
||||
### Prefer private fields, except for passive data. **[FIXME: needs RFC]**
|
||||
|
||||
Making a field public is a strong commitment: it pins down a representation
|
||||
choice, _and_ prevents the type from providing any validation or maintaining any
|
||||
invariants on the contents of the field, since clients can mutate it arbitrarily.
|
||||
|
||||
Public fields are most appropriate for `struct` types in the C spirit: compound,
|
||||
passive data structures. Otherwise, consider providing getter/setter methods
|
||||
and hiding fields instead.
|
||||
|
||||
> **[FIXME]** Cross-reference validation for function arguments.
|
||||
|
||||
### Use custom `enum`s for alternatives, `bitflags` for C-style flags. **[FIXME: needs RFC]**
|
||||
|
||||
Rust supports `enum` types with "custom discriminants":
|
||||
|
||||
~~~~
|
||||
enum Color {
|
||||
Red = 0xff0000,
|
||||
Green = 0x00ff00,
|
||||
Blue = 0x0000ff
|
||||
}
|
||||
~~~~
|
||||
|
||||
Custom discriminants are useful when an `enum` type needs to be serialized to an
|
||||
integer value compatibly with some other system/language. They support
|
||||
"typesafe" APIs: by taking a `Color`, rather than an integer, a function is
|
||||
guaranteed to get well-formed inputs, even if it later views those inputs as
|
||||
integers.
|
||||
|
||||
An `enum` allows an API to request exactly one choice from among many. Sometimes
|
||||
an API's input is instead the presence or absence of a set of flags. In C code,
|
||||
this is often done by having each flag correspond to a particular bit, allowing
|
||||
a single integer to represent, say, 32 or 64 flags. Rust's `std::bitflags`
|
||||
module provides a typesafe way for doing so.
|
||||
|
||||
### Phantom types. [FIXME]
|
||||
|
||||
> **[FIXME]** Add some material on phantom types (https://blog.mozilla.org/research/2014/06/23/static-checking-of-units-in-servo/)
|
22
src/doc/style/features/types/conversions.md
Normal file
22
src/doc/style/features/types/conversions.md
Normal file
|
@ -0,0 +1,22 @@
|
|||
% Conversions between types
|
||||
|
||||
### Associate conversions with the most specific type involved. **[FIXME: needs RFC]**
|
||||
|
||||
When in doubt, prefer `to_`/`as_`/`into_` to `from_`, because they are
|
||||
more ergonomic to use (and can be chained with other methods).
|
||||
|
||||
For many conversions between two types, one of the types is clearly more
|
||||
"specific": it provides some additional invariant or interpretation that is not
|
||||
present in the other type. For example, `str` is more specific than `&[u8]`,
|
||||
since it is a utf-8 encoded sequence of bytes.
|
||||
|
||||
Conversions should live with the more specific of the involved types. Thus,
|
||||
`str` provides both the `as_bytes` method and the `from_utf8` constructor for
|
||||
converting to and from `&[u8]` values. Besides being intuitive, this convention
|
||||
avoids polluting concrete types like `&[u8]` with endless conversion methods.
|
||||
|
||||
### Explicitly mark lossy conversions, or do not label them as conversions. **[FIXME: needs RFC]**
|
||||
|
||||
If a function's name implies that it is a conversion (prefix `from_`, `as_`,
|
||||
`to_` or `into_`), but the function loses information, add a suffix `_lossy` or
|
||||
otherwise indicate the lossyness. Consider avoiding the conversion name prefix.
|
69
src/doc/style/features/types/newtype.md
Normal file
69
src/doc/style/features/types/newtype.md
Normal file
|
@ -0,0 +1,69 @@
|
|||
% The newtype pattern
|
||||
|
||||
A "newtype" is a tuple or `struct` with a single field. The terminology is borrowed from Haskell.
|
||||
|
||||
Newtypes are a zero-cost abstraction: they introduce a new, distinct name for an
|
||||
existing type, with no runtime overhead when converting between the two types.
|
||||
|
||||
### Use newtypes to provide static distinctions. [FIXME: needs RFC]
|
||||
|
||||
Newtypes can statically distinguish between different interpretations of an
|
||||
underlying type.
|
||||
|
||||
For example, a `f64` value might be used to represent a quantity in miles or in
|
||||
kilometers. Using newtypes, we can keep track of the intended interpretation:
|
||||
|
||||
```rust
|
||||
struct Miles(pub f64);
|
||||
struct Kilometers(pub f64);
|
||||
|
||||
impl Miles {
|
||||
fn as_kilometers(&self) -> Kilometers { ... }
|
||||
}
|
||||
impl Kilometers {
|
||||
fn as_miles(&self) -> Miles { ... }
|
||||
}
|
||||
```
|
||||
|
||||
Once we have separated these two types, we can statically ensure that we do not
|
||||
confuse them. For example, the function
|
||||
|
||||
```rust
|
||||
fn are_we_there_yet(distance_travelled: Miles) -> bool { ... }
|
||||
```
|
||||
|
||||
cannot accidentally be called with a `Kilometers` value. The compiler will
|
||||
remind us to perform the conversion, thus averting certain
|
||||
[catastrophic bugs](http://en.wikipedia.org/wiki/Mars_Climate_Orbiter).
|
||||
|
||||
### Use newtypes with private fields for hiding. [FIXME: needs RFC]
|
||||
|
||||
A newtype can be used to hide representation details while making precise
|
||||
promises to the client.
|
||||
|
||||
For example, consider a function `my_transform` that returns a compound iterator
|
||||
type `Enumerate<Skip<vec::MoveItems<T>>>`. We wish to hide this type from the
|
||||
client, so that the client's view of the return type is roughly `Iterator<(uint,
|
||||
T)>`. We can do so using the newtype pattern:
|
||||
|
||||
```rust
|
||||
struct MyTransformResult<T>(Enumerate<Skip<vec::MoveItems<T>>>);
|
||||
impl<T> Iterator<(uint, T)> for MyTransformResult<T> { ... }
|
||||
|
||||
fn my_transform<T, Iter: Iterator<T>>(iter: Iter) -> MyTransformResult<T> {
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
Aside from simplifying the signature, this use of newtypes allows us to make a
|
||||
expose and promise less to the client. The client does not know _how_ the result
|
||||
iterator is constructed or represented, which means the representation can
|
||||
change in the future without breaking client code.
|
||||
|
||||
> **[FIXME]** Interaction with auto-deref.
|
||||
|
||||
### Use newtypes to provide cost-free _views_ of another type. **[FIXME]**
|
||||
|
||||
> **[FIXME]** Describe the pattern of using newtypes to provide a new set of
|
||||
> inherent or trait methods, providing a different perspective on the underlying
|
||||
> type.
|
3
src/doc/style/ownership/README.md
Normal file
3
src/doc/style/ownership/README.md
Normal file
|
@ -0,0 +1,3 @@
|
|||
% Ownership and resource management
|
||||
|
||||
> **[FIXME]** Add general remarks about ownership/resources here.
|
176
src/doc/style/ownership/builders.md
Normal file
176
src/doc/style/ownership/builders.md
Normal file
|
@ -0,0 +1,176 @@
|
|||
% The builder pattern
|
||||
|
||||
Some data structures are complicated to construct, due to their construction needing:
|
||||
|
||||
* a large number of inputs
|
||||
* compound data (e.g. slices)
|
||||
* optional configuration data
|
||||
* choice between several flavors
|
||||
|
||||
which can easily lead to a large number of distinct constructors with
|
||||
many arguments each.
|
||||
|
||||
If `T` is such a data structure, consider introducing a `T` _builder_:
|
||||
|
||||
1. Introduce a separate data type `TBuilder` for incrementally configuring a `T`
|
||||
value. When possible, choose a better name: e.g. `Command` is the builder for
|
||||
`Process`.
|
||||
2. The builder constructor should take as parameters only the data _required_ to
|
||||
to make a `T`.
|
||||
3. The builder should offer a suite of convenient methods for configuration,
|
||||
including setting up compound inputs (like slices) incrementally.
|
||||
These methods should return `self` to allow chaining.
|
||||
4. The builder should provide one or more "_terminal_" methods for actually building a `T`.
|
||||
|
||||
The builder pattern is especially appropriate when building a `T` involves side
|
||||
effects, such as spawning a task or launching a process.
|
||||
|
||||
In Rust, there are two variants of the builder pattern, differing in the
|
||||
treatment of ownership, as described below.
|
||||
|
||||
### Non-consuming builders (preferred):
|
||||
|
||||
In some cases, constructing the final `T` does not require the builder itself to
|
||||
be consumed. The follow variant on
|
||||
[`std::io::process::Command`](http://static.rust-lang.org/doc/master/std/io/process/struct.Command.html)
|
||||
is one example:
|
||||
|
||||
```rust
|
||||
// NOTE: the actual Command API does not use owned Strings;
|
||||
// this is a simplified version.
|
||||
|
||||
pub struct Command {
|
||||
program: String,
|
||||
args: Vec<String>,
|
||||
cwd: Option<String>,
|
||||
// etc
|
||||
}
|
||||
|
||||
impl Command {
|
||||
pub fn new(program: String) -> Command {
|
||||
Command {
|
||||
program: program,
|
||||
args: Vec::new(),
|
||||
cwd: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Add an argument to pass to the program.
|
||||
pub fn arg<'a>(&'a mut self, arg: String) -> &'a mut Command {
|
||||
self.args.push(arg);
|
||||
self
|
||||
}
|
||||
|
||||
/// Add multiple arguments to pass to the program.
|
||||
pub fn args<'a>(&'a mut self, args: &[String])
|
||||
-> &'a mut Command {
|
||||
self.args.push_all(args);
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the working directory for the child process.
|
||||
pub fn cwd<'a>(&'a mut self, dir: String) -> &'a mut Command {
|
||||
self.cwd = Some(dir);
|
||||
self
|
||||
}
|
||||
|
||||
/// Executes the command as a child process, which is returned.
|
||||
pub fn spawn(&self) -> IoResult<Process> {
|
||||
...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Note that the `spawn` method, which actually uses the builder configuration to
|
||||
spawn a process, takes the builder by immutable reference. This is possible
|
||||
because spawning the process does not require ownership of the configuration
|
||||
data.
|
||||
|
||||
Because the terminal `spawn` method only needs a reference, the configuration
|
||||
methods take and return a mutable borrow of `self`.
|
||||
|
||||
#### The benefit
|
||||
|
||||
By using borrows throughout, `Command` can be used conveniently for both
|
||||
one-liner and more complex constructions:
|
||||
|
||||
```rust
|
||||
// One-liners
|
||||
Command::new("/bin/cat").arg("file.txt").spawn();
|
||||
|
||||
// Complex configuration
|
||||
let mut cmd = Command::new("/bin/ls");
|
||||
cmd.arg(".");
|
||||
|
||||
if size_sorted {
|
||||
cmd.arg("-S");
|
||||
}
|
||||
|
||||
cmd.spawn();
|
||||
```
|
||||
|
||||
### Consuming builders:
|
||||
|
||||
Sometimes builders must transfer ownership when constructing the final type
|
||||
`T`, meaning that the terminal methods must take `self` rather than `&self`:
|
||||
|
||||
```rust
|
||||
// A simplified excerpt from std::task::TaskBuilder
|
||||
|
||||
impl TaskBuilder {
|
||||
/// Name the task-to-be. Currently the name is used for identification
|
||||
/// only in failure messages.
|
||||
pub fn named(mut self, name: String) -> TaskBuilder {
|
||||
self.name = Some(name);
|
||||
self
|
||||
}
|
||||
|
||||
/// Redirect task-local stdout.
|
||||
pub fn stdout(mut self, stdout: Box<Writer + Send>) -> TaskBuilder {
|
||||
self.stdout = Some(stdout);
|
||||
// ^~~~~~ this is owned and cannot be cloned/re-used
|
||||
self
|
||||
}
|
||||
|
||||
/// Creates and executes a new child task.
|
||||
pub fn spawn(self, f: proc():Send) {
|
||||
// consume self
|
||||
...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Here, the `stdout` configuration involves passing ownership of a `Writer`,
|
||||
which must be transferred to the task upon construction (in `spawn`).
|
||||
|
||||
When the terminal methods of the builder require ownership, there is a basic tradeoff:
|
||||
|
||||
* If the other builder methods take/return a mutable borrow, the complex
|
||||
configuration case will work well, but one-liner configuration becomes
|
||||
_impossible_.
|
||||
|
||||
* If the other builder methods take/return an owned `self`, one-liners
|
||||
continue to work well but complex configuration is less convenient.
|
||||
|
||||
Under the rubric of making easy things easy and hard things possible, _all_
|
||||
builder methods for a consuming builder should take and returned an owned
|
||||
`self`. Then client code works as follows:
|
||||
|
||||
```rust
|
||||
// One-liners
|
||||
TaskBuilder::new().named("my_task").spawn(proc() { ... });
|
||||
|
||||
// Complex configuration
|
||||
let mut task = TaskBuilder::new();
|
||||
task = task.named("my_task_2"); // must re-assign to retain ownership
|
||||
|
||||
if reroute {
|
||||
task = task.stdout(mywriter);
|
||||
}
|
||||
|
||||
task.spawn(proc() { ... });
|
||||
```
|
||||
|
||||
One-liners work as before, because ownership is threaded through each of the
|
||||
builder methods until being consumed by `spawn`. Complex configuration,
|
||||
however, is more verbose: it requires re-assigning the builder at each step.
|
4
src/doc/style/ownership/cell-smart.md
Normal file
4
src/doc/style/ownership/cell-smart.md
Normal file
|
@ -0,0 +1,4 @@
|
|||
% Cells and smart pointers
|
||||
|
||||
> **[FIXME]** Add guidelines about when to use Cell, RefCell, Rc and
|
||||
> Arc (and how to use them together).
|
62
src/doc/style/ownership/constructors.md
Normal file
62
src/doc/style/ownership/constructors.md
Normal file
|
@ -0,0 +1,62 @@
|
|||
% Constructors
|
||||
|
||||
### Define constructors as static, inherent methods. [FIXME: needs RFC]
|
||||
|
||||
In Rust, "constructors" are just a convention:
|
||||
|
||||
```rust
|
||||
impl<T> Vec<T> {
|
||||
pub fn new() -> Vec<T> { ... }
|
||||
}
|
||||
```
|
||||
|
||||
Constructors are static (no `self`) inherent methods for the type that they
|
||||
construct. Combined with the practice of
|
||||
[fully importing type names](../style/imports.md), this convention leads to
|
||||
informative but concise construction:
|
||||
|
||||
```rust
|
||||
use vec::Vec;
|
||||
|
||||
// construct a new vector
|
||||
let mut v = Vec::new();
|
||||
```
|
||||
|
||||
This convention also applied to conversion constructors (prefix `from` rather
|
||||
than `new`).
|
||||
|
||||
### Provide constructors for passive `struct`s with defaults. [FIXME: needs RFC]
|
||||
|
||||
Given the `struct`
|
||||
|
||||
```rust
|
||||
pub struct Config {
|
||||
pub color: Color,
|
||||
pub size: Size,
|
||||
pub shape: Shape,
|
||||
}
|
||||
```
|
||||
|
||||
provide a constructor if there are sensible defaults:
|
||||
|
||||
```rust
|
||||
impl Config {
|
||||
pub fn new() -> Config {
|
||||
Config {
|
||||
color: Brown,
|
||||
size: Medium,
|
||||
shape: Square,
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
which then allows clients to concisely override using `struct` update syntax:
|
||||
|
||||
```rust
|
||||
Config { color: Red, .. Config::new() };
|
||||
```
|
||||
|
||||
See the [guideline for field privacy](../features/types/README.md) for
|
||||
discussion on when to create such "passive" `struct`s with public
|
||||
fields.
|
22
src/doc/style/ownership/destructors.md
Normal file
22
src/doc/style/ownership/destructors.md
Normal file
|
@ -0,0 +1,22 @@
|
|||
% Destructors
|
||||
|
||||
Unlike constructors, destructors in Rust have a special status: they are added
|
||||
by implementing `Drop` for a type, and they are automatically invoked as values
|
||||
go out of scope.
|
||||
|
||||
> **[FIXME]** This section needs to be expanded.
|
||||
|
||||
### Destructors should not fail. [FIXME: needs RFC]
|
||||
|
||||
Destructors are executed on task failure, and in that context a failing
|
||||
destructor causes the program to abort.
|
||||
|
||||
Instead of failing in a destructor, provide a separate method for checking for
|
||||
clean teardown, e.g. a `close` method, that returns a `Result` to signal
|
||||
problems.
|
||||
|
||||
### Destructors should not block. [FIXME: needs RFC]
|
||||
|
||||
Similarly, destructors should not invoke blocking operations, which can make
|
||||
debugging much more difficult. Again, consider providing a separate method for
|
||||
preparing for an infallible, nonblocking teardown.
|
12
src/doc/style/ownership/raii.md
Normal file
12
src/doc/style/ownership/raii.md
Normal file
|
@ -0,0 +1,12 @@
|
|||
% RAII
|
||||
|
||||
Resource Acquisition is Initialization
|
||||
|
||||
> **[FIXME]** Explain the RAII pattern and give best practices.
|
||||
|
||||
### Whenever possible, tie resource access to guard scopes [FIXME]
|
||||
|
||||
> **[FIXME]** Example: Mutex guards guarantee that access to the
|
||||
> protected resource only happens when the guard is in scope.
|
||||
|
||||
`must_use`
|
7
src/doc/style/platform.md
Normal file
7
src/doc/style/platform.md
Normal file
|
@ -0,0 +1,7 @@
|
|||
% FFI and platform-specific code **[FIXME]**
|
||||
|
||||
> **[FIXME]** Not sure where this should live.
|
||||
|
||||
When writing cross-platform code, group platform-specific code into a
|
||||
module called `platform`. Avoid `#[cfg]` directives outside this
|
||||
`platform` module.
|
19
src/doc/style/safety/README.md
Normal file
19
src/doc/style/safety/README.md
Normal file
|
@ -0,0 +1,19 @@
|
|||
% Safety and guarantees
|
||||
|
||||
> **[FIXME]** Is there a better phrase than "strong guarantees" that encompasses
|
||||
> both e.g. memory safety and e.g. data structure invariants?
|
||||
|
||||
A _guarantee_ is a property that holds no matter what client code does, unless
|
||||
the client explicitly opts out:
|
||||
|
||||
* Rust guarantees memory safety and data-race freedom, with `unsafe`
|
||||
blocks as an opt-out mechanism.
|
||||
|
||||
* APIs in Rust often provide their own guarantees. For example, `std::str`
|
||||
guarantees that its underlying buffer is valid utf-8. The `std::path::Path` type
|
||||
guarantees no interior nulls. Both strings and paths provide `unsafe` mechanisms
|
||||
for opting out of these guarantees (and thereby avoiding runtime checks).
|
||||
|
||||
Thinking about guarantees is an essential part of writing good Rust code. The
|
||||
rest of this subsection outlines some cross-cutting principles around
|
||||
guarantees.
|
81
src/doc/style/safety/lib-guarantees.md
Normal file
81
src/doc/style/safety/lib-guarantees.md
Normal file
|
@ -0,0 +1,81 @@
|
|||
% Library-level guarantees
|
||||
|
||||
Most libraries rely on internal invariants, e.g. about their data, resource
|
||||
ownership, or protocol states. In Rust, broken invariants cannot produce
|
||||
segfaults, but they can still lead to wrong answers.
|
||||
|
||||
### Provide library-level guarantees whenever practical. **[FIXME: needs RFC]**
|
||||
|
||||
Library-level invariants should be turned into guarantees whenever
|
||||
practical. They should hold no matter what the client does, modulo
|
||||
explicit opt-outs. Depending on the kind of invariant, this can be
|
||||
achieved through a combination of static and dynamic enforcement, as
|
||||
described below.
|
||||
|
||||
#### Static enforcement:
|
||||
|
||||
Guaranteeing invariants almost always requires _hiding_,
|
||||
i.e. preventing the client from directly accessing or modifying
|
||||
internal data.
|
||||
|
||||
For example, the representation of the `str` type is hidden,
|
||||
which means that any value of type `str` must have been produced
|
||||
through an API under the control of the `str` module, and these
|
||||
APIs in turn ensure valid utf-8 encoding.
|
||||
|
||||
Rust's type system makes it possible to provide guarantees even while
|
||||
revealing more of the representation than usual. For example, the
|
||||
`as_bytes()` method on `&str` gives a _read-only_ view into the
|
||||
underlying buffer, which cannot be used to violate the utf-8 property.
|
||||
|
||||
#### Dynamic enforcement:
|
||||
|
||||
Malformed inputs from the client are hazards to library-level
|
||||
guarantees, so library APIs should validate their input.
|
||||
|
||||
For example, `std::str::from_utf8_owned` attempts to convert a `u8`
|
||||
slice into an owned string, but dynamically checks that the slice is
|
||||
valid utf-8 and returns `Err` if not.
|
||||
|
||||
See
|
||||
[the discussion on input validation](../features/functions-and-methods/input.md)
|
||||
for more detail.
|
||||
|
||||
|
||||
### Prefer static enforcement of guarantees. **[FIXME: needs RFC]**
|
||||
|
||||
Static enforcement provides two strong benefits over dynamic enforcement:
|
||||
|
||||
* Bugs are caught at compile time.
|
||||
* There is no runtime cost.
|
||||
|
||||
Sometimes purely static enforcement is impossible or impractical. In these
|
||||
cases, a library should check as much as possible statically, but defer to
|
||||
dynamic checks where needed.
|
||||
|
||||
For example, the `std::string` module exports a `String` type with the guarantee
|
||||
that all instances are valid utf-8:
|
||||
|
||||
* Any _consumer_ of a `String` is statically guaranteed utf-8 contents. For example,
|
||||
the `append` method can push a `&str` onto the end of a `String` without
|
||||
checking anything dynamically, since the existing `String` and `&str` are
|
||||
statically guaranteed to be in utf-8.
|
||||
|
||||
* Some _producers_ of a `String` must perform dynamic checks. For example, the
|
||||
`from_utf8` function attempts to convert a `Vec<u8>` into a `String`, but
|
||||
dynamically checks that the contents are utf-8.
|
||||
|
||||
### Provide opt-outs with caution; make them explicit. **[FIXME: needs RFC]**
|
||||
|
||||
Providing library-level guarantees sometimes entails inconvenience (for static
|
||||
checks) or overhead (for dynamic checks). So it is sometimes desirable to allow
|
||||
clients to sidestep this checking, while promising to use the API in a way that
|
||||
still provides the guarantee. Such escape hatches should only be be introduced
|
||||
when there is a demonstrated need for them.
|
||||
|
||||
It should be trivial for clients to audit their use of the library for
|
||||
escape hatches.
|
||||
|
||||
See
|
||||
[the discussion on input validation](../features/functions-and-methods/input.md)
|
||||
for conventions on marking opt-out functions.
|
22
src/doc/style/safety/unsafe.md
Normal file
22
src/doc/style/safety/unsafe.md
Normal file
|
@ -0,0 +1,22 @@
|
|||
% Using `unsafe`
|
||||
|
||||
### Unconditionally guarantee safety, or mark API as `unsafe`. **[FIXME: needs RFC]**
|
||||
|
||||
Memory safety, type safety, and data race freedom are basic assumptions for all
|
||||
Rust code.
|
||||
|
||||
APIs that use `unsafe` blocks internally thus have two choices:
|
||||
|
||||
* They can guarantee safety _unconditionally_ (i.e., regardless of client
|
||||
behavior or inputs) and be exported as safe code. Any safety violation is then
|
||||
the library's fault, not the client's fault.
|
||||
|
||||
* They can export potentially unsafe functions with the `unsafe` qualifier. In
|
||||
this case, the documentation should make very clear the conditions under which
|
||||
safety is guaranteed.
|
||||
|
||||
The result is that a client program can never violate safety merely by having a
|
||||
bug; it must have explicitly opted out by using an `unsafe` block.
|
||||
|
||||
Of the two options for using `unsafe`, creating such safe abstractions (the
|
||||
first option above) is strongly preferred.
|
5
src/doc/style/style/README.md
Normal file
5
src/doc/style/style/README.md
Normal file
|
@ -0,0 +1,5 @@
|
|||
% Style
|
||||
|
||||
This section gives a set of strict rules for styling Rust code.
|
||||
|
||||
> **[FIXME]** General remarks about the style guidelines
|
77
src/doc/style/style/braces.md
Normal file
77
src/doc/style/style/braces.md
Normal file
|
@ -0,0 +1,77 @@
|
|||
% Braces, semicolons, and commas [FIXME: needs RFC]
|
||||
|
||||
### Opening braces always go on the same line.
|
||||
|
||||
``` rust
|
||||
fn foo() {
|
||||
...
|
||||
}
|
||||
|
||||
fn frobnicate(a: Bar, b: Bar,
|
||||
c: Bar, d: Bar)
|
||||
-> Bar {
|
||||
...
|
||||
}
|
||||
|
||||
trait Bar {
|
||||
fn baz(&self);
|
||||
}
|
||||
|
||||
impl Bar for Baz {
|
||||
fn baz(&self) {
|
||||
...
|
||||
}
|
||||
}
|
||||
|
||||
frob(|x| {
|
||||
x.transpose()
|
||||
})
|
||||
```
|
||||
|
||||
### `match` arms get braces, except for single-line expressions.
|
||||
|
||||
``` rust
|
||||
match foo {
|
||||
bar => baz,
|
||||
quux => {
|
||||
do_something();
|
||||
do_something_else()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### `return` statements get semicolons.
|
||||
|
||||
``` rust
|
||||
fn foo() {
|
||||
do_something();
|
||||
|
||||
if condition() {
|
||||
return;
|
||||
}
|
||||
|
||||
do_something_else();
|
||||
}
|
||||
```
|
||||
|
||||
### Trailing commas
|
||||
|
||||
> **[FIXME]** We should have a guideline for when to include trailing
|
||||
> commas in `struct`s, `match`es, function calls, etc.
|
||||
>
|
||||
> One possible rule: a trailing comma should be included whenever the
|
||||
> closing delimiter appears on a separate line:
|
||||
|
||||
```rust
|
||||
Foo { bar: 0, baz: 1 }
|
||||
|
||||
Foo {
|
||||
bar: 0,
|
||||
baz: 1,
|
||||
}
|
||||
|
||||
match a_thing {
|
||||
None => 0,
|
||||
Some(x) => 1,
|
||||
}
|
||||
```
|
87
src/doc/style/style/comments.md
Normal file
87
src/doc/style/style/comments.md
Normal file
|
@ -0,0 +1,87 @@
|
|||
% Comments [FIXME: needs RFC]
|
||||
|
||||
### Avoid block comments.
|
||||
|
||||
Use line comments:
|
||||
|
||||
``` rust
|
||||
// Wait for the main task to return, and set the process error code
|
||||
// appropriately.
|
||||
```
|
||||
|
||||
Instead of:
|
||||
|
||||
``` rust
|
||||
/*
|
||||
* Wait for the main task to return, and set the process error code
|
||||
* appropriately.
|
||||
*/
|
||||
```
|
||||
|
||||
## Doc comments
|
||||
|
||||
Doc comments are prefixed by three slashes (`///`) and indicate
|
||||
documentation that you would like to be included in Rustdoc's output.
|
||||
They support
|
||||
[Markdown syntax](https://en.wikipedia.org/wiki/Markdown)
|
||||
and are the main way of documenting your public APIs.
|
||||
|
||||
The supported markdown syntax includes all of the extensions listed in the
|
||||
[GitHub Flavored Markdown]
|
||||
(https://help.github.com/articles/github-flavored-markdown) documentation,
|
||||
plus superscripts.
|
||||
|
||||
### Summary line
|
||||
|
||||
The first line in any doc comment should be a single-line short sentence
|
||||
providing a summary of the code. This line is used as a short summary
|
||||
description throughout Rustdoc's output, so it's a good idea to keep it
|
||||
short.
|
||||
|
||||
### Sentence structure
|
||||
|
||||
All doc comments, including the summary line, should begin with a
|
||||
capital letter and end with a period, question mark, or exclamation
|
||||
point. Prefer full sentences to fragments.
|
||||
|
||||
The summary line should be written in
|
||||
[third person singular present indicative form]
|
||||
(http://en.wikipedia.org/wiki/English_verbs#Third_person_singular_present).
|
||||
Basically, this means write "Returns" instead of "Return".
|
||||
|
||||
For example:
|
||||
|
||||
``` rust
|
||||
/// Sets up a default runtime configuration, given compiler-supplied arguments.
|
||||
///
|
||||
/// This function will block until the entire pool of M:N schedulers has
|
||||
/// exited. This function also requires a local task to be available.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `argc` & `argv` - The argument vector. On Unix this information is used
|
||||
/// by `os::args`.
|
||||
/// * `main` - The initial procedure to run inside of the M:N scheduling pool.
|
||||
/// Once this procedure exits, the scheduling pool will begin to shut
|
||||
/// down. The entire pool (and this function) will only return once
|
||||
/// all child tasks have finished executing.
|
||||
///
|
||||
/// # Return value
|
||||
///
|
||||
/// The return value is used as the process return code. 0 on success, 101 on
|
||||
/// error.
|
||||
```
|
||||
|
||||
### Code snippets
|
||||
|
||||
> **[FIXME]**
|
||||
|
||||
### Avoid inner doc comments.
|
||||
|
||||
Use inner doc comments _only_ to document crates and file-level modules:
|
||||
|
||||
``` rust
|
||||
//! The core library.
|
||||
//!
|
||||
//! The core library is a something something...
|
||||
```
|
13
src/doc/style/style/features.md
Normal file
13
src/doc/style/style/features.md
Normal file
|
@ -0,0 +1,13 @@
|
|||
## `return` [FIXME: needs RFC]
|
||||
|
||||
Terminate `return` statements with semicolons:
|
||||
|
||||
``` rust
|
||||
fn foo(bar: int) -> Option<int> {
|
||||
if some_condition() {
|
||||
return None;
|
||||
}
|
||||
|
||||
...
|
||||
}
|
||||
```
|
50
src/doc/style/style/imports.md
Normal file
50
src/doc/style/style/imports.md
Normal file
|
@ -0,0 +1,50 @@
|
|||
% Imports [FIXME: needs RFC]
|
||||
|
||||
The imports of a crate/module should consist of the following
|
||||
sections, in order, with a blank space between each:
|
||||
|
||||
* `extern crate` directives
|
||||
* external `use` imports
|
||||
* local `use` imports
|
||||
* `pub use` imports
|
||||
|
||||
For example:
|
||||
|
||||
```rust
|
||||
// Crates.
|
||||
extern crate getopts;
|
||||
extern crate mylib;
|
||||
|
||||
// Standard library imports.
|
||||
use getopts::{optopt, getopts};
|
||||
use std::os;
|
||||
|
||||
// Import from a library that we wrote.
|
||||
use mylib::webserver;
|
||||
|
||||
// Will be reexported when we import this module.
|
||||
pub use self::types::Webdata;
|
||||
```
|
||||
|
||||
### Avoid `use *`, except in tests.
|
||||
|
||||
Glob imports have several downsides:
|
||||
* They make it harder to tell where names are bound.
|
||||
* They are forwards-incompatible, since new upstream exports can clash
|
||||
with existing names.
|
||||
|
||||
When writing a [`test` submodule](../testing/README.md), importing `super::*` is appropriate
|
||||
as a convenience.
|
||||
|
||||
### Prefer fully importing types/traits while module-qualifying functions.
|
||||
|
||||
For example:
|
||||
|
||||
```rust
|
||||
use option::Option;
|
||||
use mem;
|
||||
|
||||
let i: int = mem::transmute(Option(0));
|
||||
```
|
||||
|
||||
> **[FIXME]** Add rationale.
|
115
src/doc/style/style/naming/README.md
Normal file
115
src/doc/style/style/naming/README.md
Normal file
|
@ -0,0 +1,115 @@
|
|||
% Naming conventions
|
||||
|
||||
### General conventions [RFC #430]
|
||||
|
||||
> The guidelines below were approved by [RFC #430](https://github.com/rust-lang/rfcs/pull/430).
|
||||
|
||||
In general, Rust tends to use `CamelCase` for "type-level" constructs
|
||||
(types and traits) and `snake_case` for "value-level" constructs. More
|
||||
precisely:
|
||||
|
||||
| Item | Convention |
|
||||
| ---- | ---------- |
|
||||
| Crates | `snake_case` (but prefer single word) |
|
||||
| Modules | `snake_case` |
|
||||
| Types | `CamelCase` |
|
||||
| Traits | `CamelCase` |
|
||||
| Enum variants | `CamelCase` |
|
||||
| Functions | `snake_case` |
|
||||
| Methods | `snake_case` |
|
||||
| General constructors | `new` or `with_more_details` |
|
||||
| Conversion constructors | `from_some_other_type` |
|
||||
| Local variables | `snake_case` |
|
||||
| Static variables | `SCREAMING_SNAKE_CASE` |
|
||||
| Constant variables | `SCREAMING_SNAKE_CASE` |
|
||||
| Type parameters | concise `CamelCase`, usually single uppercase letter: `T` |
|
||||
| Lifetimes | short, lowercase: `'a` |
|
||||
|
||||
<p>
|
||||
In `CamelCase`, acronyms count as one word: use `Uuid` rather than
|
||||
`UUID`. In `snake_case`, acronyms are lower-cased: `is_xid_start`.
|
||||
|
||||
In `snake_case` or `SCREAMING_SNAKE_CASE`, a "word" should never
|
||||
consist of a single letter unless it is the last "word". So, we have
|
||||
`btree_map` rather than `b_tree_map`, but `PI_2` rather than `PI2`.
|
||||
|
||||
### Referring to types in function/method names [RFC 344]
|
||||
|
||||
> The guidelines below were approved by [RFC #344](https://github.com/rust-lang/rfcs/pull/344).
|
||||
|
||||
Function names often involve type names, the most common example being conversions
|
||||
like `as_slice`. If the type has a purely textual name (ignoring parameters), it
|
||||
is straightforward to convert between type conventions and function conventions:
|
||||
|
||||
Type name | Text in methods
|
||||
--------- | ---------------
|
||||
`String` | `string`
|
||||
`Vec<T>` | `vec`
|
||||
`YourType`| `your_type`
|
||||
|
||||
Types that involve notation follow the convention below. There is some
|
||||
overlap on these rules; apply the most specific applicable rule:
|
||||
|
||||
Type name | Text in methods
|
||||
--------- | ---------------
|
||||
`&str` | `str`
|
||||
`&[T]` | `slice`
|
||||
`&mut [T]`| `mut_slice`
|
||||
`&[u8]` | `bytes`
|
||||
`&T` | `ref`
|
||||
`&mut T` | `mut`
|
||||
`*const T`| `ptr`
|
||||
`*mut T` | `mut_ptr`
|
||||
|
||||
### Avoid redundant prefixes [RFC 356]
|
||||
|
||||
> The guidelines below were approved by [RFC #356](https://github.com/rust-lang/rfcs/pull/356).
|
||||
|
||||
Names of items within a module should not be prefixed with that module's name:
|
||||
|
||||
Prefer
|
||||
|
||||
``` rust
|
||||
mod foo {
|
||||
pub struct Error { ... }
|
||||
}
|
||||
```
|
||||
|
||||
over
|
||||
|
||||
``` rust
|
||||
mod foo {
|
||||
pub struct FooError { ... }
|
||||
}
|
||||
```
|
||||
|
||||
This convention avoids stuttering (like `io::IoError`). Library clients can
|
||||
rename on import to avoid clashes.
|
||||
|
||||
### Getter/setter methods [RFC 344]
|
||||
|
||||
> The guidelines below were approved by [RFC #344](https://github.com/rust-lang/rfcs/pull/344).
|
||||
|
||||
Some data structures do not wish to provide direct access to their fields, but
|
||||
instead offer "getter" and "setter" methods for manipulating the field state
|
||||
(often providing checking or other functionality).
|
||||
|
||||
The convention for a field `foo: T` is:
|
||||
|
||||
* A method `foo(&self) -> &T` for getting the current value of the field.
|
||||
* A method `set_foo(&self, val: T)` for setting the field. (The `val` argument
|
||||
here may take `&T` or some other type, depending on the context.)
|
||||
|
||||
Note that this convention is about getters/setters on ordinary data types, *not*
|
||||
on [builder objects](../ownership/builders.html).
|
||||
|
||||
### Escape hatches [FIXME]
|
||||
|
||||
> **[FIXME]** Should we standardize a convention for functions that may break API
|
||||
> guarantees? e.g. `ToCStr::to_c_str_unchecked`
|
||||
|
||||
### Predicates
|
||||
|
||||
* Simple boolean predicates should be prefixed with `is_` or another
|
||||
short question word, e.g., `is_empty`.
|
||||
* Common exceptions: `lt`, `gt`, and other established predicate names.
|
69
src/doc/style/style/naming/containers.md
Normal file
69
src/doc/style/style/naming/containers.md
Normal file
|
@ -0,0 +1,69 @@
|
|||
% Common container/wrapper methods [FIXME: needs RFC]
|
||||
|
||||
Containers, wrappers, and cells all provide ways to access the data
|
||||
they enclose. Accessor methods often have variants to access the data
|
||||
by value, by reference, and by mutable reference.
|
||||
|
||||
In general, the `get` family of methods is used to access contained
|
||||
data without any risk of task failure; they return `Option` as
|
||||
appropriate. This name is chosen rather than names like `find` or
|
||||
`lookup` because it is appropriate for a wider range of container types.
|
||||
|
||||
#### Containers
|
||||
|
||||
For a container with keys/indexes of type `K` and elements of type `V`:
|
||||
|
||||
```rust
|
||||
// Look up element without failing
|
||||
fn get(&self, key: K) -> Option<&V>
|
||||
fn get_mut(&mut self, key: K) -> Option<&mut V>
|
||||
|
||||
// Convenience for .get(key).map(|elt| elt.clone())
|
||||
fn get_clone(&self, key: K) -> Option<V>
|
||||
|
||||
// Lookup element, failing if it is not found:
|
||||
impl Index<K, V> for Container { ... }
|
||||
impl IndexMut<K, V> for Container { ... }
|
||||
```
|
||||
|
||||
#### Wrappers/Cells
|
||||
|
||||
Prefer specific conversion functions like `as_bytes` or `into_vec` whenever
|
||||
possible. Otherwise, use:
|
||||
|
||||
```rust
|
||||
// Extract contents without failing
|
||||
fn get(&self) -> &V
|
||||
fn get_mut(&mut self) -> &mut V
|
||||
fn unwrap(self) -> V
|
||||
```
|
||||
|
||||
#### Wrappers/Cells around `Copy` data
|
||||
|
||||
```rust
|
||||
// Extract contents without failing
|
||||
fn get(&self) -> V
|
||||
```
|
||||
|
||||
#### `Option`-like types
|
||||
|
||||
Finally, we have the cases of types like `Option` and `Result`, which
|
||||
play a special role for failure.
|
||||
|
||||
For `Option<V>`:
|
||||
|
||||
```rust
|
||||
// Extract contents or fail if not available
|
||||
fn assert(self) -> V
|
||||
fn expect(self, &str) -> V
|
||||
```
|
||||
|
||||
For `Result<V, E>`:
|
||||
|
||||
```rust
|
||||
// Extract the contents of Ok variant; fail if Err
|
||||
fn assert(self) -> V
|
||||
|
||||
// Extract the contents of Err variant; fail if Ok
|
||||
fn assert_err(self) -> E
|
||||
```
|
32
src/doc/style/style/naming/conversions.md
Normal file
32
src/doc/style/style/naming/conversions.md
Normal file
|
@ -0,0 +1,32 @@
|
|||
% Conversions [Rust issue #7087]
|
||||
|
||||
> The guidelines below were approved by [rust issue #7087](https://github.com/rust-lang/rust/issues/7087).
|
||||
|
||||
> **[FIXME]** Should we provide standard traits for conversions? Doing
|
||||
> so nicely will require
|
||||
> [trait reform](https://github.com/rust-lang/rfcs/pull/48) to land.
|
||||
|
||||
Conversions should be provided as methods, with names prefixed as follows:
|
||||
|
||||
| Prefix | Cost | Consumes convertee |
|
||||
| ------ | ---- | ------------------ |
|
||||
| `as_` | Free | No |
|
||||
| `to_` | Expensive | No |
|
||||
| `into_` | Variable | Yes |
|
||||
|
||||
<p>
|
||||
For example:
|
||||
|
||||
* `as_bytes()` gives a `&[u8]` view into a `&str`, which is a no-op.
|
||||
* `to_owned()` copies a `&str` to a new `String`.
|
||||
* `into_bytes()` consumes a `String` and yields the underlying
|
||||
`Vec<u8>`, which is a no-op.
|
||||
|
||||
Conversions prefixed `as_` and `into_` typically _decrease abstraction_, either
|
||||
exposing a view into the underlying representation (`as`) or deconstructing data
|
||||
into its underlying representation (`into`). Conversions prefixed `to_`, on the
|
||||
other hand, typically stay at the same level of abstraction but do some work to
|
||||
change one representation into another.
|
||||
|
||||
> **[FIXME]** The distinctions between conversion methods does not work
|
||||
> so well for `from_` conversion constructors. Is that a problem?
|
32
src/doc/style/style/naming/iterators.md
Normal file
32
src/doc/style/style/naming/iterators.md
Normal file
|
@ -0,0 +1,32 @@
|
|||
% Iterators
|
||||
|
||||
#### Method names [RFC #199]
|
||||
|
||||
> The guidelines below were approved by [RFC #199](https://github.com/rust-lang/rfcs/pull/199).
|
||||
|
||||
For a container with elements of type `U`, iterator methods should be named:
|
||||
|
||||
```rust
|
||||
fn iter(&self) -> T // where T implements Iterator<&U>
|
||||
fn iter_mut(&mut self) -> T // where T implements Iterator<&mut U>
|
||||
fn into_iter(self) -> T // where T implements Iterator<U>
|
||||
```
|
||||
|
||||
The default iterator variant yields shared references `&U`.
|
||||
|
||||
#### Type names [RFC #344]
|
||||
|
||||
> The guidelines below were approved by [RFC #344](https://github.com/rust-lang/rfcs/pull/344).
|
||||
|
||||
The name of an iterator type should be the same as the method that
|
||||
produces the iterator.
|
||||
|
||||
For example:
|
||||
|
||||
* `iter` should yield an `Iter`
|
||||
* `iter_mut` should yield an `IterMut`
|
||||
* `into_iter` should yield an `IntoIter`
|
||||
* `keys` should yield `Keys`
|
||||
|
||||
These type names make the most sense when prefixed with their owning module,
|
||||
e.g. `vec::IntoIter`.
|
34
src/doc/style/style/naming/ownership.md
Normal file
34
src/doc/style/style/naming/ownership.md
Normal file
|
@ -0,0 +1,34 @@
|
|||
% Ownership variants [RFC #199]
|
||||
|
||||
> The guidelines below were approved by [RFC #199](https://github.com/rust-lang/rfcs/pull/199).
|
||||
|
||||
Functions often come in multiple variants: immutably borrowed, mutably
|
||||
borrowed, and owned.
|
||||
|
||||
The right default depends on the function in question. Variants should
|
||||
be marked through suffixes.
|
||||
|
||||
#### Immutably borrowed by default
|
||||
|
||||
If `foo` uses/produces an immutable borrow by default, use:
|
||||
|
||||
* The `_mut` suffix (e.g. `foo_mut`) for the mutably borrowed variant.
|
||||
* The `_move` suffix (e.g. `foo_move`) for the owned variant.
|
||||
|
||||
#### Owned by default
|
||||
|
||||
If `foo` uses/produces owned data by default, use:
|
||||
|
||||
* The `_ref` suffix (e.g. `foo_ref`) for the immutably borrowed variant.
|
||||
* The `_mut` suffix (e.g. `foo_mut`) for the mutably borrowed variant.
|
||||
|
||||
#### Exceptions
|
||||
|
||||
In the case of iterators, the moving variant can also be understood as
|
||||
an `into` conversion, `into_iter`, and `for x in v.into_iter()` reads
|
||||
arguably better than `for x in v.iter_move()`, so the convention is
|
||||
`into_iter`.
|
||||
|
||||
For mutably borrowed variants, if the `mut` qualifier is part of a
|
||||
type name (e.g. `as_mut_slice`), it should appear as it would appear
|
||||
in the type.
|
3
src/doc/style/style/optional.md
Normal file
3
src/doc/style/style/optional.md
Normal file
|
@ -0,0 +1,3 @@
|
|||
*
|
||||
|
||||
*
|
14
src/doc/style/style/organization.md
Normal file
14
src/doc/style/style/organization.md
Normal file
|
@ -0,0 +1,14 @@
|
|||
% Organization [FIXME: needs RFC]
|
||||
|
||||
> **[FIXME]** What else?
|
||||
|
||||
### Reexport the most important types at the crate level.
|
||||
|
||||
Crates `pub use` the most common types for convenience, so that clients do not
|
||||
have to remember or write the crate's module hierarchy to use these types.
|
||||
|
||||
### Define types and operations together.
|
||||
|
||||
Type definitions and the functions/methods that operate on them should be
|
||||
defined together in a single module, with the type appearing above the
|
||||
functions/methods.
|
133
src/doc/style/style/whitespace.md
Normal file
133
src/doc/style/style/whitespace.md
Normal file
|
@ -0,0 +1,133 @@
|
|||
% Whitespace [FIXME: needs RFC]
|
||||
|
||||
* Lines must not exceed 99 characters.
|
||||
* Use 4 spaces for indentation, _not_ tabs.
|
||||
* No trailing whitespace at the end of lines or files.
|
||||
|
||||
### Spaces
|
||||
|
||||
* Use spaces around binary operators, including the equals sign in attributes:
|
||||
|
||||
``` rust
|
||||
#[deprecated = "Use `bar` instead."]
|
||||
fn foo(a: uint, b: uint) -> uint {
|
||||
a + b
|
||||
}
|
||||
```
|
||||
|
||||
* Use a space after colons and commas:
|
||||
|
||||
``` rust
|
||||
fn foo(a: Bar);
|
||||
|
||||
MyStruct { foo: 3, bar: 4 }
|
||||
|
||||
foo(bar, baz);
|
||||
```
|
||||
|
||||
* Use a space after the opening and before the closing brace for
|
||||
single line blocks or `struct` expressions:
|
||||
|
||||
``` rust
|
||||
spawn(proc() { do_something(); })
|
||||
|
||||
Point { x: 0.1, y: 0.3 }
|
||||
```
|
||||
|
||||
### Line wrapping
|
||||
|
||||
* For multiline function signatures, each new line should align with the
|
||||
first parameter. Multiple parameters per line are permitted:
|
||||
|
||||
``` rust
|
||||
fn frobnicate(a: Bar, b: Bar,
|
||||
c: Bar, d: Bar)
|
||||
-> Bar {
|
||||
...
|
||||
}
|
||||
|
||||
fn foo<T: This,
|
||||
U: That>(
|
||||
a: Bar,
|
||||
b: Bar)
|
||||
-> Baz {
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
* Multiline function invocations generally follow the same rule as for
|
||||
signatures. However, if the final argument begins a new block, the
|
||||
contents of the block may begin on a new line, indented one level:
|
||||
|
||||
``` rust
|
||||
fn foo_bar(a: Bar, b: Bar,
|
||||
c: |Bar|) -> Bar {
|
||||
...
|
||||
}
|
||||
|
||||
// Same line is fine:
|
||||
foo_bar(x, y, |z| { z.transpose(y) });
|
||||
|
||||
// Indented body on new line is also fine:
|
||||
foo_bar(x, y, |z| {
|
||||
z.quux();
|
||||
z.rotate(x)
|
||||
})
|
||||
```
|
||||
|
||||
> **[FIXME]** Do we also want to allow the following?
|
||||
>
|
||||
> ```rust
|
||||
> frobnicate(
|
||||
> arg1,
|
||||
> arg2,
|
||||
> arg3)
|
||||
> ```
|
||||
>
|
||||
> This style could ease the conflict between line length and functions
|
||||
> with many parameters (or long method chains).
|
||||
|
||||
### Matches
|
||||
|
||||
> * **[Deprecated]** If you have multiple patterns in a single `match`
|
||||
> arm, write each pattern on a separate line:
|
||||
>
|
||||
> ``` rust
|
||||
> match foo {
|
||||
> bar(_)
|
||||
> | baz => quux,
|
||||
> x
|
||||
> | y
|
||||
> | z => {
|
||||
> quuux
|
||||
> }
|
||||
> }
|
||||
> ```
|
||||
|
||||
### Alignment
|
||||
|
||||
Idiomatic code should not use extra whitespace in the middle of a line
|
||||
to provide alignment.
|
||||
|
||||
|
||||
``` rust
|
||||
// Good
|
||||
struct Foo {
|
||||
short: f64,
|
||||
really_long: f64,
|
||||
}
|
||||
|
||||
// Bad
|
||||
struct Bar {
|
||||
short: f64,
|
||||
really_long: f64,
|
||||
}
|
||||
|
||||
// Good
|
||||
let a = 0;
|
||||
let radius = 7;
|
||||
|
||||
// Bad
|
||||
let b = 0;
|
||||
let diameter = 7;
|
||||
```
|
5
src/doc/style/testing/README.md
Normal file
5
src/doc/style/testing/README.md
Normal file
|
@ -0,0 +1,5 @@
|
|||
% Testing
|
||||
|
||||
> **[FIXME]** Add some general remarks about when and how to unit
|
||||
> test, versus other kinds of testing. What are our expectations for
|
||||
> Rust's core libraries?
|
30
src/doc/style/testing/unit.md
Normal file
30
src/doc/style/testing/unit.md
Normal file
|
@ -0,0 +1,30 @@
|
|||
% Unit testing
|
||||
|
||||
Unit tests should live in a `test` submodule at the bottom of the module they
|
||||
test. Mark the `test` submodule with `#[cfg(test)]` so it is only compiled when
|
||||
testing.
|
||||
|
||||
The `test` module should contain:
|
||||
|
||||
* Imports needed only for testing.
|
||||
* Functions marked with `#[test]` striving for full coverage of the parent module's
|
||||
definitions.
|
||||
* Auxiliary functions needed for writing the tests.
|
||||
|
||||
For example:
|
||||
|
||||
``` rust
|
||||
// Excerpt from std::str
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
#[test]
|
||||
fn test_eq() {
|
||||
assert!((eq(&"".to_owned(), &"".to_owned())));
|
||||
assert!((eq(&"foo".to_owned(), &"foo".to_owned())));
|
||||
assert!((!eq(&"foo".to_owned(), &"bar".to_owned())));
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
> **[FIXME]** add details about useful macros for testing, e.g. `assert!`
|
5
src/doc/style/todo.md
Normal file
5
src/doc/style/todo.md
Normal file
|
@ -0,0 +1,5 @@
|
|||
* [Containers and iteration]()
|
||||
* [The visitor pattern]()
|
||||
* [Concurrency]()
|
||||
* [Documentation]()
|
||||
* [Macros]()
|
|
@ -28,13 +28,14 @@
|
|||
* [Generics](generics.md)
|
||||
* [Traits](traits.md)
|
||||
* [Static and Dynamic Dispatch](static-and-dynamic-dispatch.md)
|
||||
* [Macros](macros.md)
|
||||
* [Concurrency](concurrency.md)
|
||||
* [Error Handling](error-handling.md)
|
||||
* [Documentation](documentation.md)
|
||||
* [III: Advanced Topics](advanced.md)
|
||||
* [FFI](ffi.md)
|
||||
* [Unsafe Code](unsafe.md)
|
||||
* [Macros](macros.md)
|
||||
* [Advanced Macros](advanced-macros.md)
|
||||
* [Compiler Plugins](plugins.md)
|
||||
* [Conclusion](conclusion.md)
|
||||
* [Glossary](glossary.md)
|
||||
|
|
210
src/doc/trpl/advanced-macros.md
Normal file
210
src/doc/trpl/advanced-macros.md
Normal file
|
@ -0,0 +1,210 @@
|
|||
% Advanced macros
|
||||
|
||||
This chapter picks up where the [introductory macro chapter](macros.html) left
|
||||
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.
|
||||
|
||||
One consequence is that Rust must determine, when it parses a macro invocation,
|
||||
whether the macro stands in for
|
||||
|
||||
* zero or more items,
|
||||
* zero or more methods,
|
||||
* an expression,
|
||||
* a statement, or
|
||||
* a pattern.
|
||||
|
||||
A macro invocation within a block could stand for some items, or for an
|
||||
expression / statement. Rust uses a simple rule to resolve this ambiguity. A
|
||||
macro invocation that stands for items must be either
|
||||
|
||||
* delimited by curly braces, e.g. `foo! { ... }`, or
|
||||
* terminated by a semicolon, e.g. `foo!(...);`
|
||||
|
||||
Another consequence of pre-expansion parsing is that the macro invocation must
|
||||
consist of valid Rust tokens. Furthermore, parentheses, brackets, and braces
|
||||
must be balanced within a macro invocation. For example, `foo!([)` is
|
||||
forbidden. This allows Rust to know where the macro invocation ends.
|
||||
|
||||
More formally, the macro invocation body must be a sequence of *token trees*.
|
||||
A token tree is defined recursively as either
|
||||
|
||||
* a sequence of token trees surrounded by matching `()`, `[]`, or `{}`, or
|
||||
* any other single token.
|
||||
|
||||
Within a matcher, each metavariable has a *fragment specifier*, identifying
|
||||
which syntactic form it matches.
|
||||
|
||||
* `ident`: an identifier. Examples: `x`; `foo`.
|
||||
* `path`: a qualified name. Example: `T::SpecialA`.
|
||||
* `expr`: an expression. Examples: `2 + 2`; `if true then { 1 } else { 2 }`; `f(42)`.
|
||||
* `ty`: a type. Examples: `i32`; `Vec<(char, String)>`; `&T`.
|
||||
* `pat`: a pattern. Examples: `Some(t)`; `(17, 'a')`; `_`.
|
||||
* `stmt`: a single statement. Example: `let x = 3`.
|
||||
* `block`: a brace-delimited sequence of statements. Example:
|
||||
`{ log(error, "hi"); return 12; }`.
|
||||
* `item`: an [item][]. Examples: `fn foo() { }`; `struct Bar;`.
|
||||
* `meta`: a "meta item", as found in attributes. Example: `cfg(target_os = "windows")`.
|
||||
* `tt`: a single token tree.
|
||||
|
||||
There are additional rules regarding the next token after a metavariable:
|
||||
|
||||
* `expr` variables must be followed by one of: `=> , ;`
|
||||
* `ty` and `path` variables must be followed by one of: `=> , : = > as`
|
||||
* `pat` variables must be followed by one of: `=> , =`
|
||||
* Other variables may be followed by any token.
|
||||
|
||||
These rules provide some flexibility for Rust's syntax to evolve without
|
||||
breaking existing macros.
|
||||
|
||||
The macro system does not deal with parse ambiguity at all. For example, the
|
||||
grammar `$($t:ty)* $e:expr` will always fail to parse, because the parser would
|
||||
be forced to choose between parsing `$t` and parsing `$e`. Changing the
|
||||
invocation syntax to put a distinctive token in front can solve the problem. In
|
||||
this case, you can write `$(T $t:ty)* E $e:exp`.
|
||||
|
||||
[item]: ../reference.html#items
|
||||
|
||||
# Scoping and macro import/export
|
||||
|
||||
Macros are expanded at an early stage in compilation, before name resolution.
|
||||
One downside is that scoping works differently for macros, compared to other
|
||||
constructs in the language.
|
||||
|
||||
Definition and expansion of macros both happen in a single depth-first,
|
||||
lexical-order traversal of a crate's source. So a macro defined at module scope
|
||||
is visible to any subsequent code in the same module, which includes the body
|
||||
of any subsequent child `mod` items.
|
||||
|
||||
A macro defined within the body of a single `fn`, or anywhere else not at
|
||||
module scope, is visible only within that item.
|
||||
|
||||
If a module has the `macro_use` attribute, its macros are also visible in its
|
||||
parent module after the child's `mod` item. If the parent also has `macro_use`
|
||||
then the macros will be visible in the grandparent after the parent's `mod`
|
||||
item, and so forth.
|
||||
|
||||
The `macro_use` attribute can also appear on `extern crate`. In this context
|
||||
it controls which macros are loaded from the external crate, e.g.
|
||||
|
||||
```rust,ignore
|
||||
#[macro_use(foo, bar)]
|
||||
extern crate baz;
|
||||
```
|
||||
|
||||
If the attribute is given simply as `#[macro_use]`, all macros are loaded. If
|
||||
there is no `#[macro_use]` attribute then no macros are loaded. Only macros
|
||||
defined with the `#[macro_export]` attribute may be loaded.
|
||||
|
||||
To load a crate's macros *without* linking it into the output, use `#[no_link]`
|
||||
as well.
|
||||
|
||||
An example:
|
||||
|
||||
```rust
|
||||
macro_rules! m1 { () => (()) }
|
||||
|
||||
// visible here: m1
|
||||
|
||||
mod foo {
|
||||
// visible here: m1
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! m2 { () => (()) }
|
||||
|
||||
// visible here: m1, m2
|
||||
}
|
||||
|
||||
// visible here: m1
|
||||
|
||||
macro_rules! m3 { () => (()) }
|
||||
|
||||
// visible here: m1, m3
|
||||
|
||||
#[macro_use]
|
||||
mod bar {
|
||||
// visible here: m1, m3
|
||||
|
||||
macro_rules! m4 { () => (()) }
|
||||
|
||||
// visible here: m1, m3, m4
|
||||
}
|
||||
|
||||
// visible here: m1, m3, m4
|
||||
# fn main() { }
|
||||
```
|
||||
|
||||
When this library is loaded with `#[macro_use] extern crate`, only `m2` will
|
||||
be imported.
|
||||
|
||||
The Rust Reference has a [listing of macro-related
|
||||
attributes](../reference.html#macro--and-plugin-related-attributes).
|
||||
|
||||
# The variable `$crate`
|
||||
|
||||
A further difficulty occurs when a macro is used in multiple crates. Say that
|
||||
`mylib` defines
|
||||
|
||||
```rust
|
||||
pub fn increment(x: u32) -> u32 {
|
||||
x + 1
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! inc_a {
|
||||
($x:expr) => ( ::increment($x) )
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! inc_b {
|
||||
($x:expr) => ( ::mylib::increment($x) )
|
||||
}
|
||||
# fn main() { }
|
||||
```
|
||||
|
||||
`inc_a` only works within `mylib`, while `inc_b` only works outside the
|
||||
library. Furthermore, `inc_b` will break if the user imports `mylib` under
|
||||
another name.
|
||||
|
||||
Rust does not (yet) have a hygiene system for crate references, but it does
|
||||
provide a simple workaround for this problem. Within a macro imported from a
|
||||
crate named `foo`, the special macro variable `$crate` will expand to `::foo`.
|
||||
By contrast, when a macro is defined and then used in the same crate, `$crate`
|
||||
will expand to nothing. This means we can write
|
||||
|
||||
```rust
|
||||
#[macro_export]
|
||||
macro_rules! inc {
|
||||
($x:expr) => ( $crate::increment($x) )
|
||||
}
|
||||
# fn main() { }
|
||||
```
|
||||
|
||||
to define a single macro that works both inside and outside our library. The
|
||||
function name will expand to either `::increment` or `::mylib::increment`.
|
||||
|
||||
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
|
||||
|
||||
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.
|
||||
|
||||
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
|
||||
flexibility of running arbitrary Rust code within the compiler. Syntax
|
||||
extension plugins are sometimes called *procedural macros* for this reason.
|
|
@ -322,8 +322,8 @@ 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. Lets use `use` to import can
|
||||
the `enum` variants instead. This will avoid full scoping:
|
||||
This `Ordering::Greater` notation is too long. Let's use `use` to import the
|
||||
`enum` variants instead. This will avoid full scoping:
|
||||
|
||||
```{rust}
|
||||
use std::cmp::Ordering::{self, Equal, Less, Greater};
|
||||
|
|
|
@ -57,13 +57,13 @@ place!
|
|||
## Threads
|
||||
|
||||
Rust's standard library provides a library for 'threads', which allow you to
|
||||
run Rust code in parallel. Here's a basic example of using `Thread`:
|
||||
run Rust code in parallel. Here's a basic example of using `std::thread`:
|
||||
|
||||
```
|
||||
use std::thread::Thread;
|
||||
use std::thread;
|
||||
|
||||
fn main() {
|
||||
Thread::scoped(|| {
|
||||
thread::scoped(|| {
|
||||
println!("Hello from a thread!");
|
||||
});
|
||||
}
|
||||
|
@ -73,10 +73,10 @@ 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:
|
||||
|
||||
```
|
||||
use std::thread::Thread;
|
||||
use std::thread;
|
||||
|
||||
fn main() {
|
||||
let guard = Thread::scoped(|| {
|
||||
let guard = thread::scoped(|| {
|
||||
println!("Hello from a thread!");
|
||||
});
|
||||
|
||||
|
@ -85,15 +85,15 @@ fn main() {
|
|||
```
|
||||
|
||||
When `guard` goes out of scope, it will block execution until the thread is
|
||||
finished. If we didn't want this behaviour, we could use `Thread::spawn()`:
|
||||
finished. If we didn't want this behaviour, we could use `thread::spawn()`:
|
||||
|
||||
```
|
||||
use std::thread::Thread;
|
||||
use std::thread;
|
||||
use std::old_io::timer;
|
||||
use std::time::Duration;
|
||||
|
||||
fn main() {
|
||||
Thread::spawn(|| {
|
||||
thread::spawn(|| {
|
||||
println!("Hello from a thread!");
|
||||
});
|
||||
|
||||
|
@ -101,24 +101,6 @@ fn main() {
|
|||
}
|
||||
```
|
||||
|
||||
Or call `.detach()`:
|
||||
|
||||
```
|
||||
use std::thread::Thread;
|
||||
use std::old_io::timer;
|
||||
use std::time::Duration;
|
||||
|
||||
fn main() {
|
||||
let guard = Thread::scoped(|| {
|
||||
println!("Hello from a thread!");
|
||||
});
|
||||
|
||||
guard.detach();
|
||||
|
||||
timer::sleep(Duration::milliseconds(50));
|
||||
}
|
||||
```
|
||||
|
||||
We need to `sleep` here because when `main()` ends, it kills all of the
|
||||
running threads.
|
||||
|
||||
|
@ -164,7 +146,7 @@ As an example, here is a Rust program that would have a data race in many
|
|||
languages. It will not compile:
|
||||
|
||||
```ignore
|
||||
use std::thread::Thread;
|
||||
use std::thread;
|
||||
use std::old_io::timer;
|
||||
use std::time::Duration;
|
||||
|
||||
|
@ -172,7 +154,7 @@ fn main() {
|
|||
let mut data = vec![1u32, 2, 3];
|
||||
|
||||
for i in 0..2 {
|
||||
Thread::spawn(move || {
|
||||
thread::spawn(move || {
|
||||
data[i] += 1;
|
||||
});
|
||||
}
|
||||
|
@ -203,7 +185,7 @@ only one person at a time can mutate what's inside. For that, we can use the
|
|||
but for a different reason:
|
||||
|
||||
```ignore
|
||||
use std::thread::Thread;
|
||||
use std::thread;
|
||||
use std::old_io::timer;
|
||||
use std::time::Duration;
|
||||
use std::sync::Mutex;
|
||||
|
@ -213,7 +195,7 @@ fn main() {
|
|||
|
||||
for i in 0..2 {
|
||||
let data = data.lock().unwrap();
|
||||
Thread::spawn(move || {
|
||||
thread::spawn(move || {
|
||||
data[i] += 1;
|
||||
});
|
||||
}
|
||||
|
@ -255,7 +237,7 @@ We can use `Arc<T>` to fix this. Here's the working version:
|
|||
|
||||
```
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::thread::Thread;
|
||||
use std::thread;
|
||||
use std::old_io::timer;
|
||||
use std::time::Duration;
|
||||
|
||||
|
@ -264,7 +246,7 @@ fn main() {
|
|||
|
||||
for i in 0us..2 {
|
||||
let data = data.clone();
|
||||
Thread::spawn(move || {
|
||||
thread::spawn(move || {
|
||||
let mut data = data.lock().unwrap();
|
||||
data[i] += 1;
|
||||
});
|
||||
|
@ -280,14 +262,14 @@ thread more closely:
|
|||
|
||||
```
|
||||
# use std::sync::{Arc, Mutex};
|
||||
# use std::thread::Thread;
|
||||
# use std::thread;
|
||||
# use std::old_io::timer;
|
||||
# use std::time::Duration;
|
||||
# fn main() {
|
||||
# let data = Arc::new(Mutex::new(vec![1u32, 2, 3]));
|
||||
# for i in 0us..2 {
|
||||
# let data = data.clone();
|
||||
Thread::spawn(move || {
|
||||
thread::spawn(move || {
|
||||
let mut data = data.lock().unwrap();
|
||||
data[i] += 1;
|
||||
});
|
||||
|
@ -315,7 +297,7 @@ than waiting for a specific time:
|
|||
|
||||
```
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::thread::Thread;
|
||||
use std::thread;
|
||||
use std::sync::mpsc;
|
||||
|
||||
fn main() {
|
||||
|
@ -326,7 +308,7 @@ fn main() {
|
|||
for _ in 0..10 {
|
||||
let (data, tx) = (data.clone(), tx.clone());
|
||||
|
||||
Thread::spawn(move || {
|
||||
thread::spawn(move || {
|
||||
let mut data = data.lock().unwrap();
|
||||
*data += 1;
|
||||
|
||||
|
@ -348,7 +330,7 @@ is `Send` over the channel!
|
|||
|
||||
```
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::thread::Thread;
|
||||
use std::thread;
|
||||
use std::sync::mpsc;
|
||||
|
||||
fn main() {
|
||||
|
@ -357,7 +339,7 @@ fn main() {
|
|||
for _ in 0..10 {
|
||||
let tx = tx.clone();
|
||||
|
||||
Thread::spawn(move || {
|
||||
thread::spawn(move || {
|
||||
let answer = 42u32;
|
||||
|
||||
tx.send(answer);
|
||||
|
@ -378,9 +360,9 @@ A `panic!` will crash the currently executing thread. You can use Rust's
|
|||
threads as a simple isolation mechanism:
|
||||
|
||||
```
|
||||
use std::thread::Thread;
|
||||
use std::thread;
|
||||
|
||||
let result = Thread::scoped(move || {
|
||||
let result = thread::spawn(move || {
|
||||
panic!("oops!");
|
||||
}).join();
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ comments":
|
|||
// the "link" crate attribute is currently required for rustdoc, but normally
|
||||
// isn't needed.
|
||||
#![crate_id = "universe"]
|
||||
#![crate_type="lib"]
|
||||
#![crate_type= "lib"]
|
||||
|
||||
//! 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,
|
||||
|
|
|
@ -4,19 +4,19 @@ Let's talk about loops.
|
|||
|
||||
Remember Rust's `for` loop? Here's an example:
|
||||
|
||||
```{rust}
|
||||
```rust
|
||||
for x in 0..10 {
|
||||
println!("{}", x);
|
||||
}
|
||||
```
|
||||
|
||||
Now that you know more Rust, we can talk in detail about how this works. The
|
||||
`range` function returns an *iterator*. An iterator is something that we can
|
||||
Now that you know more Rust, we can talk in detail about how this works.
|
||||
Ranges (the `0..10`) are 'iterators'. An iterator is something that we can
|
||||
call the `.next()` method on repeatedly, and it gives us a sequence of things.
|
||||
|
||||
Like this:
|
||||
|
||||
```{rust}
|
||||
```rust
|
||||
let mut range = 0..10;
|
||||
|
||||
loop {
|
||||
|
@ -29,12 +29,12 @@ loop {
|
|||
}
|
||||
```
|
||||
|
||||
We make a mutable binding to the return value of `range`, which is our iterator.
|
||||
We then `loop`, with an inner `match`. This `match` is used on the result of
|
||||
`range.next()`, which gives us a reference to the next value of the iterator.
|
||||
`next` returns an `Option<i32>`, in this case, which will be `Some(i32)` when
|
||||
we have a value and `None` once we run out. If we get `Some(i32)`, we print it
|
||||
out, and if we get `None`, we `break` out of the loop.
|
||||
We make a mutable binding to the range, which is our iterator. We then `loop`,
|
||||
with an inner `match`. This `match` is used on the result of `range.next()`,
|
||||
which gives us a reference to the next value of the iterator. `next` returns an
|
||||
`Option<i32>`, in this case, which will be `Some(i32)` when we have a value and
|
||||
`None` once we run out. If we get `Some(i32)`, we print it out, and if we get
|
||||
`None`, we `break` out of the loop.
|
||||
|
||||
This code sample is basically the same as our `for` loop version. The `for`
|
||||
loop is just a handy way to write this `loop`/`match`/`break` construct.
|
||||
|
@ -43,13 +43,13 @@ loop is just a handy way to write this `loop`/`match`/`break` construct.
|
|||
own iterator involves implementing the `Iterator` trait. While doing that is
|
||||
outside of the scope of this guide, Rust provides a number of useful iterators
|
||||
to accomplish various tasks. Before we talk about those, we should talk about a
|
||||
Rust anti-pattern. And that's `range`.
|
||||
Rust anti-pattern. And that's using ranges like this.
|
||||
|
||||
Yes, we just talked about how `range` is cool. But `range` is also very
|
||||
primitive. For example, if you needed to iterate over the contents of
|
||||
a vector, you may be tempted to write this:
|
||||
Yes, we just talked about how ranges are cool. But ranges are also very
|
||||
primitive. For example, if you needed to iterate over the contents of a vector,
|
||||
you may be tempted to write this:
|
||||
|
||||
```{rust}
|
||||
```rust
|
||||
let nums = vec![1, 2, 3];
|
||||
|
||||
for i in 0..nums.len() {
|
||||
|
@ -61,7 +61,7 @@ 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:
|
||||
|
||||
```{rust}
|
||||
```rust
|
||||
let nums = vec![1, 2, 3];
|
||||
|
||||
for num in nums.iter() {
|
||||
|
@ -83,7 +83,7 @@ works. `num` is actually of type `&i32`. That is, it's a reference to an `i32`,
|
|||
not an `i32` itself. `println!` handles the dereferencing for us, so we don't
|
||||
see it. This code works fine too:
|
||||
|
||||
```{rust}
|
||||
```rust
|
||||
let nums = vec![1, 2, 3];
|
||||
|
||||
for num in nums.iter() {
|
||||
|
@ -97,7 +97,7 @@ 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.
|
||||
|
||||
So, now that we've established that `range` is often not what you want, let's
|
||||
So, now that we've established that ranges are often not what you want, let's
|
||||
talk about what you do want instead.
|
||||
|
||||
There are three broad classes of things that are relevant here: iterators,
|
||||
|
@ -108,8 +108,7 @@ There are three broad classes of things that are relevant here: iterators,
|
|||
different output sequence.
|
||||
* *consumers* operate on an iterator, producing some final set of values.
|
||||
|
||||
Let's talk about consumers first, since you've already seen an iterator,
|
||||
`range`.
|
||||
Let's talk about consumers first, since you've already seen an iterator, ranges.
|
||||
|
||||
## Consumers
|
||||
|
||||
|
@ -118,7 +117,7 @@ The most common consumer is `collect()`. This code doesn't quite compile,
|
|||
but it shows the intention:
|
||||
|
||||
```{rust,ignore}
|
||||
let one_to_one_hundred = (1..101i32).collect();
|
||||
let one_to_one_hundred = (1..101).collect();
|
||||
```
|
||||
|
||||
As you can see, we call `collect()` on our iterator. `collect()` takes
|
||||
|
@ -127,8 +126,8 @@ of the results. So why won't this compile? Rust can't determine what
|
|||
type of things you want to collect, and so you need to let it know.
|
||||
Here's the version that does compile:
|
||||
|
||||
```{rust}
|
||||
let one_to_one_hundred = (1..101i32).collect::<Vec<i32>>();
|
||||
```rust
|
||||
let one_to_one_hundred = (1..101).collect::<Vec<i32>>();
|
||||
```
|
||||
|
||||
If you remember, the `::<>` syntax allows us to give a type hint,
|
||||
|
@ -137,7 +136,7 @@ need to use the whole type, though. Using a `_` will let you provide
|
|||
a partial hint:
|
||||
|
||||
```rust
|
||||
let one_to_one_hundred = range(1, 101).collect::<Vec<_>>();
|
||||
let one_to_one_hundred = (1..101).collect::<Vec<_>>();
|
||||
```
|
||||
|
||||
This says "Collect into a `Vec<T>`, please, but infer what the `T` is for me."
|
||||
|
@ -146,8 +145,8 @@ This says "Collect into a `Vec<T>`, please, but infer what the `T` is for me."
|
|||
`collect()` is the most common consumer, but there are others too. `find()`
|
||||
is one:
|
||||
|
||||
```{rust}
|
||||
let greater_than_forty_two = (0..100i32)
|
||||
```rust
|
||||
let greater_than_forty_two = (0..100)
|
||||
.find(|x| *x > 42);
|
||||
|
||||
match greater_than_forty_two {
|
||||
|
@ -163,9 +162,8 @@ element, `find` returns an `Option` rather than the element itself.
|
|||
|
||||
Another important consumer is `fold`. Here's what it looks like:
|
||||
|
||||
```{rust}
|
||||
let sum = (1..4)
|
||||
.fold(0, |sum, x| sum + x);
|
||||
```rust
|
||||
let sum = (1..4).fold(0, |sum, x| sum + x);
|
||||
```
|
||||
|
||||
`fold()` is a consumer that looks like this:
|
||||
|
@ -187,7 +185,7 @@ in this iterator:
|
|||
|
||||
We called `fold()` with these arguments:
|
||||
|
||||
```{rust}
|
||||
```rust
|
||||
# (1..4)
|
||||
.fold(0, |sum, x| sum + x);
|
||||
```
|
||||
|
@ -218,25 +216,25 @@ are *lazy* and don't need to generate all of the values upfront.
|
|||
This code, for example, does not actually generate the numbers
|
||||
`1-100`, and just creates a value that represents the sequence:
|
||||
|
||||
```{rust}
|
||||
```rust
|
||||
let nums = 1..100;
|
||||
```
|
||||
|
||||
Since we didn't do anything with the range, it didn't generate the sequence.
|
||||
Let's add the consumer:
|
||||
|
||||
```{rust}
|
||||
```rust
|
||||
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.
|
||||
|
||||
A range is one of two basic iterators that you'll see. The other is `iter()`,
|
||||
Ranges are one of two basic iterators that you'll see. The other is `iter()`,
|
||||
which you've used before. `iter()` can turn a vector into a simple iterator
|
||||
that gives you each element in turn:
|
||||
|
||||
```{rust}
|
||||
```rust
|
||||
let nums = [1, 2, 3];
|
||||
|
||||
for num in nums.iter() {
|
||||
|
@ -247,7 +245,7 @@ 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`:
|
||||
|
||||
```{rust}
|
||||
```rust
|
||||
std::iter::count(1, 5);
|
||||
```
|
||||
|
||||
|
@ -265,7 +263,7 @@ we need to talk about with regards to iterators. Let's get to it!
|
|||
a new iterator. The simplest one is called `map`:
|
||||
|
||||
```{rust,ignore}
|
||||
(1..100i32).map(|x| x + 1);
|
||||
(1..100).map(|x| x + 1);
|
||||
```
|
||||
|
||||
`map` is called upon another iterator, and produces a new iterator where each
|
||||
|
@ -273,7 +271,7 @@ element reference has the closure it's been given as an argument called on it.
|
|||
So this would give us the numbers from `2-100`. Well, almost! If you
|
||||
compile the example, you'll get a warning:
|
||||
|
||||
```{notrust,ignore}
|
||||
```text
|
||||
warning: unused result which must be used: iterator adaptors are lazy and
|
||||
do nothing unless consumed, #[warn(unused_must_use)] on by default
|
||||
(1..100).map(|x| x + 1);
|
||||
|
@ -295,7 +293,7 @@ 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()`:
|
||||
|
||||
```{rust}
|
||||
```rust
|
||||
for i in std::iter::count(1, 5).take(5) {
|
||||
println!("{}", i);
|
||||
}
|
||||
|
@ -303,7 +301,7 @@ for i in std::iter::count(1, 5).take(5) {
|
|||
|
||||
This will print
|
||||
|
||||
```{notrust,ignore}
|
||||
```text
|
||||
1
|
||||
6
|
||||
11
|
||||
|
@ -315,8 +313,8 @@ This will print
|
|||
returns `true` or `false`. The new iterator `filter()` produces
|
||||
only the elements that that closure returns `true` for:
|
||||
|
||||
```{rust}
|
||||
for i in (1..100i32).filter(|&x| x % 2 == 0) {
|
||||
```rust
|
||||
for i in (1..100).filter(|&x| x % 2 == 0) {
|
||||
println!("{}", i);
|
||||
}
|
||||
```
|
||||
|
@ -330,8 +328,8 @@ itself.)
|
|||
You can chain all three things together: start with an iterator, adapt it
|
||||
a few times, and then consume the result. Check it out:
|
||||
|
||||
```{rust}
|
||||
(1..1000i32)
|
||||
```rust
|
||||
(1..1000)
|
||||
.filter(|&x| x % 2 == 0)
|
||||
.filter(|&x| x % 3 == 0)
|
||||
.take(5)
|
||||
|
|
|
@ -1,588 +1,365 @@
|
|||
% Macros
|
||||
|
||||
# Introduction
|
||||
By now you've learned about many of the tools Rust provides for abstracting and
|
||||
reusing code. These units of code reuse have a rich semantic structure. For
|
||||
example, functions have a type signature, type parameters have trait bounds,
|
||||
and overloaded functions must belong to a particular trait.
|
||||
|
||||
Functions are the primary tool that programmers can use to build abstractions.
|
||||
Sometimes, however, programmers want to abstract over compile-time syntax
|
||||
rather than run-time values.
|
||||
Macros provide syntactic abstraction.
|
||||
For an example of how this can be useful, consider the following two code fragments,
|
||||
which both pattern-match on their input and both return early in one case,
|
||||
doing nothing otherwise:
|
||||
This structure means that Rust's core abstractions have powerful compile-time
|
||||
correctness checking. But this comes at the price of reduced flexibility. If
|
||||
you visually identify a pattern of repeated code, you may find it's difficult
|
||||
or cumbersome to express that pattern as a generic function, a trait, or
|
||||
anything else within Rust's semantics.
|
||||
|
||||
~~~~
|
||||
# enum T { SpecialA(u32), SpecialB(u32) }
|
||||
# fn f() -> u32 {
|
||||
# let input_1 = T::SpecialA(0);
|
||||
# let input_2 = T::SpecialA(0);
|
||||
match input_1 {
|
||||
T::SpecialA(x) => { return x; }
|
||||
_ => {}
|
||||
}
|
||||
// ...
|
||||
match input_2 {
|
||||
T::SpecialB(x) => { return x; }
|
||||
_ => {}
|
||||
}
|
||||
# return 0;
|
||||
# }
|
||||
~~~~
|
||||
Macros allow us to abstract at a *syntactic* level. A macro invocation is
|
||||
shorthand for an "expanded" syntactic form. This expansion happens early in
|
||||
compilation, before any static checking. As a result, macros can capture many
|
||||
patterns of code reuse that Rust's core abstractions cannot.
|
||||
|
||||
This code could become tiresome if repeated many times.
|
||||
However, no function can capture its functionality to make it possible
|
||||
to abstract the repetition away.
|
||||
Rust's macro system, however, can eliminate the repetition. Macros are
|
||||
lightweight custom syntax extensions, themselves defined using the
|
||||
`macro_rules!` syntax extension. The following `early_return` macro captures
|
||||
the pattern in the above code:
|
||||
The drawback is that macro-based code can be harder to understand, because
|
||||
fewer of the built-in rules apply. Like an ordinary function, a well-behaved
|
||||
macro can be used without understanding its implementation. However, it can be
|
||||
difficult to design a well-behaved macro! Additionally, compiler errors in
|
||||
macro code are harder to interpret, because they describe problems in the
|
||||
expanded code, not the source-level form that developers use.
|
||||
|
||||
~~~~
|
||||
# enum T { SpecialA(u32), SpecialB(u32) }
|
||||
# fn f() -> u32 {
|
||||
# let input_1 = T::SpecialA(0);
|
||||
# let input_2 = T::SpecialA(0);
|
||||
macro_rules! early_return {
|
||||
($inp:expr, $sp:path) => ( // invoke it like `(input_5, SpecialE)`
|
||||
match $inp {
|
||||
$sp(x) => { return x; }
|
||||
_ => {}
|
||||
}
|
||||
);
|
||||
}
|
||||
// ...
|
||||
early_return!(input_1, T::SpecialA);
|
||||
// ...
|
||||
early_return!(input_2, T::SpecialB);
|
||||
# return 0;
|
||||
# }
|
||||
# fn main() {}
|
||||
~~~~
|
||||
These drawbacks make macros something of a "feature of last resort". That's not
|
||||
to say that macros are bad; they are part of Rust because sometimes they're
|
||||
needed for truly concise, well-abstracted code. Just keep this tradeoff in
|
||||
mind.
|
||||
|
||||
Macros are defined in pattern-matching style: in the above example, the text
|
||||
`($inp:expr, $sp:path)` that appears on the left-hand side of the `=>` is the
|
||||
*macro invocation syntax*, a pattern denoting how to write a call to the
|
||||
macro. The text on the right-hand side of the `=>`, beginning with `match
|
||||
$inp`, is the *macro transcription syntax*: what the macro expands to.
|
||||
# Defining a macro
|
||||
|
||||
# Invocation syntax
|
||||
You may have seen the `vec!` macro, used to initialize a [vector][] with any
|
||||
number of elements.
|
||||
|
||||
The macro invocation syntax specifies the syntax for the arguments to the
|
||||
macro. It appears on the left-hand side of the `=>` in a macro definition. It
|
||||
conforms to the following rules:
|
||||
[vector]: arrays-vectors-and-slices.html
|
||||
|
||||
1. It must be surrounded by parentheses.
|
||||
2. `$` has special meaning (described below).
|
||||
3. The `()`s, `[]`s, and `{}`s it contains must balance. For example, `([)` is
|
||||
forbidden.
|
||||
4. Some arguments can be followed only by a limited set of separators, to
|
||||
avoid ambiguity (described below).
|
||||
```rust
|
||||
let x: Vec<u32> = vec![1, 2, 3];
|
||||
# assert_eq!(&[1,2,3], &x);
|
||||
```
|
||||
|
||||
Otherwise, the invocation syntax is free-form.
|
||||
This can't be an ordinary function, because it takes any number of arguments.
|
||||
But we can imagine it as syntactic shorthand for
|
||||
|
||||
To take a fragment of Rust code as an argument, write `$` followed by a name
|
||||
(for use on the right-hand side), followed by a `:`, followed by a *fragment
|
||||
specifier*. The fragment specifier denotes the sort of fragment to match. The
|
||||
most common fragment specifiers are:
|
||||
```rust
|
||||
let x: Vec<u32> = {
|
||||
let mut temp_vec = Vec::new();
|
||||
temp_vec.push(1);
|
||||
temp_vec.push(2);
|
||||
temp_vec.push(3);
|
||||
temp_vec
|
||||
};
|
||||
# assert_eq!(&[1,2,3], &x);
|
||||
```
|
||||
|
||||
* `ident` (an identifier, referring to a variable or item. Examples: `f`, `x`,
|
||||
`foo`.)
|
||||
* `expr` (an expression. Examples: `2 + 2`; `if true then { 1 } else { 2 }`;
|
||||
`f(42)`.)
|
||||
* `ty` (a type. Examples: `i32`, `Vec<(char, String)>`, `&T`.)
|
||||
* `path` (a path to struct or enum variant. Example: `T::SpecialA`)
|
||||
* `pat` (a pattern, usually appearing in a `match` or on the left-hand side of
|
||||
a declaration. Examples: `Some(t)`; `(17, 'a')`; `_`.)
|
||||
* `block` (a sequence of actions. Example: `{ log(error, "hi"); return 12; }`)
|
||||
We can implement this shorthand, using a macro: [^actual]
|
||||
|
||||
The parser interprets any token that's not preceded by a `$` literally. Rust's usual
|
||||
rules of tokenization apply,
|
||||
[^actual]: The actual definition of `vec!` in libcollections differs from the
|
||||
one presented here, for reasons of efficiency and reusability. Some
|
||||
of these are mentioned in the [advanced macros chapter][].
|
||||
|
||||
So `($x:ident -> (($e:expr)))`, though excessively fancy, would designate a macro
|
||||
that could be invoked like: `my_macro!(i->(( 2+2 )))`.
|
||||
|
||||
To avoid ambiguity, macro invocation syntax must conform to the following rules:
|
||||
|
||||
* `expr` must be followed by `=>`, `,` or `;`.
|
||||
* `ty` and `path` must be followed by `=>`, `,`, `:`, `=`, `>` or `as`.
|
||||
* `pat` must be followed by `=>`, `,` or `=`.
|
||||
* `ident` and `block` can be followed by any token.
|
||||
|
||||
## Invocation location
|
||||
|
||||
A macro invocation may take the place of (and therefore expand to) an
|
||||
expression, item, statement, or pattern. The Rust parser will parse the macro
|
||||
invocation as a "placeholder" for whichever syntactic form is appropriate for
|
||||
the location.
|
||||
|
||||
At expansion time, the output of the macro will be parsed as whichever of the
|
||||
three nonterminals it stands in for. This means that a single macro might,
|
||||
for example, expand to an item or an expression, depending on its arguments
|
||||
(and cause a syntax error if it is called with the wrong argument for its
|
||||
location). Although this behavior sounds excessively dynamic, it is known to
|
||||
be useful under some circumstances.
|
||||
|
||||
|
||||
# Transcription syntax
|
||||
|
||||
The right-hand side of the `=>` follows the same rules as the left-hand side,
|
||||
except that a `$` need only be followed by the name of the syntactic fragment
|
||||
to transcribe into the macro expansion; its type need not be repeated.
|
||||
|
||||
The right-hand side must be enclosed by delimiters, which the transcriber ignores.
|
||||
Therefore `() => ((1,2,3))` is a macro that expands to a tuple expression,
|
||||
`() => (let $x=$val)` is a macro that expands to a statement,
|
||||
and `() => (1,2,3)` is a macro that expands to a syntax error
|
||||
(since the transcriber interprets the parentheses on the right-hand-size as delimiters,
|
||||
and `1,2,3` is not a valid Rust expression on its own).
|
||||
|
||||
Except for permissibility of `$name` (and `$(...)*`, discussed below), the
|
||||
right-hand side of a macro definition is ordinary Rust syntax. In particular,
|
||||
macro invocations (including invocations of the macro currently being defined)
|
||||
are permitted in expression, statement, and item locations. However, nothing
|
||||
else about the code is examined or executed by the macro system; execution
|
||||
still has to wait until run-time.
|
||||
|
||||
## Interpolation location
|
||||
|
||||
The interpolation `$argument_name` may appear in any location consistent with
|
||||
its fragment specifier (i.e., if it is specified as `ident`, it may be used
|
||||
anywhere an identifier is permitted).
|
||||
|
||||
# Multiplicity
|
||||
|
||||
## Invocation
|
||||
|
||||
Going back to the motivating example, recall that `early_return` expanded into
|
||||
a `match` that would `return` if the `match`'s scrutinee matched the
|
||||
"special case" identifier provided as the second argument to `early_return`,
|
||||
and do nothing otherwise. Now suppose that we wanted to write a
|
||||
version of `early_return` that could handle a variable number of "special"
|
||||
cases.
|
||||
|
||||
The syntax `$(...)*` on the left-hand side of the `=>` in a macro definition
|
||||
accepts zero or more occurrences of its contents. It works much
|
||||
like the `*` operator in regular expressions. It also supports a
|
||||
separator token (a comma-separated list could be written `$(...),*`), and `+`
|
||||
instead of `*` to mean "at least one".
|
||||
|
||||
~~~~
|
||||
# enum T { SpecialA(u32), SpecialB(u32), SpecialC(u32), SpecialD(u32) }
|
||||
# fn f() -> u32 {
|
||||
# let input_1 = T::SpecialA(0);
|
||||
# let input_2 = T::SpecialA(0);
|
||||
macro_rules! early_return {
|
||||
($inp:expr, [ $($sp:path),+ ]) => (
|
||||
match $inp {
|
||||
```rust
|
||||
macro_rules! vec {
|
||||
( $( $x:expr ),* ) => {
|
||||
{
|
||||
let mut temp_vec = Vec::new();
|
||||
$(
|
||||
$sp(x) => { return x; }
|
||||
)+
|
||||
_ => {}
|
||||
temp_vec.push($x);
|
||||
)*
|
||||
temp_vec
|
||||
}
|
||||
)
|
||||
};
|
||||
}
|
||||
// ...
|
||||
early_return!(input_1, [T::SpecialA,T::SpecialC,T::SpecialD]);
|
||||
// ...
|
||||
early_return!(input_2, [T::SpecialB]);
|
||||
# return 0;
|
||||
# }
|
||||
# fn main() {}
|
||||
~~~~
|
||||
|
||||
### Transcription
|
||||
|
||||
As the above example demonstrates, `$(...)*` is also valid on the right-hand
|
||||
side of a macro definition. The behavior of `*` in transcription,
|
||||
especially in cases where multiple `*`s are nested, and multiple different
|
||||
names are involved, can seem somewhat magical and unintuitive at first. The
|
||||
system that interprets them is called "Macro By Example". The two rules to
|
||||
keep in mind are (1) the behavior of `$(...)*` is to walk through one "layer"
|
||||
of repetitions for all of the `$name`s it contains in lockstep, and (2) each
|
||||
`$name` must be under at least as many `$(...)*`s as it was matched against.
|
||||
If it is under more, it'll be repeated, as appropriate.
|
||||
|
||||
## Parsing limitations
|
||||
|
||||
|
||||
For technical reasons, there are two limitations to the treatment of syntax
|
||||
fragments by the macro parser:
|
||||
|
||||
1. The parser will always parse as much as possible of a Rust syntactic
|
||||
fragment. For example, if the comma were omitted from the syntax of
|
||||
`early_return!` above, `input_1 [` would've been interpreted as the beginning
|
||||
of an array index. In fact, invoking the macro would have been impossible.
|
||||
2. The parser must have eliminated all ambiguity by the time it reaches a
|
||||
`$name:fragment_specifier` declaration. This limitation can result in parse
|
||||
errors when declarations occur at the beginning of, or immediately after,
|
||||
a `$(...)*`. For example, the grammar `$($t:ty)* $e:expr` will always fail to
|
||||
parse because the parser would be forced to choose between parsing `t` and
|
||||
parsing `e`. Changing the invocation syntax to require a distinctive token in
|
||||
front can solve the problem. In the above example, `$(T $t:ty)* E $e:exp`
|
||||
solves the problem.
|
||||
|
||||
# Macro argument pattern matching
|
||||
|
||||
## Motivation
|
||||
|
||||
Now consider code like the following:
|
||||
|
||||
~~~~
|
||||
# enum T1 { Good1(T2, u32), Bad1}
|
||||
# struct T2 { body: T3 }
|
||||
# enum T3 { Good2(u32), Bad2}
|
||||
# fn f(x: T1) -> u32 {
|
||||
match x {
|
||||
T1::Good1(g1, val) => {
|
||||
match g1.body {
|
||||
T3::Good2(result) => {
|
||||
// complicated stuff goes here
|
||||
return result + val;
|
||||
},
|
||||
_ => panic!("Didn't get good_2")
|
||||
}
|
||||
}
|
||||
_ => return 0 // default value
|
||||
}
|
||||
# }
|
||||
# fn main() {}
|
||||
~~~~
|
||||
|
||||
All the complicated stuff is deeply indented, and the error-handling code is
|
||||
separated from matches that fail. We'd like to write a macro that performs
|
||||
a match, but with a syntax that suits the problem better. The following macro
|
||||
can solve the problem:
|
||||
|
||||
~~~~
|
||||
macro_rules! biased_match {
|
||||
// special case: `let (x) = ...` is illegal, so use `let x = ...` instead
|
||||
( ($e:expr) -> ($p:pat) else $err:stmt ;
|
||||
binds $bind_res:ident
|
||||
) => (
|
||||
let $bind_res = match $e {
|
||||
$p => ( $bind_res ),
|
||||
_ => { $err }
|
||||
};
|
||||
);
|
||||
// more than one name; use a tuple
|
||||
( ($e:expr) -> ($p:pat) else $err:stmt ;
|
||||
binds $( $bind_res:ident ),*
|
||||
) => (
|
||||
let ( $( $bind_res ),* ) = match $e {
|
||||
$p => ( $( $bind_res ),* ),
|
||||
_ => { $err }
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
# enum T1 { Good1(T2, u32), Bad1}
|
||||
# struct T2 { body: T3 }
|
||||
# enum T3 { Good2(u32), Bad2}
|
||||
# fn f(x: T1) -> u32 {
|
||||
biased_match!((x) -> (T1::Good1(g1, val)) else { return 0 };
|
||||
binds g1, val );
|
||||
biased_match!((g1.body) -> (T3::Good2(result) )
|
||||
else { panic!("Didn't get good_2") };
|
||||
binds result );
|
||||
// complicated stuff goes here
|
||||
return result + val;
|
||||
# }
|
||||
# fn main() {}
|
||||
~~~~
|
||||
|
||||
This solves the indentation problem. But if we have a lot of chained matches
|
||||
like this, we might prefer to write a single macro invocation. The input
|
||||
pattern we want is clear:
|
||||
|
||||
~~~~
|
||||
# fn main() {}
|
||||
# macro_rules! b {
|
||||
( $( ($e:expr) -> ($p:pat) else $err:stmt ; )*
|
||||
binds $( $bind_res:ident ),*
|
||||
)
|
||||
# => (0) }
|
||||
~~~~
|
||||
|
||||
However, it's not possible to directly expand to nested match statements. But
|
||||
there is a solution.
|
||||
|
||||
## The recursive approach to macro writing
|
||||
|
||||
A macro may accept multiple different input grammars. The first one to
|
||||
successfully match the actual argument to a macro invocation is the one that
|
||||
"wins".
|
||||
|
||||
In the case of the example above, we want to write a recursive macro to
|
||||
process the semicolon-terminated lines, one-by-one. So, we want the following
|
||||
input patterns:
|
||||
|
||||
~~~~
|
||||
# macro_rules! b {
|
||||
( binds $( $bind_res:ident ),* )
|
||||
# => (0) }
|
||||
# fn main() {}
|
||||
~~~~
|
||||
|
||||
...and:
|
||||
|
||||
~~~~
|
||||
# fn main() {}
|
||||
# macro_rules! b {
|
||||
( ($e :expr) -> ($p :pat) else $err :stmt ;
|
||||
$( ($e_rest:expr) -> ($p_rest:pat) else $err_rest:stmt ; )*
|
||||
binds $( $bind_res:ident ),*
|
||||
)
|
||||
# => (0) }
|
||||
~~~~
|
||||
|
||||
The resulting macro looks like this. Note that the separation into
|
||||
`biased_match!` and `biased_match_rec!` occurs only because we have an outer
|
||||
piece of syntax (the `let`) which we only want to transcribe once.
|
||||
|
||||
~~~~
|
||||
# fn main() {
|
||||
|
||||
macro_rules! biased_match_rec {
|
||||
// Handle the first layer
|
||||
( ($e :expr) -> ($p :pat) else $err :stmt ;
|
||||
$( ($e_rest:expr) -> ($p_rest:pat) else $err_rest:stmt ; )*
|
||||
binds $( $bind_res:ident ),*
|
||||
) => (
|
||||
match $e {
|
||||
$p => {
|
||||
// Recursively handle the next layer
|
||||
biased_match_rec!($( ($e_rest) -> ($p_rest) else $err_rest ; )*
|
||||
binds $( $bind_res ),*
|
||||
)
|
||||
}
|
||||
_ => { $err }
|
||||
}
|
||||
);
|
||||
// Produce the requested values
|
||||
( binds $( $bind_res:ident ),* ) => ( ($( $bind_res ),*) )
|
||||
}
|
||||
|
||||
// Wrap the whole thing in a `let`.
|
||||
macro_rules! biased_match {
|
||||
// special case: `let (x) = ...` is illegal, so use `let x = ...` instead
|
||||
( $( ($e:expr) -> ($p:pat) else $err:stmt ; )*
|
||||
binds $bind_res:ident
|
||||
) => (
|
||||
let $bind_res = biased_match_rec!(
|
||||
$( ($e) -> ($p) else $err ; )*
|
||||
binds $bind_res
|
||||
);
|
||||
);
|
||||
// more than one name: use a tuple
|
||||
( $( ($e:expr) -> ($p:pat) else $err:stmt ; )*
|
||||
binds $( $bind_res:ident ),*
|
||||
) => (
|
||||
let ( $( $bind_res ),* ) = biased_match_rec!(
|
||||
$( ($e) -> ($p) else $err ; )*
|
||||
binds $( $bind_res ),*
|
||||
);
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
# enum T1 { Good1(T2, u32), Bad1}
|
||||
# struct T2 { body: T3 }
|
||||
# enum T3 { Good2(u32), Bad2}
|
||||
# fn f(x: T1) -> u32 {
|
||||
biased_match!(
|
||||
(x) -> (T1::Good1(g1, val)) else { return 0 };
|
||||
(g1.body) -> (T3::Good2(result) ) else { panic!("Didn't get Good2") };
|
||||
binds val, result );
|
||||
// complicated stuff goes here
|
||||
return result + val;
|
||||
# assert_eq!(&[1,2,3], &vec![1,2,3]);
|
||||
# }
|
||||
# }
|
||||
~~~~
|
||||
```
|
||||
|
||||
This technique applies to many cases where transcribing a result all at once is not possible.
|
||||
The resulting code resembles ordinary functional programming in some respects,
|
||||
but has some important differences from functional programming.
|
||||
Whoa, that's a lot of new syntax! Let's break it down.
|
||||
|
||||
The first difference is important, but also easy to forget: the transcription
|
||||
(right-hand) side of a `macro_rules!` rule is literal syntax, which can only
|
||||
be executed at run-time. If a piece of transcription syntax does not itself
|
||||
appear inside another macro invocation, it will become part of the final
|
||||
program. If it is inside a macro invocation (for example, the recursive
|
||||
invocation of `biased_match_rec!`), it does have the opportunity to affect
|
||||
transcription, but only through the process of attempted pattern matching.
|
||||
```ignore
|
||||
macro_rules! vec { ... }
|
||||
```
|
||||
|
||||
The second, related, difference is that the evaluation order of macros feels
|
||||
"backwards" compared to ordinary programming. Given an invocation
|
||||
`m1!(m2!())`, the expander first expands `m1!`, giving it as input the literal
|
||||
syntax `m2!()`. If it transcribes its argument unchanged into an appropriate
|
||||
position (in particular, not as an argument to yet another macro invocation),
|
||||
the expander will then proceed to evaluate `m2!()` (along with any other macro
|
||||
invocations `m1!(m2!())` produced).
|
||||
This says we're defining a macro named `vec`, much as `fn vec` would define a
|
||||
function named `vec`. In prose, we informally write a macro's name with an
|
||||
exclamation point, e.g. `vec!`. The exclamation point is part of the invocation
|
||||
syntax and serves to distinguish a macro from an ordinary function.
|
||||
|
||||
# Hygiene
|
||||
## Matching
|
||||
|
||||
To prevent clashes, rust implements
|
||||
[hygienic macros](http://en.wikipedia.org/wiki/Hygienic_macro).
|
||||
The macro is defined through a series of *rules*, which are pattern-matching
|
||||
cases. Above, we had
|
||||
|
||||
As an example, `loop` and `for-loop` labels (discussed in the lifetimes guide)
|
||||
will not clash. The following code will print "Hello!" only once:
|
||||
```ignore
|
||||
( $( $x:expr ),* ) => { ... };
|
||||
```
|
||||
|
||||
~~~
|
||||
macro_rules! loop_x {
|
||||
($e: expr) => (
|
||||
// $e will not interact with this 'x
|
||||
'x: loop {
|
||||
println!("Hello!");
|
||||
$e
|
||||
}
|
||||
);
|
||||
This is like a `match` expression arm, but the matching happens on Rust syntax
|
||||
trees, at compile time. The semicolon is optional on the last (here, only)
|
||||
case. The "pattern" on the left-hand side of `=>` is known as a *matcher*.
|
||||
These have [their own little grammar] within the language.
|
||||
|
||||
[their own little grammar]: ../reference.html#macros
|
||||
|
||||
The matcher `$x:expr` will match any Rust expression, binding that syntax tree
|
||||
to the *metavariable* `$x`. The identifier `expr` is a *fragment specifier*;
|
||||
the full possibilities are enumerated in the [advanced macros chapter][].
|
||||
Surrounding the matcher with `$(...),*` will match zero or more expressions,
|
||||
separated by commas.
|
||||
|
||||
Aside from the special matcher syntax, any Rust tokens that appear in a matcher
|
||||
must match exactly. For example,
|
||||
|
||||
```rust
|
||||
macro_rules! foo {
|
||||
(x => $e:expr) => (println!("mode X: {}", $e));
|
||||
(y => $e:expr) => (println!("mode Y: {}", $e));
|
||||
}
|
||||
|
||||
fn main() {
|
||||
'x: loop {
|
||||
loop_x!(break 'x);
|
||||
println!("I am never printed.");
|
||||
}
|
||||
foo!(y => 3);
|
||||
}
|
||||
~~~
|
||||
```
|
||||
|
||||
The two `'x` names did not clash, which would have caused the loop
|
||||
to print "I am never printed" and to run forever.
|
||||
will print
|
||||
|
||||
# Scoping and macro import/export
|
||||
```text
|
||||
mode Y: 3
|
||||
```
|
||||
|
||||
Macros are expanded at an early stage in compilation, before name resolution.
|
||||
One downside is that scoping works differently for macros, compared to other
|
||||
constructs in the language.
|
||||
|
||||
Definition and expansion of macros both happen in a single depth-first,
|
||||
lexical-order traversal of a crate's source. So a macro defined at module scope
|
||||
is visible to any subsequent code in the same module, which includes the body
|
||||
of any subsequent child `mod` items.
|
||||
|
||||
A macro defined within the body of a single `fn`, or anywhere else not at
|
||||
module scope, is visible only within that item.
|
||||
|
||||
If a module has the `macro_use` attribute, its macros are also visible in its
|
||||
parent module after the child's `mod` item. If the parent also has `macro_use`
|
||||
then the macros will be visible in the grandparent after the parent's `mod`
|
||||
item, and so forth.
|
||||
|
||||
The `macro_use` attribute can also appear on `extern crate`. In this context
|
||||
it controls which macros are loaded from the external crate, e.g.
|
||||
With
|
||||
|
||||
```rust,ignore
|
||||
#[macro_use(foo, bar)]
|
||||
extern crate baz;
|
||||
foo!(z => 3);
|
||||
```
|
||||
|
||||
If the attribute is given simply as `#[macro_use]`, all macros are loaded. If
|
||||
there is no `#[macro_use]` attribute then no macros are loaded. Only macros
|
||||
defined with the `#[macro_export]` attribute may be loaded.
|
||||
we get the compiler error
|
||||
|
||||
To load a crate's macros *without* linking it into the output, use `#[no_link]`
|
||||
as well.
|
||||
```text
|
||||
error: no rules expected the token `z`
|
||||
```
|
||||
|
||||
An example:
|
||||
## Expansion
|
||||
|
||||
The right-hand side of a macro rule is ordinary Rust syntax, for the most part.
|
||||
But we can splice in bits of syntax captured by the matcher. From the original
|
||||
example:
|
||||
|
||||
```ignore
|
||||
$(
|
||||
temp_vec.push($x);
|
||||
)*
|
||||
```
|
||||
|
||||
Each matched expression `$x` will produce a single `push` statement in the
|
||||
macro expansion. The repetition in the expansion proceeds in "lockstep" with
|
||||
repetition in the matcher (more on this in a moment).
|
||||
|
||||
Because `$x` was already declared as matching an expression, we don't repeat
|
||||
`:expr` on the right-hand side. Also, we don't include a separating comma as
|
||||
part of the repetition operator. Instead, we have a terminating semicolon
|
||||
within the repeated block.
|
||||
|
||||
Another detail: the `vec!` macro has *two* pairs of braces on the right-hand
|
||||
side. They are often combined like so:
|
||||
|
||||
```ignore
|
||||
macro_rules! foo {
|
||||
() => {{
|
||||
...
|
||||
}}
|
||||
}
|
||||
```
|
||||
|
||||
The outer braces are part of the syntax of `macro_rules!`. In fact, you can use
|
||||
`()` or `[]` instead. They simply delimit the right-hand side as a whole.
|
||||
|
||||
The inner braces are part of the expanded syntax. Remember, the `vec!` macro is
|
||||
used in an expression context. To write an expression with multiple statements,
|
||||
including `let`-bindings, we use a block. If your macro expands to a single
|
||||
expression, you don't need this extra layer of braces.
|
||||
|
||||
Note that we never *declared* that the macro produces an expression. In fact,
|
||||
this is not determined until we use the macro as an expression. With care, you
|
||||
can write a macro whose expansion works in several contexts. For example,
|
||||
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:
|
||||
|
||||
1. the behavior of `$(...)*` is to walk through one "layer" of repetitions, for
|
||||
all of the `$name`s it contains, in lockstep, and
|
||||
2. each `$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.
|
||||
|
||||
This baroque macro illustrates the duplication of variables from outer
|
||||
repetition levels.
|
||||
|
||||
```rust
|
||||
macro_rules! m1 { () => (()) }
|
||||
|
||||
// visible here: m1
|
||||
|
||||
mod foo {
|
||||
// visible here: m1
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! m2 { () => (()) }
|
||||
|
||||
// visible here: m1, m2
|
||||
macro_rules! o_O {
|
||||
(
|
||||
$(
|
||||
$x:expr; [ $( $y:expr ),* ]
|
||||
);*
|
||||
) => {
|
||||
&[ $($( $x + $y ),*),* ]
|
||||
}
|
||||
}
|
||||
|
||||
// visible here: m1
|
||||
fn main() {
|
||||
let a: &[i32]
|
||||
= o_O!(10; [1, 2, 3];
|
||||
20; [4, 5, 6]);
|
||||
|
||||
macro_rules! m3 { () => (()) }
|
||||
|
||||
// visible here: m1, m3
|
||||
|
||||
#[macro_use]
|
||||
mod bar {
|
||||
// visible here: m1, m3
|
||||
|
||||
macro_rules! m4 { () => (()) }
|
||||
|
||||
// visible here: m1, m3, m4
|
||||
assert_eq!(a, [11, 12, 13, 24, 25, 26]);
|
||||
}
|
||||
|
||||
// visible here: m1, m3, m4
|
||||
# fn main() { }
|
||||
```
|
||||
|
||||
When this library is loaded with `#[use_macros] extern crate`, only `m2` will
|
||||
be imported.
|
||||
That's most of the matcher syntax. These examples use `$(...)*`, which is a
|
||||
"zero or more" match. Alternatively you can write `$(...)+` for a "one or
|
||||
more" match. Both forms optionally include a separator, which can be any token
|
||||
except `+` or `*`.
|
||||
|
||||
The Rust Reference has a [listing of macro-related
|
||||
attributes](../reference.html#macro--and-plugin-related-attributes).
|
||||
# Hygiene
|
||||
|
||||
# The variable `$crate`
|
||||
Some languages implement macros using simple text substitution, which leads to
|
||||
various problems. For example, this C program prints `13` instead of the
|
||||
expected `25`.
|
||||
|
||||
A further difficulty occurs when a macro is used in multiple crates. Say that
|
||||
`mylib` defines
|
||||
```text
|
||||
#define FIVE_TIMES(x) 5 * x
|
||||
|
||||
int main() {
|
||||
printf("%d\n", FIVE_TIMES(2 + 3));
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
After expansion we have `5 * 2 + 3`, and multiplication has greater precedence
|
||||
than addition. If you've used C macros a lot, you probably know the standard
|
||||
idioms for avoiding this problem, as well as five or six others. In Rust, we
|
||||
don't have to worry about it.
|
||||
|
||||
```rust
|
||||
pub fn increment(x: u32) -> u32 {
|
||||
x + 1
|
||||
macro_rules! five_times {
|
||||
($x:expr) => (5 * $x);
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! inc_a {
|
||||
($x:expr) => ( ::increment($x) )
|
||||
fn main() {
|
||||
assert_eq!(25, five_times!(2 + 3));
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! inc_b {
|
||||
($x:expr) => ( ::mylib::increment($x) )
|
||||
}
|
||||
# fn main() { }
|
||||
```
|
||||
|
||||
`inc_a` only works within `mylib`, while `inc_b` only works outside the
|
||||
library. Furthermore, `inc_b` will break if the user imports `mylib` under
|
||||
another name.
|
||||
The metavariable `$x` is parsed as a single expression node, and keeps its
|
||||
place in the syntax tree even after substitution.
|
||||
|
||||
Rust does not (yet) have a hygiene system for crate references, but it does
|
||||
provide a simple workaround for this problem. Within a macro imported from a
|
||||
crate named `foo`, the special macro variable `$crate` will expand to `::foo`.
|
||||
By contrast, when a macro is defined and then used in the same crate, `$crate`
|
||||
will expand to nothing. This means we can write
|
||||
Another common problem in macro systems is *variable capture*. Here's a C
|
||||
macro, using [a GNU C extension] to emulate Rust's expression blocks.
|
||||
|
||||
[a GNU C extension]: https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html
|
||||
|
||||
```text
|
||||
#define LOG(msg) ({ \
|
||||
int state = get_log_state(); \
|
||||
if (state > 0) { \
|
||||
printf("log(%d): %s\n", state, msg); \
|
||||
} \
|
||||
})
|
||||
```
|
||||
|
||||
This looks reasonable, but watch what happens in this example:
|
||||
|
||||
```text
|
||||
const char *state = "reticulating splines";
|
||||
LOG(state);
|
||||
```
|
||||
|
||||
The program will likely segfault, after it tries to execute
|
||||
|
||||
```text
|
||||
printf("log(%d): %s\n", state, state);
|
||||
```
|
||||
|
||||
The equivalent Rust macro has the desired behavior.
|
||||
|
||||
```rust
|
||||
#[macro_export]
|
||||
macro_rules! inc {
|
||||
($x:expr) => ( $crate::increment($x) )
|
||||
# fn get_log_state() -> i32 { 3 }
|
||||
macro_rules! log {
|
||||
($msg:expr) => {{
|
||||
let state: i32 = get_log_state();
|
||||
if state > 0 {
|
||||
println!("log({}): {}", state, $msg);
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let state: &str = "reticulating splines";
|
||||
log!(state);
|
||||
}
|
||||
# fn main() { }
|
||||
```
|
||||
|
||||
to define a single macro that works both inside and outside our library. The
|
||||
function name will expand to either `::increment` or `::mylib::increment`.
|
||||
This works because Rust has a [hygienic macro system][]. Each macro expansion
|
||||
happens in a distinct *syntax context*, and each variable is tagged with the
|
||||
syntax context where it was introduced. It's as though the variable `state`
|
||||
inside `main` is painted a different "color" from the variable `state` inside
|
||||
the macro, and therefore they don't conflict.
|
||||
|
||||
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.
|
||||
[hygienic macro system]: http://en.wikipedia.org/wiki/Hygienic_macro
|
||||
|
||||
# A final note
|
||||
This also restricts the ability of macros to introduce new bindings at the
|
||||
invocation site. Code such as the following will not work:
|
||||
|
||||
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.
|
||||
```rust,ignore
|
||||
macro_rules! foo {
|
||||
() => (let x = 3);
|
||||
}
|
||||
|
||||
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
|
||||
flexibility of running arbitrary Rust code within the compiler. Syntax
|
||||
extension plugins are sometimes called *procedural macros* for this reason.
|
||||
fn main() {
|
||||
foo!();
|
||||
println!("{}", x);
|
||||
}
|
||||
```
|
||||
|
||||
Instead you need to pass the variable name into the invocation, so it's tagged
|
||||
with the right syntax context.
|
||||
|
||||
```rust
|
||||
macro_rules! foo {
|
||||
($v:ident) => (let $v = 3);
|
||||
}
|
||||
|
||||
fn main() {
|
||||
foo!(x);
|
||||
println!("{}", x);
|
||||
}
|
||||
```
|
||||
|
||||
This holds for `let` bindings and loop labels, but not for [items][].
|
||||
So the following code does compile:
|
||||
|
||||
```rust
|
||||
macro_rules! foo {
|
||||
() => (fn x() { });
|
||||
}
|
||||
|
||||
fn main() {
|
||||
foo!();
|
||||
x();
|
||||
}
|
||||
```
|
||||
|
||||
[items]: ../reference.html#items
|
||||
|
||||
# Further reading
|
||||
|
||||
The [advanced macros chapter][] goes into more detail about macro syntax. It
|
||||
also describes how to share macros between different modules or crates.
|
||||
|
||||
[advanced macros chapter]: advanced-macros.html
|
||||
|
|
|
@ -99,8 +99,8 @@ fn grow(&self) -> Circle {
|
|||
# Circle } }
|
||||
```
|
||||
|
||||
We just say we're returning a `Circle`. With this, we can grow a new circle
|
||||
that's twice as big as the old one.
|
||||
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.
|
||||
|
||||
## Static methods
|
||||
|
||||
|
|
|
@ -293,7 +293,7 @@ struct Foo<'a> {
|
|||
}
|
||||
|
||||
fn main() {
|
||||
let y = &5; // this is the same as `let _y = 5; let y = &_y;
|
||||
let y = &5; // this is the same as `let _y = 5; let y = &_y;`
|
||||
let f = Foo { x: y };
|
||||
|
||||
println!("{}", f.x);
|
||||
|
|
|
@ -273,6 +273,96 @@ 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.
|
||||
|
||||
## Where clause
|
||||
|
||||
Writing functions with only a few generic types and a small number of trait
|
||||
bounds isn't too bad, but as the number increases, the syntax gets increasingly
|
||||
awkward:
|
||||
|
||||
```
|
||||
use std::fmt::Debug;
|
||||
|
||||
fn foo<T: Clone, K: Clone + Debug>(x: T, y: K) {
|
||||
x.clone();
|
||||
y.clone();
|
||||
println!("{:?}", y);
|
||||
}
|
||||
```
|
||||
|
||||
The name of the function is on the far left, and the parameter list is on the
|
||||
far right. The bounds are getting in the way.
|
||||
|
||||
Rust has a solution, and it's called a '`where` clause':
|
||||
|
||||
```
|
||||
use std::fmt::Debug;
|
||||
|
||||
fn foo<T: Clone, K: Clone + Debug>(x: T, y: K) {
|
||||
x.clone();
|
||||
y.clone();
|
||||
println!("{:?}", y);
|
||||
}
|
||||
|
||||
fn bar<T, K>(x: T, y: K) where T: Clone, K: Clone + Debug {
|
||||
x.clone();
|
||||
y.clone();
|
||||
println!("{:?}", y);
|
||||
}
|
||||
|
||||
fn main() {
|
||||
foo("Hello", "world");
|
||||
bar("Hello", "workd");
|
||||
}
|
||||
```
|
||||
|
||||
`foo()` uses the syntax we showed earlier, and `bar()` uses a `where` clause.
|
||||
All you need to do is leave off the bounds when defining your type parameters,
|
||||
and then add `where` after the parameter list. For longer lists, whitespace can
|
||||
be added:
|
||||
|
||||
```
|
||||
use std::fmt::Debug;
|
||||
|
||||
fn bar<T, K>(x: T, y: K)
|
||||
where T: Clone,
|
||||
K: Clone + Debug {
|
||||
|
||||
x.clone();
|
||||
y.clone();
|
||||
println!("{:?}", y);
|
||||
}
|
||||
```
|
||||
|
||||
This flexibility can add clarity in complex situations.
|
||||
|
||||
`where` is also more powerful than the simpler syntax. For example:
|
||||
|
||||
```
|
||||
trait ConvertTo<Output> {
|
||||
fn convert(&self) -> Output;
|
||||
}
|
||||
|
||||
impl ConvertTo<i64> for i32 {
|
||||
fn convert(&self) -> i64 { *self as i64 }
|
||||
}
|
||||
|
||||
// can be called with T == i32
|
||||
fn normal<T: ConvertTo<i64>>(x: &T) -> i64 {
|
||||
x.convert()
|
||||
}
|
||||
|
||||
// can be called with T == i64
|
||||
fn inverse<T>() -> T
|
||||
// this is using ConvertTo as if it were "ConvertFrom<i32>"
|
||||
where i32: ConvertTo<T> {
|
||||
1i32.convert()
|
||||
}
|
||||
```
|
||||
|
||||
This shows off the additional feature of `where` clauses: they allow bounds
|
||||
where the left-hand side is an arbitrary type (`i32` in this case), not just a
|
||||
plain type parameter (like `T`).
|
||||
|
||||
## Our `inverse` Example
|
||||
|
||||
Back in [Generics](generics.html), we were trying to write code like this:
|
||||
|
|
|
@ -308,7 +308,7 @@ crate to allow) and of course requires an `unsafe` block.
|
|||
## Assembly template
|
||||
|
||||
The `assembly template` is the only required parameter and must be a
|
||||
literal string (i.e `""`)
|
||||
literal string (i.e. `""`)
|
||||
|
||||
```
|
||||
#![feature(asm)]
|
||||
|
@ -412,7 +412,7 @@ 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
|
||||
separated literal strings (i.e. `:"foo", "bar", "baz"`). It's used to
|
||||
specify some extra info about the inline assembly:
|
||||
|
||||
Current valid options are:
|
||||
|
@ -420,7 +420,7 @@ 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
|
||||
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.
|
||||
|
||||
|
@ -646,8 +646,8 @@ 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".
|
||||
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`
|
||||
|
|
|
@ -35,14 +35,14 @@
|
|||
//!
|
||||
//! ```
|
||||
//! use std::sync::Arc;
|
||||
//! use std::thread::Thread;
|
||||
//! use std::thread;
|
||||
//!
|
||||
//! let five = Arc::new(5);
|
||||
//!
|
||||
//! for _ in 0..10 {
|
||||
//! let five = five.clone();
|
||||
//!
|
||||
//! Thread::spawn(move || {
|
||||
//! thread::spawn(move || {
|
||||
//! println!("{:?}", five);
|
||||
//! });
|
||||
//! }
|
||||
|
@ -52,14 +52,14 @@
|
|||
//!
|
||||
//! ```
|
||||
//! use std::sync::{Arc, Mutex};
|
||||
//! use std::thread::Thread;
|
||||
//! use std::thread;
|
||||
//!
|
||||
//! let five = Arc::new(Mutex::new(5));
|
||||
//!
|
||||
//! for _ in 0..10 {
|
||||
//! let five = five.clone();
|
||||
//!
|
||||
//! Thread::spawn(move || {
|
||||
//! thread::spawn(move || {
|
||||
//! let mut number = five.lock().unwrap();
|
||||
//!
|
||||
//! *number += 1;
|
||||
|
@ -95,7 +95,7 @@ use heap::deallocate;
|
|||
///
|
||||
/// ```rust
|
||||
/// use std::sync::Arc;
|
||||
/// use std::thread::Thread;
|
||||
/// use std::thread;
|
||||
///
|
||||
/// fn main() {
|
||||
/// let numbers: Vec<_> = (0..100u32).map(|i| i as f32).collect();
|
||||
|
@ -104,7 +104,7 @@ use heap::deallocate;
|
|||
/// for _ in 0..10 {
|
||||
/// let child_numbers = shared_numbers.clone();
|
||||
///
|
||||
/// Thread::spawn(move || {
|
||||
/// thread::spawn(move || {
|
||||
/// let local_numbers = child_numbers.as_slice();
|
||||
///
|
||||
/// // Work with the local numbers
|
||||
|
@ -621,7 +621,7 @@ mod tests {
|
|||
use std::option::Option::{Some, None};
|
||||
use std::sync::atomic;
|
||||
use std::sync::atomic::Ordering::{Acquire, SeqCst};
|
||||
use std::thread::Thread;
|
||||
use std::thread;
|
||||
use std::vec::Vec;
|
||||
use super::{Arc, Weak, weak_count, strong_count};
|
||||
use std::sync::Mutex;
|
||||
|
@ -648,7 +648,7 @@ mod tests {
|
|||
|
||||
let (tx, rx) = channel();
|
||||
|
||||
let _t = Thread::spawn(move || {
|
||||
let _t = thread::spawn(move || {
|
||||
let arc_v: Arc<Vec<i32>> = rx.recv().unwrap();
|
||||
assert_eq!((*arc_v)[3], 4);
|
||||
});
|
||||
|
|
|
@ -126,11 +126,3 @@ pub fn oom() -> ! {
|
|||
// optimize it out).
|
||||
#[doc(hidden)]
|
||||
pub fn fixme_14344_be_sure_to_link_to_collections() {}
|
||||
|
||||
// NOTE: remove after next snapshot
|
||||
#[cfg(all(stage0, not(test)))]
|
||||
#[doc(hidden)]
|
||||
mod std {
|
||||
pub use core::fmt;
|
||||
pub use core::option;
|
||||
}
|
||||
|
|
|
@ -170,7 +170,7 @@ struct RcBox<T> {
|
|||
weak: Cell<usize>
|
||||
}
|
||||
|
||||
/// An immutable reference-counted pointer type.
|
||||
/// A reference-counted pointer type over an immutable value.
|
||||
///
|
||||
/// See the [module level documentation](./index.html) for more details.
|
||||
#[unsafe_no_drop_flag]
|
||||
|
@ -776,9 +776,7 @@ impl<T> RcBoxPtr<T> for Rc<T> {
|
|||
// the contract anyway.
|
||||
// This allows the null check to be elided in the destructor if we
|
||||
// manipulated the reference count in the same function.
|
||||
if cfg!(not(stage0)) { // NOTE remove cfg after next snapshot
|
||||
assume(!self._ptr.is_null());
|
||||
}
|
||||
assume(!self._ptr.is_null());
|
||||
&(**self._ptr)
|
||||
}
|
||||
}
|
||||
|
@ -792,9 +790,7 @@ impl<T> RcBoxPtr<T> for Weak<T> {
|
|||
// the contract anyway.
|
||||
// This allows the null check to be elided in the destructor if we
|
||||
// manipulated the reference count in the same function.
|
||||
if cfg!(not(stage0)) { // NOTE remove cfg after next snapshot
|
||||
assume(!self._ptr.is_null());
|
||||
}
|
||||
assume(!self._ptr.is_null());
|
||||
&(**self._ptr)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -655,17 +655,7 @@ impl<T: Ord> FromIterator<T> for BinaryHeap<T> {
|
|||
}
|
||||
}
|
||||
|
||||
// NOTE(stage0): remove impl after a snapshot
|
||||
#[cfg(stage0)]
|
||||
impl<T: Ord> IntoIterator for BinaryHeap<T> {
|
||||
type IntoIter = IntoIter<T>;
|
||||
|
||||
fn into_iter(self) -> IntoIter<T> {
|
||||
self.into_iter()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: Ord> IntoIterator for BinaryHeap<T> {
|
||||
type Item = T;
|
||||
type IntoIter = IntoIter<T>;
|
||||
|
@ -675,17 +665,7 @@ impl<T: Ord> IntoIterator for BinaryHeap<T> {
|
|||
}
|
||||
}
|
||||
|
||||
// NOTE(stage0): remove impl after a snapshot
|
||||
#[cfg(stage0)]
|
||||
impl<'a, T> IntoIterator for &'a BinaryHeap<T> where T: Ord {
|
||||
type IntoIter = Iter<'a, T>;
|
||||
|
||||
fn into_iter(self) -> Iter<'a, T> {
|
||||
self.iter()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<'a, T> IntoIterator for &'a BinaryHeap<T> where T: Ord {
|
||||
type Item = &'a T;
|
||||
type IntoIter = Iter<'a, T>;
|
||||
|
|
|
@ -1070,17 +1070,7 @@ impl<'a> RandomAccessIterator for Iter<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
// NOTE(stage0): remove impl after a snapshot
|
||||
#[cfg(stage0)]
|
||||
impl<'a> IntoIterator for &'a Bitv {
|
||||
type IntoIter = Iter<'a>;
|
||||
|
||||
fn into_iter(self) -> Iter<'a> {
|
||||
self.iter()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<'a> IntoIterator for &'a Bitv {
|
||||
type Item = bool;
|
||||
type IntoIter = Iter<'a>;
|
||||
|
@ -1894,17 +1884,7 @@ impl<'a> Iterator for SymmetricDifference<'a> {
|
|||
#[inline] fn size_hint(&self) -> (usize, Option<usize>) { self.0.size_hint() }
|
||||
}
|
||||
|
||||
// NOTE(stage0): remove impl after a snapshot
|
||||
#[cfg(stage0)]
|
||||
impl<'a> IntoIterator for &'a BitvSet {
|
||||
type IntoIter = SetIter<'a>;
|
||||
|
||||
fn into_iter(self) -> SetIter<'a> {
|
||||
self.iter()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<'a> IntoIterator for &'a BitvSet {
|
||||
type Item = usize;
|
||||
type IntoIter = SetIter<'a>;
|
||||
|
|
|
@ -462,17 +462,7 @@ impl<K: Ord, V> BTreeMap<K, V> {
|
|||
}
|
||||
}
|
||||
|
||||
// NOTE(stage0): remove impl after a snapshot
|
||||
#[cfg(stage0)]
|
||||
impl<K, V> IntoIterator for BTreeMap<K, V> {
|
||||
type IntoIter = IntoIter<K, V>;
|
||||
|
||||
fn into_iter(self) -> IntoIter<K, V> {
|
||||
self.into_iter()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<K, V> IntoIterator for BTreeMap<K, V> {
|
||||
type Item = (K, V);
|
||||
type IntoIter = IntoIter<K, V>;
|
||||
|
@ -482,17 +472,7 @@ impl<K, V> IntoIterator for BTreeMap<K, V> {
|
|||
}
|
||||
}
|
||||
|
||||
// NOTE(stage0): remove impl after a snapshot
|
||||
#[cfg(stage0)]
|
||||
impl<'a, K, V> IntoIterator for &'a BTreeMap<K, V> {
|
||||
type IntoIter = Iter<'a, K, V>;
|
||||
|
||||
fn into_iter(self) -> Iter<'a, K, V> {
|
||||
self.iter()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<'a, K, V> IntoIterator for &'a BTreeMap<K, V> {
|
||||
type Item = (&'a K, &'a V);
|
||||
type IntoIter = Iter<'a, K, V>;
|
||||
|
@ -502,17 +482,7 @@ impl<'a, K, V> IntoIterator for &'a BTreeMap<K, V> {
|
|||
}
|
||||
}
|
||||
|
||||
// NOTE(stage0): remove impl after a snapshot
|
||||
#[cfg(stage0)]
|
||||
impl<'a, K, V> IntoIterator for &'a mut BTreeMap<K, V> {
|
||||
type IntoIter = IterMut<'a, K, V>;
|
||||
|
||||
fn into_iter(mut self) -> IterMut<'a, K, V> {
|
||||
self.iter_mut()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<'a, K, V> IntoIterator for &'a mut BTreeMap<K, V> {
|
||||
type Item = (&'a K, &'a mut V);
|
||||
type IntoIter = IterMut<'a, K, V>;
|
||||
|
|
|
@ -480,17 +480,7 @@ impl<T: Ord> FromIterator<T> for BTreeSet<T> {
|
|||
}
|
||||
}
|
||||
|
||||
// NOTE(stage0): remove impl after a snapshot
|
||||
#[cfg(stage0)]
|
||||
impl<T> IntoIterator for BTreeSet<T> {
|
||||
type IntoIter = IntoIter<T>;
|
||||
|
||||
fn into_iter(self) -> IntoIter<T> {
|
||||
self.into_iter()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T> IntoIterator for BTreeSet<T> {
|
||||
type Item = T;
|
||||
type IntoIter = IntoIter<T>;
|
||||
|
@ -500,17 +490,7 @@ impl<T> IntoIterator for BTreeSet<T> {
|
|||
}
|
||||
}
|
||||
|
||||
// NOTE(stage0): remove impl after a snapshot
|
||||
#[cfg(stage0)]
|
||||
impl<'a, T> IntoIterator for &'a BTreeSet<T> {
|
||||
type IntoIter = Iter<'a, T>;
|
||||
|
||||
fn into_iter(self) -> Iter<'a, T> {
|
||||
self.iter()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<'a, T> IntoIterator for &'a BTreeSet<T> {
|
||||
type Item = &'a T;
|
||||
type IntoIter = Iter<'a, T>;
|
||||
|
|
|
@ -837,17 +837,7 @@ impl<A> FromIterator<A> for DList<A> {
|
|||
}
|
||||
}
|
||||
|
||||
// NOTE(stage0): remove impl after a snapshot
|
||||
#[cfg(stage0)]
|
||||
impl<T> IntoIterator for DList<T> {
|
||||
type IntoIter = IntoIter<T>;
|
||||
|
||||
fn into_iter(self) -> IntoIter<T> {
|
||||
self.into_iter()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T> IntoIterator for DList<T> {
|
||||
type Item = T;
|
||||
type IntoIter = IntoIter<T>;
|
||||
|
@ -857,17 +847,7 @@ impl<T> IntoIterator for DList<T> {
|
|||
}
|
||||
}
|
||||
|
||||
// NOTE(stage0): remove impl after a snapshot
|
||||
#[cfg(stage0)]
|
||||
impl<'a, T> IntoIterator for &'a DList<T> {
|
||||
type IntoIter = Iter<'a, T>;
|
||||
|
||||
fn into_iter(self) -> Iter<'a, T> {
|
||||
self.iter()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<'a, T> IntoIterator for &'a DList<T> {
|
||||
type Item = &'a T;
|
||||
type IntoIter = Iter<'a, T>;
|
||||
|
@ -877,17 +857,6 @@ impl<'a, T> IntoIterator for &'a DList<T> {
|
|||
}
|
||||
}
|
||||
|
||||
// NOTE(stage0): remove impl after a snapshot
|
||||
#[cfg(stage0)]
|
||||
impl<'a, T> IntoIterator for &'a mut DList<T> {
|
||||
type IntoIter = IterMut<'a, T>;
|
||||
|
||||
fn into_iter(mut self) -> IterMut<'a, T> {
|
||||
self.iter_mut()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot
|
||||
impl<'a, T> IntoIterator for &'a mut DList<T> {
|
||||
type Item = &'a mut T;
|
||||
type IntoIter = IterMut<'a, T>;
|
||||
|
@ -971,7 +940,7 @@ mod tests {
|
|||
use prelude::*;
|
||||
use std::rand;
|
||||
use std::hash::{self, SipHasher};
|
||||
use std::thread::Thread;
|
||||
use std::thread;
|
||||
use test::Bencher;
|
||||
use test;
|
||||
|
||||
|
@ -1320,7 +1289,7 @@ mod tests {
|
|||
#[test]
|
||||
fn test_send() {
|
||||
let n = list_from(&[1,2,3]);
|
||||
Thread::scoped(move || {
|
||||
thread::spawn(move || {
|
||||
check_links(&n);
|
||||
let a: &[_] = &[&1,&2,&3];
|
||||
assert_eq!(a, n.iter().collect::<Vec<_>>());
|
||||
|
|
|
@ -257,17 +257,7 @@ impl<E:CLike> FromIterator<E> for EnumSet<E> {
|
|||
}
|
||||
}
|
||||
|
||||
// NOTE(stage0): remove impl after a snapshot
|
||||
#[cfg(stage0)]
|
||||
impl<'a, E> IntoIterator for &'a EnumSet<E> where E: CLike {
|
||||
type IntoIter = Iter<E>;
|
||||
|
||||
fn into_iter(self) -> Iter<E> {
|
||||
self.iter()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<'a, E> IntoIterator for &'a EnumSet<E> where E: CLike {
|
||||
type Item = E;
|
||||
type IntoIter = Iter<E>;
|
||||
|
|
|
@ -111,15 +111,6 @@ pub fn fixme_14344_be_sure_to_link_to_collections() {}
|
|||
|
||||
#[cfg(not(test))]
|
||||
mod std {
|
||||
// NOTE: remove after next snapshot
|
||||
#[cfg(stage0)] pub use core::clone; // derive(Clone)
|
||||
#[cfg(stage0)] pub use core::cmp; // derive(Eq, Ord, etc.)
|
||||
#[cfg(stage0)] pub use core::marker; // derive(Copy)
|
||||
#[cfg(stage0)] pub use core::hash; // derive(Hash)
|
||||
#[cfg(stage0)] pub use core::iter;
|
||||
#[cfg(stage0)] pub use core::fmt; // necessary for panic!()
|
||||
#[cfg(stage0)] pub use core::option; // necessary for panic!()
|
||||
|
||||
pub use core::ops; // RangeFull
|
||||
}
|
||||
|
||||
|
|
|
@ -9,12 +9,34 @@
|
|||
// except according to those terms.
|
||||
|
||||
/// Creates a `Vec` containing the arguments.
|
||||
///
|
||||
/// `vec!` allows `Vec`s to be defined with the same syntax as array expressions.
|
||||
/// There are two forms of this macro:
|
||||
///
|
||||
/// - Create a `Vec` containing a given list of elements:
|
||||
///
|
||||
/// ```
|
||||
/// let v = vec![1, 2, 3];
|
||||
/// assert_eq!(v[0], 1);
|
||||
/// assert_eq!(v[1], 2);
|
||||
/// assert_eq!(v[2], 3);
|
||||
/// ```
|
||||
///
|
||||
/// - Create a `Vec` from a given element and size:
|
||||
///
|
||||
/// ```
|
||||
/// let v = vec![1; 3];
|
||||
/// assert_eq!(v, vec![1, 1, 1]);
|
||||
/// ```
|
||||
///
|
||||
/// Note that unlike array expressions this syntax supports all elements
|
||||
/// which implement `Clone` and the number of elements doesn't have to be
|
||||
/// a constant.
|
||||
#[macro_export]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
macro_rules! vec {
|
||||
($x:expr; $y:expr) => (
|
||||
<[_] as $crate::slice::SliceExt>::into_vec(
|
||||
$crate::boxed::Box::new([$x; $y]))
|
||||
($elem:expr; $n:expr) => (
|
||||
$crate::vec::from_elem($elem, $n)
|
||||
);
|
||||
($($x:expr),*) => (
|
||||
<[_] as $crate::slice::SliceExt>::into_vec(
|
||||
|
|
|
@ -8,9 +8,13 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! This crate implements a double-ended queue with `O(1)` amortized inserts and removals from both
|
||||
//! ends of the container. It also has `O(1)` indexing like a vector. The contained elements are
|
||||
//! not required to be copyable, and the queue will be sendable if the contained type is sendable.
|
||||
//! RingBuf is a double-ended queue, which is implemented with the help of a
|
||||
//! growing circular buffer.
|
||||
//!
|
||||
//! This queue has `O(1)` amortized inserts and removals from both ends of the
|
||||
//! container. It also has `O(1)` indexing like a vector. The contained elements
|
||||
//! are not required to be copyable, and the queue will be sendable if the
|
||||
//! contained type is sendable.
|
||||
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
|
||||
|
@ -113,7 +117,8 @@ impl<T> RingBuf<T> {
|
|||
#[inline]
|
||||
fn is_full(&self) -> bool { self.cap - self.len() == 1 }
|
||||
|
||||
/// Returns the index in the underlying buffer for a given logical element index.
|
||||
/// Returns the index in the underlying buffer for a given logical element
|
||||
/// index.
|
||||
#[inline]
|
||||
fn wrap_index(&self, idx: usize) -> usize { wrap_index(idx, self.cap) }
|
||||
|
||||
|
@ -1699,17 +1704,7 @@ impl<A> FromIterator<A> for RingBuf<A> {
|
|||
}
|
||||
}
|
||||
|
||||
// NOTE(stage0): remove impl after a snapshot
|
||||
#[cfg(stage0)]
|
||||
impl<T> IntoIterator for RingBuf<T> {
|
||||
type IntoIter = IntoIter<T>;
|
||||
|
||||
fn into_iter(self) -> IntoIter<T> {
|
||||
self.into_iter()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T> IntoIterator for RingBuf<T> {
|
||||
type Item = T;
|
||||
type IntoIter = IntoIter<T>;
|
||||
|
@ -1719,17 +1714,7 @@ impl<T> IntoIterator for RingBuf<T> {
|
|||
}
|
||||
}
|
||||
|
||||
// NOTE(stage0): remove impl after a snapshot
|
||||
#[cfg(stage0)]
|
||||
impl<'a, T> IntoIterator for &'a RingBuf<T> {
|
||||
type IntoIter = Iter<'a, T>;
|
||||
|
||||
fn into_iter(self) -> Iter<'a, T> {
|
||||
self.iter()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<'a, T> IntoIterator for &'a RingBuf<T> {
|
||||
type Item = &'a T;
|
||||
type IntoIter = Iter<'a, T>;
|
||||
|
@ -1739,17 +1724,7 @@ impl<'a, T> IntoIterator for &'a RingBuf<T> {
|
|||
}
|
||||
}
|
||||
|
||||
// NOTE(stage0): remove impl after a snapshot
|
||||
#[cfg(stage0)]
|
||||
impl<'a, T> IntoIterator for &'a mut RingBuf<T> {
|
||||
type IntoIter = IterMut<'a, T>;
|
||||
|
||||
fn into_iter(mut self) -> IterMut<'a, T> {
|
||||
self.iter_mut()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<'a, T> IntoIterator for &'a mut RingBuf<T> {
|
||||
type Item = &'a mut T;
|
||||
type IntoIter = IterMut<'a, T>;
|
||||
|
|
|
@ -1252,6 +1252,30 @@ unsafe fn dealloc<T>(ptr: *mut T, len: usize) {
|
|||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn from_elem<T: Clone>(elem: T, n: usize) -> Vec<T> {
|
||||
unsafe {
|
||||
let mut v = Vec::with_capacity(n);
|
||||
let mut ptr = v.as_mut_ptr();
|
||||
|
||||
// Write all elements except the last one
|
||||
for i in 1..n {
|
||||
ptr::write(ptr, Clone::clone(&elem));
|
||||
ptr = ptr.offset(1);
|
||||
v.set_len(i); // Increment the length in every step in case Clone::clone() panics
|
||||
}
|
||||
|
||||
if n > 0 {
|
||||
// We can write the last element directly without cloning needlessly
|
||||
ptr::write(ptr, elem);
|
||||
v.set_len(n);
|
||||
}
|
||||
|
||||
v
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Common trait implementations for Vec
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -1383,7 +1407,7 @@ impl<T> ops::DerefMut for Vec<T> {
|
|||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T> FromIterator<T> for Vec<T> {
|
||||
#[inline]
|
||||
fn from_iter<I:Iterator<Item=T>>(iterator: I) -> Vec<T> {
|
||||
fn from_iter<I:Iterator<Item=T>>(mut iterator: I) -> Vec<T> {
|
||||
let (lower, _) = iterator.size_hint();
|
||||
let mut vector = Vec::with_capacity(lower);
|
||||
|
||||
|
@ -1393,13 +1417,20 @@ impl<T> FromIterator<T> for Vec<T> {
|
|||
// vector.push(item);
|
||||
// }
|
||||
//
|
||||
// This equivalent crucially runs the iterator precisely once. The
|
||||
// optimization below (eliding bound/growth checks) means that we
|
||||
// actually run the iterator twice. To ensure the "moral equivalent" we
|
||||
// do a `fuse()` operation to ensure that the iterator continues to
|
||||
// return `None` after seeing the first `None`.
|
||||
let mut i = iterator.fuse();
|
||||
for element in i.by_ref().take(vector.capacity()) {
|
||||
// This equivalent crucially runs the iterator precisely once. Below we
|
||||
// actually in theory run the iterator twice (one without bounds checks
|
||||
// and one with). To achieve the "moral equivalent", we use the `if`
|
||||
// statement below to break out early.
|
||||
//
|
||||
// If the first loop has terminated, then we have one of two conditions.
|
||||
//
|
||||
// 1. The underlying iterator returned `None`. In this case we are
|
||||
// guaranteed that less than `vector.capacity()` elements have been
|
||||
// returned, so we break out early.
|
||||
// 2. The underlying iterator yielded `vector.capacity()` elements and
|
||||
// has not yielded `None` yet. In this case we run the iterator to
|
||||
// its end below.
|
||||
for element in iterator.by_ref().take(vector.capacity()) {
|
||||
let len = vector.len();
|
||||
unsafe {
|
||||
ptr::write(vector.get_unchecked_mut(len), element);
|
||||
|
@ -1407,24 +1438,16 @@ impl<T> FromIterator<T> for Vec<T> {
|
|||
}
|
||||
}
|
||||
|
||||
for element in i {
|
||||
vector.push(element)
|
||||
if vector.len() == vector.capacity() {
|
||||
for element in iterator {
|
||||
vector.push(element);
|
||||
}
|
||||
}
|
||||
vector
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE(stage0): remove impl after a snapshot
|
||||
#[cfg(stage0)]
|
||||
impl<T> IntoIterator for Vec<T> {
|
||||
type IntoIter = IntoIter<T>;
|
||||
|
||||
fn into_iter(self) -> IntoIter<T> {
|
||||
self.into_iter()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T> IntoIterator for Vec<T> {
|
||||
type Item = T;
|
||||
type IntoIter = IntoIter<T>;
|
||||
|
@ -1434,17 +1457,7 @@ impl<T> IntoIterator for Vec<T> {
|
|||
}
|
||||
}
|
||||
|
||||
// NOTE(stage0): remove impl after a snapshot
|
||||
#[cfg(stage0)]
|
||||
impl<'a, T> IntoIterator for &'a Vec<T> {
|
||||
type IntoIter = slice::Iter<'a, T>;
|
||||
|
||||
fn into_iter(self) -> slice::Iter<'a, T> {
|
||||
self.iter()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<'a, T> IntoIterator for &'a Vec<T> {
|
||||
type Item = &'a T;
|
||||
type IntoIter = slice::Iter<'a, T>;
|
||||
|
@ -1454,17 +1467,7 @@ impl<'a, T> IntoIterator for &'a Vec<T> {
|
|||
}
|
||||
}
|
||||
|
||||
// NOTE(stage0): remove impl after a snapshot
|
||||
#[cfg(stage0)]
|
||||
impl<'a, T> IntoIterator for &'a mut Vec<T> {
|
||||
type IntoIter = slice::IterMut<'a, T>;
|
||||
|
||||
fn into_iter(mut self) -> slice::IterMut<'a, T> {
|
||||
self.iter_mut()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<'a, T> IntoIterator for &'a mut Vec<T> {
|
||||
type Item = &'a mut T;
|
||||
type IntoIter = slice::IterMut<'a, T>;
|
||||
|
|
|
@ -668,17 +668,7 @@ impl<V> FromIterator<(usize, V)> for VecMap<V> {
|
|||
}
|
||||
}
|
||||
|
||||
// NOTE(stage0): remove impl after a snapshot
|
||||
#[cfg(stage0)]
|
||||
impl<T> IntoIterator for VecMap<T> {
|
||||
type IntoIter = IntoIter<T>;
|
||||
|
||||
fn into_iter(self) -> IntoIter<T> {
|
||||
self.into_iter()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T> IntoIterator for VecMap<T> {
|
||||
type Item = (usize, T);
|
||||
type IntoIter = IntoIter<T>;
|
||||
|
@ -688,17 +678,7 @@ impl<T> IntoIterator for VecMap<T> {
|
|||
}
|
||||
}
|
||||
|
||||
// NOTE(stage0): remove impl after a snapshot
|
||||
#[cfg(stage0)]
|
||||
impl<'a, T> IntoIterator for &'a VecMap<T> {
|
||||
type IntoIter = Iter<'a, T>;
|
||||
|
||||
fn into_iter(self) -> Iter<'a, T> {
|
||||
self.iter()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<'a, T> IntoIterator for &'a VecMap<T> {
|
||||
type Item = (usize, &'a T);
|
||||
type IntoIter = Iter<'a, T>;
|
||||
|
@ -708,17 +688,7 @@ impl<'a, T> IntoIterator for &'a VecMap<T> {
|
|||
}
|
||||
}
|
||||
|
||||
// NOTE(stage0): remove impl after a snapshot
|
||||
#[cfg(stage0)]
|
||||
impl<'a, T> IntoIterator for &'a mut VecMap<T> {
|
||||
type IntoIter = IterMut<'a, T>;
|
||||
|
||||
fn into_iter(mut self) -> IterMut<'a, T> {
|
||||
self.iter_mut()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<'a, T> IntoIterator for &'a mut VecMap<T> {
|
||||
type Item = (usize, &'a mut T);
|
||||
type IntoIter = IterMut<'a, T>;
|
||||
|
|
|
@ -48,17 +48,7 @@ macro_rules! array_impls {
|
|||
}
|
||||
}
|
||||
|
||||
// NOTE(stage0): remove impl after a snapshot
|
||||
#[cfg(stage0)]
|
||||
impl<'a, T> IntoIterator for &'a [T; $N] {
|
||||
type IntoIter = Iter<'a, T>;
|
||||
|
||||
fn into_iter(self) -> Iter<'a, T> {
|
||||
self.iter()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<'a, T> IntoIterator for &'a [T; $N] {
|
||||
type Item = &'a T;
|
||||
type IntoIter = Iter<'a, T>;
|
||||
|
@ -68,17 +58,7 @@ macro_rules! array_impls {
|
|||
}
|
||||
}
|
||||
|
||||
// NOTE(stage0): remove impl after a snapshot
|
||||
#[cfg(stage0)]
|
||||
impl<'a, T> IntoIterator for &'a mut [T; $N] {
|
||||
type IntoIter = IterMut<'a, T>;
|
||||
|
||||
fn into_iter(self) -> IterMut<'a, T> {
|
||||
self.iter_mut()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<'a, T> IntoIterator for &'a mut [T; $N] {
|
||||
type Item = &'a mut T;
|
||||
type IntoIter = IterMut<'a, T>;
|
||||
|
|
|
@ -42,13 +42,13 @@
|
|||
//! ```
|
||||
//! use std::sync::Arc;
|
||||
//! use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
//! use std::thread::Thread;
|
||||
//! use std::thread;
|
||||
//!
|
||||
//! fn main() {
|
||||
//! let spinlock = Arc::new(AtomicUsize::new(1));
|
||||
//!
|
||||
//! let spinlock_clone = spinlock.clone();
|
||||
//! Thread::spawn(move|| {
|
||||
//! thread::spawn(move|| {
|
||||
//! spinlock_clone.store(0, Ordering::SeqCst);
|
||||
//! });
|
||||
//!
|
||||
|
|
|
@ -78,12 +78,12 @@
|
|||
//! use std::cell::RefCell;
|
||||
//!
|
||||
//! struct Graph {
|
||||
//! edges: Vec<(uint, uint)>,
|
||||
//! span_tree_cache: RefCell<Option<Vec<(uint, uint)>>>
|
||||
//! edges: Vec<(i32, i32)>,
|
||||
//! span_tree_cache: RefCell<Option<Vec<(i32, i32)>>>
|
||||
//! }
|
||||
//!
|
||||
//! impl Graph {
|
||||
//! fn minimum_spanning_tree(&self) -> Vec<(uint, uint)> {
|
||||
//! fn minimum_spanning_tree(&self) -> Vec<(i32, i32)> {
|
||||
//! // Create a new scope to contain the lifetime of the
|
||||
//! // dynamic borrow
|
||||
//! {
|
||||
|
@ -104,7 +104,7 @@
|
|||
//! // This is the major hazard of using `RefCell`.
|
||||
//! self.minimum_spanning_tree()
|
||||
//! }
|
||||
//! # fn calc_span_tree(&self) -> Vec<(uint, uint)> { vec![] }
|
||||
//! # fn calc_span_tree(&self) -> Vec<(i32, i32)> { vec![] }
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
|
@ -125,7 +125,7 @@
|
|||
//!
|
||||
//! struct RcBox<T> {
|
||||
//! value: T,
|
||||
//! refcount: Cell<uint>
|
||||
//! refcount: Cell<usize>
|
||||
//! }
|
||||
//!
|
||||
//! impl<T> Clone for Rc<T> {
|
||||
|
@ -279,8 +279,8 @@ pub enum BorrowState {
|
|||
}
|
||||
|
||||
// Values [1, MAX-1] represent the number of `Ref` active
|
||||
// (will not outgrow its range since `uint` is the size of the address space)
|
||||
type BorrowFlag = uint;
|
||||
// (will not outgrow its range since `usize` is the size of the address space)
|
||||
type BorrowFlag = usize;
|
||||
const UNUSED: BorrowFlag = 0;
|
||||
const WRITING: BorrowFlag = -1;
|
||||
|
||||
|
@ -375,9 +375,9 @@ impl<T> RefCell<T> {
|
|||
///
|
||||
/// ```
|
||||
/// use std::cell::RefCell;
|
||||
/// use std::thread::Thread;
|
||||
/// use std::thread;
|
||||
///
|
||||
/// let result = Thread::scoped(move || {
|
||||
/// let result = thread::spawn(move || {
|
||||
/// let c = RefCell::new(5);
|
||||
/// let m = c.borrow_mut();
|
||||
///
|
||||
|
@ -436,9 +436,9 @@ impl<T> RefCell<T> {
|
|||
///
|
||||
/// ```
|
||||
/// use std::cell::RefCell;
|
||||
/// use std::thread::Thread;
|
||||
/// use std::thread;
|
||||
///
|
||||
/// let result = Thread::scoped(move || {
|
||||
/// let result = thread::spawn(move || {
|
||||
/// let c = RefCell::new(5);
|
||||
/// let m = c.borrow_mut();
|
||||
///
|
||||
|
@ -649,8 +649,7 @@ impl<'b, T> DerefMut for RefMut<'b, T> {
|
|||
///
|
||||
/// **NOTE:** `UnsafeCell<T>`'s fields are public to allow static initializers. It is not
|
||||
/// recommended to access its fields directly, `get` should be used instead.
|
||||
#[cfg_attr(stage0, lang="unsafe")] // NOTE: remove after next snapshot
|
||||
#[cfg_attr(not(stage0), lang="unsafe_cell")]
|
||||
#[lang="unsafe_cell"]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub struct UnsafeCell<T> {
|
||||
/// Wrapped value
|
||||
|
|
|
@ -8,35 +8,33 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! Defines the `PartialOrd` and `PartialEq` comparison traits.
|
||||
//! Functionality for ordering and comparison.
|
||||
//!
|
||||
//! This module defines both `PartialOrd` and `PartialEq` traits which are used by the
|
||||
//! compiler to implement comparison operators. Rust programs may implement
|
||||
//!`PartialOrd` to overload the `<`, `<=`, `>`, and `>=` operators, and may implement
|
||||
//! `PartialEq` to overload the `==` and `!=` operators.
|
||||
//! This module defines both `PartialOrd` and `PartialEq` traits which are used by the compiler to
|
||||
//! implement comparison operators. Rust programs may implement `PartialOrd` to overload the `<`,
|
||||
//! `<=`, `>`, and `>=` operators, and may implement `PartialEq` to overload the `==` and `!=`
|
||||
//! operators.
|
||||
//!
|
||||
//! For example, to define a type with a customized definition for the PartialEq
|
||||
//! operators, you could do the following:
|
||||
//! For example, to define a type with a customized definition for the PartialEq operators, you
|
||||
//! could do the following:
|
||||
//!
|
||||
//! ```rust
|
||||
//! ```
|
||||
//! use core::num::SignedInt;
|
||||
//!
|
||||
//! // Our type.
|
||||
//! struct SketchyNum {
|
||||
//! num : int
|
||||
//! struct FuzzyNum {
|
||||
//! num: i32,
|
||||
//! }
|
||||
//!
|
||||
//! // Our implementation of `PartialEq` to support `==` and `!=`.
|
||||
//! impl PartialEq for SketchyNum {
|
||||
//! impl PartialEq for FuzzyNum {
|
||||
//! // Our custom eq allows numbers which are near each other to be equal! :D
|
||||
//! fn eq(&self, other: &SketchyNum) -> bool {
|
||||
//! fn eq(&self, other: &FuzzyNum) -> bool {
|
||||
//! (self.num - other.num).abs() < 5
|
||||
//! }
|
||||
//! }
|
||||
//!
|
||||
//! // Now these binary operators will work when applied!
|
||||
//! assert!(SketchyNum {num: 37} == SketchyNum {num: 34});
|
||||
//! assert!(SketchyNum {num: 25} != SketchyNum {num: 57});
|
||||
//! assert!(FuzzyNum { num: 37 } == FuzzyNum { num: 34 });
|
||||
//! assert!(FuzzyNum { num: 25 } != FuzzyNum { num: 57 });
|
||||
//! ```
|
||||
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
|
@ -49,24 +47,22 @@ use option::Option::{self, Some, None};
|
|||
/// Trait for equality comparisons which are [partial equivalence relations](
|
||||
/// http://en.wikipedia.org/wiki/Partial_equivalence_relation).
|
||||
///
|
||||
/// This trait allows for partial equality, for types that do not have a full
|
||||
/// equivalence relation. For example, in floating point numbers `NaN != NaN`,
|
||||
/// so floating point types implement `PartialEq` but not `Eq`.
|
||||
/// This trait allows for partial equality, for types that do not have a full equivalence relation.
|
||||
/// For example, in floating point numbers `NaN != NaN`, so floating point types implement
|
||||
/// `PartialEq` but not `Eq`.
|
||||
///
|
||||
/// Formally, the equality must be (for all `a`, `b` and `c`):
|
||||
///
|
||||
/// - symmetric: `a == b` implies `b == a`; and
|
||||
/// - transitive: `a == b` and `b == c` implies `a == c`.
|
||||
///
|
||||
/// Note that these requirements mean that the trait itself must be
|
||||
/// implemented symmetrically and transitively: if `T: PartialEq<U>`
|
||||
/// and `U: PartialEq<V>` then `U: PartialEq<T>` and `T:
|
||||
/// Note that these requirements mean that the trait itself must be implemented symmetrically and
|
||||
/// transitively: if `T: PartialEq<U>` and `U: PartialEq<V>` then `U: PartialEq<T>` and `T:
|
||||
/// PartialEq<V>`.
|
||||
///
|
||||
/// PartialEq only requires the `eq` method to be implemented; `ne` is defined
|
||||
/// in terms of it by default. Any manual implementation of `ne` *must* respect
|
||||
/// the rule that `eq` is a strict inverse of `ne`; that is, `!(a == b)` if and
|
||||
/// only if `a != b`.
|
||||
/// PartialEq only requires the `eq` method to be implemented; `ne` is defined in terms of it by
|
||||
/// default. Any manual implementation of `ne` *must* respect the rule that `eq` is a strict
|
||||
/// inverse of `ne`; that is, `!(a == b)` if and only if `a != b`.
|
||||
#[lang="eq"]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[old_orphan_check]
|
||||
|
@ -84,12 +80,15 @@ pub trait PartialEq<Rhs: ?Sized = Self> {
|
|||
/// Trait for equality comparisons which are [equivalence relations](
|
||||
/// https://en.wikipedia.org/wiki/Equivalence_relation).
|
||||
///
|
||||
/// This means, that in addition to `a == b` and `a != b` being strict
|
||||
/// inverses, the equality must be (for all `a`, `b` and `c`):
|
||||
/// This means, that in addition to `a == b` and `a != b` being strict inverses, the equality must
|
||||
/// be (for all `a`, `b` and `c`):
|
||||
///
|
||||
/// - reflexive: `a == a`;
|
||||
/// - symmetric: `a == b` implies `b == a`; and
|
||||
/// - transitive: `a == b` and `b == c` implies `a == c`.
|
||||
///
|
||||
/// This property cannot be checked by the compiler, and therefore `Eq` implies
|
||||
/// `PartialEq`, and has no extra methods.
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub trait Eq: PartialEq<Self> {
|
||||
// FIXME #13101: this method is used solely by #[deriving] to
|
||||
|
@ -101,10 +100,26 @@ pub trait Eq: PartialEq<Self> {
|
|||
// This should never be implemented by hand.
|
||||
#[doc(hidden)]
|
||||
#[inline(always)]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
fn assert_receiver_is_total_eq(&self) {}
|
||||
}
|
||||
|
||||
/// An ordering is, e.g, a result of a comparison between two values.
|
||||
/// An `Ordering` is the result of a comparison between two values.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::cmp::Ordering;
|
||||
///
|
||||
/// let result = 1.cmp(&2);
|
||||
/// assert_eq!(Ordering::Less, result);
|
||||
///
|
||||
/// let result = 1.cmp(&1);
|
||||
/// assert_eq!(Ordering::Equal, result);
|
||||
///
|
||||
/// let result = 2.cmp(&1);
|
||||
/// assert_eq!(Ordering::Greater, result);
|
||||
/// ```
|
||||
#[derive(Clone, Copy, PartialEq, Debug)]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub enum Ordering {
|
||||
|
@ -120,17 +135,28 @@ pub enum Ordering {
|
|||
}
|
||||
|
||||
impl Ordering {
|
||||
/// Reverse the `Ordering`, so that `Less` becomes `Greater` and
|
||||
/// vice versa.
|
||||
/// Reverse the `Ordering`.
|
||||
///
|
||||
/// # Example
|
||||
/// * `Less` becomes `Greater`.
|
||||
/// * `Greater` becomes `Less`.
|
||||
/// * `Equal` becomes `Equal`.
|
||||
///
|
||||
/// ```rust
|
||||
/// use std::cmp::Ordering::{Less, Equal, Greater};
|
||||
/// # Examples
|
||||
///
|
||||
/// assert_eq!(Less.reverse(), Greater);
|
||||
/// assert_eq!(Equal.reverse(), Equal);
|
||||
/// assert_eq!(Greater.reverse(), Less);
|
||||
/// Basic behavior:
|
||||
///
|
||||
/// ```
|
||||
/// use std::cmp::Ordering;
|
||||
///
|
||||
/// assert_eq!(Ordering::Less.reverse(), Ordering::Greater);
|
||||
/// assert_eq!(Ordering::Equal.reverse(), Ordering::Equal);
|
||||
/// assert_eq!(Ordering::Greater.reverse(), Ordering::Less);
|
||||
/// ```
|
||||
///
|
||||
/// This method can be used to reverse a comparison:
|
||||
///
|
||||
/// ```
|
||||
/// use std::cmp::Ordering;
|
||||
///
|
||||
/// let mut data: &mut [_] = &mut [2, 10, 5, 8];
|
||||
///
|
||||
|
@ -155,28 +181,27 @@ impl Ordering {
|
|||
}
|
||||
}
|
||||
|
||||
/// Trait for types that form a [total order](
|
||||
/// https://en.wikipedia.org/wiki/Total_order).
|
||||
/// Trait for types that form a [total order](https://en.wikipedia.org/wiki/Total_order).
|
||||
///
|
||||
/// An order is a total order if it is (for all `a`, `b` and `c`):
|
||||
///
|
||||
/// - total and antisymmetric: exactly one of `a < b`, `a == b` or `a > b` is
|
||||
/// true; and
|
||||
/// - transitive, `a < b` and `b < c` implies `a < c`. The same must hold for
|
||||
/// both `==` and `>`.
|
||||
/// - total and antisymmetric: exactly one of `a < b`, `a == b` or `a > b` is true; and
|
||||
/// - transitive, `a < b` and `b < c` implies `a < c`. The same must hold for both `==` and `>`.
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub trait Ord: Eq + PartialOrd<Self> {
|
||||
/// This method returns an ordering between `self` and `other` values.
|
||||
/// This method returns an `Ordering` between `self` and `other`.
|
||||
///
|
||||
/// By convention, `self.cmp(&other)` returns the ordering matching
|
||||
/// the expression `self <operator> other` if true. For example:
|
||||
/// By convention, `self.cmp(&other)` returns the ordering matching the expression
|
||||
/// `self <operator> other` if true.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::cmp::Ordering::{Less, Equal, Greater};
|
||||
/// use std::cmp::Ordering;
|
||||
///
|
||||
/// assert_eq!( 5.cmp(&10), Less); // because 5 < 10
|
||||
/// assert_eq!(10.cmp(&5), Greater); // because 10 > 5
|
||||
/// assert_eq!( 5.cmp(&5), Equal); // because 5 == 5
|
||||
/// assert_eq!(5.cmp(&10), Ordering::Less);
|
||||
/// assert_eq!(10.cmp(&5), Ordering::Greater);
|
||||
/// assert_eq!(5.cmp(&5), Ordering::Equal);
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
fn cmp(&self, other: &Self) -> Ordering;
|
||||
|
@ -208,30 +233,60 @@ impl PartialOrd for Ordering {
|
|||
/// The comparison must satisfy, for all `a`, `b` and `c`:
|
||||
///
|
||||
/// - antisymmetry: if `a < b` then `!(a > b)` and vice versa; and
|
||||
/// - transitivity: `a < b` and `b < c` implies `a < c`. The same must hold for
|
||||
/// both `==` and `>`.
|
||||
/// - transitivity: `a < b` and `b < c` implies `a < c`. The same must hold for both `==` and `>`.
|
||||
///
|
||||
/// Note that these requirements mean that the trait itself must be
|
||||
/// implemented symmetrically and transitively: if `T: PartialOrd<U>`
|
||||
/// and `U: PartialOrd<V>` then `U: PartialOrd<T>` and `T:
|
||||
/// Note that these requirements mean that the trait itself must be implemented symmetrically and
|
||||
/// transitively: if `T: PartialOrd<U>` and `U: PartialOrd<V>` then `U: PartialOrd<T>` and `T:
|
||||
/// PartialOrd<V>`.
|
||||
///
|
||||
/// PartialOrd only requires implementation of the `partial_cmp` method,
|
||||
/// with the others generated from default implementations.
|
||||
/// PartialOrd only requires implementation of the `partial_cmp` method, with the others generated
|
||||
/// from default implementations.
|
||||
///
|
||||
/// However it remains possible to implement the others separately for types
|
||||
/// which do not have a total order. For example, for floating point numbers,
|
||||
/// `NaN < 0 == false` and `NaN >= 0 == false` (cf. IEEE 754-2008 section
|
||||
/// 5.11).
|
||||
/// However it remains possible to implement the others separately for types which do not have a
|
||||
/// total order. For example, for floating point numbers, `NaN < 0 == false` and `NaN >= 0 ==
|
||||
/// false` (cf. IEEE 754-2008 section 5.11).
|
||||
#[lang="ord"]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> {
|
||||
/// This method returns an ordering between `self` and `other` values
|
||||
/// if one exists.
|
||||
/// This method returns an ordering between `self` and `other` values if one exists.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::cmp::Ordering;
|
||||
///
|
||||
/// let result = 1.0.partial_cmp(&2.0);
|
||||
/// assert_eq!(result, Some(Ordering::Less));
|
||||
///
|
||||
/// let result = 1.0.partial_cmp(&1.0);
|
||||
/// assert_eq!(result, Some(Ordering::Equal));
|
||||
///
|
||||
/// let result = 2.0.partial_cmp(&1.0);
|
||||
/// assert_eq!(result, Some(Ordering::Greater));
|
||||
/// ```
|
||||
///
|
||||
/// When comparison is impossible:
|
||||
///
|
||||
/// ```
|
||||
/// let result = std::f64::NAN.partial_cmp(&1.0);
|
||||
/// assert_eq!(result, None);
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
fn partial_cmp(&self, other: &Rhs) -> Option<Ordering>;
|
||||
|
||||
/// This method tests less than (for `self` and `other`) and is used by the `<` operator.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::cmp::Ordering;
|
||||
///
|
||||
/// let result = 1.0 < 2.0;
|
||||
/// assert_eq!(result, true);
|
||||
///
|
||||
/// let result = 2.0 < 1.0;
|
||||
/// assert_eq!(result, false);
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
fn lt(&self, other: &Rhs) -> bool {
|
||||
|
@ -241,7 +296,18 @@ pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> {
|
|||
}
|
||||
}
|
||||
|
||||
/// This method tests less than or equal to (`<=`).
|
||||
/// This method tests less than or equal to (for `self` and `other`) and is used by the `<=`
|
||||
/// operator.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// let result = 1.0 <= 2.0;
|
||||
/// assert_eq!(result, true);
|
||||
///
|
||||
/// let result = 2.0 <= 2.0;
|
||||
/// assert_eq!(result, true);
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
fn le(&self, other: &Rhs) -> bool {
|
||||
|
@ -251,7 +317,17 @@ pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> {
|
|||
}
|
||||
}
|
||||
|
||||
/// This method tests greater than (`>`).
|
||||
/// This method tests greater than (for `self` and `other`) and is used by the `>` operator.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// let result = 1.0 > 2.0;
|
||||
/// assert_eq!(result, false);
|
||||
///
|
||||
/// let result = 2.0 > 2.0;
|
||||
/// assert_eq!(result, false);
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
fn gt(&self, other: &Rhs) -> bool {
|
||||
|
@ -261,7 +337,18 @@ pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> {
|
|||
}
|
||||
}
|
||||
|
||||
/// This method tests greater than or equal to (`>=`).
|
||||
/// This method tests greater than or equal to (for `self` and `other`) and is used by the `>=`
|
||||
/// operator.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// let result = 2.0 >= 1.0;
|
||||
/// assert_eq!(result, true);
|
||||
///
|
||||
/// let result = 2.0 >= 2.0;
|
||||
/// assert_eq!(result, true);
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
fn ge(&self, other: &Rhs) -> bool {
|
||||
|
@ -273,6 +360,15 @@ pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> {
|
|||
}
|
||||
|
||||
/// Compare and return the minimum of two values.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::cmp;
|
||||
///
|
||||
/// assert_eq!(1, cmp::min(1, 2));
|
||||
/// assert_eq!(2, cmp::min(2, 2));
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn min<T: Ord>(v1: T, v2: T) -> T {
|
||||
|
@ -280,6 +376,15 @@ pub fn min<T: Ord>(v1: T, v2: T) -> T {
|
|||
}
|
||||
|
||||
/// Compare and return the maximum of two values.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::cmp;
|
||||
///
|
||||
/// assert_eq!(2, cmp::max(1, 2));
|
||||
/// assert_eq!(2, cmp::max(2, 2));
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn max<T: Ord>(v1: T, v2: T) -> T {
|
||||
|
@ -289,6 +394,24 @@ pub fn max<T: Ord>(v1: T, v2: T) -> T {
|
|||
/// Compare and return the minimum of two values if there is one.
|
||||
///
|
||||
/// Returns the first argument if the comparison determines them to be equal.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::cmp;
|
||||
///
|
||||
/// assert_eq!(Some(1), cmp::partial_min(1, 2));
|
||||
/// assert_eq!(Some(2), cmp::partial_min(2, 2));
|
||||
/// ```
|
||||
///
|
||||
/// When comparison is impossible:
|
||||
///
|
||||
/// ```
|
||||
/// use std::cmp;
|
||||
///
|
||||
/// let result = cmp::partial_min(std::f64::NAN, 1.0);
|
||||
/// assert_eq!(result, None);
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable(feature = "core")]
|
||||
pub fn partial_min<T: PartialOrd>(v1: T, v2: T) -> Option<T> {
|
||||
|
@ -302,6 +425,24 @@ pub fn partial_min<T: PartialOrd>(v1: T, v2: T) -> Option<T> {
|
|||
/// Compare and return the maximum of two values if there is one.
|
||||
///
|
||||
/// Returns the first argument if the comparison determines them to be equal.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::cmp;
|
||||
///
|
||||
/// assert_eq!(Some(2), cmp::partial_max(1, 2));
|
||||
/// assert_eq!(Some(2), cmp::partial_max(2, 2));
|
||||
/// ```
|
||||
///
|
||||
/// When comparison is impossible:
|
||||
///
|
||||
/// ```
|
||||
/// use std::cmp;
|
||||
///
|
||||
/// let result = cmp::partial_max(std::f64::NAN, 1.0);
|
||||
/// assert_eq!(result, None);
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable(feature = "core")]
|
||||
pub fn partial_max<T: PartialOrd>(v1: T, v2: T) -> Option<T> {
|
||||
|
|
|
@ -197,6 +197,7 @@ impl<'a> Arguments<'a> {
|
|||
/// created with `argumentuint`. However, failing to do so doesn't cause
|
||||
/// unsafety, but will ignore invalid .
|
||||
#[doc(hidden)] #[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn new_v1_formatted(pieces: &'a [&'a str],
|
||||
args: &'a [ArgumentV1<'a>],
|
||||
fmt: &'a [rt::v1::Argument]) -> Arguments<'a> {
|
||||
|
|
|
@ -118,21 +118,13 @@ pub trait FromIterator<A> {
|
|||
fn from_iter<T: Iterator<Item=A>>(iterator: T) -> Self;
|
||||
}
|
||||
|
||||
// NOTE(stage0): remove trait after a snapshot
|
||||
#[cfg(stage0)]
|
||||
/// Conversion into an `Iterator`
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub trait IntoIterator {
|
||||
type IntoIter: Iterator;
|
||||
|
||||
/// Consumes `Self` and returns an iterator over it
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
fn into_iter(self) -> Self::IntoIter;
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot
|
||||
/// Conversion into an `Iterator`
|
||||
pub trait IntoIterator {
|
||||
type Item;
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
type IntoIter: Iterator<Item=Self::Item>;
|
||||
|
||||
/// Consumes `Self` and returns an iterator over it
|
||||
|
@ -140,17 +132,7 @@ pub trait IntoIterator {
|
|||
fn into_iter(self) -> Self::IntoIter;
|
||||
}
|
||||
|
||||
// NOTE(stage0): remove impl after a snapshot
|
||||
#[cfg(stage0)]
|
||||
impl<I> IntoIterator for I where I: Iterator {
|
||||
type IntoIter = I;
|
||||
|
||||
fn into_iter(self) -> I {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<I: Iterator> IntoIterator for I {
|
||||
type Item = I::Item;
|
||||
type IntoIter = I;
|
||||
|
@ -2374,7 +2356,7 @@ impl<A, St, F> Iterator for Unfold<St, F> where F: FnMut(&mut St) -> Option<A> {
|
|||
/// iteration
|
||||
#[derive(Clone)]
|
||||
#[unstable(feature = "core",
|
||||
reason = "may be renamed or replaced by range notation adapaters")]
|
||||
reason = "may be renamed or replaced by range notation adapters")]
|
||||
pub struct Counter<A> {
|
||||
/// The current state the counter is at (next value to be yielded)
|
||||
state: A,
|
||||
|
@ -2385,7 +2367,7 @@ pub struct Counter<A> {
|
|||
/// Creates a new counter with the specified start/step
|
||||
#[inline]
|
||||
#[unstable(feature = "core",
|
||||
reason = "may be renamed or replaced by range notation adapaters")]
|
||||
reason = "may be renamed or replaced by range notation adapters")]
|
||||
pub fn count<A>(start: A, step: A) -> Counter<A> {
|
||||
Counter{state: start, step: step}
|
||||
}
|
||||
|
|
|
@ -67,6 +67,7 @@
|
|||
#![feature(simd, unsafe_destructor)]
|
||||
#![feature(staged_api)]
|
||||
#![feature(unboxed_closures)]
|
||||
#![feature(rustc_attrs)]
|
||||
|
||||
#[macro_use]
|
||||
mod macros;
|
||||
|
@ -153,25 +154,16 @@ mod array;
|
|||
mod core {
|
||||
pub use panicking;
|
||||
pub use fmt;
|
||||
#[cfg(not(stage0))] pub use clone;
|
||||
#[cfg(not(stage0))] pub use cmp;
|
||||
#[cfg(not(stage0))] pub use hash;
|
||||
#[cfg(not(stage0))] pub use marker;
|
||||
#[cfg(not(stage0))] pub use option;
|
||||
#[cfg(not(stage0))] pub use iter;
|
||||
pub use clone;
|
||||
pub use cmp;
|
||||
pub use hash;
|
||||
pub use marker;
|
||||
pub use option;
|
||||
pub use iter;
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
mod std {
|
||||
// NOTE: remove after next snapshot
|
||||
#[cfg(stage0)] pub use clone;
|
||||
#[cfg(stage0)] pub use cmp;
|
||||
#[cfg(stage0)] pub use hash;
|
||||
#[cfg(stage0)] pub use marker;
|
||||
#[cfg(stage0)] pub use option;
|
||||
#[cfg(stage0)] pub use fmt;
|
||||
#[cfg(stage0)] pub use iter;
|
||||
|
||||
// range syntax
|
||||
pub use ops;
|
||||
}
|
||||
|
|
|
@ -32,9 +32,19 @@ use clone::Clone;
|
|||
reason = "will be overhauled with new lifetime rules; see RFC 458")]
|
||||
#[lang="send"]
|
||||
#[rustc_on_unimplemented = "`{Self}` cannot be sent between threads safely"]
|
||||
#[cfg(stage0)]
|
||||
pub unsafe trait Send: 'static {
|
||||
// empty.
|
||||
}
|
||||
/// Types able to be transferred across thread boundaries.
|
||||
#[unstable(feature = "core",
|
||||
reason = "will be overhauled with new lifetime rules; see RFC 458")]
|
||||
#[lang="send"]
|
||||
#[rustc_on_unimplemented = "`{Self}` cannot be sent between threads safely"]
|
||||
#[cfg(not(stage0))]
|
||||
pub unsafe trait Send {
|
||||
// empty.
|
||||
}
|
||||
|
||||
/// Types with a constant size known at compile-time.
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
@ -424,3 +434,11 @@ pub struct NoCopy;
|
|||
#[lang="managed_bound"]
|
||||
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct Managed;
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
mod impls {
|
||||
use super::{Send, Sync, Sized};
|
||||
|
||||
unsafe impl<'a, T: Sync + ?Sized> Send for &'a T {}
|
||||
unsafe impl<'a, T: Send + ?Sized> Send for &'a mut T {}
|
||||
}
|
||||
|
|
|
@ -43,7 +43,7 @@ pub use intrinsics::forget;
|
|||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn size_of<T>() -> uint {
|
||||
pub fn size_of<T>() -> usize {
|
||||
unsafe { intrinsics::size_of::<T>() }
|
||||
}
|
||||
|
||||
|
@ -58,7 +58,7 @@ pub fn size_of<T>() -> uint {
|
|||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn size_of_val<T>(_val: &T) -> uint {
|
||||
pub fn size_of_val<T>(_val: &T) -> usize {
|
||||
size_of::<T>()
|
||||
}
|
||||
|
||||
|
@ -75,7 +75,7 @@ pub fn size_of_val<T>(_val: &T) -> uint {
|
|||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn min_align_of<T>() -> uint {
|
||||
pub fn min_align_of<T>() -> usize {
|
||||
unsafe { intrinsics::min_align_of::<T>() }
|
||||
}
|
||||
|
||||
|
@ -90,7 +90,7 @@ pub fn min_align_of<T>() -> uint {
|
|||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn min_align_of_val<T>(_val: &T) -> uint {
|
||||
pub fn min_align_of_val<T>(_val: &T) -> usize {
|
||||
min_align_of::<T>()
|
||||
}
|
||||
|
||||
|
@ -108,7 +108,7 @@ pub fn min_align_of_val<T>(_val: &T) -> uint {
|
|||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn align_of<T>() -> uint {
|
||||
pub fn align_of<T>() -> usize {
|
||||
// We use the preferred alignment as the default alignment for a type. This
|
||||
// appears to be what clang migrated towards as well:
|
||||
//
|
||||
|
@ -130,7 +130,7 @@ pub fn align_of<T>() -> uint {
|
|||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn align_of_val<T>(_val: &T) -> uint {
|
||||
pub fn align_of_val<T>(_val: &T) -> usize {
|
||||
align_of::<T>()
|
||||
}
|
||||
|
||||
|
@ -150,7 +150,7 @@ pub fn align_of_val<T>(_val: &T) -> uint {
|
|||
/// ```
|
||||
/// use std::mem;
|
||||
///
|
||||
/// let x: int = unsafe { mem::zeroed() };
|
||||
/// let x: i32 = unsafe { mem::zeroed() };
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
@ -171,7 +171,7 @@ pub unsafe fn zeroed<T>() -> T {
|
|||
/// ```
|
||||
/// use std::mem;
|
||||
///
|
||||
/// let x: int = unsafe { mem::uninitialized() };
|
||||
/// let x: i32 = unsafe { mem::uninitialized() };
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
|
|
@ -19,8 +19,8 @@ pub unsafe trait Zeroable {}
|
|||
unsafe impl<T> Zeroable for *const T {}
|
||||
unsafe impl<T> Zeroable for *mut T {}
|
||||
unsafe impl<T> Zeroable for Unique<T> { }
|
||||
unsafe impl Zeroable for int {}
|
||||
unsafe impl Zeroable for uint {}
|
||||
unsafe impl Zeroable for isize {}
|
||||
unsafe impl Zeroable for usize {}
|
||||
unsafe impl Zeroable for i8 {}
|
||||
unsafe impl Zeroable for u8 {}
|
||||
unsafe impl Zeroable for i16 {}
|
||||
|
|
|
@ -605,6 +605,8 @@ impl<T> Option<T> {
|
|||
/// Returns `None` if the option is `None`, otherwise calls `f` with the
|
||||
/// wrapped value and returns the result.
|
||||
///
|
||||
/// Some languages call this operation flatmap.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue