mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-21 11:23:03 +00:00
auto merge of #20320 : alexcrichton/rust/rollup, r=alexcrichton
This commit is contained in:
commit
d2368c3c11
@ -99,7 +99,7 @@
|
||||
# This is hardly all there is to know of The Rust Build System's
|
||||
# mysteries. The tale continues on the wiki[1][2].
|
||||
#
|
||||
# [1]: https://github.com/rust-lang/rust/wiki/Note-build-system
|
||||
# [1]: https://github.com/rust-lang/rust/wiki/Note-getting-started-developing-Rust
|
||||
# [2]: https://github.com/rust-lang/rust/wiki/Note-testsuite
|
||||
#
|
||||
# If you really feel like getting your hands dirty, then:
|
||||
|
97
mk/dist.mk
97
mk/dist.mk
@ -23,6 +23,8 @@
|
||||
# * dist-docs - Stage docs for upload
|
||||
|
||||
PKG_NAME := $(CFG_PACKAGE_NAME)
|
||||
DOC_PKG_NAME := rust-docs-$(CFG_PACKAGE_VERS)
|
||||
MINGW_PKG_NAME := rust-mingw-$(CFG_PACKAGE_VERS)
|
||||
|
||||
# License suitable for displaying in a popup
|
||||
LICENSE.txt: $(S)COPYRIGHT $(S)LICENSE-APACHE $(S)LICENSE-MIT
|
||||
@ -229,10 +231,20 @@ dist-install-dir-$(1): prepare-base-dir-$(1) docs compiler-docs
|
||||
$$(Q)$$(PREPARE_MAN_CMD) $$(S)LICENSE-APACHE $$(PREPARE_DEST_DIR)
|
||||
$$(Q)$$(PREPARE_MAN_CMD) $$(S)LICENSE-MIT $$(PREPARE_DEST_DIR)
|
||||
$$(Q)$$(PREPARE_MAN_CMD) $$(S)README.md $$(PREPARE_DEST_DIR)
|
||||
$$(Q)[ ! -d doc ] || cp -r doc $$(PREPARE_DEST_DIR)
|
||||
$$(Q)mkdir -p $$(PREPARE_DEST_DIR)/share/doc/rust
|
||||
$$(Q)$$(PREPARE_MAN_CMD) $$(S)COPYRIGHT $$(PREPARE_DEST_DIR)/share/doc/rust
|
||||
$$(Q)$$(PREPARE_MAN_CMD) $$(S)LICENSE-APACHE $$(PREPARE_DEST_DIR)/share/doc/rust
|
||||
$$(Q)$$(PREPARE_MAN_CMD) $$(S)LICENSE-MIT $$(PREPARE_DEST_DIR)/share/doc/rust
|
||||
$$(Q)$$(PREPARE_MAN_CMD) $$(S)README.md $$(PREPARE_DEST_DIR)/share/doc/rust
|
||||
|
||||
dist/$$(PKG_NAME)-$(1).tar.gz: dist-install-dir-$(1)
|
||||
@$(call E, build: $$@)
|
||||
# Copy essential gcc components into installer
|
||||
ifdef CFG_WINDOWSY_$(1)
|
||||
$$(Q)rm -Rf dist/win-rust-gcc-$(1)
|
||||
$$(Q)$$(CFG_PYTHON) $$(S)src/etc/make-win-dist.py tmp/dist/$$(PKG_NAME)-$(1)-image dist/win-rust-gcc-$(1) $(1)
|
||||
$$(Q)cp -r $$(S)src/etc/third-party tmp/dist/$$(PKG_NAME)-$(1)-image/share/doc/
|
||||
endif
|
||||
$$(Q)$$(S)src/rust-installer/gen-installer.sh \
|
||||
--product-name=Rust \
|
||||
--verify-bin=rustc \
|
||||
@ -242,9 +254,50 @@ dist/$$(PKG_NAME)-$(1).tar.gz: dist-install-dir-$(1)
|
||||
--work-dir=tmp/dist \
|
||||
--output-dir=dist \
|
||||
--non-installed-prefixes=$$(NON_INSTALLED_PREFIXES) \
|
||||
--package-name=$$(PKG_NAME)-$(1)
|
||||
--package-name=$$(PKG_NAME)-$(1) \
|
||||
--component-name=rustc \
|
||||
--legacy-manifest-dirs=rustlib,cargo
|
||||
$$(Q)rm -R tmp/dist/$$(PKG_NAME)-$(1)-image
|
||||
|
||||
dist-doc-install-dir-$(1): docs compiler-docs
|
||||
$$(Q)mkdir -p tmp/dist/$$(DOC_PKG_NAME)-$(1)-image/share/doc/rust
|
||||
$$(Q)cp -r doc tmp/dist/$$(DOC_PKG_NAME)-$(1)-image/share/doc/rust/html
|
||||
|
||||
dist/$$(DOC_PKG_NAME)-$(1).tar.gz: dist-doc-install-dir-$(1)
|
||||
@$(call E, build: $$@)
|
||||
$$(Q)$$(S)src/rust-installer/gen-installer.sh \
|
||||
--product-name=Rust-Documentation \
|
||||
--rel-manifest-dir=rustlib \
|
||||
--success-message=Rust-documentation-is-installed. \
|
||||
--image-dir=tmp/dist/$$(DOC_PKG_NAME)-$(1)-image \
|
||||
--work-dir=tmp/dist \
|
||||
--output-dir=dist \
|
||||
--package-name=$$(DOC_PKG_NAME)-$(1) \
|
||||
--component-name=rust-docs \
|
||||
--legacy-manifest-dirs=rustlib,cargo \
|
||||
--bulk-dirs=share/doc/rust/html
|
||||
$$(Q)rm -R tmp/dist/$$(DOC_PKG_NAME)-$(1)-image
|
||||
|
||||
dist-mingw-install-dir-$(1):
|
||||
$$(Q)mkdir -p tmp/dist/rust-mingw-tmp-$(1)-image
|
||||
$$(Q)rm -Rf tmp/dist/$$(MINGW_PKG_NAME)-$(1)-image
|
||||
$$(Q)$$(CFG_PYTHON) $$(S)src/etc/make-win-dist.py \
|
||||
tmp/dist/rust-mingw-tmp-$(1)-image tmp/dist/$$(MINGW_PKG_NAME)-$(1)-image $(1)
|
||||
|
||||
dist/$$(MINGW_PKG_NAME)-$(1).tar.gz: dist-mingw-install-dir-$(1)
|
||||
@$(call E, build: $$@)
|
||||
$$(Q)$$(S)src/rust-installer/gen-installer.sh \
|
||||
--product-name=Rust-MinGW \
|
||||
--rel-manifest-dir=rustlib \
|
||||
--success-message=Rust-MinGW-is-installed. \
|
||||
--image-dir=tmp/dist/$$(MINGW_PKG_NAME)-$(1)-image \
|
||||
--work-dir=tmp/dist \
|
||||
--output-dir=dist \
|
||||
--package-name=$$(MINGW_PKG_NAME)-$(1) \
|
||||
--component-name=rust-mingw \
|
||||
--legacy-manifest-dirs=rustlib,cargo
|
||||
$$(Q)rm -R tmp/dist/$$(MINGW_PKG_NAME)-$(1)-image
|
||||
|
||||
endef
|
||||
|
||||
ifneq ($(CFG_ENABLE_DIST_HOST_ONLY),)
|
||||
@ -257,7 +310,16 @@ endif
|
||||
|
||||
dist-install-dirs: $(foreach host,$(CFG_HOST),dist-install-dir-$(host))
|
||||
|
||||
dist-tar-bins: $(foreach host,$(CFG_HOST),dist/$(PKG_NAME)-$(host).tar.gz)
|
||||
ifdef CFG_WINDOWSY_$(CFG_BUILD)
|
||||
MAYBE_MINGW_TARBALLS=$(foreach host,$(CFG_HOST),dist/$(MINGW_PKG_NAME)-$(host).tar.gz)
|
||||
endif
|
||||
|
||||
ifeq ($(CFG_DISABLE_DOCS),)
|
||||
MAYBE_DOC_TARBALLS=$(foreach host,$(CFG_HOST),dist/$(DOC_PKG_NAME)-$(host).tar.gz)
|
||||
endif
|
||||
|
||||
dist-tar-bins: $(foreach host,$(CFG_HOST),dist/$(PKG_NAME)-$(host).tar.gz) \
|
||||
$(MAYBE_DOC_TARBALLS) $(MAYBE_MINGW_TARBALLS)
|
||||
|
||||
# Just try to run the compiler for the build host
|
||||
distcheck-tar-bins: dist-tar-bins
|
||||
@ -289,27 +351,20 @@ distcheck-docs: dist-docs
|
||||
# Primary targets (dist, distcheck)
|
||||
######################################################################
|
||||
|
||||
ifdef CFG_WINDOWSY_$(CFG_BUILD)
|
||||
|
||||
dist: dist-win dist-tar-bins
|
||||
|
||||
distcheck: distcheck-win
|
||||
$(Q)rm -Rf tmp/distcheck
|
||||
@echo
|
||||
@echo -----------------------------------------------
|
||||
@echo "Rust ready for distribution (see ./dist)"
|
||||
@echo -----------------------------------------------
|
||||
|
||||
else
|
||||
MAYBE_DIST_TAR_SRC=dist-tar-src
|
||||
MAYBE_DISTCHECK_TAR_SRC=distcheck-tar-src
|
||||
|
||||
# FIXME #13224: On OS X don't produce tarballs simply because --exclude-vcs don't work.
|
||||
# This is a huge hack because I just don't have time to figure out another solution.
|
||||
ifeq ($(CFG_OSTYPE), apple-darwin)
|
||||
MAYBE_DIST_TAR_SRC=
|
||||
MAYBE_DISTCHECK_TAR_SRC=
|
||||
else
|
||||
MAYBE_DIST_TAR_SRC=dist-tar-src
|
||||
MAYBE_DISTCHECK_TAR_SRC=distcheck-tar-src
|
||||
endif
|
||||
|
||||
# Don't bother with source tarballs on windows just because we historically haven't.
|
||||
ifeq ($(CFG_OSTYPE), pc-windows-gnu)
|
||||
MAYBE_DIST_TAR_SRC=
|
||||
MAYBE_DISTCHECK_TAR_SRC=
|
||||
endif
|
||||
|
||||
ifneq ($(CFG_DISABLE_DOCS),)
|
||||
@ -320,15 +375,13 @@ MAYBE_DIST_DOCS=dist-docs
|
||||
MAYBE_DISTCHECK_DOCS=distcheck-docs
|
||||
endif
|
||||
|
||||
dist: $(MAYBE_DIST_TAR_SRC) dist-osx dist-tar-bins $(MAYBE_DIST_DOCS)
|
||||
dist: $(MAYBE_DIST_TAR_SRC) dist-osx dist-win dist-tar-bins $(MAYBE_DIST_DOCS)
|
||||
|
||||
distcheck: $(MAYBE_DISTCHECK_TAR_SRC) distcheck-osx distcheck-tar-bins $(MAYBE_DISTCHECK_DOCS)
|
||||
distcheck: $(MAYBE_DISTCHECK_TAR_SRC) distcheck-osx distcheck-win distcheck-tar-bins $(MAYBE_DISTCHECK_DOCS)
|
||||
$(Q)rm -Rf tmp/distcheck
|
||||
@echo
|
||||
@echo -----------------------------------------------
|
||||
@echo "Rust ready for distribution (see ./dist)"
|
||||
@echo -----------------------------------------------
|
||||
|
||||
endif
|
||||
|
||||
.PHONY: dist distcheck
|
||||
|
@ -31,7 +31,7 @@ $(BG):
|
||||
$(Q)mkdir -p $(BG)
|
||||
|
||||
$(BG)RustLexer.class: $(BG) $(SG)RustLexer.g4
|
||||
$(Q)$(CFG_ANTLR4) -o $(B)grammar $(SG)RustLexer.g4
|
||||
$(Q)$(CFG_ANTLR4) -o $(BG) $(SG)RustLexer.g4
|
||||
$(Q)$(CFG_JAVAC) -d $(BG) $(BG)RustLexer.java
|
||||
|
||||
check-build-lexer-verifier: $(BG)verify
|
||||
|
@ -20,6 +20,9 @@ ifeq (root user, $(USER) $(patsubst %,user,$(SUDO_USER)))
|
||||
$(Q)sudo -u "$$SUDO_USER" $(MAKE) prepare_install
|
||||
else
|
||||
$(Q)$(MAKE) prepare_install
|
||||
endif
|
||||
ifeq ($(CFG_DISABLE_DOCS),)
|
||||
$(Q)cd tmp/empty_dir && sh ../../tmp/dist/$(DOC_PKG_NAME)-$(CFG_BUILD)/install.sh --prefix="$(DESTDIR)$(CFG_PREFIX)" --libdir="$(DESTDIR)$(CFG_LIBDIR)" --mandir="$(DESTDIR)$(CFG_MANDIR)" "$(MAYBE_DISABLE_VERIFY)"
|
||||
endif
|
||||
$(Q)cd tmp/empty_dir && sh ../../tmp/dist/$(PKG_NAME)-$(CFG_BUILD)/install.sh --prefix="$(DESTDIR)$(CFG_PREFIX)" --libdir="$(DESTDIR)$(CFG_LIBDIR)" --mandir="$(DESTDIR)$(CFG_MANDIR)" "$(MAYBE_DISABLE_VERIFY)"
|
||||
# Remove tmp files because it's a decent amount of disk space
|
||||
@ -33,6 +36,9 @@ ifeq (root user, $(USER) $(patsubst %,user,$(SUDO_USER)))
|
||||
$(Q)sudo -u "$$SUDO_USER" $(MAKE) prepare_uninstall
|
||||
else
|
||||
$(Q)$(MAKE) prepare_uninstall
|
||||
endif
|
||||
ifeq ($(CFG_DISABLE_DOCS),)
|
||||
$(Q)cd tmp/empty_dir && sh ../../tmp/dist/$(DOC_PKG_NAME)-$(CFG_BUILD)/install.sh --uninstall --prefix="$(DESTDIR)$(CFG_PREFIX)" --libdir="$(DESTDIR)$(CFG_LIBDIR)" --mandir="$(DESTDIR)$(CFG_MANDIR)"
|
||||
endif
|
||||
$(Q)cd tmp/empty_dir && sh ../../tmp/dist/$(PKG_NAME)-$(CFG_BUILD)/install.sh --uninstall --prefix="$(DESTDIR)$(CFG_PREFIX)" --libdir="$(DESTDIR)$(CFG_LIBDIR)" --mandir="$(DESTDIR)$(CFG_MANDIR)"
|
||||
# Remove tmp files because it's a decent amount of disk space
|
||||
|
@ -74,14 +74,6 @@ endif
|
||||
TEST_LOG_FILE=tmp/check-stage$(1)-T-$(2)-H-$(3)-$(4).log
|
||||
TEST_OK_FILE=tmp/check-stage$(1)-T-$(2)-H-$(3)-$(4).ok
|
||||
|
||||
# If we're sharding the testsuite between parallel testers,
|
||||
# pass this argument along to the compiletest and crate test
|
||||
# invocations.
|
||||
ifdef TEST_SHARD
|
||||
CTEST_TESTARGS += --test-shard=$(TEST_SHARD)
|
||||
CRATE_TEST_EXTRA_ARGS += --test-shard=$(TEST_SHARD)
|
||||
endif
|
||||
|
||||
define DEF_TARGET_COMMANDS
|
||||
|
||||
ifdef CFG_UNIXY_$(1)
|
||||
@ -297,6 +289,7 @@ tidy:
|
||||
| grep '^$(S)src/doc' -v \
|
||||
| grep '^$(S)src/compiler-rt' -v \
|
||||
| grep '^$(S)src/libbacktrace' -v \
|
||||
| grep '^$(S)src/rust-installer' -v \
|
||||
| xargs $(CFG_PYTHON) $(S)src/etc/check-binaries.py
|
||||
|
||||
endif
|
||||
|
@ -1,6 +1,6 @@
|
||||
% The Rust Tasks and Communication Guide
|
||||
% The Rust Threads and Communication Guide
|
||||
|
||||
**NOTE** This guide is badly out of date an needs to be rewritten.
|
||||
**NOTE** This guide is badly out of date and needs to be rewritten.
|
||||
|
||||
# Introduction
|
||||
|
||||
@ -9,36 +9,36 @@ primitives. This guide will describe the concurrency model in Rust, how it
|
||||
relates to the Rust type system, and introduce the fundamental library
|
||||
abstractions for constructing concurrent programs.
|
||||
|
||||
Tasks provide failure isolation and recovery. When a fatal error occurs in Rust
|
||||
Threads provide failure isolation and recovery. When a fatal error occurs in Rust
|
||||
code as a result of an explicit call to `panic!()`, an assertion failure, or
|
||||
another invalid operation, the runtime system destroys the entire task. Unlike
|
||||
another invalid operation, the runtime system destroys the entire thread. Unlike
|
||||
in languages such as Java and C++, there is no way to `catch` an exception.
|
||||
Instead, tasks may monitor each other to see if they panic.
|
||||
Instead, threads may monitor each other to see if they panic.
|
||||
|
||||
Tasks use Rust's type system to provide strong memory safety guarantees. In
|
||||
particular, the type system guarantees that tasks cannot induce a data race
|
||||
Threads use Rust's type system to provide strong memory safety guarantees. In
|
||||
particular, the type system guarantees that threads cannot induce a data race
|
||||
from shared mutable state.
|
||||
|
||||
# Basics
|
||||
|
||||
At its simplest, creating a task is a matter of calling the `spawn` function
|
||||
with a closure argument. `spawn` executes the closure in the new task.
|
||||
At its simplest, creating a thread is a matter of calling the `spawn` function
|
||||
with a closure argument. `spawn` executes the closure in the new thread.
|
||||
|
||||
```{rust,ignore}
|
||||
# use std::task::spawn;
|
||||
# use std::thread::spawn;
|
||||
|
||||
// Print something profound in a different task using a named function
|
||||
fn print_message() { println!("I am running in a different task!"); }
|
||||
// Print something profound in a different thread using a named function
|
||||
fn print_message() { println!("I am running in a different thread!"); }
|
||||
spawn(print_message);
|
||||
|
||||
// Alternatively, use a `move ||` expression instead of a named function.
|
||||
// `||` expressions evaluate to an unnamed closure. The `move` keyword
|
||||
// indicates that the closure should take ownership of any variables it
|
||||
// touches.
|
||||
spawn(move || println!("I am also running in a different task!"));
|
||||
spawn(move || println!("I am also running in a different thread!"));
|
||||
```
|
||||
|
||||
In Rust, a task is not a concept that appears in the language semantics.
|
||||
In Rust, a thread is not a concept that appears in the language semantics.
|
||||
Instead, Rust's type system provides all the tools necessary to implement safe
|
||||
concurrency: particularly, ownership. The language leaves the implementation
|
||||
details to the standard library.
|
||||
@ -49,26 +49,26 @@ argument a closure (of type `F`) that it will run exactly once. This
|
||||
closure is limited to capturing `Send`-able data from its environment
|
||||
(that is, data which is deeply owned). Limiting the closure to `Send`
|
||||
ensures that `spawn` can safely move the entire closure and all its
|
||||
associated state into an entirely different task for execution.
|
||||
associated state into an entirely different thread for execution.
|
||||
|
||||
```{rust,ignore}
|
||||
# use std::task::spawn;
|
||||
# fn generate_task_number() -> int { 0 }
|
||||
# use std::thread::spawn;
|
||||
# fn generate_thread_number() -> int { 0 }
|
||||
// Generate some state locally
|
||||
let child_task_number = generate_task_number();
|
||||
let child_thread_number = generate_thread_number();
|
||||
|
||||
spawn(move || {
|
||||
// Capture it in the remote task. The `move` keyword indicates
|
||||
// that this closure should move `child_task_number` into its
|
||||
// Capture it in the remote thread. The `move` keyword indicates
|
||||
// that this closure should move `child_thread_number` into its
|
||||
// environment, rather than capturing a reference into the
|
||||
// enclosing stack frame.
|
||||
println!("I am child number {}", child_task_number);
|
||||
println!("I am child number {}", child_thread_number);
|
||||
});
|
||||
```
|
||||
|
||||
## Communication
|
||||
|
||||
Now that we have spawned a new task, it would be nice if we could communicate
|
||||
Now that we have spawned a new thread, it would be nice if we could communicate
|
||||
with it. For this, we use *channels*. A channel is simply a pair of endpoints:
|
||||
one for sending messages and another for receiving messages.
|
||||
|
||||
@ -78,7 +78,7 @@ of a channel, and a **receiver** is the receiving endpoint. Consider the followi
|
||||
example of calculating two results concurrently:
|
||||
|
||||
```{rust,ignore}
|
||||
# use std::task::spawn;
|
||||
# use std::thread::spawn;
|
||||
|
||||
let (tx, rx): (Sender<int>, Receiver<int>) = channel();
|
||||
|
||||
@ -102,12 +102,12 @@ into its component parts).
|
||||
let (tx, rx): (Sender<int>, Receiver<int>) = channel();
|
||||
```
|
||||
|
||||
The child task will use the sender to send data to the parent task, which will
|
||||
The child thread will use the sender to send data to the parent thread, which will
|
||||
wait to receive the data on the receiver. The next statement spawns the child
|
||||
task.
|
||||
thread.
|
||||
|
||||
```{rust,ignore}
|
||||
# use std::task::spawn;
|
||||
# use std::thread::spawn;
|
||||
# fn some_expensive_computation() -> int { 42 }
|
||||
# let (tx, rx) = channel();
|
||||
spawn(move || {
|
||||
@ -116,10 +116,10 @@ spawn(move || {
|
||||
});
|
||||
```
|
||||
|
||||
Notice that the creation of the task closure transfers `tx` to the child task
|
||||
Notice that the creation of the thread closure transfers `tx` to the child thread
|
||||
implicitly: the closure captures `tx` in its environment. Both `Sender` and
|
||||
`Receiver` are sendable types and may be captured into tasks or otherwise
|
||||
transferred between them. In the example, the child task runs an expensive
|
||||
`Receiver` are sendable types and may be captured into threads or otherwise
|
||||
transferred between them. In the example, the child thread runs an expensive
|
||||
computation, then sends the result over the captured channel.
|
||||
|
||||
Finally, the parent continues with some other expensive computation, then waits
|
||||
@ -137,7 +137,7 @@ The `Sender` and `Receiver` pair created by `channel` enables efficient
|
||||
communication between a single sender and a single receiver, but multiple
|
||||
senders cannot use a single `Sender` value, and multiple receivers cannot use a
|
||||
single `Receiver` value. What if our example needed to compute multiple
|
||||
results across a number of tasks? The following program is ill-typed:
|
||||
results across a number of threads? The following program is ill-typed:
|
||||
|
||||
```{rust,ignore}
|
||||
# fn some_expensive_computation() -> int { 42 }
|
||||
@ -160,7 +160,7 @@ Instead we can clone the `tx`, which allows for multiple senders.
|
||||
let (tx, rx) = channel();
|
||||
|
||||
for init_val in range(0u, 3) {
|
||||
// Create a new channel handle to distribute to the child task
|
||||
// Create a new channel handle to distribute to the child thread
|
||||
let child_tx = tx.clone();
|
||||
spawn(move || {
|
||||
child_tx.send(some_expensive_computation(init_val));
|
||||
@ -172,7 +172,7 @@ let result = rx.recv() + rx.recv() + rx.recv();
|
||||
```
|
||||
|
||||
Cloning a `Sender` produces a new handle to the same channel, allowing multiple
|
||||
tasks to send data to a single receiver. It upgrades the channel internally in
|
||||
threads to send data to a single receiver. It upgrades the channel internally in
|
||||
order to allow this functionality, which means that channels that are not
|
||||
cloned can avoid the overhead required to handle multiple senders. But this
|
||||
fact has no bearing on the channel's usage: the upgrade is transparent.
|
||||
@ -182,9 +182,9 @@ simply use three `Sender` pairs, but it serves to illustrate the point. For
|
||||
reference, written with multiple streams, it might look like the example below.
|
||||
|
||||
```{rust,ignore}
|
||||
# use std::task::spawn;
|
||||
# use std::thread::spawn;
|
||||
|
||||
// Create a vector of ports, one for each child task
|
||||
// Create a vector of ports, one for each child thread
|
||||
let rxs = Vec::from_fn(3, |init_val| {
|
||||
let (tx, rx) = channel();
|
||||
spawn(move || {
|
||||
@ -256,18 +256,18 @@ fn main() {
|
||||
|
||||
## Sharing without copying: Arc
|
||||
|
||||
To share data between tasks, a first approach would be to only use channel as
|
||||
To share data between threads, a first approach would be to only use channel as
|
||||
we have seen previously. A copy of the data to share would then be made for
|
||||
each task. In some cases, this would add up to a significant amount of wasted
|
||||
each thread. In some cases, this would add up to a significant amount of wasted
|
||||
memory and would require copying the same data more than necessary.
|
||||
|
||||
To tackle this issue, one can use an Atomically Reference Counted wrapper
|
||||
(`Arc`) as implemented in the `sync` library of Rust. With an Arc, the data
|
||||
will no longer be copied for each task. The Arc acts as a reference to the
|
||||
will no longer be copied for each thread. The Arc acts as a reference to the
|
||||
shared data and only this reference is shared and cloned.
|
||||
|
||||
Here is a small example showing how to use Arcs. We wish to run concurrently
|
||||
several computations on a single large vector of floats. Each task needs the
|
||||
several computations on a single large vector of floats. Each thread needs the
|
||||
full vector to perform its duty.
|
||||
|
||||
```{rust,ignore}
|
||||
@ -284,10 +284,10 @@ fn main() {
|
||||
let numbers_arc = Arc::new(numbers);
|
||||
|
||||
for num in range(1u, 10) {
|
||||
let task_numbers = numbers_arc.clone();
|
||||
let thread_numbers = numbers_arc.clone();
|
||||
|
||||
spawn(move || {
|
||||
println!("{}-norm = {}", num, pnorm(task_numbers.as_slice(), num));
|
||||
println!("{}-norm = {}", num, pnorm(thread_numbers.as_slice(), num));
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -306,8 +306,8 @@ let numbers_arc = Arc::new(numbers);
|
||||
# }
|
||||
```
|
||||
|
||||
and a clone is captured for each task via a procedure. This only copies
|
||||
the wrapper and not its contents. Within the task's procedure, the captured
|
||||
and a clone is captured for each thread via a procedure. This only copies
|
||||
the wrapper and not its contents. Within the thread's procedure, the captured
|
||||
Arc reference can be used as a shared reference to the underlying vector as
|
||||
if it were local.
|
||||
|
||||
@ -319,29 +319,29 @@ if it were local.
|
||||
# let numbers=Vec::from_fn(1000000, |_| rand::random::<f64>());
|
||||
# let numbers_arc = Arc::new(numbers);
|
||||
# let num = 4;
|
||||
let task_numbers = numbers_arc.clone();
|
||||
let thread_numbers = numbers_arc.clone();
|
||||
spawn(move || {
|
||||
// Capture task_numbers and use it as if it was the underlying vector
|
||||
println!("{}-norm = {}", num, pnorm(task_numbers.as_slice(), num));
|
||||
// Capture thread_numbers and use it as if it was the underlying vector
|
||||
println!("{}-norm = {}", num, pnorm(thread_numbers.as_slice(), num));
|
||||
});
|
||||
# }
|
||||
```
|
||||
|
||||
# Handling task panics
|
||||
# Handling thread panics
|
||||
|
||||
Rust has a built-in mechanism for raising exceptions. The `panic!()` macro
|
||||
(which can also be written with an error string as an argument: `panic!(
|
||||
~reason)`) and the `assert!` construct (which effectively calls `panic!()` if a
|
||||
boolean expression is false) are both ways to raise exceptions. When a task
|
||||
raises an exception, the task unwinds its stack—running destructors and
|
||||
boolean expression is false) are both ways to raise exceptions. When a thread
|
||||
raises an exception, the thread unwinds its stack—running destructors and
|
||||
freeing memory along the way—and then exits. Unlike exceptions in C++,
|
||||
exceptions in Rust are unrecoverable within a single task: once a task panics,
|
||||
exceptions in Rust are unrecoverable within a single thread: once a thread panics,
|
||||
there is no way to "catch" the exception.
|
||||
|
||||
While it isn't possible for a task to recover from panicking, tasks may notify
|
||||
While it isn't possible for a thread to recover from panicking, threads may notify
|
||||
each other if they panic. The simplest way of handling a panic is with the
|
||||
`try` function, which is similar to `spawn`, but immediately blocks and waits
|
||||
for the child task to finish. `try` returns a value of type
|
||||
for the child thread to finish. `try` returns a value of type
|
||||
`Result<T, Box<Any + Send>>`. `Result` is an `enum` type with two variants:
|
||||
`Ok` and `Err`. In this case, because the type arguments to `Result` are `int`
|
||||
and `()`, callers can pattern-match on a result to check whether it's an `Ok`
|
||||
@ -364,14 +364,14 @@ assert!(result.is_err());
|
||||
|
||||
Unlike `spawn`, the function spawned using `try` may return a value, which
|
||||
`try` will dutifully propagate back to the caller in a [`Result`] enum. If the
|
||||
child task terminates successfully, `try` will return an `Ok` result; if the
|
||||
child task panics, `try` will return an `Error` result.
|
||||
child thread terminates successfully, `try` will return an `Ok` result; if the
|
||||
child thread panics, `try` will return an `Error` result.
|
||||
|
||||
[`Result`]: std/result/index.html
|
||||
|
||||
> *Note:* A panicked task does not currently produce a useful error
|
||||
> *Note:* A panicked thread does not currently produce a useful error
|
||||
> value (`try` always returns `Err(())`). In the
|
||||
> future, it may be possible for tasks to intercept the value passed to
|
||||
> future, it may be possible for threads to intercept the value passed to
|
||||
> `panic!()`.
|
||||
|
||||
But not all panics are created equal. In some cases you might need to abort
|
||||
@ -379,4 +379,4 @@ the entire program (perhaps you're writing an assert which, if it trips,
|
||||
indicates an unrecoverable logic error); in other cases you might want to
|
||||
contain the panic at a certain boundary (perhaps a small piece of input from
|
||||
the outside world, which you happen to be processing in parallel, is malformed
|
||||
such that the processing task cannot proceed).
|
||||
such that the processing thread cannot proceed).
|
||||
|
@ -23,11 +23,16 @@ Linux or a Mac, all you need to do is this (note that you don't need to type
|
||||
in the `$`s, they just indicate the start of each command):
|
||||
|
||||
```bash
|
||||
$ curl -s https://static.rust-lang.org/rustup.sh | sudo sh
|
||||
curl -L https://static.rust-lang.org/rustup.sh | sudo sh
|
||||
```
|
||||
|
||||
(If you're concerned about `curl | sudo sh`, please keep reading. Disclaimer
|
||||
below.)
|
||||
If you're concerned about the [potential insecurity](http://curlpipesh.tumblr.com/) of using `curl | sudo sh`,
|
||||
please keep reading and see our disclaimer below. And feel free to use a two-step version of the installation and examine our installation script:
|
||||
|
||||
```bash
|
||||
curl -L https://static.rust-lang.org/rustup.sh -O
|
||||
sudo sh rustup.sh
|
||||
```
|
||||
|
||||
If you're on Windows, please download either the [32-bit
|
||||
installer](https://static.rust-lang.org/dist/rust-nightly-i686-pc-windows-gnu.exe)
|
||||
@ -482,7 +487,7 @@ src/main.rs:2 let x;
|
||||
|
||||
Giving it a type will compile, though:
|
||||
|
||||
```{ignore}
|
||||
```{rust}
|
||||
let x: int;
|
||||
```
|
||||
|
||||
@ -1044,7 +1049,9 @@ struct Point(int, int, int);
|
||||
|
||||
These two will not be equal, even if they have the same values:
|
||||
|
||||
```{rust,ignore}
|
||||
```{rust}
|
||||
# struct Color(int, int, int);
|
||||
# struct Point(int, int, int);
|
||||
let black = Color(0, 0, 0);
|
||||
let origin = Point(0, 0, 0);
|
||||
```
|
||||
@ -1604,10 +1611,6 @@ let a = [1i, 2i, 3i]; // a: [int, ..3]
|
||||
let mut m = [1i, 2i, 3i]; // mut m: [int, ..3]
|
||||
```
|
||||
|
||||
You can create an array with a given number of elements, all initialized to the
|
||||
same value, with `[val, ..N]` syntax. The compiler ensures that arrays are
|
||||
always initialized.
|
||||
|
||||
There's a shorthand for initializing each element of an array to the same
|
||||
value. In this example, each element of `a` will be initialized to `0i`:
|
||||
|
||||
@ -1895,7 +1898,7 @@ authors = ["Your Name <you@example.com>"]
|
||||
Cargo gets this information from your environment. If it's not correct, go ahead
|
||||
and fix that.
|
||||
|
||||
Finally, Cargo generated a hello, world for us. Check out `src/main.rs`:
|
||||
Finally, Cargo generated a "Hello, world!" for us. Check out `src/main.rs`:
|
||||
|
||||
```{rust}
|
||||
fn main() {
|
||||
@ -3036,7 +3039,7 @@ test foo ... FAILED
|
||||
failures:
|
||||
|
||||
---- foo stdout ----
|
||||
task 'foo' failed at 'assertion failed: false', /home/you/projects/testing/tests/lib.rs:3
|
||||
thread 'foo' failed at 'assertion failed: false', /home/you/projects/testing/tests/lib.rs:3
|
||||
|
||||
|
||||
|
||||
@ -3045,7 +3048,7 @@ failures:
|
||||
|
||||
test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured
|
||||
|
||||
task '<main>' failed at 'Some tests failed', /home/you/src/rust/src/libtest/lib.rs:243
|
||||
thread '<main>' failed at 'Some tests failed', /home/you/src/rust/src/libtest/lib.rs:243
|
||||
```
|
||||
|
||||
Lots of output! Let's break this down:
|
||||
@ -3088,7 +3091,7 @@ failed, especially as we accumulate more tests.
|
||||
failures:
|
||||
|
||||
---- foo stdout ----
|
||||
task 'foo' failed at 'assertion failed: false', /home/you/projects/testing/tests/lib.rs:3
|
||||
thread 'foo' failed at 'assertion failed: false', /home/you/projects/testing/tests/lib.rs:3
|
||||
|
||||
|
||||
|
||||
@ -3097,7 +3100,7 @@ failures:
|
||||
|
||||
test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured
|
||||
|
||||
task '<main>' failed at 'Some tests failed', /home/you/src/rust/src/libtest/lib.rs:243
|
||||
thread '<main>' failed at 'Some tests failed', /home/you/src/rust/src/libtest/lib.rs:243
|
||||
```
|
||||
|
||||
After all the tests run, Rust will show us any output from our failed tests.
|
||||
@ -4263,7 +4266,7 @@ is that a moving closure always takes ownership of all variables that
|
||||
it uses. Ordinary closures, in contrast, just create a reference into
|
||||
the enclosing stack frame. Moving closures are most useful with Rust's
|
||||
concurrency features, and so we'll just leave it at this for
|
||||
now. We'll talk about them more in the "Tasks" section of the guide.
|
||||
now. We'll talk about them more in the "Threads" section of the guide.
|
||||
|
||||
## Accepting closures as arguments
|
||||
|
||||
@ -4290,7 +4293,9 @@ let square = |x: int| { x * x };
|
||||
We've seen this before. We make a closure that takes an integer, and returns
|
||||
its square.
|
||||
|
||||
```{rust,ignore}
|
||||
```{rust}
|
||||
# fn twice(x: int, f: |int| -> int) -> int { f(x) + f(x) }
|
||||
# let square = |x: int| { x * x };
|
||||
twice(5i, square); // evaluates to 50
|
||||
```
|
||||
|
||||
@ -5213,9 +5218,7 @@ as you can see, there's no overhead of deciding which version to call here,
|
||||
hence 'statically dispatched'. The downside is that we have two copies of
|
||||
the same function, so our binary is a little bit larger.
|
||||
|
||||
# Tasks
|
||||
|
||||
**NOTE**: this section is currently out of date and will be rewritten soon.
|
||||
# Threads
|
||||
|
||||
Concurrency and parallelism are topics that are of increasing interest to a
|
||||
broad subsection of software developers. Modern computers are often multi-core,
|
||||
@ -5224,24 +5227,22 @@ processor. Rust's semantics lend themselves very nicely to solving a number of
|
||||
issues that programmers have with concurrency. Many concurrency errors that are
|
||||
runtime errors in other languages are compile-time errors in Rust.
|
||||
|
||||
Rust's concurrency primitive is called a **task**. Tasks are similar to
|
||||
threads, and do not share memory in an unsafe manner, preferring message
|
||||
passing to communicate. It's worth noting that tasks are implemented as a
|
||||
library, and not part of the language. This means that in the future, other
|
||||
concurrency libraries can be written for Rust to help in specific scenarios.
|
||||
Here's an example of creating a task:
|
||||
Rust's concurrency primitive is called a **thread**. It's worth noting that
|
||||
threads are implemented as a library, and not part of the language. This means
|
||||
that in the future, other concurrency libraries can be written for Rust to help
|
||||
in specific scenarios. Here's an example of creating a thread:
|
||||
|
||||
```{rust,ignore}
|
||||
spawn(move || {
|
||||
println!("Hello from a task!");
|
||||
println!("Hello from a thread!");
|
||||
});
|
||||
```
|
||||
|
||||
The `spawn` function takes a closure as an argument, and runs that
|
||||
closure in a new task. Typically, you will want to use a moving
|
||||
closure in a new thread. Typically, you will want to use a moving
|
||||
closure, so that the closure takes ownership of any variables that it
|
||||
touches. This implies that those variables are not usable from the
|
||||
parent task after the child task is spawned:
|
||||
parent thread after the child thread is spawned:
|
||||
|
||||
```{rust,ignore}
|
||||
let mut x = vec![1i, 2i, 3i];
|
||||
@ -5257,15 +5258,15 @@ println!("The value of x[0] is: {}", x[0]); // error: use of moved value: `x`
|
||||
other languages would let us do this, but it's not safe to do
|
||||
so. Rust's borrow checker catches the error.
|
||||
|
||||
If tasks were only able to capture these values, they wouldn't be very useful.
|
||||
Luckily, tasks can communicate with each other through **channel**s. Channels
|
||||
If threads were only able to capture these values, they wouldn't be very useful.
|
||||
Luckily, threads can communicate with each other through **channel**s. Channels
|
||||
work like this:
|
||||
|
||||
```{rust,ignore}
|
||||
let (tx, rx) = channel();
|
||||
|
||||
spawn(move || {
|
||||
tx.send("Hello from a task!".to_string());
|
||||
tx.send("Hello from a thread!".to_string());
|
||||
});
|
||||
|
||||
let message = rx.recv();
|
||||
@ -5278,14 +5279,14 @@ receive the message on the `Receiver<T>` side with the `recv()` method. This
|
||||
method blocks until it gets a message. There's a similar method, `.try_recv()`,
|
||||
which returns an `Result<T, TryRecvError>` and does not block.
|
||||
|
||||
If you want to send messages to the task as well, create two channels!
|
||||
If you want to send messages to the thread as well, create two channels!
|
||||
|
||||
```{rust,ignore}
|
||||
let (tx1, rx1) = channel();
|
||||
let (tx2, rx2) = channel();
|
||||
|
||||
spawn(move || {
|
||||
tx1.send("Hello from a task!".to_string());
|
||||
tx1.send("Hello from a thread!".to_string());
|
||||
let message = rx2.recv();
|
||||
println!("{}", message);
|
||||
});
|
||||
@ -5296,9 +5297,9 @@ println!("{}", message);
|
||||
tx2.send("Goodbye from main!".to_string());
|
||||
```
|
||||
|
||||
The closure has one sending end and one receiving end, and the main
|
||||
task has one of each as well. Now they can talk back and forth in
|
||||
whatever way they wish.
|
||||
The closure has one sending end and one receiving end, and the main thread has
|
||||
one of each as well. Now they can talk back and forth in whatever way they
|
||||
wish.
|
||||
|
||||
Notice as well that because `Sender` and `Receiver` are generic, while you can
|
||||
pass any kind of information through the channel, the ends are strongly typed.
|
||||
@ -5337,7 +5338,7 @@ we'll just get the value immediately.
|
||||
|
||||
## Success and failure
|
||||
|
||||
Tasks don't always succeed, they can also panic. A task that wishes to panic
|
||||
Threads don't always succeed, they can also panic. A thread that wishes to panic
|
||||
can call the `panic!` macro, passing a message:
|
||||
|
||||
```{rust,ignore}
|
||||
@ -5346,14 +5347,14 @@ spawn(move || {
|
||||
});
|
||||
```
|
||||
|
||||
If a task panics, it is not possible for it to recover. However, it can
|
||||
notify other tasks that it has panicked. We can do this with `task::try`:
|
||||
If a thread panics, it is not possible for it to recover. However, it can
|
||||
notify other thread that it has panicked. We can do this with `thread::try`:
|
||||
|
||||
```{rust,ignore}
|
||||
use std::task;
|
||||
use std::thread;
|
||||
use std::rand;
|
||||
|
||||
let result = task::try(move || {
|
||||
let result = thread::try(move || {
|
||||
if rand::random() {
|
||||
println!("OK");
|
||||
} else {
|
||||
@ -5362,7 +5363,7 @@ let result = task::try(move || {
|
||||
});
|
||||
```
|
||||
|
||||
This task will randomly panic or succeed. `task::try` returns a `Result`
|
||||
This thread will randomly panic or succeed. `thread::try` returns a `Result`
|
||||
type, so we can handle the response like any other computation that may
|
||||
fail.
|
||||
|
||||
@ -5410,7 +5411,7 @@ fn main() {
|
||||
}
|
||||
```
|
||||
|
||||
You can have the macros expanded like this: `rustc print.rs --pretty=expanded`, which will
|
||||
You can have the macros expanded like this: `rustc --pretty=expanded print.rs`, which will
|
||||
give us this huge result:
|
||||
|
||||
```{rust,ignore}
|
||||
|
@ -58,7 +58,7 @@ a guide that can help you out:
|
||||
* [Strings](guide-strings.html)
|
||||
* [Pointers](guide-pointers.html)
|
||||
* [Crates and modules](guide-crates.html)
|
||||
* [Tasks and Communication](guide-tasks.html)
|
||||
* [Threads and Communication](guide-threads.html)
|
||||
* [Error Handling](guide-error-handling.html)
|
||||
* [Foreign Function Interface](guide-ffi.html)
|
||||
* [Writing Unsafe and Low-Level Code](guide-unsafe.html)
|
||||
|
@ -483,7 +483,7 @@ fn main() {
|
||||
for i in range(0u, 3u) {
|
||||
let number = numbers.clone();
|
||||
Thread::spawn(move || {
|
||||
let mut array = number.lock();
|
||||
let mut array = number.lock().unwrap();
|
||||
|
||||
(*array)[i] += 1;
|
||||
|
||||
|
@ -194,11 +194,11 @@ grammar as double-quoted strings. Other tokens have exact rules given.
|
||||
| else | enum | extern | false | final |
|
||||
| fn | for | if | impl | in |
|
||||
| let | loop | match | mod | move |
|
||||
| mut | offsetof | once | override | priv |
|
||||
| pub | pure | ref | return | sizeof |
|
||||
| static | self | struct | super | true |
|
||||
| trait | type | typeof | unsafe | unsized |
|
||||
| use | virtual | where | while | yield |
|
||||
| mut | offsetof | override | priv | pub |
|
||||
| pure | ref | return | sizeof | static |
|
||||
| self | struct | super | true | trait |
|
||||
| type | typeof | unsafe | unsized | use |
|
||||
| virtual | where | while | yield |
|
||||
|
||||
|
||||
Each of these keywords has special meaning in its grammar, and all of them are
|
||||
@ -899,8 +899,8 @@ mirrors the module hierarchy.
|
||||
// Load the `vec` module from `vec.rs`
|
||||
mod vec;
|
||||
|
||||
mod task {
|
||||
// Load the `local_data` module from `task/local_data.rs`
|
||||
mod thread {
|
||||
// Load the `local_data` module from `thread/local_data.rs`
|
||||
mod local_data;
|
||||
}
|
||||
```
|
||||
@ -909,9 +909,9 @@ The directories and files used for loading external file modules can be
|
||||
influenced with the `path` attribute.
|
||||
|
||||
```{.ignore}
|
||||
#[path = "task_files"]
|
||||
mod task {
|
||||
// Load the `local_data` module from `task_files/tls.rs`
|
||||
#[path = "thread_files"]
|
||||
mod thread {
|
||||
// Load the `local_data` module from `thread_files/tls.rs`
|
||||
#[path = "tls.rs"]
|
||||
mod local_data;
|
||||
}
|
||||
@ -1188,7 +1188,7 @@ code safe, in the surrounding context.
|
||||
Unsafe blocks are used to wrap foreign libraries, make direct use of hardware
|
||||
or implement features not directly present in the language. For example, Rust
|
||||
provides the language features necessary to implement memory-safe concurrency
|
||||
in the language but the implementation of tasks and message passing is in the
|
||||
in the language but the implementation of threads and message passing is in the
|
||||
standard library.
|
||||
|
||||
Rust's type system is a conservative approximation of the dynamic safety
|
||||
@ -1500,7 +1500,7 @@ be modified by the program. One of Rust's goals is to make concurrency bugs
|
||||
hard to run into, and this is obviously a very large source of race conditions
|
||||
or other bugs. For this reason, an `unsafe` block is required when either
|
||||
reading or writing a mutable static variable. Care should be taken to ensure
|
||||
that modifications to a mutable static are safe with respect to other tasks
|
||||
that modifications to a mutable static are safe with respect to other threads
|
||||
running in the same process.
|
||||
|
||||
Mutable statics are still very useful, however. They can be used with C
|
||||
@ -2253,11 +2253,11 @@ A complete list of the built-in language items follows:
|
||||
* `drop`
|
||||
: Have destructors.
|
||||
* `send`
|
||||
: Able to be sent across task boundaries.
|
||||
: Able to be sent across thread boundaries.
|
||||
* `sized`
|
||||
: Has a size known at compile time.
|
||||
* `sync`
|
||||
: Able to be safely shared between tasks when aliased.
|
||||
: Able to be safely shared between threads when aliased.
|
||||
|
||||
#### Operators
|
||||
|
||||
@ -2621,7 +2621,7 @@ The currently implemented features of the reference compiler are:
|
||||
LLVM's implementation which works in concert with the kernel
|
||||
loader and dynamic linker. This is not necessarily available
|
||||
on all platforms, and usage of it is discouraged (rust
|
||||
focuses more on task-local data instead of thread-local
|
||||
focuses more on thread-local data instead of thread-local
|
||||
data).
|
||||
|
||||
* `trace_macros` - Allows use of the `trace_macros` macro, which is a nasty
|
||||
@ -2939,7 +2939,7 @@ array is mutable, the resulting [lvalue](#lvalues,-rvalues-and-temporaries) can
|
||||
be assigned to.
|
||||
|
||||
Indices are zero-based, and may be of any integral type. Vector access is
|
||||
bounds-checked at run-time. When the check fails, it will put the task in a
|
||||
bounds-checked at run-time. When the check fails, it will put the thread in a
|
||||
_panicked state_.
|
||||
|
||||
```{should-fail}
|
||||
@ -3950,7 +3950,7 @@ Types in Rust are categorized into kinds, based on various properties of the
|
||||
components of the type. The kinds are:
|
||||
|
||||
* `Send`
|
||||
: Types of this kind can be safely sent between tasks.
|
||||
: Types of this kind can be safely sent between threads.
|
||||
This kind includes scalars, boxes, procs, and
|
||||
structural types containing only other owned types.
|
||||
All `Send` types are `'static`.
|
||||
@ -3998,21 +3998,21 @@ to sendable.
|
||||
|
||||
# Memory and concurrency models
|
||||
|
||||
Rust has a memory model centered around concurrently-executing _tasks_. Thus
|
||||
Rust has a memory model centered around concurrently-executing _threads_. Thus
|
||||
its memory model and its concurrency model are best discussed simultaneously,
|
||||
as parts of each only make sense when considered from the perspective of the
|
||||
other.
|
||||
|
||||
When reading about the memory model, keep in mind that it is partitioned in
|
||||
order to support tasks; and when reading about tasks, keep in mind that their
|
||||
order to support threads; and when reading about threads, keep in mind that their
|
||||
isolation and communication mechanisms are only possible due to the ownership
|
||||
and lifetime semantics of the memory model.
|
||||
|
||||
## Memory model
|
||||
|
||||
A Rust program's memory consists of a static set of *items*, a set of
|
||||
[tasks](#tasks) each with its own *stack*, and a *heap*. Immutable portions of
|
||||
the heap may be shared between tasks, mutable portions may not.
|
||||
[threads](#threads) each with its own *stack*, and a *heap*. Immutable portions of
|
||||
the heap may be shared between threads, mutable portions may not.
|
||||
|
||||
Allocations in the stack consist of *slots*, and allocations in the heap
|
||||
consist of *boxes*.
|
||||
@ -4023,8 +4023,8 @@ The _items_ of a program are those functions, modules and types that have their
|
||||
value calculated at compile-time and stored uniquely in the memory image of the
|
||||
rust process. Items are neither dynamically allocated nor freed.
|
||||
|
||||
A task's _stack_ consists of activation frames automatically allocated on entry
|
||||
to each function as the task executes. A stack allocation is reclaimed when
|
||||
A thread's _stack_ consists of activation frames automatically allocated on entry
|
||||
to each function as the thread executes. A stack allocation is reclaimed when
|
||||
control leaves the frame containing it.
|
||||
|
||||
The _heap_ is a general term that describes boxes. The lifetime of an
|
||||
@ -4034,10 +4034,10 @@ in the heap, heap allocations may outlive the frame they are allocated within.
|
||||
|
||||
### Memory ownership
|
||||
|
||||
A task owns all memory it can *safely* reach through local variables, as well
|
||||
A thread owns all memory it can *safely* reach through local variables, as well
|
||||
as boxes and references.
|
||||
|
||||
When a task sends a value that has the `Send` trait to another task, it loses
|
||||
When a thread sends a value that has the `Send` trait to another thread, it loses
|
||||
ownership of the value sent and can no longer refer to it. This is statically
|
||||
guaranteed by the combined use of "move semantics", and the compiler-checked
|
||||
_meaning_ of the `Send` trait: it is only instantiated for (transitively)
|
||||
@ -4046,12 +4046,12 @@ sendable kinds of data constructor and pointers, never including references.
|
||||
When a stack frame is exited, its local allocations are all released, and its
|
||||
references to boxes are dropped.
|
||||
|
||||
When a task finishes, its stack is necessarily empty and it therefore has no
|
||||
When a thread finishes, its stack is necessarily empty and it therefore has no
|
||||
references to any boxes; the remainder of its heap is immediately freed.
|
||||
|
||||
### Memory slots
|
||||
|
||||
A task's stack contains slots.
|
||||
A thread's stack contains slots.
|
||||
|
||||
A _slot_ is a component of a stack frame, either a function parameter, a
|
||||
[temporary](#lvalues,-rvalues-and-temporaries), or a local variable.
|
||||
@ -4105,72 +4105,69 @@ let y = x;
|
||||
// attempting to use `x` will result in an error here
|
||||
```
|
||||
|
||||
## Tasks
|
||||
## Threads
|
||||
|
||||
An executing Rust program consists of a tree of tasks. A Rust _task_ consists
|
||||
of an entry function, a stack, a set of outgoing communication channels and
|
||||
incoming communication ports, and ownership of some portion of the heap of a
|
||||
single operating-system process.
|
||||
Rust's primary concurrency mechanism is called a **thread**.
|
||||
|
||||
### Communication between tasks
|
||||
### Communication between threads
|
||||
|
||||
Rust tasks are isolated and generally unable to interfere with one another's
|
||||
Rust threads are isolated and generally unable to interfere with one another's
|
||||
memory directly, except through [`unsafe` code](#unsafe-functions). All
|
||||
contact between tasks is mediated by safe forms of ownership transfer, and data
|
||||
contact between threads is mediated by safe forms of ownership transfer, and data
|
||||
races on memory are prohibited by the type system.
|
||||
|
||||
When you wish to send data between tasks, the values are restricted to the
|
||||
When you wish to send data between threads, the values are restricted to the
|
||||
[`Send` type-kind](#type-kinds). Restricting communication interfaces to this
|
||||
kind ensures that no references move between tasks. Thus access to an entire
|
||||
kind ensures that no references move between threads. Thus access to an entire
|
||||
data structure can be mediated through its owning "root" value; no further
|
||||
locking or copying is required to avoid data races within the substructure of
|
||||
such a value.
|
||||
|
||||
### Task lifecycle
|
||||
### Thread
|
||||
|
||||
The _lifecycle_ of a task consists of a finite set of states and events that
|
||||
cause transitions between the states. The lifecycle states of a task are:
|
||||
The _lifecycle_ of a threads consists of a finite set of states and events that
|
||||
cause transitions between the states. The lifecycle states of a thread are:
|
||||
|
||||
* running
|
||||
* blocked
|
||||
* panicked
|
||||
* dead
|
||||
|
||||
A task begins its lifecycle — once it has been spawned — in the
|
||||
A thread begins its lifecycle — once it has been spawned — in the
|
||||
*running* state. In this state it executes the statements of its entry
|
||||
function, and any functions called by the entry function.
|
||||
|
||||
A task may transition from the *running* state to the *blocked* state any time
|
||||
A thread may transition from the *running* state to the *blocked* state any time
|
||||
it makes a blocking communication call. When the call can be completed —
|
||||
when a message arrives at a sender, or a buffer opens to receive a message
|
||||
— then the blocked task will unblock and transition back to *running*.
|
||||
— then the blocked thread will unblock and transition back to *running*.
|
||||
|
||||
A task may transition to the *panicked* state at any time, due being killed by
|
||||
A thread may transition to the *panicked* state at any time, due being killed by
|
||||
some external event or internally, from the evaluation of a `panic!()` macro.
|
||||
Once *panicking*, a task unwinds its stack and transitions to the *dead* state.
|
||||
Unwinding the stack of a task is done by the task itself, on its own control
|
||||
Once *panicking*, a thread unwinds its stack and transitions to the *dead* state.
|
||||
Unwinding the stack of a thread is done by the thread itself, on its own control
|
||||
stack. If a value with a destructor is freed during unwinding, the code for the
|
||||
destructor is run, also on the task's control stack. Running the destructor
|
||||
destructor is run, also on the thread's control stack. Running the destructor
|
||||
code causes a temporary transition to a *running* state, and allows the
|
||||
destructor code to cause any subsequent state transitions. The original task
|
||||
destructor code to cause any subsequent state transitions. The original thread
|
||||
of unwinding and panicking thereby may suspend temporarily, and may involve
|
||||
(recursive) unwinding of the stack of a failed destructor. Nonetheless, the
|
||||
outermost unwinding activity will continue until the stack is unwound and the
|
||||
task transitions to the *dead* state. There is no way to "recover" from task
|
||||
panics. Once a task has temporarily suspended its unwinding in the *panicking*
|
||||
thread transitions to the *dead* state. There is no way to "recover" from thread
|
||||
panics. Once a thread has temporarily suspended its unwinding in the *panicking*
|
||||
state, a panic occurring from within this destructor results in *hard* panic.
|
||||
A hard panic currently results in the process aborting.
|
||||
|
||||
A task in the *dead* state cannot transition to other states; it exists only to
|
||||
have its termination status inspected by other tasks, and/or to await
|
||||
A thread in the *dead* state cannot transition to other states; it exists only to
|
||||
have its termination status inspected by other threads, and/or to await
|
||||
reclamation when the last reference to it drops.
|
||||
|
||||
# Runtime services, linkage and debugging
|
||||
|
||||
The Rust _runtime_ is a relatively compact collection of Rust code that
|
||||
provides fundamental services and datatypes to all Rust tasks at run-time. It
|
||||
provides fundamental services and datatypes to all Rust threads at run-time. It
|
||||
is smaller and simpler than many modern language runtimes. It is tightly
|
||||
integrated into the language's execution model of memory, tasks, communication
|
||||
integrated into the language's execution model of memory, threads, communication
|
||||
and logging.
|
||||
|
||||
### Memory allocation
|
||||
@ -4181,7 +4178,7 @@ environment and releases them back to its environment when they are no longer
|
||||
needed. The default implementation of the service-provider interface consists
|
||||
of the C runtime functions `malloc` and `free`.
|
||||
|
||||
The runtime memory-management system, in turn, supplies Rust tasks with
|
||||
The runtime memory-management system, in turn, supplies Rust threads with
|
||||
facilities for allocating releasing stacks, as well as allocating and freeing
|
||||
heap data.
|
||||
|
||||
@ -4189,15 +4186,15 @@ heap data.
|
||||
|
||||
The runtime provides C and Rust code to assist with various built-in types,
|
||||
such as arrays, strings, and the low level communication system (ports,
|
||||
channels, tasks).
|
||||
channels, threads).
|
||||
|
||||
Support for other built-in types such as simple types, tuples and enums is
|
||||
open-coded by the Rust compiler.
|
||||
|
||||
### Task scheduling and communication
|
||||
### Thread scheduling and communication
|
||||
|
||||
The runtime provides code to manage inter-task communication. This includes
|
||||
the system of task-lifecycle state transitions depending on the contents of
|
||||
The runtime provides code to manage inter-thread communication. This includes
|
||||
the system of thread-lifecycle state transitions depending on the contents of
|
||||
queues, as well as code to copy values between queues and their recipients and
|
||||
to serialize values for transmission over operating-system inter-process
|
||||
communication facilities.
|
||||
|
@ -245,6 +245,7 @@
|
||||
<context attribute="CharEscape" lineEndContext="#pop" name="CharEscape">
|
||||
<AnyChar String="nrt\'"" attribute="CharEscape" context="#pop"/>
|
||||
<RegExpr String="x[0-9a-fA-F]{2}" attribute="CharEscape" context="#pop"/>
|
||||
<RegExpr String="u\{[0-9a-fA-F]{1,6}\}" attribute="CharEscape" context="#pop"/>
|
||||
<RegExpr String="u[0-9a-fA-F]{4}" attribute="CharEscape" context="#pop"/>
|
||||
<RegExpr String="U[0-9a-fA-F]{8}" attribute="CharEscape" context="#pop"/>
|
||||
<RegExpr String="." attribute="Error" context="#pop"/>
|
||||
@ -255,7 +256,7 @@
|
||||
<Detect2Chars char="*" char1="/" attribute="Comment" context="#pop" endRegion="Comment"/>
|
||||
</context>
|
||||
</contexts>
|
||||
<itemDatas>
|
||||
<itemDatas>
|
||||
<itemData name="Normal Text" defStyleNum="dsNormal"/>
|
||||
<itemData name="Keyword" defStyleNum="dsKeyword" color="#770088" bold="1"/>
|
||||
<itemData name="Self" defStyleNum="dsKeyword" color="#FF0000" bold="1"/>
|
||||
|
@ -114,11 +114,5 @@ def make_win_dist(rust_root, gcc_root, target_triple):
|
||||
for src in target_libs:
|
||||
shutil.copy(src, target_lib_dir)
|
||||
|
||||
# Copy license files
|
||||
lic_dir = os.path.join(rust_root, "bin", "third-party")
|
||||
if os.path.exists(lic_dir):
|
||||
shutil.rmtree(lic_dir) # copytree() won't overwrite existing files
|
||||
shutil.copytree(os.path.join(os.path.dirname(__file__), "third-party"), lic_dir)
|
||||
|
||||
if __name__=="__main__":
|
||||
make_win_dist(sys.argv[1], sys.argv[2], sys.argv[3])
|
||||
|
@ -112,7 +112,8 @@ LIT_INTEGER
|
||||
;
|
||||
|
||||
LIT_FLOAT
|
||||
: [0-9][0-9_]* ('.' | ('.' [0-9][0-9_]*)? ([eE] [-+]? [0-9][0-9_]*)? SUFFIX?)
|
||||
: [0-9][0-9_]* ( '.' {_input.LA(1) != '.'}?
|
||||
| ('.' [0-9][0-9_]*)? ([eE] [-+]? [0-9][0-9_]*)? SUFFIX?)
|
||||
;
|
||||
|
||||
LIT_STR
|
||||
|
@ -61,7 +61,7 @@ fn parse_token_list(file: &str) -> HashMap<String, token::Token> {
|
||||
"SHL" => token::BinOp(token::Shl),
|
||||
"LBRACE" => token::OpenDelim(token::Brace),
|
||||
"RARROW" => token::RArrow,
|
||||
"LIT_STR" => token::Literal(token::Str_(Name(0))),
|
||||
"LIT_STR" => token::Literal(token::Str_(Name(0)), None),
|
||||
"DOTDOT" => token::DotDot,
|
||||
"MOD_SEP" => token::ModSep,
|
||||
"DOTDOTDOT" => token::DotDotDot,
|
||||
@ -71,7 +71,7 @@ fn parse_token_list(file: &str) -> HashMap<String, token::Token> {
|
||||
"ANDAND" => token::AndAnd,
|
||||
"AT" => token::At,
|
||||
"LBRACKET" => token::OpenDelim(token::Bracket),
|
||||
"LIT_STR_RAW" => token::Literal(token::StrRaw(Name(0), 0)),
|
||||
"LIT_STR_RAW" => token::Literal(token::StrRaw(Name(0), 0), None),
|
||||
"RPAREN" => token::CloseDelim(token::Paren),
|
||||
"SLASH" => token::BinOp(token::Slash),
|
||||
"COMMA" => token::Comma,
|
||||
@ -80,8 +80,8 @@ fn parse_token_list(file: &str) -> HashMap<String, token::Token> {
|
||||
"TILDE" => token::Tilde,
|
||||
"IDENT" => id(),
|
||||
"PLUS" => token::BinOp(token::Plus),
|
||||
"LIT_CHAR" => token::Literal(token::Char(Name(0))),
|
||||
"LIT_BYTE" => token::Literal(token::Byte(Name(0))),
|
||||
"LIT_CHAR" => token::Literal(token::Char(Name(0)), None),
|
||||
"LIT_BYTE" => token::Literal(token::Byte(Name(0)), None),
|
||||
"EQ" => token::Eq,
|
||||
"RBRACKET" => token::CloseDelim(token::Bracket),
|
||||
"COMMENT" => token::Comment,
|
||||
@ -95,9 +95,9 @@ fn parse_token_list(file: &str) -> HashMap<String, token::Token> {
|
||||
"BINOP" => token::BinOp(token::Plus),
|
||||
"POUND" => token::Pound,
|
||||
"OROR" => token::OrOr,
|
||||
"LIT_INTEGER" => token::Literal(token::Integer(Name(0))),
|
||||
"LIT_INTEGER" => token::Literal(token::Integer(Name(0)), None),
|
||||
"BINOPEQ" => token::BinOpEq(token::Plus),
|
||||
"LIT_FLOAT" => token::Literal(token::Float(Name(0))),
|
||||
"LIT_FLOAT" => token::Literal(token::Float(Name(0)), None),
|
||||
"WHITESPACE" => token::Whitespace,
|
||||
"UNDERSCORE" => token::Underscore,
|
||||
"MINUS" => token::BinOp(token::Minus),
|
||||
@ -107,8 +107,8 @@ fn parse_token_list(file: &str) -> HashMap<String, token::Token> {
|
||||
"OR" => token::BinOp(token::Or),
|
||||
"GT" => token::Gt,
|
||||
"LE" => token::Le,
|
||||
"LIT_BINARY" => token::Literal(token::Binary(Name(0))),
|
||||
"LIT_BINARY_RAW" => token::Literal(token::BinaryRaw(Name(0), 0)),
|
||||
"LIT_BINARY" => token::Literal(token::Binary(Name(0)), None),
|
||||
"LIT_BINARY_RAW" => token::Literal(token::BinaryRaw(Name(0), 0), None),
|
||||
_ => continue,
|
||||
};
|
||||
|
||||
@ -189,17 +189,17 @@ fn parse_antlr_token(s: &str, tokens: &HashMap<String, token::Token>) -> TokenAn
|
||||
token::BinOp(..) => token::BinOp(str_to_binop(content)),
|
||||
token::BinOpEq(..) => token::BinOpEq(str_to_binop(content.slice_to(
|
||||
content.len() - 1))),
|
||||
token::Literal(token::Str_(..)) => token::Literal(token::Str_(fix(content))),
|
||||
token::Literal(token::StrRaw(..)) => token::Literal(token::StrRaw(fix(content),
|
||||
count(content))),
|
||||
token::Literal(token::Char(..)) => token::Literal(token::Char(fixchar(content))),
|
||||
token::Literal(token::Byte(..)) => token::Literal(token::Byte(fixchar(content))),
|
||||
token::Literal(token::Str_(..), n) => token::Literal(token::Str_(fix(content)), n),
|
||||
token::Literal(token::StrRaw(..), n) => token::Literal(token::StrRaw(fix(content),
|
||||
count(content)), n),
|
||||
token::Literal(token::Char(..), n) => token::Literal(token::Char(fixchar(content)), n),
|
||||
token::Literal(token::Byte(..), n) => token::Literal(token::Byte(fixchar(content)), n),
|
||||
token::DocComment(..) => token::DocComment(nm),
|
||||
token::Literal(token::Integer(..)) => token::Literal(token::Integer(nm)),
|
||||
token::Literal(token::Float(..)) => token::Literal(token::Float(nm)),
|
||||
token::Literal(token::Binary(..)) => token::Literal(token::Binary(nm)),
|
||||
token::Literal(token::BinaryRaw(..)) => token::Literal(token::BinaryRaw(fix(content),
|
||||
count(content))),
|
||||
token::Literal(token::Integer(..), n) => token::Literal(token::Integer(nm), n),
|
||||
token::Literal(token::Float(..), n) => token::Literal(token::Float(nm), n),
|
||||
token::Literal(token::Binary(..), n) => token::Literal(token::Binary(nm), n),
|
||||
token::Literal(token::BinaryRaw(..), n) => token::Literal(token::BinaryRaw(fix(content),
|
||||
count(content)), n),
|
||||
token::Ident(..) => token::Ident(ast::Ident { name: nm, ctxt: 0 },
|
||||
token::ModName),
|
||||
token::Lifetime(..) => token::Lifetime(ast::Ident { name: nm, ctxt: 0 }),
|
||||
@ -214,8 +214,8 @@ fn parse_antlr_token(s: &str, tokens: &HashMap<String, token::Token>) -> TokenAn
|
||||
};
|
||||
|
||||
let sp = syntax::codemap::Span {
|
||||
lo: syntax::codemap::BytePos(from_str::<u32>(start).unwrap() - offset),
|
||||
hi: syntax::codemap::BytePos(from_str::<u32>(end).unwrap() + 1),
|
||||
lo: syntax::codemap::BytePos(start.parse::<u32>().unwrap() - offset),
|
||||
hi: syntax::codemap::BytePos(end.parse::<u32>().unwrap() + 1),
|
||||
expn_id: syntax::codemap::NO_EXPANSION
|
||||
};
|
||||
|
||||
@ -247,7 +247,9 @@ fn main() {
|
||||
let token_map = parse_token_list(token_file.read_to_string().unwrap().as_slice());
|
||||
|
||||
let mut stdin = std::io::stdin();
|
||||
let mut antlr_tokens = stdin.lines().map(|l| parse_antlr_token(l.unwrap().as_slice().trim(),
|
||||
let mut lock = stdin.lock();
|
||||
let lines = lock.lines();
|
||||
let mut antlr_tokens = lines.map(|l| parse_antlr_token(l.unwrap().as_slice().trim(),
|
||||
&token_map));
|
||||
|
||||
let code = File::open(&Path::new(args[1].as_slice())).unwrap().read_to_string().unwrap();
|
||||
@ -284,17 +286,17 @@ fn main() {
|
||||
ref c => assert!(c == &antlr_tok.tok, "{} is not {}", rustc_tok, antlr_tok)
|
||||
}
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
matches!(
|
||||
token::Literal(token::Byte(..)),
|
||||
token::Literal(token::Char(..)),
|
||||
token::Literal(token::Integer(..)),
|
||||
token::Literal(token::Float(..)),
|
||||
token::Literal(token::Str_(..)),
|
||||
token::Literal(token::StrRaw(..)),
|
||||
token::Literal(token::Binary(..)),
|
||||
token::Literal(token::BinaryRaw(..)),
|
||||
token::Literal(token::Byte(..), _),
|
||||
token::Literal(token::Char(..), _),
|
||||
token::Literal(token::Integer(..), _),
|
||||
token::Literal(token::Float(..), _),
|
||||
token::Literal(token::Str_(..), _),
|
||||
token::Literal(token::StrRaw(..), _),
|
||||
token::Literal(token::Binary(..), _),
|
||||
token::Literal(token::BinaryRaw(..), _),
|
||||
token::Ident(..),
|
||||
token::Lifetime(..),
|
||||
token::Interpolated(..),
|
||||
|
@ -58,7 +58,7 @@
|
||||
//! let five = five.clone();
|
||||
//!
|
||||
//! Thread::spawn(move || {
|
||||
//! let mut number = five.lock();
|
||||
//! let mut number = five.lock().unwrap();
|
||||
//!
|
||||
//! *number += 1;
|
||||
//!
|
||||
@ -80,7 +80,7 @@ use core::nonzero::NonZero;
|
||||
use core::ops::{Drop, Deref};
|
||||
use core::option::Option;
|
||||
use core::option::Option::{Some, None};
|
||||
use core::ptr::{mod, RawPtr};
|
||||
use core::ptr::{mod, PtrExt};
|
||||
use heap::deallocate;
|
||||
|
||||
/// An atomically reference counted wrapper for shared state.
|
||||
@ -722,7 +722,7 @@ mod tests {
|
||||
|
||||
let a = Arc::new(Cycle { x: Mutex::new(None) });
|
||||
let b = a.clone().downgrade();
|
||||
*a.x.lock() = Some(b);
|
||||
*a.x.lock().unwrap() = Some(b);
|
||||
|
||||
// hopefully we don't double-free (or leak)...
|
||||
}
|
||||
|
@ -8,7 +8,7 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use core::ptr::RawPtr;
|
||||
use core::ptr::PtrExt;
|
||||
|
||||
// FIXME: #13996: mark the `allocate` and `reallocate` return value as `noalias`
|
||||
|
||||
@ -371,7 +371,7 @@ mod imp {
|
||||
mod test {
|
||||
extern crate test;
|
||||
use self::test::Bencher;
|
||||
use core::ptr::RawPtr;
|
||||
use core::ptr::PtrExt;
|
||||
use heap;
|
||||
|
||||
#[test]
|
||||
|
@ -8,7 +8,7 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! Task-local reference-counted boxes (the `Rc<T>` type).
|
||||
//! Thread-local reference-counted boxes (the `Rc<T>` type).
|
||||
//!
|
||||
//! The `Rc<T>` type provides shared ownership of an immutable value. Destruction is deterministic,
|
||||
//! and will occur as soon as the last owner is gone. It is marked as non-sendable because it
|
||||
@ -154,7 +154,7 @@ use core::nonzero::NonZero;
|
||||
use core::ops::{Deref, Drop};
|
||||
use core::option::Option;
|
||||
use core::option::Option::{Some, None};
|
||||
use core::ptr::{mod, RawPtr};
|
||||
use core::ptr::{mod, PtrExt};
|
||||
use core::result::Result;
|
||||
use core::result::Result::{Ok, Err};
|
||||
|
||||
|
@ -412,7 +412,7 @@ impl<T> TypedArenaChunk<T> {
|
||||
let size = calculate_size::<T>(self.capacity);
|
||||
deallocate(self as *mut TypedArenaChunk<T> as *mut u8, size,
|
||||
mem::min_align_of::<TypedArenaChunk<T>>());
|
||||
if next.is_not_null() {
|
||||
if !next.is_null() {
|
||||
let capacity = (*next).capacity;
|
||||
(*next).destroy(capacity);
|
||||
}
|
||||
|
@ -95,7 +95,7 @@ impl<T> Rawlink<T> {
|
||||
/// Convert the `Rawlink` into an Option value
|
||||
fn resolve_immut<'a>(&self) -> Option<&'a T> {
|
||||
unsafe {
|
||||
self.p.as_ref()
|
||||
mem::transmute(self.p.as_ref())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -114,14 +114,14 @@ mod prelude {
|
||||
pub use core::ops::{Drop, Fn, FnMut, FnOnce};
|
||||
pub use core::option::Option;
|
||||
pub use core::option::Option::{Some, None};
|
||||
pub use core::ptr::RawPtr;
|
||||
pub use core::ptr::PtrExt;
|
||||
pub use core::result::Result;
|
||||
pub use core::result::Result::{Ok, Err};
|
||||
|
||||
// in core and collections (may differ).
|
||||
pub use slice::{PartialEqSliceExt, OrdSliceExt};
|
||||
pub use slice::{AsSlice, SliceExt};
|
||||
pub use str::{from_str, Str};
|
||||
pub use str::{from_str, Str, StrExt};
|
||||
|
||||
// from other crates.
|
||||
pub use alloc::boxed::Box;
|
||||
|
@ -96,7 +96,7 @@ use core::mem::size_of;
|
||||
use core::mem;
|
||||
use core::ops::{FnMut,SliceMut};
|
||||
use core::prelude::{Clone, Greater, Iterator, IteratorExt, Less, None, Option};
|
||||
use core::prelude::{Ord, Ordering, RawPtr, Some, range};
|
||||
use core::prelude::{Ord, Ordering, PtrExt, Some, range};
|
||||
use core::ptr;
|
||||
use core::slice as core_slice;
|
||||
use self::Direction::*;
|
||||
@ -1343,11 +1343,14 @@ pub mod raw {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::boxed::Box;
|
||||
use prelude::*;
|
||||
use prelude::{Some, None, range, Vec, ToString, Clone, Greater, Less, Equal};
|
||||
use prelude::{SliceExt, Iterator, IteratorExt, DoubleEndedIteratorExt};
|
||||
use prelude::{OrdSliceExt, CloneSliceExt, PartialEqSliceExt, AsSlice};
|
||||
use prelude::{RandomAccessIterator, Ord, VectorVector};
|
||||
use core::cell::Cell;
|
||||
use core::default::Default;
|
||||
use core::mem;
|
||||
use std::rand::{Rng, task_rng};
|
||||
use std::rand::{Rng, thread_rng};
|
||||
use std::rc::Rc;
|
||||
use super::ElementSwaps;
|
||||
|
||||
@ -1963,7 +1966,7 @@ mod tests {
|
||||
fn test_sort() {
|
||||
for len in range(4u, 25) {
|
||||
for _ in range(0i, 100) {
|
||||
let mut v = task_rng().gen_iter::<uint>().take(len)
|
||||
let mut v = thread_rng().gen_iter::<uint>().take(len)
|
||||
.collect::<Vec<uint>>();
|
||||
let mut v1 = v.clone();
|
||||
|
||||
@ -1999,7 +2002,7 @@ mod tests {
|
||||
// number this element is, i.e. the second elements
|
||||
// will occur in sorted order.
|
||||
let mut v = range(0, len).map(|_| {
|
||||
let n = task_rng().gen::<uint>() % 10;
|
||||
let n = thread_rng().gen::<uint>() % 10;
|
||||
counts[n] += 1;
|
||||
(n, counts[n])
|
||||
}).collect::<Vec<(uint, int)>>();
|
||||
|
@ -89,8 +89,6 @@ pub use unicode::str::{Words, Graphemes, GraphemeIndices};
|
||||
pub use core::str::{Split, SplitTerminator};
|
||||
pub use core::str::{SplitN, RSplitN};
|
||||
|
||||
// FIXME(conventions): ensure bit/char conventions are followed by str's API
|
||||
|
||||
/*
|
||||
Section: Creating a string
|
||||
*/
|
||||
@ -1768,26 +1766,13 @@ impl StrExt for str {}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::iter::AdditiveIterator;
|
||||
use std::iter::range;
|
||||
use std::default::Default;
|
||||
use std::char::Char;
|
||||
use std::clone::Clone;
|
||||
use std::cmp::{Ord, PartialOrd, Equiv};
|
||||
use std::cmp::Ordering::{Equal, Greater, Less};
|
||||
use std::option::Option::{mod, Some, None};
|
||||
use std::result::Result::{Ok, Err};
|
||||
use std::ptr::RawPtr;
|
||||
use std::iter::{Iterator, IteratorExt, DoubleEndedIteratorExt};
|
||||
use prelude::*;
|
||||
|
||||
use super::*;
|
||||
use core::default::Default;
|
||||
use core::iter::AdditiveIterator;
|
||||
use super::{from_utf8, is_utf8, raw};
|
||||
use super::MaybeOwned::{Owned, Slice};
|
||||
use std::slice::{AsSlice, SliceExt};
|
||||
use string::{String, ToString};
|
||||
use vec::Vec;
|
||||
use slice::CloneSliceExt;
|
||||
|
||||
use unicode::char::UnicodeChar;
|
||||
use super::Utf8Error;
|
||||
|
||||
#[test]
|
||||
fn test_le() {
|
||||
@ -3354,7 +3339,7 @@ mod tests {
|
||||
#[cfg(test)]
|
||||
mod bench {
|
||||
use super::*;
|
||||
use prelude::*;
|
||||
use prelude::{SliceExt, IteratorExt, DoubleEndedIteratorExt};
|
||||
use test::Bencher;
|
||||
use test::black_box;
|
||||
|
||||
|
@ -12,6 +12,8 @@
|
||||
|
||||
//! An owned, growable string that enforces that its contents are valid UTF-8.
|
||||
|
||||
#![stable]
|
||||
|
||||
use core::prelude::*;
|
||||
|
||||
use core::borrow::{Cow, IntoCow};
|
||||
@ -36,6 +38,18 @@ pub struct String {
|
||||
vec: Vec<u8>,
|
||||
}
|
||||
|
||||
/// A possible error value from the `String::from_utf8` function.
|
||||
#[stable]
|
||||
pub struct FromUtf8Error {
|
||||
bytes: Vec<u8>,
|
||||
error: Utf8Error,
|
||||
}
|
||||
|
||||
/// A possible error value from the `String::from_utf16` function.
|
||||
#[stable]
|
||||
#[allow(missing_copy_implementations)]
|
||||
pub struct FromUtf16Error(());
|
||||
|
||||
impl String {
|
||||
/// Creates a new string buffer initialized with the empty string.
|
||||
///
|
||||
@ -98,19 +112,20 @@ impl String {
|
||||
/// use std::str::Utf8Error;
|
||||
///
|
||||
/// let hello_vec = vec![104, 101, 108, 108, 111];
|
||||
/// let s = String::from_utf8(hello_vec);
|
||||
/// assert_eq!(s, Ok("hello".to_string()));
|
||||
/// let s = String::from_utf8(hello_vec).unwrap();
|
||||
/// assert_eq!(s, "hello");
|
||||
///
|
||||
/// let invalid_vec = vec![240, 144, 128];
|
||||
/// let s = String::from_utf8(invalid_vec);
|
||||
/// assert_eq!(s, Err((vec![240, 144, 128], Utf8Error::TooShort)));
|
||||
/// let s = String::from_utf8(invalid_vec).err().unwrap();
|
||||
/// assert_eq!(s.utf8_error(), Utf8Error::TooShort);
|
||||
/// assert_eq!(s.into_bytes(), vec![240, 144, 128]);
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable = "error type may change"]
|
||||
pub fn from_utf8(vec: Vec<u8>) -> Result<String, (Vec<u8>, Utf8Error)> {
|
||||
#[stable]
|
||||
pub fn from_utf8(vec: Vec<u8>) -> Result<String, FromUtf8Error> {
|
||||
match str::from_utf8(vec.as_slice()) {
|
||||
Ok(..) => Ok(String { vec: vec }),
|
||||
Err(e) => Err((vec, e))
|
||||
Err(e) => Err(FromUtf8Error { bytes: vec, error: e })
|
||||
}
|
||||
}
|
||||
|
||||
@ -124,7 +139,7 @@ impl String {
|
||||
/// let output = String::from_utf8_lossy(input);
|
||||
/// assert_eq!(output.as_slice(), "Hello \u{FFFD}World");
|
||||
/// ```
|
||||
#[unstable = "return type may change"]
|
||||
#[stable]
|
||||
pub fn from_utf8_lossy<'a>(v: &'a [u8]) -> CowString<'a> {
|
||||
match str::from_utf8(v) {
|
||||
Ok(s) => return Cow::Borrowed(s),
|
||||
@ -251,22 +266,23 @@ impl String {
|
||||
/// // 𝄞music
|
||||
/// let mut v = &mut [0xD834, 0xDD1E, 0x006d, 0x0075,
|
||||
/// 0x0073, 0x0069, 0x0063];
|
||||
/// assert_eq!(String::from_utf16(v), Some("𝄞music".to_string()));
|
||||
/// assert_eq!(String::from_utf16(v).unwrap(),
|
||||
/// "𝄞music".to_string());
|
||||
///
|
||||
/// // 𝄞mu<invalid>ic
|
||||
/// v[4] = 0xD800;
|
||||
/// assert_eq!(String::from_utf16(v), None);
|
||||
/// assert!(String::from_utf16(v).is_err());
|
||||
/// ```
|
||||
#[unstable = "error value in return may change"]
|
||||
pub fn from_utf16(v: &[u16]) -> Option<String> {
|
||||
#[stable]
|
||||
pub fn from_utf16(v: &[u16]) -> Result<String, FromUtf16Error> {
|
||||
let mut s = String::with_capacity(v.len());
|
||||
for c in unicode_str::utf16_items(v) {
|
||||
match c {
|
||||
Utf16Item::ScalarValue(c) => s.push(c),
|
||||
Utf16Item::LoneSurrogate(_) => return None
|
||||
Utf16Item::LoneSurrogate(_) => return Err(FromUtf16Error(())),
|
||||
}
|
||||
}
|
||||
Some(s)
|
||||
Ok(s)
|
||||
}
|
||||
|
||||
/// Decode a UTF-16 encoded vector `v` into a string, replacing
|
||||
@ -293,12 +309,13 @@ impl String {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # #![allow(deprecated)]
|
||||
/// let chars = &['h', 'e', 'l', 'l', 'o'];
|
||||
/// let s = String::from_chars(chars);
|
||||
/// assert_eq!(s.as_slice(), "hello");
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable = "may be removed in favor of .collect()"]
|
||||
#[deprecated = "use .collect() instead"]
|
||||
pub fn from_chars(chs: &[char]) -> String {
|
||||
chs.iter().map(|c| *c).collect()
|
||||
}
|
||||
@ -309,7 +326,7 @@ impl String {
|
||||
/// * We call `Vec::from_raw_parts` to get a `Vec<u8>`;
|
||||
/// * We assume that the `Vec` contains valid UTF-8.
|
||||
#[inline]
|
||||
#[unstable = "function just moved from string::raw"]
|
||||
#[stable]
|
||||
pub unsafe fn from_raw_parts(buf: *mut u8, length: uint, capacity: uint) -> String {
|
||||
String {
|
||||
vec: Vec::from_raw_parts(buf, length, capacity),
|
||||
@ -344,7 +361,7 @@ impl String {
|
||||
/// it contains valid UTF-8. This is unsafe because it assumes that
|
||||
/// the UTF-8-ness of the vector has already been validated.
|
||||
#[inline]
|
||||
#[unstable = "awaiting stabilization"]
|
||||
#[stable]
|
||||
pub unsafe fn from_utf8_unchecked(bytes: Vec<u8>) -> String {
|
||||
String { vec: bytes }
|
||||
}
|
||||
@ -369,12 +386,12 @@ impl String {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # #![allow(deprecated)]
|
||||
/// let s = String::from_char(5, 'a');
|
||||
/// assert_eq!(s.as_slice(), "aaaaa");
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable = "may be replaced with iterators, questionable usability, and \
|
||||
the name may change"]
|
||||
#[deprecated = "use repeat(ch).take(length).collect() instead"]
|
||||
pub fn from_char(length: uint, ch: char) -> String {
|
||||
if length == 0 {
|
||||
return String::new()
|
||||
@ -400,7 +417,7 @@ impl String {
|
||||
/// assert_eq!(s.as_slice(), "foobar");
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable = "extra variants of `push`, could possibly be based on iterators"]
|
||||
#[stable]
|
||||
pub fn push_str(&mut self, string: &str) {
|
||||
self.vec.push_all(string.as_bytes())
|
||||
}
|
||||
@ -410,19 +427,21 @@ impl String {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # #![allow(deprecated)]
|
||||
/// let mut s = String::from_str("foo");
|
||||
/// s.grow(5, 'Z');
|
||||
/// assert_eq!(s.as_slice(), "fooZZZZZ");
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable = "duplicate of iterator-based functionality"]
|
||||
#[deprecated = "deprecated in favor of .extend(repeat(ch).take(count))"]
|
||||
pub fn grow(&mut self, count: uint, ch: char) {
|
||||
for _ in range(0, count) {
|
||||
self.push(ch)
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the number of bytes that this string buffer can hold without reallocating.
|
||||
/// Returns the number of bytes that this string buffer can hold without
|
||||
/// reallocating.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@ -431,7 +450,7 @@ impl String {
|
||||
/// assert!(s.capacity() >= 10);
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable = "matches collection reform specification, waiting for dust to settle"]
|
||||
#[stable]
|
||||
pub fn capacity(&self) -> uint {
|
||||
self.vec.capacity()
|
||||
}
|
||||
@ -442,8 +461,9 @@ impl String {
|
||||
self.vec.reserve(extra)
|
||||
}
|
||||
|
||||
/// Reserves capacity for at least `additional` more bytes to be inserted in the given
|
||||
/// `String`. The collection may reserve more space to avoid frequent reallocations.
|
||||
/// Reserves capacity for at least `additional` more bytes to be inserted
|
||||
/// in the given `String`. The collection may reserve more space to avoid
|
||||
/// frequent reallocations.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
@ -457,17 +477,18 @@ impl String {
|
||||
/// assert!(s.capacity() >= 10);
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable = "matches collection reform specification, waiting for dust to settle"]
|
||||
#[stable]
|
||||
pub fn reserve(&mut self, additional: uint) {
|
||||
self.vec.reserve(additional)
|
||||
}
|
||||
|
||||
/// Reserves the minimum capacity for exactly `additional` more bytes to be inserted in the
|
||||
/// given `String`. Does nothing if the capacity is already sufficient.
|
||||
/// Reserves the minimum capacity for exactly `additional` more bytes to be
|
||||
/// inserted in the given `String`. Does nothing if the capacity is already
|
||||
/// sufficient.
|
||||
///
|
||||
/// Note that the allocator may give the collection more space than it requests. Therefore
|
||||
/// capacity can not be relied upon to be precisely minimal. Prefer `reserve` if future
|
||||
/// insertions are expected.
|
||||
/// Note that the allocator may give the collection more space than it
|
||||
/// requests. Therefore capacity can not be relied upon to be precisely
|
||||
/// minimal. Prefer `reserve` if future insertions are expected.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
@ -481,7 +502,7 @@ impl String {
|
||||
/// assert!(s.capacity() >= 10);
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable = "matches collection reform specification, waiting for dust to settle"]
|
||||
#[stable]
|
||||
pub fn reserve_exact(&mut self, additional: uint) {
|
||||
self.vec.reserve_exact(additional)
|
||||
}
|
||||
@ -498,7 +519,7 @@ impl String {
|
||||
/// assert_eq!(s.capacity(), 3);
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable = "matches collection reform specification, waiting for dust to settle"]
|
||||
#[stable]
|
||||
pub fn shrink_to_fit(&mut self) {
|
||||
self.vec.shrink_to_fit()
|
||||
}
|
||||
@ -515,7 +536,7 @@ impl String {
|
||||
/// assert_eq!(s.as_slice(), "abc123");
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable = "function just renamed from push_char"]
|
||||
#[stable]
|
||||
pub fn push(&mut self, ch: char) {
|
||||
if (ch as u32) < 0x80 {
|
||||
self.vec.push(ch as u8);
|
||||
@ -568,7 +589,7 @@ impl String {
|
||||
/// assert_eq!(s.as_slice(), "he");
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable = "the panic conventions for strings are under development"]
|
||||
#[stable]
|
||||
pub fn truncate(&mut self, new_len: uint) {
|
||||
assert!(self.is_char_boundary(new_len));
|
||||
self.vec.truncate(new_len)
|
||||
@ -587,7 +608,7 @@ impl String {
|
||||
/// assert_eq!(s.pop(), None);
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable = "this function was just renamed from pop_char"]
|
||||
#[stable]
|
||||
pub fn pop(&mut self) -> Option<char> {
|
||||
let len = self.len();
|
||||
if len == 0 {
|
||||
@ -602,7 +623,7 @@ impl String {
|
||||
}
|
||||
|
||||
/// Removes the character from the string buffer at byte position `idx` and
|
||||
/// returns it. Returns `None` if `idx` is out of bounds.
|
||||
/// returns it.
|
||||
///
|
||||
/// # Warning
|
||||
///
|
||||
@ -611,23 +632,21 @@ impl String {
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// If `idx` does not lie on a character boundary, then this function will
|
||||
/// panic.
|
||||
/// If `idx` does not lie on a character boundary, or if it is out of
|
||||
/// bounds, then this function will panic.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// let mut s = String::from_str("foo");
|
||||
/// assert_eq!(s.remove(0), Some('f'));
|
||||
/// assert_eq!(s.remove(1), Some('o'));
|
||||
/// assert_eq!(s.remove(0), Some('o'));
|
||||
/// assert_eq!(s.remove(0), None);
|
||||
/// assert_eq!(s.remove(0), 'f');
|
||||
/// assert_eq!(s.remove(1), 'o');
|
||||
/// assert_eq!(s.remove(0), 'o');
|
||||
/// ```
|
||||
#[unstable = "the panic semantics of this function and return type \
|
||||
may change"]
|
||||
pub fn remove(&mut self, idx: uint) -> Option<char> {
|
||||
#[stable]
|
||||
pub fn remove(&mut self, idx: uint) -> char {
|
||||
let len = self.len();
|
||||
if idx >= len { return None }
|
||||
assert!(idx <= len);
|
||||
|
||||
let CharRange { ch, next } = self.char_range_at(idx);
|
||||
unsafe {
|
||||
@ -636,7 +655,7 @@ impl String {
|
||||
len - next);
|
||||
self.vec.set_len(len - (next - idx));
|
||||
}
|
||||
Some(ch)
|
||||
ch
|
||||
}
|
||||
|
||||
/// Insert a character into the string buffer at byte position `idx`.
|
||||
@ -650,7 +669,7 @@ impl String {
|
||||
///
|
||||
/// If `idx` does not lie on a character boundary or is out of bounds, then
|
||||
/// this function will panic.
|
||||
#[unstable = "the panic semantics of this function are uncertain"]
|
||||
#[stable]
|
||||
pub fn insert(&mut self, idx: uint, ch: char) {
|
||||
let len = self.len();
|
||||
assert!(idx <= len);
|
||||
@ -686,7 +705,7 @@ impl String {
|
||||
/// }
|
||||
/// assert_eq!(s.as_slice(), "olleh");
|
||||
/// ```
|
||||
#[unstable = "the name of this method may be changed"]
|
||||
#[stable]
|
||||
pub unsafe fn as_mut_vec<'a>(&'a mut self) -> &'a mut Vec<u8> {
|
||||
&mut self.vec
|
||||
}
|
||||
@ -713,6 +732,7 @@ impl String {
|
||||
/// v.push('a');
|
||||
/// assert!(!v.is_empty());
|
||||
/// ```
|
||||
#[stable]
|
||||
pub fn is_empty(&self) -> bool { self.len() == 0 }
|
||||
|
||||
/// Truncates the string, returning it to 0 length.
|
||||
@ -731,6 +751,29 @@ impl String {
|
||||
}
|
||||
}
|
||||
|
||||
impl FromUtf8Error {
|
||||
/// Consume this error, returning the bytes that were attempted to make a
|
||||
/// `String` with.
|
||||
#[stable]
|
||||
pub fn into_bytes(self) -> Vec<u8> { self.bytes }
|
||||
|
||||
/// Access the underlying UTF8-error that was the cause of this error.
|
||||
#[stable]
|
||||
pub fn utf8_error(&self) -> Utf8Error { self.error }
|
||||
}
|
||||
|
||||
impl fmt::Show for FromUtf8Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
self.error.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Show for FromUtf16Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
"invalid utf-16: lone surrogate found".fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
#[experimental = "waiting on FromIterator stabilization"]
|
||||
impl FromIterator<char> for String {
|
||||
fn from_iter<I:Iterator<char>>(iterator: I) -> String {
|
||||
@ -933,6 +976,7 @@ impl FromStr for String {
|
||||
}
|
||||
|
||||
/// Trait for converting a type to a string, consuming it in the process.
|
||||
#[deprecated = "trait will be removed"]
|
||||
pub trait IntoString {
|
||||
/// Consume and convert to a string.
|
||||
fn into_string(self) -> String;
|
||||
@ -1038,7 +1082,7 @@ mod tests {
|
||||
use prelude::*;
|
||||
use test::Bencher;
|
||||
|
||||
use str::{StrExt, Utf8Error};
|
||||
use str::Utf8Error;
|
||||
use str;
|
||||
use super::as_string;
|
||||
|
||||
@ -1057,16 +1101,17 @@ mod tests {
|
||||
#[test]
|
||||
fn test_from_utf8() {
|
||||
let xs = b"hello".to_vec();
|
||||
assert_eq!(String::from_utf8(xs),
|
||||
Ok(String::from_str("hello")));
|
||||
assert_eq!(String::from_utf8(xs).unwrap(),
|
||||
String::from_str("hello"));
|
||||
|
||||
let xs = "ศไทย中华Việt Nam".as_bytes().to_vec();
|
||||
assert_eq!(String::from_utf8(xs),
|
||||
Ok(String::from_str("ศไทย中华Việt Nam")));
|
||||
assert_eq!(String::from_utf8(xs).unwrap(),
|
||||
String::from_str("ศไทย中华Việt Nam"));
|
||||
|
||||
let xs = b"hello\xFF".to_vec();
|
||||
assert_eq!(String::from_utf8(xs),
|
||||
Err((b"hello\xFF".to_vec(), Utf8Error::TooShort)));
|
||||
let err = String::from_utf8(xs).err().unwrap();
|
||||
assert_eq!(err.utf8_error(), Utf8Error::TooShort);
|
||||
assert_eq!(err.into_bytes(), b"hello\xff".to_vec());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -1171,15 +1216,15 @@ mod tests {
|
||||
fn test_utf16_invalid() {
|
||||
// completely positive cases tested above.
|
||||
// lead + eof
|
||||
assert_eq!(String::from_utf16(&[0xD800]), None);
|
||||
assert!(String::from_utf16(&[0xD800]).is_err());
|
||||
// lead + lead
|
||||
assert_eq!(String::from_utf16(&[0xD800, 0xD800]), None);
|
||||
assert!(String::from_utf16(&[0xD800, 0xD800]).is_err());
|
||||
|
||||
// isolated trail
|
||||
assert_eq!(String::from_utf16(&[0x0061, 0xDC00]), None);
|
||||
assert!(String::from_utf16(&[0x0061, 0xDC00]).is_err());
|
||||
|
||||
// general
|
||||
assert_eq!(String::from_utf16(&[0xD800, 0xd801, 0xdc8b, 0xD800]), None);
|
||||
assert!(String::from_utf16(&[0xD800, 0xd801, 0xdc8b, 0xD800]).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -1312,12 +1357,10 @@ mod tests {
|
||||
#[test]
|
||||
fn remove() {
|
||||
let mut s = "ศไทย中华Việt Nam; foobar".to_string();;
|
||||
assert_eq!(s.remove(0), Some('ศ'));
|
||||
assert_eq!(s.remove(0), 'ศ');
|
||||
assert_eq!(s.len(), 33);
|
||||
assert_eq!(s, "ไทย中华Việt Nam; foobar");
|
||||
assert_eq!(s.remove(33), None);
|
||||
assert_eq!(s.remove(300), None);
|
||||
assert_eq!(s.remove(17), Some('ệ'));
|
||||
assert_eq!(s.remove(17), 'ệ');
|
||||
assert_eq!(s, "ไทย中华Vit Nam; foobar");
|
||||
}
|
||||
|
||||
|
@ -158,7 +158,7 @@
|
||||
use clone::Clone;
|
||||
use cmp::PartialEq;
|
||||
use default::Default;
|
||||
use kinds::{marker, Copy};
|
||||
use kinds::{Copy, Send};
|
||||
use ops::{Deref, DerefMut, Drop};
|
||||
use option::Option;
|
||||
use option::Option::{None, Some};
|
||||
@ -167,7 +167,6 @@ use option::Option::{None, Some};
|
||||
#[stable]
|
||||
pub struct Cell<T> {
|
||||
value: UnsafeCell<T>,
|
||||
noshare: marker::NoSync,
|
||||
}
|
||||
|
||||
impl<T:Copy> Cell<T> {
|
||||
@ -176,7 +175,6 @@ impl<T:Copy> Cell<T> {
|
||||
pub fn new(value: T) -> Cell<T> {
|
||||
Cell {
|
||||
value: UnsafeCell::new(value),
|
||||
noshare: marker::NoSync,
|
||||
}
|
||||
}
|
||||
|
||||
@ -208,6 +206,9 @@ impl<T:Copy> Cell<T> {
|
||||
}
|
||||
}
|
||||
|
||||
#[stable]
|
||||
unsafe impl<T> Send for Cell<T> where T: Send {}
|
||||
|
||||
#[stable]
|
||||
impl<T:Copy> Clone for Cell<T> {
|
||||
fn clone(&self) -> Cell<T> {
|
||||
@ -235,7 +236,6 @@ impl<T:PartialEq + Copy> PartialEq for Cell<T> {
|
||||
pub struct RefCell<T> {
|
||||
value: UnsafeCell<T>,
|
||||
borrow: Cell<BorrowFlag>,
|
||||
noshare: marker::NoSync,
|
||||
}
|
||||
|
||||
// Values [1, MAX-1] represent the number of `Ref` active
|
||||
@ -251,7 +251,6 @@ impl<T> RefCell<T> {
|
||||
RefCell {
|
||||
value: UnsafeCell::new(value),
|
||||
borrow: Cell::new(UNUSED),
|
||||
noshare: marker::NoSync,
|
||||
}
|
||||
}
|
||||
|
||||
@ -341,6 +340,9 @@ impl<T> RefCell<T> {
|
||||
}
|
||||
}
|
||||
|
||||
#[stable]
|
||||
unsafe impl<T> Send for RefCell<T> where T: Send {}
|
||||
|
||||
#[stable]
|
||||
impl<T: Clone> Clone for RefCell<T> {
|
||||
fn clone(&self) -> RefCell<T> {
|
||||
|
@ -36,7 +36,7 @@ pub trait Clone {
|
||||
/// but can be overridden to reuse the resources of `a` to avoid unnecessary
|
||||
/// allocations.
|
||||
#[inline(always)]
|
||||
#[unstable = "this function rarely unused"]
|
||||
#[unstable = "this function is rarely used"]
|
||||
fn clone_from(&mut self, source: &Self) {
|
||||
*self = source.clone()
|
||||
}
|
||||
|
@ -85,16 +85,6 @@ macro_rules! assert {
|
||||
);
|
||||
}
|
||||
|
||||
/// Runtime assertion, only without `--cfg ndebug`
|
||||
#[macro_export]
|
||||
macro_rules! debug_assert {
|
||||
($(a:tt)*) => ({
|
||||
if cfg!(not(ndebug)) {
|
||||
assert!($($a)*);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Runtime assertion for equality, for details see std::macros
|
||||
#[macro_export]
|
||||
macro_rules! assert_eq {
|
||||
@ -117,7 +107,7 @@ macro_rules! debug_assert_eq {
|
||||
})
|
||||
}
|
||||
|
||||
/// Runtime assertion, disableable at compile time
|
||||
/// Runtime assertion, disableable at compile time with `--cfg ndebug`
|
||||
#[macro_export]
|
||||
macro_rules! debug_assert {
|
||||
($($arg:tt)*) => (if cfg!(not(ndebug)) { assert!($($arg)*); })
|
||||
|
@ -57,7 +57,7 @@ pub use iter::{IteratorOrdExt, MutableDoubleEndedIterator, ExactSizeIterator};
|
||||
pub use num::{ToPrimitive, FromPrimitive};
|
||||
pub use option::Option;
|
||||
pub use option::Option::{Some, None};
|
||||
pub use ptr::RawPtr;
|
||||
pub use ptr::{PtrExt, MutPtrExt};
|
||||
pub use result::Result;
|
||||
pub use result::Result::{Ok, Err};
|
||||
pub use str::{Str, StrExt};
|
||||
|
@ -16,11 +16,10 @@
|
||||
//! typically limited to a few patterns.
|
||||
//!
|
||||
//! Use the [`null` function](fn.null.html) to create null pointers,
|
||||
//! the [`is_null`](trait.RawPtr.html#tymethod.is_null)
|
||||
//! and [`is_not_null`](trait.RawPtr.html#method.is_not_null)
|
||||
//! methods of the [`RawPtr` trait](trait.RawPtr.html) to check for null.
|
||||
//! The `RawPtr` trait is imported by the prelude, so `is_null` etc.
|
||||
//! work everywhere. The `RawPtr` also defines the `offset` method,
|
||||
//! the [`is_null`](trait.PtrExt.html#tymethod.is_null)
|
||||
//! methods of the [`PtrExt` trait](trait.PtrExt.html) to check for null.
|
||||
//! The `PtrExt` trait is imported by the prelude, so `is_null` etc.
|
||||
//! work everywhere. The `PtrExt` also defines the `offset` method,
|
||||
//! for pointer math.
|
||||
//!
|
||||
//! # Common ways to create unsafe pointers
|
||||
@ -87,16 +86,16 @@
|
||||
//! but C APIs hand out a lot of pointers generally, so are a common source
|
||||
//! of unsafe pointers in Rust.
|
||||
|
||||
#![stable]
|
||||
|
||||
use mem;
|
||||
use clone::Clone;
|
||||
use intrinsics;
|
||||
use option::Option::{mod, Some, None};
|
||||
use kinds::{Send, Sync};
|
||||
use option::Option;
|
||||
use option::Option::{Some, None};
|
||||
|
||||
use cmp::{PartialEq, Eq, Ord, PartialOrd, Equiv};
|
||||
use cmp::Ordering;
|
||||
use cmp::Ordering::{Less, Equal, Greater};
|
||||
use cmp::Ordering::{mod, Less, Equal, Greater};
|
||||
|
||||
// FIXME #19649: instrinsic docs don't render, so these have no docs :(
|
||||
|
||||
@ -121,7 +120,7 @@ pub use intrinsics::set_memory;
|
||||
/// assert!(p.is_null());
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable = "may need a different name after pending changes to pointer types"]
|
||||
#[stable]
|
||||
pub fn null<T>() -> *const T { 0 as *const T }
|
||||
|
||||
/// Creates a null mutable raw pointer.
|
||||
@ -135,31 +134,31 @@ pub fn null<T>() -> *const T { 0 as *const T }
|
||||
/// assert!(p.is_null());
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable = "may need a different name after pending changes to pointer types"]
|
||||
#[stable]
|
||||
pub fn null_mut<T>() -> *mut T { 0 as *mut T }
|
||||
|
||||
/// Zeroes out `count * size_of::<T>` bytes of memory at `dst`. `count` may be `0`.
|
||||
/// Zeroes out `count * size_of::<T>` bytes of memory at `dst`. `count` may be
|
||||
/// `0`.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Beyond accepting a raw pointer, this is unsafe because it will not drop the contents of `dst`,
|
||||
/// and may be used to create invalid instances of `T`.
|
||||
/// Beyond accepting a raw pointer, this is unsafe because it will not drop the
|
||||
/// contents of `dst`, and may be used to create invalid instances of `T`.
|
||||
#[inline]
|
||||
#[experimental = "uncertain about naming and semantics"]
|
||||
#[allow(experimental)]
|
||||
#[unstable = "may play a larger role in std::ptr future extensions"]
|
||||
pub unsafe fn zero_memory<T>(dst: *mut T, count: uint) {
|
||||
set_memory(dst, 0, count);
|
||||
}
|
||||
|
||||
/// Swaps the values at two mutable locations of the same type, without
|
||||
/// deinitialising either. They may overlap, unlike `mem::swap` which is otherwise
|
||||
/// equivalent.
|
||||
/// deinitialising either. They may overlap, unlike `mem::swap` which is
|
||||
/// otherwise equivalent.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This is only unsafe because it accepts a raw pointer.
|
||||
#[inline]
|
||||
#[unstable]
|
||||
#[stable]
|
||||
pub unsafe fn swap<T>(x: *mut T, y: *mut T) {
|
||||
// Give ourselves some scratch space to work with
|
||||
let mut tmp: T = mem::uninitialized();
|
||||
@ -183,7 +182,7 @@ pub unsafe fn swap<T>(x: *mut T, y: *mut T) {
|
||||
/// This is only unsafe because it accepts a raw pointer.
|
||||
/// Otherwise, this operation is identical to `mem::replace`.
|
||||
#[inline]
|
||||
#[unstable]
|
||||
#[stable]
|
||||
pub unsafe fn replace<T>(dest: *mut T, mut src: T) -> T {
|
||||
mem::swap(mem::transmute(dest), &mut src); // cannot overlap
|
||||
src
|
||||
@ -201,7 +200,7 @@ pub unsafe fn replace<T>(dest: *mut T, mut src: T) -> T {
|
||||
/// `zero_memory`, or `copy_memory`). Note that `*src = foo` counts as a use
|
||||
/// because it will attempt to drop the value previously at `*src`.
|
||||
#[inline(always)]
|
||||
#[unstable]
|
||||
#[stable]
|
||||
pub unsafe fn read<T>(src: *const T) -> T {
|
||||
let mut tmp: T = mem::uninitialized();
|
||||
copy_nonoverlapping_memory(&mut tmp, src, 1);
|
||||
@ -214,8 +213,7 @@ pub unsafe fn read<T>(src: *const T) -> T {
|
||||
///
|
||||
/// This is unsafe for the same reasons that `read` is unsafe.
|
||||
#[inline(always)]
|
||||
#[experimental]
|
||||
#[allow(experimental)]
|
||||
#[unstable = "may play a larger role in std::ptr future extensions"]
|
||||
pub unsafe fn read_and_zero<T>(dest: *mut T) -> T {
|
||||
// Copy the data out from `dest`:
|
||||
let tmp = read(&*dest);
|
||||
@ -226,8 +224,8 @@ pub unsafe fn read_and_zero<T>(dest: *mut T) -> T {
|
||||
tmp
|
||||
}
|
||||
|
||||
/// Overwrites a memory location with the given value without reading or dropping
|
||||
/// the old value.
|
||||
/// Overwrites a memory location with the given value without reading or
|
||||
/// dropping the old value.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
@ -235,36 +233,44 @@ pub unsafe fn read_and_zero<T>(dest: *mut T) -> T {
|
||||
/// not drop the contents of `dst`. This could leak allocations or resources,
|
||||
/// so care must be taken not to overwrite an object that should be dropped.
|
||||
///
|
||||
/// This is appropriate for initializing uninitialized memory, or overwritting memory
|
||||
/// that has previously been `read` from.
|
||||
/// This is appropriate for initializing uninitialized memory, or overwritting
|
||||
/// memory that has previously been `read` from.
|
||||
#[inline]
|
||||
#[unstable]
|
||||
#[stable]
|
||||
pub unsafe fn write<T>(dst: *mut T, src: T) {
|
||||
intrinsics::move_val_init(&mut *dst, src)
|
||||
}
|
||||
|
||||
/// Methods on raw pointers
|
||||
pub trait RawPtr<T> {
|
||||
/// Returns a null raw pointer.
|
||||
#[stable]
|
||||
pub trait PtrExt<T> {
|
||||
/// Returns the null pointer.
|
||||
#[deprecated = "call ptr::null instead"]
|
||||
fn null() -> Self;
|
||||
|
||||
/// Returns true if the pointer is null.
|
||||
fn is_null(&self) -> bool;
|
||||
#[stable]
|
||||
fn is_null(self) -> bool;
|
||||
|
||||
/// Returns true if the pointer is not equal to the null pointer.
|
||||
#[deprecated = "use !p.is_null() instead"]
|
||||
fn is_not_null(self) -> bool { !self.is_null() }
|
||||
|
||||
/// Returns true if the pointer is not null.
|
||||
fn is_not_null(&self) -> bool { !self.is_null() }
|
||||
#[deprecated = "use `as uint` instead"]
|
||||
fn to_uint(self) -> uint;
|
||||
|
||||
/// Returns the address of the pointer.
|
||||
fn to_uint(&self) -> uint;
|
||||
|
||||
/// Returns `None` if the pointer is null, or else returns a reference to the
|
||||
/// value wrapped in `Some`.
|
||||
/// Returns `None` if the pointer is null, or else returns a reference to
|
||||
/// the value wrapped in `Some`.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// While this method and its mutable counterpart are useful for null-safety,
|
||||
/// it is important to note that this is still an unsafe operation because
|
||||
/// the returned value could be pointing to invalid memory.
|
||||
/// While this method and its mutable counterpart are useful for
|
||||
/// null-safety, it is important to note that this is still an unsafe
|
||||
/// operation because the returned value could be pointing to invalid
|
||||
/// memory.
|
||||
#[unstable = "Option is not clearly the right return type, and we may want \
|
||||
to tie the return lifetime to a borrow of the raw pointer"]
|
||||
unsafe fn as_ref<'a>(&self) -> Option<&'a T>;
|
||||
|
||||
/// Calculates the offset from a pointer. `count` is in units of T; e.g. a
|
||||
@ -272,39 +278,51 @@ pub trait RawPtr<T> {
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The offset must be in-bounds of the object, or one-byte-past-the-end. Otherwise
|
||||
/// `offset` invokes Undefined Behaviour, regardless of whether the pointer is used.
|
||||
/// The offset must be in-bounds of the object, or one-byte-past-the-end.
|
||||
/// Otherwise `offset` invokes Undefined Behaviour, regardless of whether
|
||||
/// the pointer is used.
|
||||
#[stable]
|
||||
unsafe fn offset(self, count: int) -> Self;
|
||||
}
|
||||
|
||||
/// Methods on mutable raw pointers
|
||||
pub trait RawMutPtr<T>{
|
||||
/// Returns `None` if the pointer is null, or else returns a mutable reference
|
||||
/// to the value wrapped in `Some`.
|
||||
#[stable]
|
||||
pub trait MutPtrExt<T>{
|
||||
/// Returns `None` if the pointer is null, or else returns a mutable
|
||||
/// reference to the value wrapped in `Some`.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// As with `as_ref`, this is unsafe because it cannot verify the validity
|
||||
/// of the returned pointer.
|
||||
#[unstable = "Option is not clearly the right return type, and we may want \
|
||||
to tie the return lifetime to a borrow of the raw pointer"]
|
||||
unsafe fn as_mut<'a>(&self) -> Option<&'a mut T>;
|
||||
}
|
||||
|
||||
impl<T> RawPtr<T> for *const T {
|
||||
#[stable]
|
||||
impl<T> PtrExt<T> for *const T {
|
||||
#[inline]
|
||||
#[deprecated = "call ptr::null instead"]
|
||||
fn null() -> *const T { null() }
|
||||
|
||||
#[inline]
|
||||
fn is_null(&self) -> bool { *self == RawPtr::null() }
|
||||
#[stable]
|
||||
fn is_null(self) -> bool { self as uint == 0 }
|
||||
|
||||
#[inline]
|
||||
fn to_uint(&self) -> uint { *self as uint }
|
||||
#[deprecated = "use `as uint` instead"]
|
||||
fn to_uint(self) -> uint { self as uint }
|
||||
|
||||
#[inline]
|
||||
#[stable]
|
||||
unsafe fn offset(self, count: int) -> *const T {
|
||||
intrinsics::offset(self, count)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[unstable = "return value does not necessarily convey all possible \
|
||||
information"]
|
||||
unsafe fn as_ref<'a>(&self) -> Option<&'a T> {
|
||||
if self.is_null() {
|
||||
None
|
||||
@ -314,22 +332,29 @@ impl<T> RawPtr<T> for *const T {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> RawPtr<T> for *mut T {
|
||||
#[stable]
|
||||
impl<T> PtrExt<T> for *mut T {
|
||||
#[inline]
|
||||
#[deprecated = "call ptr::null instead"]
|
||||
fn null() -> *mut T { null_mut() }
|
||||
|
||||
#[inline]
|
||||
fn is_null(&self) -> bool { *self == RawPtr::null() }
|
||||
#[stable]
|
||||
fn is_null(self) -> bool { self as uint == 0 }
|
||||
|
||||
#[inline]
|
||||
fn to_uint(&self) -> uint { *self as uint }
|
||||
#[deprecated = "use `as uint` instead"]
|
||||
fn to_uint(self) -> uint { self as uint }
|
||||
|
||||
#[inline]
|
||||
#[stable]
|
||||
unsafe fn offset(self, count: int) -> *mut T {
|
||||
intrinsics::offset(self as *const T, count) as *mut T
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[unstable = "return value does not necessarily convey all possible \
|
||||
information"]
|
||||
unsafe fn as_ref<'a>(&self) -> Option<&'a T> {
|
||||
if self.is_null() {
|
||||
None
|
||||
@ -339,8 +364,11 @@ impl<T> RawPtr<T> for *mut T {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> RawMutPtr<T> for *mut T {
|
||||
#[stable]
|
||||
impl<T> MutPtrExt<T> for *mut T {
|
||||
#[inline]
|
||||
#[unstable = "return value does not necessarily convey all possible \
|
||||
information"]
|
||||
unsafe fn as_mut<'a>(&self) -> Option<&'a mut T> {
|
||||
if self.is_null() {
|
||||
None
|
||||
@ -510,28 +538,33 @@ impl<T> PartialOrd for *mut T {
|
||||
/// raw `*mut T` (which conveys no particular ownership semantics).
|
||||
/// Useful for building abstractions like `Vec<T>` or `Box<T>`, which
|
||||
/// internally use raw pointers to manage the memory that they own.
|
||||
#[unstable = "recently added to this module"]
|
||||
pub struct Unique<T>(pub *mut T);
|
||||
|
||||
/// `Unique` pointers are `Send` if `T` is `Send` because the data they
|
||||
/// reference is unaliased. Note that this aliasing invariant is
|
||||
/// unenforced by the type system; the abstraction using the
|
||||
/// `Unique` must enforce it.
|
||||
#[unstable = "recently added to this module"]
|
||||
unsafe impl<T:Send> Send for Unique<T> { }
|
||||
|
||||
/// `Unique` pointers are `Sync` if `T` is `Sync` because the data they
|
||||
/// reference is unaliased. Note that this aliasing invariant is
|
||||
/// unenforced by the type system; the abstraction using the
|
||||
/// `Unique` must enforce it.
|
||||
#[unstable = "recently added to this module"]
|
||||
unsafe impl<T:Sync> Sync for Unique<T> { }
|
||||
|
||||
impl<T> Unique<T> {
|
||||
/// Returns a null Unique.
|
||||
#[unstable = "recently added to this module"]
|
||||
pub fn null() -> Unique<T> {
|
||||
Unique(RawPtr::null())
|
||||
Unique(null_mut())
|
||||
}
|
||||
|
||||
/// Return an (unsafe) pointer into the memory owned by `self`.
|
||||
#[unstable = "recently added to this module"]
|
||||
pub unsafe fn offset(self, offset: int) -> *mut T {
|
||||
(self.0 as *const T).offset(offset) as *mut T
|
||||
self.0.offset(offset)
|
||||
}
|
||||
}
|
||||
|
@ -332,7 +332,7 @@ impl<T, E> Result<T, E> {
|
||||
|
||||
/// Convert from `Result<T, E>` to `Option<E>`
|
||||
///
|
||||
/// Converts `self` into an `Option<T>`, consuming `self`,
|
||||
/// Converts `self` into an `Option<E>`, consuming `self`,
|
||||
/// and discarding the value, if any.
|
||||
///
|
||||
/// # Example
|
||||
|
@ -47,7 +47,7 @@ use ops::{FnMut, mod};
|
||||
use option::Option;
|
||||
use option::Option::{None, Some};
|
||||
use ptr;
|
||||
use ptr::RawPtr;
|
||||
use ptr::PtrExt;
|
||||
use mem;
|
||||
use mem::size_of;
|
||||
use kinds::{Sized, marker};
|
||||
@ -1335,7 +1335,7 @@ pub unsafe fn from_raw_mut_buf<'a, T>(p: &'a *mut T, len: uint) -> &'a mut [T] {
|
||||
#[deprecated]
|
||||
pub mod raw {
|
||||
use mem::transmute;
|
||||
use ptr::RawPtr;
|
||||
use ptr::PtrExt;
|
||||
use raw::Slice;
|
||||
use ops::FnOnce;
|
||||
use option::Option;
|
||||
|
@ -28,7 +28,7 @@ use mem;
|
||||
use num::Int;
|
||||
use ops::{Fn, FnMut};
|
||||
use option::Option::{mod, None, Some};
|
||||
use ptr::RawPtr;
|
||||
use ptr::PtrExt;
|
||||
use raw::{Repr, Slice};
|
||||
use result::Result::{mod, Ok, Err};
|
||||
use slice::{mod, SliceExt};
|
||||
@ -1073,7 +1073,7 @@ const TAG_CONT_U8: u8 = 0b1000_0000u8;
|
||||
/// Unsafe operations
|
||||
#[deprecated]
|
||||
pub mod raw {
|
||||
use ptr::RawPtr;
|
||||
use ptr::PtrExt;
|
||||
use raw::Slice;
|
||||
use slice::SliceExt;
|
||||
use str::StrExt;
|
||||
|
@ -112,7 +112,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_flate_round_trip() {
|
||||
let mut r = rand::task_rng();
|
||||
let mut r = rand::thread_rng();
|
||||
let mut words = vec!();
|
||||
for _ in range(0u, 20) {
|
||||
let range = r.gen_range(1u, 10);
|
||||
|
@ -64,7 +64,7 @@ impl Rand for Exp1 {
|
||||
/// use std::rand::distributions::{Exp, IndependentSample};
|
||||
///
|
||||
/// let exp = Exp::new(2.0);
|
||||
/// let v = exp.ind_sample(&mut rand::task_rng());
|
||||
/// let v = exp.ind_sample(&mut rand::thread_rng());
|
||||
/// println!("{} is from a Exp(2) distribution", v);
|
||||
/// ```
|
||||
#[deriving(Copy)]
|
||||
|
@ -44,7 +44,7 @@ use super::{IndependentSample, Sample, Exp};
|
||||
/// use std::rand::distributions::{IndependentSample, Gamma};
|
||||
///
|
||||
/// let gamma = Gamma::new(2.0, 5.0);
|
||||
/// let v = gamma.ind_sample(&mut rand::task_rng());
|
||||
/// let v = gamma.ind_sample(&mut rand::thread_rng());
|
||||
/// println!("{} is from a Gamma(2, 5) distribution", v);
|
||||
/// ```
|
||||
///
|
||||
@ -191,7 +191,7 @@ impl IndependentSample<f64> for GammaLargeShape {
|
||||
/// use std::rand::distributions::{ChiSquared, IndependentSample};
|
||||
///
|
||||
/// let chi = ChiSquared::new(11.0);
|
||||
/// let v = chi.ind_sample(&mut rand::task_rng());
|
||||
/// let v = chi.ind_sample(&mut rand::thread_rng());
|
||||
/// println!("{} is from a χ²(11) distribution", v)
|
||||
/// ```
|
||||
pub struct ChiSquared {
|
||||
@ -248,7 +248,7 @@ impl IndependentSample<f64> for ChiSquared {
|
||||
/// use std::rand::distributions::{FisherF, IndependentSample};
|
||||
///
|
||||
/// let f = FisherF::new(2.0, 32.0);
|
||||
/// let v = f.ind_sample(&mut rand::task_rng());
|
||||
/// let v = f.ind_sample(&mut rand::thread_rng());
|
||||
/// println!("{} is from an F(2, 32) distribution", v)
|
||||
/// ```
|
||||
pub struct FisherF {
|
||||
@ -292,7 +292,7 @@ impl IndependentSample<f64> for FisherF {
|
||||
/// use std::rand::distributions::{StudentT, IndependentSample};
|
||||
///
|
||||
/// let t = StudentT::new(11.0);
|
||||
/// let v = t.ind_sample(&mut rand::task_rng());
|
||||
/// let v = t.ind_sample(&mut rand::thread_rng());
|
||||
/// println!("{} is from a t(11) distribution", v)
|
||||
/// ```
|
||||
pub struct StudentT {
|
||||
|
@ -96,7 +96,7 @@ pub struct Weighted<T> {
|
||||
/// Weighted { weight: 4, item: 'b' },
|
||||
/// Weighted { weight: 1, item: 'c' });
|
||||
/// let wc = WeightedChoice::new(items.as_mut_slice());
|
||||
/// let mut rng = rand::task_rng();
|
||||
/// let mut rng = rand::thread_rng();
|
||||
/// for _ in range(0u, 16) {
|
||||
/// // on average prints 'a' 4 times, 'b' 8 and 'c' twice.
|
||||
/// println!("{}", wc.ind_sample(&mut rng));
|
||||
|
@ -81,7 +81,7 @@ impl Rand for StandardNormal {
|
||||
///
|
||||
/// // mean 2, standard deviation 3
|
||||
/// let normal = Normal::new(2.0, 3.0);
|
||||
/// let v = normal.ind_sample(&mut rand::task_rng());
|
||||
/// let v = normal.ind_sample(&mut rand::thread_rng());
|
||||
/// println!("{} is from a N(2, 9) distribution", v)
|
||||
/// ```
|
||||
#[deriving(Copy)]
|
||||
@ -129,7 +129,7 @@ impl IndependentSample<f64> for Normal {
|
||||
///
|
||||
/// // mean 2, standard deviation 3
|
||||
/// let log_normal = LogNormal::new(2.0, 3.0);
|
||||
/// let v = log_normal.ind_sample(&mut rand::task_rng());
|
||||
/// let v = log_normal.ind_sample(&mut rand::thread_rng());
|
||||
/// println!("{} is from an ln N(2, 9) distribution", v)
|
||||
/// ```
|
||||
#[deriving(Copy)]
|
||||
|
@ -39,7 +39,7 @@ use distributions::{Sample, IndependentSample};
|
||||
///
|
||||
/// fn main() {
|
||||
/// let between = Range::new(10u, 10000u);
|
||||
/// let mut rng = std::rand::task_rng();
|
||||
/// let mut rng = std::rand::thread_rng();
|
||||
/// let mut sum = 0;
|
||||
/// for _ in range(0u, 1000) {
|
||||
/// sum += between.ind_sample(&mut rng);
|
||||
|
@ -138,10 +138,10 @@ pub trait Rng {
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use std::rand::{task_rng, Rng};
|
||||
/// use std::rand::{thread_rng, Rng};
|
||||
///
|
||||
/// let mut v = [0u8, .. 13579];
|
||||
/// task_rng().fill_bytes(&mut v);
|
||||
/// thread_rng().fill_bytes(&mut v);
|
||||
/// println!("{}", v.as_slice());
|
||||
/// ```
|
||||
fn fill_bytes(&mut self, dest: &mut [u8]) {
|
||||
@ -173,9 +173,9 @@ pub trait Rng {
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use std::rand::{task_rng, Rng};
|
||||
/// use std::rand::{thread_rng, Rng};
|
||||
///
|
||||
/// let mut rng = task_rng();
|
||||
/// let mut rng = thread_rng();
|
||||
/// let x: uint = rng.gen();
|
||||
/// println!("{}", x);
|
||||
/// println!("{}", rng.gen::<(f64, bool)>());
|
||||
@ -191,9 +191,9 @@ pub trait Rng {
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use std::rand::{task_rng, Rng};
|
||||
/// use std::rand::{thread_rng, Rng};
|
||||
///
|
||||
/// let mut rng = task_rng();
|
||||
/// let mut rng = thread_rng();
|
||||
/// let x = rng.gen_iter::<uint>().take(10).collect::<Vec<uint>>();
|
||||
/// println!("{}", x);
|
||||
/// println!("{}", rng.gen_iter::<(f64, bool)>().take(5)
|
||||
@ -218,9 +218,9 @@ pub trait Rng {
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use std::rand::{task_rng, Rng};
|
||||
/// use std::rand::{thread_rng, Rng};
|
||||
///
|
||||
/// let mut rng = task_rng();
|
||||
/// let mut rng = thread_rng();
|
||||
/// let n: uint = rng.gen_range(0u, 10);
|
||||
/// println!("{}", n);
|
||||
/// let m: f64 = rng.gen_range(-40.0f64, 1.3e5f64);
|
||||
@ -236,9 +236,9 @@ pub trait Rng {
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use std::rand::{task_rng, Rng};
|
||||
/// use std::rand::{thread_rng, Rng};
|
||||
///
|
||||
/// let mut rng = task_rng();
|
||||
/// let mut rng = thread_rng();
|
||||
/// println!("{}", rng.gen_weighted_bool(3));
|
||||
/// ```
|
||||
fn gen_weighted_bool(&mut self, n: uint) -> bool {
|
||||
@ -250,9 +250,9 @@ pub trait Rng {
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use std::rand::{task_rng, Rng};
|
||||
/// use std::rand::{thread_rng, Rng};
|
||||
///
|
||||
/// let s: String = task_rng().gen_ascii_chars().take(10).collect();
|
||||
/// let s: String = thread_rng().gen_ascii_chars().take(10).collect();
|
||||
/// println!("{}", s);
|
||||
/// ```
|
||||
fn gen_ascii_chars<'a>(&'a mut self) -> AsciiGenerator<'a, Self> {
|
||||
@ -266,10 +266,10 @@ pub trait Rng {
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use std::rand::{task_rng, Rng};
|
||||
/// use std::rand::{thread_rng, Rng};
|
||||
///
|
||||
/// let choices = [1i, 2, 4, 8, 16, 32];
|
||||
/// let mut rng = task_rng();
|
||||
/// let mut rng = thread_rng();
|
||||
/// println!("{}", rng.choose(&choices));
|
||||
/// assert_eq!(rng.choose(choices[..0]), None);
|
||||
/// ```
|
||||
@ -286,9 +286,9 @@ pub trait Rng {
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use std::rand::{task_rng, Rng};
|
||||
/// use std::rand::{thread_rng, Rng};
|
||||
///
|
||||
/// let mut rng = task_rng();
|
||||
/// let mut rng = thread_rng();
|
||||
/// let mut y = [1i, 2, 3];
|
||||
/// rng.shuffle(&mut y);
|
||||
/// println!("{}", y.as_slice());
|
||||
@ -520,8 +520,8 @@ mod test {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn rng() -> MyRng<rand::TaskRng> {
|
||||
MyRng { inner: rand::task_rng() }
|
||||
pub fn rng() -> MyRng<rand::ThreadRng> {
|
||||
MyRng { inner: rand::thread_rng() }
|
||||
}
|
||||
|
||||
pub fn weak_rng() -> MyRng<rand::XorShiftRng> {
|
||||
|
@ -215,7 +215,7 @@ impl<T:Rand> Rand for Option<T> {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::prelude::*;
|
||||
use std::rand::{Rng, task_rng, Open01, Closed01};
|
||||
use std::rand::{Rng, thread_rng, Open01, Closed01};
|
||||
|
||||
struct ConstantRng(u64);
|
||||
impl Rng for ConstantRng {
|
||||
@ -240,7 +240,7 @@ mod tests {
|
||||
fn rand_open() {
|
||||
// this is unlikely to catch an incorrect implementation that
|
||||
// generates exactly 0 or 1, but it keeps it sane.
|
||||
let mut rng = task_rng();
|
||||
let mut rng = thread_rng();
|
||||
for _ in range(0u, 1_000) {
|
||||
// strict inequalities
|
||||
let Open01(f) = rng.gen::<Open01<f64>>();
|
||||
@ -253,7 +253,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn rand_closed() {
|
||||
let mut rng = task_rng();
|
||||
let mut rng = thread_rng();
|
||||
for _ in range(0u, 1_000) {
|
||||
// strict inequalities
|
||||
let Closed01(f) = rng.gen::<Closed01<f64>>();
|
||||
|
@ -519,8 +519,8 @@ impl<'a> Parser<'a> {
|
||||
};
|
||||
self.chari = closer;
|
||||
let greed = try!(self.get_next_greedy());
|
||||
let inner = String::from_chars(
|
||||
self.chars[start+1..closer]);
|
||||
let inner = self.chars[start+1..closer].iter().cloned()
|
||||
.collect::<String>();
|
||||
|
||||
// Parse the min and max values from the regex.
|
||||
let (mut min, mut max): (uint, Option<uint>);
|
||||
@ -954,7 +954,7 @@ impl<'a> Parser<'a> {
|
||||
}
|
||||
|
||||
fn slice(&self, start: uint, end: uint) -> String {
|
||||
String::from_chars(self.chars[start..end])
|
||||
self.chars[start..end].iter().cloned().collect()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -9,8 +9,9 @@
|
||||
// except according to those terms.
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
use std::rand::{Rng, task_rng};
|
||||
use std::rand::{Rng, thread_rng};
|
||||
use stdtest::Bencher;
|
||||
use std::iter::repeat;
|
||||
|
||||
use regex::{Regex, NoExpand};
|
||||
|
||||
@ -22,30 +23,30 @@ fn bench_assert_match(b: &mut Bencher, re: Regex, text: &str) {
|
||||
fn no_exponential(b: &mut Bencher) {
|
||||
let n = 100;
|
||||
let re = Regex::new(format!("{}{}",
|
||||
"a?".repeat(n),
|
||||
"a".repeat(n)).as_slice()).unwrap();
|
||||
let text = "a".repeat(n);
|
||||
repeat("a?").take(n).collect::<String>(),
|
||||
repeat("a").take(n).collect::<String>()).as_slice()).unwrap();
|
||||
let text = repeat("a").take(n).collect::<String>();
|
||||
bench_assert_match(b, re, text.as_slice());
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn literal(b: &mut Bencher) {
|
||||
let re = regex!("y");
|
||||
let text = format!("{}y", "x".repeat(50));
|
||||
let text = format!("{}y", repeat("x").take(50).collect::<String>());
|
||||
bench_assert_match(b, re, text.as_slice());
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn not_literal(b: &mut Bencher) {
|
||||
let re = regex!(".y");
|
||||
let text = format!("{}y", "x".repeat(50));
|
||||
let text = format!("{}y", repeat("x").take(50).collect::<String>());
|
||||
bench_assert_match(b, re, text.as_slice());
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn match_class(b: &mut Bencher) {
|
||||
let re = regex!("[abcdw]");
|
||||
let text = format!("{}w", "xxxx".repeat(20));
|
||||
let text = format!("{}w", repeat("xxxx").take(20).collect::<String>());
|
||||
bench_assert_match(b, re, text.as_slice());
|
||||
}
|
||||
|
||||
@ -53,7 +54,7 @@ fn match_class(b: &mut Bencher) {
|
||||
fn match_class_in_range(b: &mut Bencher) {
|
||||
// 'b' is between 'a' and 'c', so the class range checking doesn't help.
|
||||
let re = regex!("[ac]");
|
||||
let text = format!("{}c", "bbbb".repeat(20));
|
||||
let text = format!("{}c", repeat("bbbb").take(20).collect::<String>());
|
||||
bench_assert_match(b, re, text.as_slice());
|
||||
}
|
||||
|
||||
@ -77,7 +78,7 @@ fn anchored_literal_short_non_match(b: &mut Bencher) {
|
||||
#[bench]
|
||||
fn anchored_literal_long_non_match(b: &mut Bencher) {
|
||||
let re = regex!("^zbc(d|e)");
|
||||
let text = "abcdefghijklmnopqrstuvwxyz".repeat(15);
|
||||
let text = repeat("abcdefghijklmnopqrstuvwxyz").take(15).collect::<String>();
|
||||
b.iter(|| re.is_match(text.as_slice()));
|
||||
}
|
||||
|
||||
@ -91,7 +92,7 @@ fn anchored_literal_short_match(b: &mut Bencher) {
|
||||
#[bench]
|
||||
fn anchored_literal_long_match(b: &mut Bencher) {
|
||||
let re = regex!("^.bc(d|e)");
|
||||
let text = "abcdefghijklmnopqrstuvwxyz".repeat(15);
|
||||
let text = repeat("abcdefghijklmnopqrstuvwxyz").take(15).collect::<String>();
|
||||
b.iter(|| re.is_match(text.as_slice()));
|
||||
}
|
||||
|
||||
@ -154,7 +155,7 @@ fn medium() -> Regex { regex!("[XYZ]ABCDEFGHIJKLMNOPQRSTUVWXYZ$") }
|
||||
fn hard() -> Regex { regex!("[ -~]*ABCDEFGHIJKLMNOPQRSTUVWXYZ$") }
|
||||
|
||||
fn gen_text(n: uint) -> String {
|
||||
let mut rng = task_rng();
|
||||
let mut rng = thread_rng();
|
||||
let mut bytes = rng.gen_ascii_chars().map(|n| n as u8).take(n)
|
||||
.collect::<Vec<u8>>();
|
||||
for (i, b) in bytes.iter_mut().enumerate() {
|
||||
|
@ -1782,9 +1782,9 @@ impl LintPass for Stability {
|
||||
if self.is_internal(cx, item.span) { return }
|
||||
|
||||
match item.node {
|
||||
ast::ItemTrait(_, _, _, ref supertraits, _) => {
|
||||
ast::ItemTrait(_, _, ref supertraits, _) => {
|
||||
for t in supertraits.iter() {
|
||||
if let ast::TraitTyParamBound(ref t) = *t {
|
||||
if let ast::TraitTyParamBound(ref t, _) = *t {
|
||||
let id = ty::trait_ref_to_def_id(cx.tcx, &t.trait_ref);
|
||||
self.lint(cx, id, t.trait_ref.path.span);
|
||||
}
|
||||
|
@ -1308,7 +1308,7 @@ fn encode_info_for_item(ecx: &EncodeContext,
|
||||
}
|
||||
}
|
||||
}
|
||||
ast::ItemTrait(_, _, _, _, ref ms) => {
|
||||
ast::ItemTrait(_, _, _, ref ms) => {
|
||||
add_to_index(item, rbml_w, index);
|
||||
rbml_w.start_tag(tag_items_data_item);
|
||||
encode_def_id(rbml_w, def_id);
|
||||
|
@ -25,7 +25,7 @@ use middle::ty::*;
|
||||
use middle::ty;
|
||||
use std::fmt;
|
||||
use std::iter::AdditiveIterator;
|
||||
use std::iter::range_inclusive;
|
||||
use std::iter::{range_inclusive, repeat};
|
||||
use std::num::Float;
|
||||
use std::slice;
|
||||
use syntax::ast::{mod, DUMMY_NODE_ID, NodeId, Pat};
|
||||
@ -76,7 +76,7 @@ impl<'a> fmt::Show for Matrix<'a> {
|
||||
}).collect();
|
||||
|
||||
let total_width = column_widths.iter().map(|n| *n).sum() + column_count * 3 + 1;
|
||||
let br = String::from_char(total_width, '+');
|
||||
let br = repeat('+').take(total_width).collect::<String>();
|
||||
try!(write!(f, "{}\n", br));
|
||||
for row in pretty_printed_matrix.into_iter() {
|
||||
try!(write!(f, "+"));
|
||||
|
@ -1043,7 +1043,6 @@ impl<'a, 'tcx> Rebuilder<'a, 'tcx> {
|
||||
ident: ty_param.ident,
|
||||
id: ty_param.id,
|
||||
bounds: bounds,
|
||||
unbound: ty_param.unbound.clone(),
|
||||
default: ty_param.default.clone(),
|
||||
span: ty_param.span,
|
||||
}
|
||||
@ -1063,7 +1062,7 @@ impl<'a, 'tcx> Rebuilder<'a, 'tcx> {
|
||||
// be passing down a map.
|
||||
ast::RegionTyParamBound(lt)
|
||||
}
|
||||
&ast::TraitTyParamBound(ref poly_tr) => {
|
||||
&ast::TraitTyParamBound(ref poly_tr, modifier) => {
|
||||
let tr = &poly_tr.trait_ref;
|
||||
let last_seg = tr.path.segments.last().unwrap();
|
||||
let mut insert = Vec::new();
|
||||
@ -1087,7 +1086,7 @@ impl<'a, 'tcx> Rebuilder<'a, 'tcx> {
|
||||
path: new_path,
|
||||
ref_id: tr.ref_id,
|
||||
}
|
||||
})
|
||||
}, modifier)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
@ -122,7 +122,7 @@ impl<'v> Visitor<'v> for ParentVisitor {
|
||||
// method to the root. In this case, if the trait is private, then
|
||||
// parent all the methods to the trait to indicate that they're
|
||||
// private.
|
||||
ast::ItemTrait(_, _, _, _, ref methods) if item.vis != ast::Public => {
|
||||
ast::ItemTrait(_, _, _, ref methods) if item.vis != ast::Public => {
|
||||
for m in methods.iter() {
|
||||
match *m {
|
||||
ast::ProvidedMethod(ref m) => {
|
||||
@ -328,7 +328,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> {
|
||||
|
||||
// Default methods on traits are all public so long as the trait
|
||||
// is public
|
||||
ast::ItemTrait(_, _, _, _, ref methods) if public_first => {
|
||||
ast::ItemTrait(_, _, _, ref methods) if public_first => {
|
||||
for method in methods.iter() {
|
||||
match *method {
|
||||
ast::ProvidedMethod(ref m) => {
|
||||
@ -1178,7 +1178,7 @@ impl<'a, 'tcx> SanePrivacyVisitor<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
ast::ItemTrait(_, _, _, _, ref methods) => {
|
||||
ast::ItemTrait(_, _, _, ref methods) => {
|
||||
for m in methods.iter() {
|
||||
match *m {
|
||||
ast::ProvidedMethod(ref m) => {
|
||||
@ -1242,7 +1242,7 @@ impl<'a, 'tcx> SanePrivacyVisitor<'a, 'tcx> {
|
||||
|
||||
ast::ItemStruct(ref def, _) => check_struct(&**def),
|
||||
|
||||
ast::ItemTrait(_, _, _, _, ref methods) => {
|
||||
ast::ItemTrait(_, _, _, ref methods) => {
|
||||
for m in methods.iter() {
|
||||
match *m {
|
||||
ast::RequiredMethod(..) => {}
|
||||
@ -1306,7 +1306,7 @@ impl<'a, 'tcx> VisiblePrivateTypesVisitor<'a, 'tcx> {
|
||||
|
||||
fn check_ty_param_bound(&self,
|
||||
ty_param_bound: &ast::TyParamBound) {
|
||||
if let ast::TraitTyParamBound(ref trait_ref) = *ty_param_bound {
|
||||
if let ast::TraitTyParamBound(ref trait_ref, _) = *ty_param_bound {
|
||||
if !self.tcx.sess.features.borrow().visible_private_types &&
|
||||
self.path_is_private_type(trait_ref.trait_ref.ref_id) {
|
||||
let span = trait_ref.trait_ref.path.span;
|
||||
@ -1349,7 +1349,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for VisiblePrivateTypesVisitor<'a, 'tcx> {
|
||||
// namespace (the contents have their own privacies).
|
||||
ast::ItemForeignMod(_) => {}
|
||||
|
||||
ast::ItemTrait(_, _, _, ref bounds, _) => {
|
||||
ast::ItemTrait(_, _, ref bounds, _) => {
|
||||
if !self.trait_is_public(item.id) {
|
||||
return
|
||||
}
|
||||
|
@ -105,7 +105,7 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> {
|
||||
ast::ItemTy(_, ref generics) |
|
||||
ast::ItemEnum(_, ref generics) |
|
||||
ast::ItemStruct(_, ref generics) |
|
||||
ast::ItemTrait(_, ref generics, _, _, _) |
|
||||
ast::ItemTrait(_, ref generics, _, _) |
|
||||
ast::ItemImpl(_, ref generics, _, _, _) => {
|
||||
// These kinds of items have only early bound lifetime parameters.
|
||||
let lifetimes = &generics.lifetimes;
|
||||
@ -232,7 +232,9 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_poly_trait_ref(&mut self, trait_ref: &ast::PolyTraitRef) {
|
||||
fn visit_poly_trait_ref(&mut self, trait_ref:
|
||||
&ast::PolyTraitRef,
|
||||
_modifier: &ast::TraitBoundModifier) {
|
||||
debug!("visit_poly_trait_ref trait_ref={}", trait_ref);
|
||||
|
||||
self.with(LateScope(&trait_ref.bound_lifetimes, self.scope), |old_scope, this| {
|
||||
|
@ -4740,7 +4740,7 @@ pub fn provided_trait_methods<'tcx>(cx: &ctxt<'tcx>, id: ast::DefId)
|
||||
match cx.map.find(id.node) {
|
||||
Some(ast_map::NodeItem(item)) => {
|
||||
match item.node {
|
||||
ItemTrait(_, _, _, _, ref ms) => {
|
||||
ItemTrait(_, _, _, ref ms) => {
|
||||
let (_, p) =
|
||||
ast_util::split_trait_methods(ms[]);
|
||||
p.iter()
|
||||
|
@ -26,7 +26,7 @@ pub fn get_target_strs(target_triple: String, target_os: abi::Os) -> target_strs
|
||||
-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64\
|
||||
-f32:32:32-f64:64:64\
|
||||
-v64:64:64-v128:64:128\
|
||||
-a0:0:64-n32".to_string()
|
||||
-a:0:64-n32".to_string()
|
||||
}
|
||||
|
||||
abi::OsiOS => {
|
||||
@ -34,7 +34,7 @@ pub fn get_target_strs(target_triple: String, target_os: abi::Os) -> target_strs
|
||||
-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64\
|
||||
-f32:32:32-f64:64:64\
|
||||
-v64:64:64-v128:64:128\
|
||||
-a0:0:64-n32".to_string()
|
||||
-a:0:64-n32".to_string()
|
||||
}
|
||||
|
||||
abi::OsWindows => {
|
||||
@ -42,7 +42,7 @@ pub fn get_target_strs(target_triple: String, target_os: abi::Os) -> target_strs
|
||||
-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64\
|
||||
-f32:32:32-f64:64:64\
|
||||
-v64:64:64-v128:64:128\
|
||||
-a0:0:64-n32".to_string()
|
||||
-a:0:64-n32".to_string()
|
||||
}
|
||||
|
||||
abi::OsLinux => {
|
||||
@ -50,7 +50,7 @@ pub fn get_target_strs(target_triple: String, target_os: abi::Os) -> target_strs
|
||||
-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64\
|
||||
-f32:32:32-f64:64:64\
|
||||
-v64:64:64-v128:64:128\
|
||||
-a0:0:64-n32".to_string()
|
||||
-a:0:64-n32".to_string()
|
||||
}
|
||||
|
||||
abi::OsAndroid => {
|
||||
@ -58,7 +58,7 @@ pub fn get_target_strs(target_triple: String, target_os: abi::Os) -> target_strs
|
||||
-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64\
|
||||
-f32:32:32-f64:64:64\
|
||||
-v64:64:64-v128:64:128\
|
||||
-a0:0:64-n32".to_string()
|
||||
-a:0:64-n32".to_string()
|
||||
}
|
||||
|
||||
abi::OsFreebsd | abi::OsDragonfly => {
|
||||
@ -66,7 +66,7 @@ pub fn get_target_strs(target_triple: String, target_os: abi::Os) -> target_strs
|
||||
-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64\
|
||||
-f32:32:32-f64:64:64\
|
||||
-v64:64:64-v128:64:128\
|
||||
-a0:0:64-n32".to_string()
|
||||
-a:0:64-n32".to_string()
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -21,7 +21,7 @@ pub fn get_target_strs(target_triple: String, target_os: abi::Os) -> target_strs
|
||||
-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64\
|
||||
-f32:32:32-f64:64:64\
|
||||
-v64:64:64-v128:64:128\
|
||||
-a0:0:64-n32".to_string()
|
||||
-a:0:64-n32".to_string()
|
||||
}
|
||||
|
||||
abi::OsiOS => {
|
||||
@ -29,7 +29,7 @@ pub fn get_target_strs(target_triple: String, target_os: abi::Os) -> target_strs
|
||||
-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64\
|
||||
-f32:32:32-f64:64:64\
|
||||
-v64:64:64-v128:64:128\
|
||||
-a0:0:64-n32".to_string()
|
||||
-a:0:64-n32".to_string()
|
||||
}
|
||||
|
||||
abi::OsWindows => {
|
||||
@ -37,7 +37,7 @@ pub fn get_target_strs(target_triple: String, target_os: abi::Os) -> target_strs
|
||||
-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64\
|
||||
-f32:32:32-f64:64:64\
|
||||
-v64:64:64-v128:64:128\
|
||||
-a0:0:64-n32".to_string()
|
||||
-a:0:64-n32".to_string()
|
||||
}
|
||||
|
||||
abi::OsLinux => {
|
||||
@ -45,7 +45,7 @@ pub fn get_target_strs(target_triple: String, target_os: abi::Os) -> target_strs
|
||||
-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64\
|
||||
-f32:32:32-f64:64:64\
|
||||
-v64:64:64-v128:64:128\
|
||||
-a0:0:64-n32".to_string()
|
||||
-a:0:64-n32".to_string()
|
||||
}
|
||||
|
||||
abi::OsAndroid => {
|
||||
@ -53,7 +53,7 @@ pub fn get_target_strs(target_triple: String, target_os: abi::Os) -> target_strs
|
||||
-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64\
|
||||
-f32:32:32-f64:64:64\
|
||||
-v64:64:64-v128:64:128\
|
||||
-a0:0:64-n32".to_string()
|
||||
-a:0:64-n32".to_string()
|
||||
}
|
||||
|
||||
abi::OsFreebsd | abi::OsDragonfly => {
|
||||
@ -61,7 +61,7 @@ pub fn get_target_strs(target_triple: String, target_os: abi::Os) -> target_strs
|
||||
-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64\
|
||||
-f32:32:32-f64:64:64\
|
||||
-v64:64:64-v128:64:128\
|
||||
-a0:0:64-n32".to_string()
|
||||
-a:0:64-n32".to_string()
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -21,7 +21,7 @@ pub fn get_target_strs(target_triple: String, target_os: abi::Os) -> target_strs
|
||||
-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64\
|
||||
-f32:32:32-f64:64:64\
|
||||
-v64:64:64-v128:64:128\
|
||||
-a0:0:64-n32".to_string()
|
||||
-a:0:64-n32".to_string()
|
||||
}
|
||||
|
||||
abi::OsiOS => {
|
||||
@ -29,7 +29,7 @@ pub fn get_target_strs(target_triple: String, target_os: abi::Os) -> target_strs
|
||||
-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64\
|
||||
-f32:32:32-f64:64:64\
|
||||
-v64:64:64-v128:64:128\
|
||||
-a0:0:64-n32".to_string()
|
||||
-a:0:64-n32".to_string()
|
||||
}
|
||||
|
||||
abi::OsWindows => {
|
||||
@ -37,7 +37,7 @@ pub fn get_target_strs(target_triple: String, target_os: abi::Os) -> target_strs
|
||||
-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64\
|
||||
-f32:32:32-f64:64:64\
|
||||
-v64:64:64-v128:64:128\
|
||||
-a0:0:64-n32".to_string()
|
||||
-a:0:64-n32".to_string()
|
||||
}
|
||||
|
||||
abi::OsLinux => {
|
||||
@ -45,7 +45,7 @@ pub fn get_target_strs(target_triple: String, target_os: abi::Os) -> target_strs
|
||||
-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64\
|
||||
-f32:32:32-f64:64:64\
|
||||
-v64:64:64-v128:64:128\
|
||||
-a0:0:64-n32".to_string()
|
||||
-a:0:64-n32".to_string()
|
||||
}
|
||||
|
||||
abi::OsAndroid => {
|
||||
@ -53,7 +53,7 @@ pub fn get_target_strs(target_triple: String, target_os: abi::Os) -> target_strs
|
||||
-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64\
|
||||
-f32:32:32-f64:64:64\
|
||||
-v64:64:64-v128:64:128\
|
||||
-a0:0:64-n32".to_string()
|
||||
-a:0:64-n32".to_string()
|
||||
}
|
||||
|
||||
abi::OsFreebsd | abi::OsDragonfly => {
|
||||
@ -61,7 +61,7 @@ pub fn get_target_strs(target_triple: String, target_os: abi::Os) -> target_strs
|
||||
-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64\
|
||||
-f32:32:32-f64:64:64\
|
||||
-v64:64:64-v128:64:128\
|
||||
-a0:0:64-n32".to_string()
|
||||
-a:0:64-n32".to_string()
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -16,7 +16,7 @@ pub fn target() -> Target {
|
||||
-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64\
|
||||
-f32:32:32-f64:64:64\
|
||||
-v64:64:64-v128:64:128\
|
||||
-a0:0:64-n32".to_string(),
|
||||
-a:0:64-n32".to_string(),
|
||||
llvm_target: "arm-apple-ios".to_string(),
|
||||
target_endian: "little".to_string(),
|
||||
target_word_size: "32".to_string(),
|
||||
|
@ -24,7 +24,7 @@ pub fn target() -> Target {
|
||||
-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64\
|
||||
-f32:32:32-f64:64:64\
|
||||
-v64:64:64-v128:64:128\
|
||||
-a0:0:64-n32".to_string(),
|
||||
-a:0:64-n32".to_string(),
|
||||
llvm_target: "arm-linux-androideabi".to_string(),
|
||||
target_endian: "little".to_string(),
|
||||
target_word_size: "32".to_string(),
|
||||
|
@ -17,7 +17,7 @@ pub fn target() -> Target {
|
||||
-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64\
|
||||
-f32:32:32-f64:64:64\
|
||||
-v64:64:64-v128:64:128\
|
||||
-a0:0:64-n32".to_string(),
|
||||
-a:0:64-n32".to_string(),
|
||||
llvm_target: "arm-unknown-linux-gnueabi".to_string(),
|
||||
target_endian: "little".to_string(),
|
||||
target_word_size: "32".to_string(),
|
||||
|
@ -17,7 +17,7 @@ pub fn target() -> Target {
|
||||
-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64\
|
||||
-f32:32:32-f64:64:64\
|
||||
-v64:64:64-v128:64:128\
|
||||
-a0:0:64-n32".to_string(),
|
||||
-a:0:64-n32".to_string(),
|
||||
llvm_target: "arm-unknown-linux-gnueabihf".to_string(),
|
||||
target_endian: "little".to_string(),
|
||||
target_word_size: "32".to_string(),
|
||||
|
@ -15,7 +15,7 @@ pub fn target() -> Target {
|
||||
data_layout: "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16\
|
||||
-i32:32:32-i64:32:64\
|
||||
-f32:32:32-f64:32:64-v64:64:64\
|
||||
-v128:128:128-a0:0:64-f80:128:128\
|
||||
-v128:128:128-a:0:64-f80:128:128\
|
||||
-n8:16:32".to_string(),
|
||||
llvm_target: "i386-apple-ios".to_string(),
|
||||
target_endian: "little".to_string(),
|
||||
|
@ -18,7 +18,7 @@ pub fn target() -> Target {
|
||||
data_layout: "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16\
|
||||
-i32:32:32-i64:32:64\
|
||||
-f32:32:32-f64:32:64-v64:64:64\
|
||||
-v128:128:128-a0:0:64-f80:128:128\
|
||||
-v128:128:128-a:0:64-f80:128:128\
|
||||
-n8:16:32".to_string(),
|
||||
llvm_target: "i686-apple-darwin".to_string(),
|
||||
target_endian: "little".to_string(),
|
||||
|
@ -16,7 +16,7 @@ pub fn target() -> Target {
|
||||
-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64\
|
||||
-f32:32:32-f64:64:64\
|
||||
-v64:64:64-v128:64:128\
|
||||
-a0:0:64-n32".to_string(),
|
||||
-a:0:64-n32".to_string(),
|
||||
llvm_target: "mips-unknown-linux-gnu".to_string(),
|
||||
target_endian: "big".to_string(),
|
||||
target_word_size: "32".to_string(),
|
||||
|
@ -16,7 +16,7 @@ pub fn target() -> Target {
|
||||
-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64\
|
||||
-f32:32:32-f64:64:64\
|
||||
-v64:64:64-v128:64:128\
|
||||
-a0:0:64-n32".to_string(),
|
||||
-a:0:64-n32".to_string(),
|
||||
llvm_target: "mipsel-unknown-linux-gnu".to_string(),
|
||||
target_endian: "little".to_string(),
|
||||
target_word_size: "32".to_string(),
|
||||
|
@ -17,7 +17,7 @@ pub fn target() -> Target {
|
||||
|
||||
Target {
|
||||
data_layout: "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-\
|
||||
f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-\
|
||||
f32:32:32-f64:64:64-v64:64:64-v128:128:128-a:0:64-\
|
||||
s0:64:64-f80:128:128-n8:16:32:64".to_string(),
|
||||
llvm_target: "x86_64-apple-darwin".to_string(),
|
||||
target_endian: "little".to_string(),
|
||||
|
@ -19,7 +19,7 @@ pub fn target() -> Target {
|
||||
Target {
|
||||
// FIXME: Test this. Copied from linux (#2398)
|
||||
data_layout: "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-\
|
||||
f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-\
|
||||
f32:32:32-f64:64:64-v64:64:64-v128:128:128-a:0:64-\
|
||||
s0:64:64-f80:128:128-n8:16:32:64-S128".to_string(),
|
||||
llvm_target: "x86_64-pc-windows-gnu".to_string(),
|
||||
target_endian: "little".to_string(),
|
||||
|
@ -16,7 +16,7 @@ pub fn target() -> Target {
|
||||
|
||||
Target {
|
||||
data_layout: "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-\
|
||||
f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-\
|
||||
f32:32:32-f64:64:64-v64:64:64-v128:128:128-a:0:64-\
|
||||
s0:64:64-f80:128:128-n8:16:32:64-S128".to_string(),
|
||||
llvm_target: "x86_64-unknown-dragonfly".to_string(),
|
||||
target_endian: "little".to_string(),
|
||||
|
@ -16,7 +16,7 @@ pub fn target() -> Target {
|
||||
|
||||
Target {
|
||||
data_layout: "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-\
|
||||
f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-\
|
||||
f32:32:32-f64:64:64-v64:64:64-v128:128:128-a:0:64-\
|
||||
s0:64:64-f80:128:128-n8:16:32:64-S128".to_string(),
|
||||
llvm_target: "x86_64-unknown-freebsd".to_string(),
|
||||
target_endian: "little".to_string(),
|
||||
|
@ -16,7 +16,7 @@ pub fn target() -> Target {
|
||||
|
||||
Target {
|
||||
data_layout: "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-\
|
||||
f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-\
|
||||
f32:32:32-f64:64:64-v64:64:64-v128:128:128-a:0:64-\
|
||||
s0:64:64-f80:128:128-n8:16:32:64-S128".to_string(),
|
||||
llvm_target: "x86_64-unknown-linux-gnu".to_string(),
|
||||
target_endian: "little".to_string(),
|
||||
|
@ -22,7 +22,7 @@ pub fn get_target_strs(target_triple: String, target_os: abi::Os)
|
||||
"e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16\
|
||||
-i32:32:32-i64:32:64\
|
||||
-f32:32:32-f64:32:64-v64:64:64\
|
||||
-v128:128:128-a0:0:64-f80:128:128\
|
||||
-v128:128:128-a:0:64-f80:128:128\
|
||||
-n8:16:32".to_string()
|
||||
}
|
||||
|
||||
@ -30,7 +30,7 @@ pub fn get_target_strs(target_triple: String, target_os: abi::Os)
|
||||
"e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16\
|
||||
-i32:32:32-i64:32:64\
|
||||
-f32:32:32-f64:32:64-v64:64:64\
|
||||
-v128:128:128-a0:0:64-f80:128:128\
|
||||
-v128:128:128-a:0:64-f80:128:128\
|
||||
-n8:16:32".to_string()
|
||||
}
|
||||
|
||||
|
@ -19,42 +19,42 @@ pub fn get_target_strs(target_triple: String, target_os: abi::Os) -> target_strs
|
||||
data_layout: match target_os {
|
||||
abi::OsMacos => {
|
||||
"e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-\
|
||||
f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-\
|
||||
f32:32:32-f64:64:64-v64:64:64-v128:128:128-a:0:64-\
|
||||
s0:64:64-f80:128:128-n8:16:32:64".to_string()
|
||||
}
|
||||
|
||||
abi::OsiOS => {
|
||||
"e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-\
|
||||
f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-\
|
||||
f32:32:32-f64:64:64-v64:64:64-v128:128:128-a:0:64-\
|
||||
s0:64:64-f80:128:128-n8:16:32:64".to_string()
|
||||
}
|
||||
|
||||
abi::OsWindows => {
|
||||
// FIXME: Test this. Copied from Linux (#2398)
|
||||
"e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-\
|
||||
f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-\
|
||||
f32:32:32-f64:64:64-v64:64:64-v128:128:128-a:0:64-\
|
||||
s0:64:64-f80:128:128-n8:16:32:64-S128".to_string()
|
||||
}
|
||||
|
||||
abi::OsLinux => {
|
||||
"e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-\
|
||||
f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-\
|
||||
f32:32:32-f64:64:64-v64:64:64-v128:128:128-a:0:64-\
|
||||
s0:64:64-f80:128:128-n8:16:32:64-S128".to_string()
|
||||
}
|
||||
abi::OsAndroid => {
|
||||
"e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-\
|
||||
f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-\
|
||||
f32:32:32-f64:64:64-v64:64:64-v128:128:128-a:0:64-\
|
||||
s0:64:64-f80:128:128-n8:16:32:64-S128".to_string()
|
||||
}
|
||||
|
||||
abi::OsFreebsd => {
|
||||
"e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-\
|
||||
f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-\
|
||||
f32:32:32-f64:64:64-v64:64:64-v128:128:128-a:0:64-\
|
||||
s0:64:64-f80:128:128-n8:16:32:64-S128".to_string()
|
||||
}
|
||||
abi::OsDragonfly => {
|
||||
"e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-\
|
||||
f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-\
|
||||
f32:32:32-f64:64:64-v64:64:64-v128:128:128-a:0:64-\
|
||||
s0:64:64-f80:128:128-n8:16:32:64-S128".to_string()
|
||||
}
|
||||
|
||||
|
@ -540,7 +540,7 @@ pub fn monitor<F:FnOnce()+Send>(f: F) {
|
||||
match cfg.spawn(move || { std::io::stdio::set_stderr(box w); f() }).join() {
|
||||
Ok(()) => { /* fallthrough */ }
|
||||
Err(value) => {
|
||||
// Task panicked without emitting a fatal diagnostic
|
||||
// Thread panicked without emitting a fatal diagnostic
|
||||
if !value.is::<diagnostic::FatalError>() {
|
||||
let mut emitter = diagnostic::EmitterWriter::stderr(diagnostic::Auto, None);
|
||||
|
||||
|
@ -345,9 +345,6 @@ impl Rib {
|
||||
#[deriving(Show,PartialEq,Clone,Copy)]
|
||||
enum Shadowable {
|
||||
Always,
|
||||
/// Means that the recorded import obeys the glob shadowing rules, i.e., can
|
||||
/// only be shadowed by another glob import.
|
||||
Glob,
|
||||
Never
|
||||
}
|
||||
|
||||
@ -462,6 +459,22 @@ impl ImportResolution {
|
||||
|
||||
target.unwrap().shadowable
|
||||
}
|
||||
|
||||
fn set_target_and_id(&mut self,
|
||||
namespace: Namespace,
|
||||
target: Option<Target>,
|
||||
id: NodeId) {
|
||||
match namespace {
|
||||
TypeNS => {
|
||||
self.type_target = target;
|
||||
self.type_id = id;
|
||||
}
|
||||
ValueNS => {
|
||||
self.value_target = target;
|
||||
self.value_id = id;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The link from a module up to its nearest parent node.
|
||||
@ -1493,7 +1506,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||
|
||||
ItemImpl(_, _, Some(_), _, _) => parent,
|
||||
|
||||
ItemTrait(_, _, _, _, ref items) => {
|
||||
ItemTrait(_, _, _, ref items) => {
|
||||
let name_bindings =
|
||||
self.add_child(name,
|
||||
parent.clone(),
|
||||
@ -1719,11 +1732,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||
view_path.span,
|
||||
id,
|
||||
is_public,
|
||||
if shadowable == Shadowable::Never {
|
||||
Shadowable::Glob
|
||||
} else {
|
||||
shadowable
|
||||
});
|
||||
shadowable);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2712,64 +2721,45 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||
// We've successfully resolved the import. Write the results in.
|
||||
let mut import_resolutions = module_.import_resolutions.borrow_mut();
|
||||
let import_resolution = &mut (*import_resolutions)[target];
|
||||
{
|
||||
let check_and_write_import = |namespace, result: &_, used_public: &mut bool| {
|
||||
let namespace_name = match namespace {
|
||||
TypeNS => "type",
|
||||
ValueNS => "value",
|
||||
};
|
||||
|
||||
match value_result {
|
||||
BoundResult(ref target_module, ref name_bindings) => {
|
||||
debug!("(resolving single import) found value target: {}",
|
||||
{ name_bindings.value_def.borrow().clone().unwrap().def });
|
||||
self.check_for_conflicting_import(
|
||||
&import_resolution.value_target,
|
||||
directive.span,
|
||||
target,
|
||||
ValueNS);
|
||||
match *result {
|
||||
BoundResult(ref target_module, ref name_bindings) => {
|
||||
debug!("(resolving single import) found {} target: {}",
|
||||
namespace_name,
|
||||
name_bindings.def_for_namespace(namespace));
|
||||
self.check_for_conflicting_import(
|
||||
&import_resolution.target_for_namespace(namespace),
|
||||
directive.span,
|
||||
target,
|
||||
namespace);
|
||||
|
||||
self.check_that_import_is_importable(
|
||||
&**name_bindings,
|
||||
directive.span,
|
||||
target,
|
||||
ValueNS);
|
||||
self.check_that_import_is_importable(
|
||||
&**name_bindings,
|
||||
directive.span,
|
||||
target,
|
||||
namespace);
|
||||
|
||||
import_resolution.value_target =
|
||||
Some(Target::new(target_module.clone(),
|
||||
name_bindings.clone(),
|
||||
directive.shadowable));
|
||||
import_resolution.value_id = directive.id;
|
||||
import_resolution.is_public = directive.is_public;
|
||||
value_used_public = name_bindings.defined_in_public_namespace(ValueNS);
|
||||
}
|
||||
UnboundResult => { /* Continue. */ }
|
||||
UnknownResult => {
|
||||
panic!("value result should be known at this point");
|
||||
}
|
||||
}
|
||||
match type_result {
|
||||
BoundResult(ref target_module, ref name_bindings) => {
|
||||
debug!("(resolving single import) found type target: {}",
|
||||
{ name_bindings.type_def.borrow().clone().unwrap().type_def });
|
||||
self.check_for_conflicting_import(
|
||||
&import_resolution.type_target,
|
||||
directive.span,
|
||||
target,
|
||||
TypeNS);
|
||||
|
||||
self.check_that_import_is_importable(
|
||||
&**name_bindings,
|
||||
directive.span,
|
||||
target,
|
||||
TypeNS);
|
||||
|
||||
import_resolution.type_target =
|
||||
Some(Target::new(target_module.clone(),
|
||||
name_bindings.clone(),
|
||||
directive.shadowable));
|
||||
import_resolution.type_id = directive.id;
|
||||
import_resolution.is_public = directive.is_public;
|
||||
type_used_public = name_bindings.defined_in_public_namespace(TypeNS);
|
||||
}
|
||||
UnboundResult => { /* Continue. */ }
|
||||
UnknownResult => {
|
||||
panic!("type result should be known at this point");
|
||||
}
|
||||
let target = Some(Target::new(target_module.clone(),
|
||||
name_bindings.clone(),
|
||||
directive.shadowable));
|
||||
import_resolution.set_target_and_id(namespace, target, directive.id);
|
||||
import_resolution.is_public = directive.is_public;
|
||||
*used_public = name_bindings.defined_in_public_namespace(namespace);
|
||||
}
|
||||
UnboundResult => { /* Continue. */ }
|
||||
UnknownResult => {
|
||||
panic!("{} result should be known at this point", namespace_name);
|
||||
}
|
||||
}
|
||||
};
|
||||
check_and_write_import(ValueNS, &value_result, &mut value_used_public);
|
||||
check_and_write_import(TypeNS, &type_result, &mut type_used_public);
|
||||
}
|
||||
|
||||
self.check_for_conflicts_between_imports_and_items(
|
||||
@ -2825,7 +2815,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||
|
||||
// Resolves a glob import. Note that this function cannot fail; it either
|
||||
// succeeds or bails out (as importing * from an empty module or a module
|
||||
// that exports nothing is valid).
|
||||
// that exports nothing is valid). containing_module is the module we are
|
||||
// actually importing, i.e., `foo` in `use foo::*`.
|
||||
fn resolve_glob_import(&mut self,
|
||||
module_: &Module,
|
||||
containing_module: Rc<Module>,
|
||||
@ -2851,12 +2842,11 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||
assert_eq!(containing_module.glob_count.get(), 0);
|
||||
|
||||
// Add all resolved imports from the containing module.
|
||||
let import_resolutions = containing_module.import_resolutions
|
||||
.borrow();
|
||||
let import_resolutions = containing_module.import_resolutions.borrow();
|
||||
for (ident, target_import_resolution) in import_resolutions.iter() {
|
||||
debug!("(resolving glob import) writing module resolution \
|
||||
{} into `{}`",
|
||||
target_import_resolution.type_target.is_none(),
|
||||
token::get_name(*ident),
|
||||
self.module_to_string(module_));
|
||||
|
||||
if !target_import_resolution.is_public {
|
||||
@ -2876,8 +2866,11 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||
// Continue.
|
||||
}
|
||||
Some(ref value_target) => {
|
||||
dest_import_resolution.value_target =
|
||||
Some(value_target.clone());
|
||||
self.check_for_conflicting_import(&dest_import_resolution.value_target,
|
||||
import_directive.span,
|
||||
*ident,
|
||||
ValueNS);
|
||||
dest_import_resolution.value_target = Some(value_target.clone());
|
||||
}
|
||||
}
|
||||
match target_import_resolution.type_target {
|
||||
@ -2885,8 +2878,11 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||
// Continue.
|
||||
}
|
||||
Some(ref type_target) => {
|
||||
dest_import_resolution.type_target =
|
||||
Some(type_target.clone());
|
||||
self.check_for_conflicting_import(&dest_import_resolution.type_target,
|
||||
import_directive.span,
|
||||
*ident,
|
||||
TypeNS);
|
||||
dest_import_resolution.type_target = Some(type_target.clone());
|
||||
}
|
||||
}
|
||||
dest_import_resolution.is_public = is_public;
|
||||
@ -2908,8 +2904,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||
// Add all children from the containing module.
|
||||
self.populate_module_if_necessary(&containing_module);
|
||||
|
||||
for (&name, name_bindings) in containing_module.children
|
||||
.borrow().iter() {
|
||||
for (&name, name_bindings) in containing_module.children.borrow().iter() {
|
||||
self.merge_import_resolution(module_,
|
||||
containing_module.clone(),
|
||||
import_directive,
|
||||
@ -2919,8 +2914,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||
}
|
||||
|
||||
// Add external module children from the containing module.
|
||||
for (&name, module) in containing_module.external_module_children
|
||||
.borrow().iter() {
|
||||
for (&name, module) in containing_module.external_module_children.borrow().iter() {
|
||||
let name_bindings =
|
||||
Rc::new(Resolver::create_name_bindings_from_module(module.clone()));
|
||||
self.merge_import_resolution(module_,
|
||||
@ -2965,41 +2959,39 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||
|
||||
debug!("(resolving glob import) writing resolution `{}` in `{}` \
|
||||
to `{}`",
|
||||
token::get_name(name).get().to_string(),
|
||||
token::get_name(name).get(),
|
||||
self.module_to_string(&*containing_module),
|
||||
self.module_to_string(module_));
|
||||
|
||||
// Merge the child item into the import resolution.
|
||||
if name_bindings.defined_in_namespace_with(ValueNS, IMPORTABLE | PUBLIC) {
|
||||
debug!("(resolving glob import) ... for value target");
|
||||
if dest_import_resolution.shadowable(ValueNS) == Shadowable::Never {
|
||||
let msg = format!("a value named `{}` has already been imported \
|
||||
in this module",
|
||||
token::get_name(name).get());
|
||||
self.session.span_err(import_directive.span, msg.as_slice());
|
||||
} else {
|
||||
dest_import_resolution.value_target =
|
||||
Some(Target::new(containing_module.clone(),
|
||||
name_bindings.clone(),
|
||||
import_directive.shadowable));
|
||||
dest_import_resolution.value_id = id;
|
||||
}
|
||||
}
|
||||
if name_bindings.defined_in_namespace_with(TypeNS, IMPORTABLE | PUBLIC) {
|
||||
debug!("(resolving glob import) ... for type target");
|
||||
if dest_import_resolution.shadowable(TypeNS) == Shadowable::Never {
|
||||
let msg = format!("a type named `{}` has already been imported \
|
||||
in this module",
|
||||
token::get_name(name).get());
|
||||
self.session.span_err(import_directive.span, msg.as_slice());
|
||||
} else {
|
||||
dest_import_resolution.type_target =
|
||||
Some(Target::new(containing_module,
|
||||
name_bindings.clone(),
|
||||
import_directive.shadowable));
|
||||
dest_import_resolution.type_id = id;
|
||||
}
|
||||
{
|
||||
let merge_child_item = |namespace| {
|
||||
if name_bindings.defined_in_namespace_with(namespace, IMPORTABLE | PUBLIC) {
|
||||
let namespace_name = match namespace {
|
||||
TypeNS => "type",
|
||||
ValueNS => "value",
|
||||
};
|
||||
debug!("(resolving glob import) ... for {} target", namespace_name);
|
||||
if dest_import_resolution.shadowable(namespace) == Shadowable::Never {
|
||||
let msg = format!("a {} named `{}` has already been imported \
|
||||
in this module",
|
||||
namespace_name,
|
||||
token::get_name(name).get());
|
||||
self.session.span_err(import_directive.span, msg.as_slice());
|
||||
} else {
|
||||
let target = Target::new(containing_module.clone(),
|
||||
name_bindings.clone(),
|
||||
import_directive.shadowable);
|
||||
dest_import_resolution.set_target_and_id(namespace,
|
||||
Some(target),
|
||||
id);
|
||||
}
|
||||
}
|
||||
};
|
||||
merge_child_item(ValueNS);
|
||||
merge_child_item(TypeNS);
|
||||
}
|
||||
|
||||
dest_import_resolution.is_public = is_public;
|
||||
|
||||
self.check_for_conflicts_between_imports_and_items(
|
||||
@ -3019,6 +3011,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||
return
|
||||
}
|
||||
|
||||
debug!("check_for_conflicting_import: {}; target exists: {}",
|
||||
token::get_name(name).get(),
|
||||
target.is_some());
|
||||
|
||||
match *target {
|
||||
Some(ref target) if target.shadowable != Shadowable::Always => {
|
||||
let msg = format!("a {} named `{}` has already been imported \
|
||||
@ -4008,6 +4004,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Searches the current set of local scopes and
|
||||
/// applies translations for closures.
|
||||
fn search_ribs(&self,
|
||||
ribs: &[Rib],
|
||||
name: Name,
|
||||
@ -4029,6 +4027,27 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||
None
|
||||
}
|
||||
|
||||
/// Searches the current set of local scopes for labels.
|
||||
/// Stops after meeting a closure.
|
||||
fn search_label(&self, name: Name) -> Option<DefLike> {
|
||||
for rib in self.label_ribs.iter().rev() {
|
||||
match rib.kind {
|
||||
NormalRibKind => {
|
||||
// Continue
|
||||
}
|
||||
_ => {
|
||||
// Do not resolve labels across function boundary
|
||||
return None
|
||||
}
|
||||
}
|
||||
let result = rib.bindings.get(&name).cloned();
|
||||
if result.is_some() {
|
||||
return result
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn resolve_crate(&mut self, krate: &ast::Crate) {
|
||||
debug!("(resolving crate) starting");
|
||||
|
||||
@ -4093,7 +4112,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||
impl_items[]);
|
||||
}
|
||||
|
||||
ItemTrait(_, ref generics, ref unbound, ref bounds, ref trait_items) => {
|
||||
ItemTrait(_, ref generics, ref bounds, ref trait_items) => {
|
||||
// Create a new rib for the self type.
|
||||
let mut self_type_rib = Rib::new(ItemRibKind);
|
||||
|
||||
@ -4114,13 +4133,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||
this.resolve_type_parameter_bounds(item.id, bounds,
|
||||
TraitDerivation);
|
||||
|
||||
match *unbound {
|
||||
Some(ref tpb) => {
|
||||
this.resolve_trait_reference(item.id, tpb, TraitDerivation);
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
|
||||
for trait_item in (*trait_items).iter() {
|
||||
// Create a new rib for the trait_item-specific type
|
||||
// parameters.
|
||||
@ -4368,12 +4380,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||
self.resolve_type_parameter_bound(type_parameter.id, bound,
|
||||
TraitBoundingTypeParameter);
|
||||
}
|
||||
match &type_parameter.unbound {
|
||||
&Some(ref unbound) =>
|
||||
self.resolve_trait_reference(
|
||||
type_parameter.id, unbound, TraitBoundingTypeParameter),
|
||||
&None => {}
|
||||
}
|
||||
match type_parameter.default {
|
||||
Some(ref ty) => self.resolve_type(&**ty),
|
||||
None => {}
|
||||
@ -4395,7 +4401,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||
type_parameter_bound: &TyParamBound,
|
||||
reference_type: TraitReferenceType) {
|
||||
match *type_parameter_bound {
|
||||
TraitTyParamBound(ref tref) => {
|
||||
TraitTyParamBound(ref tref, _) => {
|
||||
self.resolve_poly_trait_reference(id, tref, reference_type)
|
||||
}
|
||||
RegionTyParamBound(..) => {}
|
||||
@ -5848,8 +5854,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||
|
||||
ExprBreak(Some(label)) | ExprAgain(Some(label)) => {
|
||||
let renamed = mtwt::resolve(label);
|
||||
match self.search_ribs(self.label_ribs[],
|
||||
renamed, expr.span) {
|
||||
match self.search_label(renamed) {
|
||||
None => {
|
||||
self.resolve_error(
|
||||
expr.span,
|
||||
|
@ -98,7 +98,7 @@ impl SharedEmitter {
|
||||
}
|
||||
|
||||
fn dump(&mut self, handler: &Handler) {
|
||||
let mut buffer = self.buffer.lock();
|
||||
let mut buffer = self.buffer.lock().unwrap();
|
||||
for diag in buffer.iter() {
|
||||
match diag.code {
|
||||
Some(ref code) => {
|
||||
@ -123,7 +123,7 @@ impl Emitter for SharedEmitter {
|
||||
msg: &str, code: Option<&str>, lvl: Level) {
|
||||
assert!(cmsp.is_none(), "SharedEmitter doesn't support spans");
|
||||
|
||||
self.buffer.lock().push(Diagnostic {
|
||||
self.buffer.lock().unwrap().push(Diagnostic {
|
||||
msg: msg.to_string(),
|
||||
code: code.map(|s| s.to_string()),
|
||||
lvl: lvl,
|
||||
@ -915,7 +915,7 @@ fn run_work_multithreaded(sess: &Session,
|
||||
|
||||
loop {
|
||||
// Avoid holding the lock for the entire duration of the match.
|
||||
let maybe_work = work_items_arc.lock().pop();
|
||||
let maybe_work = work_items_arc.lock().unwrap().pop();
|
||||
match maybe_work {
|
||||
Some(work) => {
|
||||
execute_work_item(&cgcx, work);
|
||||
|
@ -636,7 +636,7 @@ impl <'l, 'tcx> DxrVisitor<'l, 'tcx> {
|
||||
item.id);
|
||||
|
||||
for field in struct_def.fields.iter() {
|
||||
self.process_struct_field_def(field, enum_name[], variant.node.id);
|
||||
self.process_struct_field_def(field, qualname[], variant.node.id);
|
||||
self.visit_ty(&*field.node.ty);
|
||||
}
|
||||
}
|
||||
@ -710,7 +710,7 @@ impl <'l, 'tcx> DxrVisitor<'l, 'tcx> {
|
||||
// super-traits
|
||||
for super_bound in trait_refs.iter() {
|
||||
let trait_ref = match *super_bound {
|
||||
ast::TraitTyParamBound(ref trait_ref) => {
|
||||
ast::TraitTyParamBound(ref trait_ref, _) => {
|
||||
trait_ref
|
||||
}
|
||||
ast::RegionTyParamBound(..) => {
|
||||
@ -763,37 +763,38 @@ impl <'l, 'tcx> DxrVisitor<'l, 'tcx> {
|
||||
}
|
||||
|
||||
fn process_path(&mut self,
|
||||
ex: &ast::Expr,
|
||||
path: &ast::Path) {
|
||||
id: NodeId,
|
||||
span: Span,
|
||||
path: &ast::Path,
|
||||
ref_kind: Option<recorder::Row>) {
|
||||
if generated_code(path.span) {
|
||||
return
|
||||
}
|
||||
|
||||
let def_map = self.analysis.ty_cx.def_map.borrow();
|
||||
if !def_map.contains_key(&ex.id) {
|
||||
self.sess.span_bug(ex.span,
|
||||
format!("def_map has no key for {} in visit_expr",
|
||||
ex.id)[]);
|
||||
if !def_map.contains_key(&id) {
|
||||
self.sess.span_bug(span,
|
||||
format!("def_map has no key for {} in visit_expr", id)[]);
|
||||
}
|
||||
let def = &(*def_map)[ex.id];
|
||||
let sub_span = self.span.span_for_last_ident(ex.span);
|
||||
let def = &(*def_map)[id];
|
||||
let sub_span = self.span.span_for_last_ident(span);
|
||||
match *def {
|
||||
def::DefUpvar(..) |
|
||||
def::DefLocal(..) |
|
||||
def::DefStatic(..) |
|
||||
def::DefConst(..) |
|
||||
def::DefVariant(..) => self.fmt.ref_str(recorder::VarRef,
|
||||
ex.span,
|
||||
def::DefVariant(..) => self.fmt.ref_str(ref_kind.unwrap_or(recorder::VarRef),
|
||||
span,
|
||||
sub_span,
|
||||
def.def_id(),
|
||||
self.cur_scope),
|
||||
def::DefStruct(def_id) => self.fmt.ref_str(recorder::StructRef,
|
||||
ex.span,
|
||||
span,
|
||||
sub_span,
|
||||
def_id,
|
||||
self.cur_scope),
|
||||
self.cur_scope),
|
||||
def::DefStaticMethod(declid, provenence) => {
|
||||
let sub_span = self.span.sub_span_for_meth_name(ex.span);
|
||||
let sub_span = self.span.sub_span_for_meth_name(span);
|
||||
let defid = if declid.krate == ast::LOCAL_CRATE {
|
||||
let ti = ty::impl_or_trait_item(&self.analysis.ty_cx,
|
||||
declid);
|
||||
@ -828,34 +829,31 @@ impl <'l, 'tcx> DxrVisitor<'l, 'tcx> {
|
||||
} else {
|
||||
None
|
||||
};
|
||||
self.fmt.meth_call_str(ex.span,
|
||||
self.fmt.meth_call_str(span,
|
||||
sub_span,
|
||||
defid,
|
||||
Some(declid),
|
||||
self.cur_scope);
|
||||
},
|
||||
def::DefFn(def_id, _) => self.fmt.fn_call_str(ex.span,
|
||||
sub_span,
|
||||
def_id,
|
||||
self.cur_scope),
|
||||
_ => self.sess.span_bug(ex.span,
|
||||
def::DefFn(def_id, _) => self.fmt.fn_call_str(span,
|
||||
sub_span,
|
||||
def_id,
|
||||
self.cur_scope),
|
||||
_ => self.sess.span_bug(span,
|
||||
format!("Unexpected def kind while looking up path in '{}'",
|
||||
self.span.snippet(ex.span))[]),
|
||||
self.span.snippet(span))[]),
|
||||
}
|
||||
// modules or types in the path prefix
|
||||
match *def {
|
||||
def::DefStaticMethod(..) => {
|
||||
self.write_sub_path_trait_truncated(path);
|
||||
},
|
||||
def::DefStaticMethod(..) => self.write_sub_path_trait_truncated(path),
|
||||
def::DefLocal(_) |
|
||||
def::DefStatic(_,_) |
|
||||
def::DefConst(..) |
|
||||
def::DefStruct(_) |
|
||||
def::DefVariant(..) |
|
||||
def::DefFn(..) => self.write_sub_paths_truncated(path),
|
||||
_ => {},
|
||||
}
|
||||
|
||||
visit::walk_path(self, path);
|
||||
}
|
||||
|
||||
fn process_struct_lit(&mut self,
|
||||
@ -982,18 +980,19 @@ impl <'l, 'tcx> DxrVisitor<'l, 'tcx> {
|
||||
}
|
||||
};
|
||||
for &Spanned { node: ref field, span } in fields.iter() {
|
||||
self.visit_pat(&*field.pat);
|
||||
let sub_span = self.span.span_for_first_ident(span);
|
||||
let fields = ty::lookup_struct_fields(&self.analysis.ty_cx, struct_def);
|
||||
for f in fields.iter() {
|
||||
if f.name == field.ident.name {
|
||||
self.fmt.ref_str(recorder::VarRef,
|
||||
p.span,
|
||||
Some(span),
|
||||
span,
|
||||
sub_span,
|
||||
f.id,
|
||||
self.cur_scope);
|
||||
break;
|
||||
}
|
||||
}
|
||||
self.visit_pat(&*field.pat);
|
||||
}
|
||||
}
|
||||
ast::PatEnum(ref path, _) => {
|
||||
@ -1052,7 +1051,7 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DxrVisitor<'l, 'tcx> {
|
||||
&**typ,
|
||||
impl_items)
|
||||
}
|
||||
ast::ItemTrait(_, ref generics, _, ref trait_refs, ref methods) =>
|
||||
ast::ItemTrait(_, ref generics, ref trait_refs, ref methods) =>
|
||||
self.process_trait(item, generics, trait_refs, methods),
|
||||
ast::ItemMod(ref m) => self.process_mod(item, m),
|
||||
ast::ItemTy(ref ty, ref ty_params) => {
|
||||
@ -1076,7 +1075,7 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DxrVisitor<'l, 'tcx> {
|
||||
fn visit_generics(&mut self, generics: &ast::Generics) {
|
||||
for param in generics.ty_params.iter() {
|
||||
for bound in param.bounds.iter() {
|
||||
if let ast::TraitTyParamBound(ref trait_ref) = *bound {
|
||||
if let ast::TraitTyParamBound(ref trait_ref, _) = *bound {
|
||||
self.process_trait_ref(&trait_ref.trait_ref, None);
|
||||
}
|
||||
}
|
||||
@ -1162,8 +1161,8 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DxrVisitor<'l, 'tcx> {
|
||||
}
|
||||
|
||||
match i.node {
|
||||
ast::ViewItemUse(ref path) => {
|
||||
match path.node {
|
||||
ast::ViewItemUse(ref item) => {
|
||||
match item.node {
|
||||
ast::ViewPathSimple(ident, ref path, id) => {
|
||||
let sub_span = self.span.span_for_last_ident(path.span);
|
||||
let mod_id = match self.lookup_type_ref(id) {
|
||||
@ -1184,7 +1183,7 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DxrVisitor<'l, 'tcx> {
|
||||
// 'use' always introduces an alias, if there is not an explicit
|
||||
// one, there is an implicit one.
|
||||
let sub_span =
|
||||
match self.span.sub_span_before_token(path.span, token::Eq) {
|
||||
match self.span.sub_span_after_keyword(item.span, keywords::As) {
|
||||
Some(sub_span) => Some(sub_span),
|
||||
None => sub_span,
|
||||
};
|
||||
@ -1308,7 +1307,10 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DxrVisitor<'l, 'tcx> {
|
||||
// because just walking the callee path does what we want.
|
||||
visit::walk_expr(self, ex);
|
||||
},
|
||||
ast::ExprPath(ref path) => self.process_path(ex, path),
|
||||
ast::ExprPath(ref path) => {
|
||||
self.process_path(ex.id, ex.span, path, None);
|
||||
visit::walk_path(self, path);
|
||||
}
|
||||
ast::ExprStruct(ref path, ref fields, ref base) =>
|
||||
self.process_struct_lit(ex, path, fields, base),
|
||||
ast::ExprMethodCall(_, _, ref args) => self.process_method_call(ex, args),
|
||||
@ -1405,46 +1407,50 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DxrVisitor<'l, 'tcx> {
|
||||
fn visit_arm(&mut self, arm: &ast::Arm) {
|
||||
assert!(self.collected_paths.len() == 0 && !self.collecting);
|
||||
self.collecting = true;
|
||||
|
||||
for pattern in arm.pats.iter() {
|
||||
// collect paths from the arm's patterns
|
||||
self.visit_pat(&**pattern);
|
||||
}
|
||||
self.collecting = false;
|
||||
|
||||
// This is to get around borrow checking, because we need mut self to call process_path.
|
||||
let mut paths_to_process = vec![];
|
||||
// process collected paths
|
||||
for &(id, ref p, ref immut, ref_kind) in self.collected_paths.iter() {
|
||||
let value = if *immut {
|
||||
self.span.snippet(p.span).to_string()
|
||||
} else {
|
||||
"<mutable>".to_string()
|
||||
};
|
||||
let sub_span = self.span.span_for_first_ident(p.span);
|
||||
let def_map = self.analysis.ty_cx.def_map.borrow();
|
||||
if !def_map.contains_key(&id) {
|
||||
self.sess.span_bug(p.span,
|
||||
format!("def_map has no key for {} in visit_arm",
|
||||
id)[]);
|
||||
format!("def_map has no key for {} in visit_arm", id)[]);
|
||||
}
|
||||
let def = &(*def_map)[id];
|
||||
match *def {
|
||||
def::DefLocal(id) => self.fmt.variable_str(p.span,
|
||||
sub_span,
|
||||
id,
|
||||
path_to_string(p)[],
|
||||
value[],
|
||||
""),
|
||||
def::DefVariant(_,id,_) => self.fmt.ref_str(ref_kind,
|
||||
p.span,
|
||||
sub_span,
|
||||
id,
|
||||
self.cur_scope),
|
||||
// FIXME(nrc) what is this doing here?
|
||||
def::DefLocal(id) => {
|
||||
let value = if *immut {
|
||||
self.span.snippet(p.span).to_string()
|
||||
} else {
|
||||
"<mutable>".to_string()
|
||||
};
|
||||
|
||||
assert!(p.segments.len() == 1, "qualified path for local variable def in arm");
|
||||
self.fmt.variable_str(p.span,
|
||||
Some(p.span),
|
||||
id,
|
||||
path_to_string(p)[],
|
||||
value[],
|
||||
"")
|
||||
}
|
||||
def::DefVariant(..) => {
|
||||
paths_to_process.push((id, p.span, p.clone(), Some(ref_kind)))
|
||||
}
|
||||
// FIXME(nrc) what are these doing here?
|
||||
def::DefStatic(_, _) => {}
|
||||
def::DefConst(..) => {}
|
||||
_ => error!("unexpected definition kind when processing collected paths: {}",
|
||||
*def)
|
||||
_ => error!("unexpected definition kind when processing collected paths: {}", *def)
|
||||
}
|
||||
}
|
||||
for &(id, span, ref path, ref_kind) in paths_to_process.iter() {
|
||||
self.process_path(id, span, path, ref_kind);
|
||||
}
|
||||
self.collecting = false;
|
||||
self.collected_paths.clear();
|
||||
visit::walk_expr_opt(self, &arm.guard);
|
||||
self.visit_expr(&*arm.body);
|
||||
|
@ -61,7 +61,7 @@ macro_rules! svec {
|
||||
})
|
||||
}
|
||||
|
||||
#[deriving(Copy)]
|
||||
#[deriving(Copy,Show)]
|
||||
pub enum Row {
|
||||
Variable,
|
||||
Enum,
|
||||
|
@ -294,8 +294,8 @@ impl<'a> SpanUtils<'a> {
|
||||
}
|
||||
|
||||
pub fn sub_span_after_keyword(&self,
|
||||
span: Span,
|
||||
keyword: keywords::Keyword) -> Option<Span> {
|
||||
span: Span,
|
||||
keyword: keywords::Keyword) -> Option<Span> {
|
||||
let mut toks = self.retokenise_span(span);
|
||||
loop {
|
||||
let ts = toks.real_token();
|
||||
|
@ -983,23 +983,14 @@ pub fn invoke<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
llfn: ValueRef,
|
||||
llargs: &[ValueRef],
|
||||
fn_ty: Ty<'tcx>,
|
||||
call_info: Option<NodeInfo>,
|
||||
// FIXME(15064) is_lang_item is a horrible hack, please remove it
|
||||
// at the soonest opportunity.
|
||||
is_lang_item: bool)
|
||||
call_info: Option<NodeInfo>)
|
||||
-> (ValueRef, Block<'blk, 'tcx>) {
|
||||
let _icx = push_ctxt("invoke_");
|
||||
if bcx.unreachable.get() {
|
||||
return (C_null(Type::i8(bcx.ccx())), bcx);
|
||||
}
|
||||
|
||||
// FIXME(15064) Lang item methods may (in the reflect case) not have proper
|
||||
// types, so doing an attribute lookup will fail.
|
||||
let attributes = if is_lang_item {
|
||||
llvm::AttrBuilder::new()
|
||||
} else {
|
||||
get_fn_llvm_attributes(bcx.ccx(), fn_ty)
|
||||
};
|
||||
let attributes = get_fn_llvm_attributes(bcx.ccx(), fn_ty);
|
||||
|
||||
match bcx.opt_node_id {
|
||||
None => {
|
||||
@ -1554,8 +1545,7 @@ pub fn arg_kind<'a, 'tcx>(cx: &FunctionContext<'a, 'tcx>, t: Ty<'tcx>)
|
||||
}
|
||||
|
||||
// work around bizarre resolve errors
|
||||
pub type RvalueDatum<'tcx> = datum::Datum<'tcx, datum::Rvalue>;
|
||||
pub type LvalueDatum<'tcx> = datum::Datum<'tcx, datum::Lvalue>;
|
||||
type RvalueDatum<'tcx> = datum::Datum<'tcx, datum::Rvalue>;
|
||||
|
||||
// create_datums_for_fn_args: creates rvalue datums for each of the
|
||||
// incoming function arguments. These will later be stored into
|
||||
|
@ -501,7 +501,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
debug!("Store {} -> {}",
|
||||
self.ccx.tn().val_to_string(val),
|
||||
self.ccx.tn().val_to_string(ptr));
|
||||
assert!(self.llbuilder.is_not_null());
|
||||
assert!(!self.llbuilder.is_null());
|
||||
self.count_insn("store");
|
||||
unsafe {
|
||||
llvm::LLVMBuildStore(self.llbuilder, val, ptr);
|
||||
@ -512,7 +512,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
debug!("Store {} -> {}",
|
||||
self.ccx.tn().val_to_string(val),
|
||||
self.ccx.tn().val_to_string(ptr));
|
||||
assert!(self.llbuilder.is_not_null());
|
||||
assert!(!self.llbuilder.is_null());
|
||||
self.count_insn("store.volatile");
|
||||
unsafe {
|
||||
let insn = llvm::LLVMBuildStore(self.llbuilder, val, ptr);
|
||||
|
@ -779,8 +779,7 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
|
||||
llfn,
|
||||
llargs[],
|
||||
callee_ty,
|
||||
call_info,
|
||||
dest.is_none());
|
||||
call_info);
|
||||
bcx = b;
|
||||
llresult = llret;
|
||||
|
||||
|
@ -190,8 +190,8 @@ pub fn validate_substs(substs: &Substs) {
|
||||
}
|
||||
|
||||
// work around bizarre resolve errors
|
||||
pub type RvalueDatum<'tcx> = datum::Datum<'tcx, datum::Rvalue>;
|
||||
pub type LvalueDatum<'tcx> = datum::Datum<'tcx, datum::Lvalue>;
|
||||
type RvalueDatum<'tcx> = datum::Datum<'tcx, datum::Rvalue>;
|
||||
type LvalueDatum<'tcx> = datum::Datum<'tcx, datum::Lvalue>;
|
||||
|
||||
// Function context. Every LLVM function we create will have one of
|
||||
// these.
|
||||
|
@ -292,7 +292,7 @@ fn trans_struct_drop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
class_did,
|
||||
&[get_drop_glue_type(bcx.ccx(), t)],
|
||||
ty::mk_nil(bcx.tcx()));
|
||||
let (_, variant_cx) = invoke(variant_cx, dtor_addr, args[], dtor_ty, None, false);
|
||||
let (_, variant_cx) = invoke(variant_cx, dtor_addr, args[], dtor_ty, None);
|
||||
|
||||
variant_cx.fcx.pop_and_trans_custom_cleanup_scope(variant_cx, field_scope);
|
||||
variant_cx
|
||||
|
@ -20,7 +20,7 @@ pub struct Value(pub ValueRef);
|
||||
macro_rules! opt_val { ($e:expr) => (
|
||||
unsafe {
|
||||
match $e {
|
||||
p if p.is_not_null() => Some(Value(p)),
|
||||
p if !p.is_null() => Some(Value(p)),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
@ -37,7 +37,7 @@ impl Value {
|
||||
pub fn get_parent(self) -> Option<BasicBlock> {
|
||||
unsafe {
|
||||
match llvm::LLVMGetInstructionParent(self.get()) {
|
||||
p if p.is_not_null() => Some(BasicBlock(p)),
|
||||
p if !p.is_null() => Some(BasicBlock(p)),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
@ -77,7 +77,7 @@ impl Value {
|
||||
pub fn get_first_use(self) -> Option<Use> {
|
||||
unsafe {
|
||||
match llvm::LLVMGetFirstUse(self.get()) {
|
||||
u if u.is_not_null() => Some(Use(u)),
|
||||
u if !u.is_null() => Some(Use(u)),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
@ -119,7 +119,7 @@ impl Value {
|
||||
/// Tests if this value is a terminator instruction
|
||||
pub fn is_a_terminator_inst(self) -> bool {
|
||||
unsafe {
|
||||
llvm::LLVMIsATerminatorInst(self.get()).is_not_null()
|
||||
!llvm::LLVMIsATerminatorInst(self.get()).is_null()
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -142,7 +142,7 @@ impl Use {
|
||||
pub fn get_next_use(self) -> Option<Use> {
|
||||
unsafe {
|
||||
match llvm::LLVMGetNextUse(self.get()) {
|
||||
u if u.is_not_null() => Some(Use(u)),
|
||||
u if !u.is_null() => Some(Use(u)),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
|
@ -164,10 +164,16 @@ pub fn opt_ast_region_to_region<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
|
||||
let mut m = String::new();
|
||||
let len = v.len();
|
||||
for (i, (name, n)) in v.into_iter().enumerate() {
|
||||
m.push_str(if n == 1 {
|
||||
format!("`{}`", name)
|
||||
let help_name = if name.is_empty() {
|
||||
format!("argument {}", i + 1)
|
||||
} else {
|
||||
format!("one of `{}`'s {} elided lifetimes", name, n)
|
||||
format!("`{}`", name)
|
||||
};
|
||||
|
||||
m.push_str(if n == 1 {
|
||||
help_name
|
||||
} else {
|
||||
format!("one of {}'s {} elided lifetimes", help_name, n)
|
||||
}[]);
|
||||
|
||||
if len == 2 && i == 0 {
|
||||
@ -1626,7 +1632,7 @@ pub fn partition_bounds<'a>(tcx: &ty::ctxt,
|
||||
let mut trait_def_ids = DefIdMap::new();
|
||||
for ast_bound in ast_bounds.iter() {
|
||||
match *ast_bound {
|
||||
ast::TraitTyParamBound(ref b) => {
|
||||
ast::TraitTyParamBound(ref b, ast::TraitBoundModifier::None) => {
|
||||
match ::lookup_def_tcx(tcx, b.trait_ref.path.span, b.trait_ref.ref_id) {
|
||||
def::DefTrait(trait_did) => {
|
||||
match trait_def_ids.get(&trait_did) {
|
||||
@ -1664,6 +1670,7 @@ pub fn partition_bounds<'a>(tcx: &ty::ctxt,
|
||||
}
|
||||
trait_bounds.push(b);
|
||||
}
|
||||
ast::TraitTyParamBound(_, ast::TraitBoundModifier::Maybe) => {}
|
||||
ast::RegionTyParamBound(ref l) => {
|
||||
region_bounds.push(l);
|
||||
}
|
||||
|
@ -673,7 +673,7 @@ pub fn check_item(ccx: &CrateCtxt, it: &ast::Item) {
|
||||
}
|
||||
|
||||
}
|
||||
ast::ItemTrait(_, _, _, _, ref trait_methods) => {
|
||||
ast::ItemTrait(_, _, _, ref trait_methods) => {
|
||||
let trait_def = ty::lookup_trait_def(ccx.tcx, local_def(it.id));
|
||||
for trait_method in trait_methods.iter() {
|
||||
match *trait_method {
|
||||
|
@ -259,7 +259,7 @@ fn collect_trait_methods<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
||||
trait_def: &ty::TraitDef<'tcx>) {
|
||||
let tcx = ccx.tcx;
|
||||
if let ast_map::NodeItem(item) = tcx.map.get(trait_id) {
|
||||
if let ast::ItemTrait(_, _, _, _, ref trait_items) = item.node {
|
||||
if let ast::ItemTrait(_, _, _, ref trait_items) = item.node {
|
||||
// For each method, construct a suitable ty::Method and
|
||||
// store it into the `tcx.impl_or_trait_items` table:
|
||||
for trait_item in trait_items.iter() {
|
||||
@ -627,11 +627,6 @@ pub fn ensure_no_ty_param_bounds(ccx: &CrateCtxt,
|
||||
ast::RegionTyParamBound(..) => { }
|
||||
}
|
||||
}
|
||||
|
||||
match ty_param.unbound {
|
||||
Some(_) => { warn = true; }
|
||||
None => { }
|
||||
}
|
||||
}
|
||||
|
||||
if warn {
|
||||
@ -1146,7 +1141,7 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::Item) {
|
||||
AllowEqConstraints::DontAllow);
|
||||
}
|
||||
},
|
||||
ast::ItemTrait(_, _, _, _, ref trait_methods) => {
|
||||
ast::ItemTrait(_, _, _, ref trait_methods) => {
|
||||
let trait_def = trait_def_of_item(ccx, it);
|
||||
|
||||
debug!("trait_def: ident={} trait_def={}",
|
||||
@ -1338,13 +1333,12 @@ pub fn trait_def_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
||||
return def.clone();
|
||||
}
|
||||
|
||||
let (unsafety, generics, unbound, bounds, items) = match it.node {
|
||||
let (unsafety, generics, bounds, items) = match it.node {
|
||||
ast::ItemTrait(unsafety,
|
||||
ref generics,
|
||||
ref unbound,
|
||||
ref supertraits,
|
||||
ref items) => {
|
||||
(unsafety, generics, unbound, supertraits, items.as_slice())
|
||||
(unsafety, generics, supertraits, items.as_slice())
|
||||
}
|
||||
ref s => {
|
||||
tcx.sess.span_bug(
|
||||
@ -1367,7 +1361,6 @@ pub fn trait_def_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
||||
token::SELF_KEYWORD_NAME,
|
||||
self_param_ty,
|
||||
bounds.as_slice(),
|
||||
unbound,
|
||||
it.span);
|
||||
|
||||
let substs = mk_item_substs(ccx, &ty_generics);
|
||||
@ -1683,29 +1676,37 @@ fn ty_generics_for_fn_or_method<'tcx,AC>(
|
||||
create_type_parameters_for_associated_types)
|
||||
}
|
||||
|
||||
// Add the Sized bound, unless the type parameter is marked as `Sized?`.
|
||||
// Add the Sized bound, unless the type parameter is marked as `?Sized`.
|
||||
fn add_unsized_bound<'tcx,AC>(this: &AC,
|
||||
unbound: &Option<ast::TraitRef>,
|
||||
bounds: &mut ty::BuiltinBounds,
|
||||
desc: &str,
|
||||
ast_bounds: &[ast::TyParamBound],
|
||||
span: Span)
|
||||
where AC: AstConv<'tcx> {
|
||||
// Try to find an unbound in bounds.
|
||||
let mut unbound = None;
|
||||
for ab in ast_bounds.iter() {
|
||||
if let &ast::TraitTyParamBound(ref ptr, ast::TraitBoundModifier::Maybe) = ab {
|
||||
if unbound.is_none() {
|
||||
assert!(ptr.bound_lifetimes.is_empty());
|
||||
unbound = Some(ptr.trait_ref.clone());
|
||||
} else {
|
||||
this.tcx().sess.span_err(span, "type parameter has more than one relaxed default \
|
||||
bound, only one is supported");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let kind_id = this.tcx().lang_items.require(SizedTraitLangItem);
|
||||
match unbound {
|
||||
&Some(ref tpb) => {
|
||||
Some(ref tpb) => {
|
||||
// FIXME(#8559) currently requires the unbound to be built-in.
|
||||
let trait_def_id = ty::trait_ref_to_def_id(this.tcx(), tpb);
|
||||
match kind_id {
|
||||
Ok(kind_id) if trait_def_id != kind_id => {
|
||||
this.tcx().sess.span_warn(span,
|
||||
format!("default bound relaxed \
|
||||
for a {}, but this \
|
||||
does nothing because \
|
||||
the given bound is not \
|
||||
a default. \
|
||||
Only `Sized?` is \
|
||||
supported",
|
||||
desc)[]);
|
||||
"default bound relaxed for a type parameter, but \
|
||||
this does nothing because the given bound is not \
|
||||
a default. Only `?Sized` is supported");
|
||||
ty::try_add_builtin_trait(this.tcx(),
|
||||
kind_id,
|
||||
bounds);
|
||||
@ -1717,7 +1718,7 @@ fn add_unsized_bound<'tcx,AC>(this: &AC,
|
||||
ty::try_add_builtin_trait(this.tcx(), kind_id.unwrap(), bounds);
|
||||
}
|
||||
// No lang item for Sized, so we can't add it as a bound.
|
||||
&None => {}
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1807,7 +1808,7 @@ fn ty_generics<'tcx,AC>(this: &AC,
|
||||
|
||||
for bound in bound_pred.bounds.iter() {
|
||||
match bound {
|
||||
&ast::TyParamBound::TraitTyParamBound(ref poly_trait_ref) => {
|
||||
&ast::TyParamBound::TraitTyParamBound(ref poly_trait_ref, _) => {
|
||||
let trait_ref = astconv::instantiate_poly_trait_ref(
|
||||
this,
|
||||
&ExplicitRscope,
|
||||
@ -1880,7 +1881,7 @@ fn ty_generics<'tcx,AC>(this: &AC,
|
||||
for bound in param.bounds.iter() {
|
||||
// In the above example, `ast_trait_ref` is `Iterator`.
|
||||
let ast_trait_ref = match *bound {
|
||||
ast::TraitTyParamBound(ref r) => r,
|
||||
ast::TraitTyParamBound(ref r, _) => r,
|
||||
ast::RegionTyParamBound(..) => { continue; }
|
||||
};
|
||||
|
||||
@ -1978,7 +1979,6 @@ fn get_or_create_type_parameter_def<'tcx,AC>(this: &AC,
|
||||
param.ident.name,
|
||||
param_ty,
|
||||
param.bounds[],
|
||||
¶m.unbound,
|
||||
param.span);
|
||||
let default = match param.default {
|
||||
None => None,
|
||||
@ -2023,7 +2023,6 @@ fn compute_bounds<'tcx,AC>(this: &AC,
|
||||
name_of_bounded_thing: ast::Name,
|
||||
param_ty: ty::ParamTy,
|
||||
ast_bounds: &[ast::TyParamBound],
|
||||
unbound: &Option<ast::TraitRef>,
|
||||
span: Span)
|
||||
-> ty::ParamBounds<'tcx>
|
||||
where AC: AstConv<'tcx> {
|
||||
@ -2032,11 +2031,9 @@ fn compute_bounds<'tcx,AC>(this: &AC,
|
||||
param_ty,
|
||||
ast_bounds);
|
||||
|
||||
|
||||
add_unsized_bound(this,
|
||||
unbound,
|
||||
&mut param_bounds.builtin_bounds,
|
||||
"type parameter",
|
||||
ast_bounds,
|
||||
span);
|
||||
|
||||
check_bounds_compatible(this.tcx(),
|
||||
|
@ -353,7 +353,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for TermsContext<'a, 'tcx> {
|
||||
match item.node {
|
||||
ast::ItemEnum(_, ref generics) |
|
||||
ast::ItemStruct(_, ref generics) |
|
||||
ast::ItemTrait(_, ref generics, _, _, _) => {
|
||||
ast::ItemTrait(_, ref generics, _, _) => {
|
||||
for (i, p) in generics.lifetimes.iter().enumerate() {
|
||||
let id = p.lifetime.id;
|
||||
self.add_inferred(item.id, RegionParam, TypeSpace, i, id);
|
||||
|
@ -163,13 +163,12 @@ pub fn build_external_trait(cx: &DocContext, tcx: &ty::ctxt,
|
||||
}
|
||||
});
|
||||
let trait_def = ty::lookup_trait_def(tcx, did);
|
||||
let (bounds, default_unbound) = trait_def.bounds.clean(cx);
|
||||
let bounds = trait_def.bounds.clean(cx);
|
||||
clean::Trait {
|
||||
unsafety: def.unsafety,
|
||||
generics: (&def.generics, subst::TypeSpace).clean(cx),
|
||||
items: items.collect(),
|
||||
bounds: bounds,
|
||||
default_unbound: default_unbound
|
||||
}
|
||||
}
|
||||
|
||||
@ -328,7 +327,7 @@ fn build_impl(cx: &DocContext, tcx: &ty::ctxt,
|
||||
derived: clean::detect_derived(attrs.as_slice()),
|
||||
trait_: associated_trait.clean(cx).map(|bound| {
|
||||
match bound {
|
||||
clean::TraitBound(polyt) => polyt.trait_,
|
||||
clean::TraitBound(polyt, _) => polyt.trait_,
|
||||
clean::RegionBound(..) => unreachable!(),
|
||||
}
|
||||
}),
|
||||
|
@ -458,8 +458,6 @@ pub struct TyParam {
|
||||
pub did: ast::DefId,
|
||||
pub bounds: Vec<TyParamBound>,
|
||||
pub default: Option<Type>,
|
||||
/// An optional default bound on the parameter which is unbound, like `Sized?`
|
||||
pub default_unbound: Option<Type>
|
||||
}
|
||||
|
||||
impl Clean<TyParam> for ast::TyParam {
|
||||
@ -469,7 +467,6 @@ impl Clean<TyParam> for ast::TyParam {
|
||||
did: ast::DefId { krate: ast::LOCAL_CRATE, node: self.id },
|
||||
bounds: self.bounds.clean(cx),
|
||||
default: self.default.clean(cx),
|
||||
default_unbound: self.unbound.clean(cx)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -478,13 +475,12 @@ impl<'tcx> Clean<TyParam> for ty::TypeParameterDef<'tcx> {
|
||||
fn clean(&self, cx: &DocContext) -> TyParam {
|
||||
cx.external_typarams.borrow_mut().as_mut().unwrap()
|
||||
.insert(self.def_id, self.name.clean(cx));
|
||||
let (bounds, default_unbound) = self.bounds.clean(cx);
|
||||
let bounds = self.bounds.clean(cx);
|
||||
TyParam {
|
||||
name: self.name.clean(cx),
|
||||
did: self.def_id,
|
||||
bounds: bounds,
|
||||
default: self.default.clean(cx),
|
||||
default_unbound: default_unbound
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -492,14 +488,14 @@ impl<'tcx> Clean<TyParam> for ty::TypeParameterDef<'tcx> {
|
||||
#[deriving(Clone, RustcEncodable, RustcDecodable, PartialEq)]
|
||||
pub enum TyParamBound {
|
||||
RegionBound(Lifetime),
|
||||
TraitBound(PolyTrait)
|
||||
TraitBound(PolyTrait, ast::TraitBoundModifier)
|
||||
}
|
||||
|
||||
impl Clean<TyParamBound> for ast::TyParamBound {
|
||||
fn clean(&self, cx: &DocContext) -> TyParamBound {
|
||||
match *self {
|
||||
ast::RegionTyParamBound(lt) => RegionBound(lt.clean(cx)),
|
||||
ast::TraitTyParamBound(ref t) => TraitBound(t.clean(cx)),
|
||||
ast::TraitTyParamBound(ref t, modifier) => TraitBound(t.clean(cx), modifier),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -600,7 +596,7 @@ impl Clean<TyParamBound> for ty::BuiltinBound {
|
||||
did: did,
|
||||
},
|
||||
lifetimes: vec![]
|
||||
})
|
||||
}, ast::TraitBoundModifier::None)
|
||||
}
|
||||
}
|
||||
|
||||
@ -648,37 +644,20 @@ impl<'tcx> Clean<TyParamBound> for ty::TraitRef<'tcx> {
|
||||
TraitBound(PolyTrait {
|
||||
trait_: ResolvedPath { path: path, typarams: None, did: self.def_id, },
|
||||
lifetimes: late_bounds
|
||||
})
|
||||
}, ast::TraitBoundModifier::None)
|
||||
}
|
||||
}
|
||||
|
||||
// Returns (bounds, default_unbound)
|
||||
impl<'tcx> Clean<(Vec<TyParamBound>, Option<Type>)> for ty::ParamBounds<'tcx> {
|
||||
fn clean(&self, cx: &DocContext) -> (Vec<TyParamBound>, Option<Type>) {
|
||||
impl<'tcx> Clean<Vec<TyParamBound>> for ty::ParamBounds<'tcx> {
|
||||
fn clean(&self, cx: &DocContext) -> Vec<TyParamBound> {
|
||||
let mut v = Vec::new();
|
||||
let mut has_sized_bound = false;
|
||||
for b in self.builtin_bounds.iter() {
|
||||
if b != ty::BoundSized {
|
||||
v.push(b.clean(cx));
|
||||
} else {
|
||||
has_sized_bound = true;
|
||||
}
|
||||
}
|
||||
for t in self.trait_bounds.iter() {
|
||||
v.push(t.clean(cx));
|
||||
}
|
||||
for r in self.region_bounds.iter().filter_map(|r| r.clean(cx)) {
|
||||
v.push(RegionBound(r));
|
||||
}
|
||||
if has_sized_bound {
|
||||
(v, None)
|
||||
} else {
|
||||
let ty = match ty::BoundSized.clean(cx) {
|
||||
TraitBound(polyt) => polyt.trait_,
|
||||
_ => unreachable!()
|
||||
};
|
||||
(v, Some(ty))
|
||||
}
|
||||
v
|
||||
}
|
||||
}
|
||||
|
||||
@ -689,7 +668,7 @@ impl<'tcx> Clean<Option<Vec<TyParamBound>>> for subst::Substs<'tcx> {
|
||||
v.extend(self.types.iter().map(|t| TraitBound(PolyTrait {
|
||||
trait_: t.clean(cx),
|
||||
lifetimes: vec![]
|
||||
})));
|
||||
}, ast::TraitBoundModifier::None)));
|
||||
if v.len() > 0 {Some(v)} else {None}
|
||||
}
|
||||
}
|
||||
@ -1047,8 +1026,6 @@ pub struct Trait {
|
||||
pub items: Vec<TraitMethod>,
|
||||
pub generics: Generics,
|
||||
pub bounds: Vec<TyParamBound>,
|
||||
/// An optional default bound not required for `Self`, like `Sized?`
|
||||
pub default_unbound: Option<Type>
|
||||
}
|
||||
|
||||
impl Clean<Item> for doctree::Trait {
|
||||
@ -1065,7 +1042,6 @@ impl Clean<Item> for doctree::Trait {
|
||||
items: self.items.clean(cx),
|
||||
generics: self.generics.clean(cx),
|
||||
bounds: self.bounds.clean(cx),
|
||||
default_unbound: self.default_unbound.clean(cx)
|
||||
}),
|
||||
}
|
||||
}
|
||||
@ -2412,7 +2388,6 @@ impl Clean<Item> for ty::AssociatedType {
|
||||
},
|
||||
bounds: vec![],
|
||||
default: None,
|
||||
default_unbound: None
|
||||
}),
|
||||
visibility: None,
|
||||
def_id: self.def_id,
|
||||
|
@ -178,7 +178,6 @@ pub struct Trait {
|
||||
pub whence: Span,
|
||||
pub vis: ast::Visibility,
|
||||
pub stab: Option<attr::Stability>,
|
||||
pub default_unbound: Option<ast::TraitRef> // FIXME(tomjakubowski)
|
||||
}
|
||||
|
||||
pub struct Impl {
|
||||
|
@ -97,9 +97,6 @@ impl fmt::Show for clean::Generics {
|
||||
if i > 0 {
|
||||
try!(f.write(", ".as_bytes()))
|
||||
}
|
||||
if let Some(ref unbound) = tp.default_unbound {
|
||||
try!(write!(f, "{}? ", unbound));
|
||||
};
|
||||
try!(f.write(tp.name.as_bytes()));
|
||||
|
||||
if tp.bounds.len() > 0 {
|
||||
@ -123,7 +120,7 @@ impl<'a> fmt::Show for WhereClause<'a> {
|
||||
if gens.where_predicates.len() == 0 {
|
||||
return Ok(());
|
||||
}
|
||||
try!(f.write(" where ".as_bytes()));
|
||||
try!(f.write(" <span class='where'>where ".as_bytes()));
|
||||
for (i, pred) in gens.where_predicates.iter().enumerate() {
|
||||
if i > 0 {
|
||||
try!(f.write(", ".as_bytes()));
|
||||
@ -149,6 +146,7 @@ impl<'a> fmt::Show for WhereClause<'a> {
|
||||
}
|
||||
}
|
||||
}
|
||||
try!(f.write("</span>".as_bytes()));
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@ -182,8 +180,12 @@ impl fmt::Show for clean::TyParamBound {
|
||||
clean::RegionBound(ref lt) => {
|
||||
write!(f, "{}", *lt)
|
||||
}
|
||||
clean::TraitBound(ref ty) => {
|
||||
write!(f, "{}", *ty)
|
||||
clean::TraitBound(ref ty, modifier) => {
|
||||
let modifier_str = match modifier {
|
||||
ast::TraitBoundModifier::None => "",
|
||||
ast::TraitBoundModifier::Maybe => "?",
|
||||
};
|
||||
write!(f, "{}{}", modifier_str, *ty)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -458,12 +460,15 @@ impl fmt::Show for clean::Type {
|
||||
for bound in decl.bounds.iter() {
|
||||
match *bound {
|
||||
clean::RegionBound(..) => {}
|
||||
clean::TraitBound(ref t) => {
|
||||
clean::TraitBound(ref t, modifier) => {
|
||||
if ret.len() == 0 {
|
||||
ret.push_str(": ");
|
||||
} else {
|
||||
ret.push_str(" + ");
|
||||
}
|
||||
if modifier == ast::TraitBoundModifier::Maybe {
|
||||
ret.push_str("?");
|
||||
}
|
||||
ret.push_str(format!("{}",
|
||||
*t).as_slice());
|
||||
}
|
||||
|
@ -1679,9 +1679,6 @@ fn item_function(w: &mut fmt::Formatter, it: &clean::Item,
|
||||
fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
|
||||
t: &clean::Trait) -> fmt::Result {
|
||||
let mut bounds = String::new();
|
||||
if let Some(ref ty) = t.default_unbound {
|
||||
bounds.push_str(format!(" for {}?", ty).as_slice());
|
||||
}
|
||||
if t.bounds.len() > 0 {
|
||||
if bounds.len() > 0 {
|
||||
bounds.push(' ');
|
||||
|
@ -306,6 +306,11 @@ nav.sub {
|
||||
font-size: 1em;
|
||||
position: relative;
|
||||
}
|
||||
/* Shift "where ..." part of method definition down a line */
|
||||
.content .method .where { display: block; }
|
||||
/* Bit of whitespace to indent it */
|
||||
.content .method .where::before { content: ' '; }
|
||||
|
||||
.content .methods .docblock { margin-left: 40px; }
|
||||
|
||||
.content .impl-items .docblock { margin-left: 40px; }
|
||||
|
@ -322,7 +322,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
|
||||
};
|
||||
om.constants.push(s);
|
||||
},
|
||||
ast::ItemTrait(unsafety, ref gen, ref def_ub, ref b, ref items) => {
|
||||
ast::ItemTrait(unsafety, ref gen, ref b, ref items) => {
|
||||
let t = Trait {
|
||||
unsafety: unsafety,
|
||||
name: name,
|
||||
@ -334,7 +334,6 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
|
||||
whence: item.span,
|
||||
vis: item.vis,
|
||||
stab: self.stability(item.id),
|
||||
default_unbound: def_ub.clone()
|
||||
};
|
||||
om.traits.push(t);
|
||||
},
|
||||
|
@ -392,10 +392,10 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_base64_random() {
|
||||
use std::rand::{task_rng, random, Rng};
|
||||
use std::rand::{thread_rng, random, Rng};
|
||||
|
||||
for _ in range(0u, 1000) {
|
||||
let times = task_rng().gen_range(1u, 100);
|
||||
let times = thread_rng().gen_range(1u, 100);
|
||||
let v = Vec::from_fn(times, |_| random::<u8>());
|
||||
assert_eq!(v.to_base64(STANDARD)
|
||||
.from_base64()
|
||||
|
@ -29,7 +29,7 @@
|
||||
//! * `String`: equivalent to rust's `String`
|
||||
//! * `Array`: equivalent to rust's `Vec<T>`, but also allowing objects of different types in the
|
||||
//! same array
|
||||
//! * `Object`: equivalent to rust's `Treemap<String, json::Json>`
|
||||
//! * `Object`: equivalent to rust's `BTreeMap<String, json::Json>`
|
||||
//! * `Null`
|
||||
//!
|
||||
//! An object is a series of string keys mapping to values, in `"key": value` format.
|
||||
@ -2517,7 +2517,7 @@ mod tests {
|
||||
#[test]
|
||||
fn test_from_str_trait() {
|
||||
let s = "null";
|
||||
assert!(::std::str::from_str::<Json>(s).unwrap() == from_str(s).unwrap());
|
||||
assert!(s.parse::<Json>().unwrap() == s.parse().unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -3729,8 +3729,8 @@ mod tests {
|
||||
let array3 = Array(vec!(U64(1), U64(2), U64(3)));
|
||||
let object = {
|
||||
let mut tree_map = BTreeMap::new();
|
||||
tree_map.insert("a".into_string(), U64(1));
|
||||
tree_map.insert("b".into_string(), U64(2));
|
||||
tree_map.insert("a".to_string(), U64(1));
|
||||
tree_map.insert("b".to_string(), U64(2));
|
||||
Object(tree_map)
|
||||
};
|
||||
|
||||
@ -3762,8 +3762,8 @@ mod tests {
|
||||
assert_eq!((vec![1u, 2]).to_json(), array2);
|
||||
assert_eq!(vec!(1u, 2, 3).to_json(), array3);
|
||||
let mut tree_map = BTreeMap::new();
|
||||
tree_map.insert("a".into_string(), 1u);
|
||||
tree_map.insert("b".into_string(), 2);
|
||||
tree_map.insert("a".to_string(), 1u);
|
||||
tree_map.insert("b".to_string(), 2);
|
||||
assert_eq!(tree_map.to_json(), object);
|
||||
let mut hash_map = HashMap::new();
|
||||
hash_map.insert("a".to_string(), 1u);
|
||||
|
@ -104,6 +104,10 @@
|
||||
/// - `empty`: an empty set of flags
|
||||
/// - `all`: the set of all flags
|
||||
/// - `bits`: the raw value of the flags currently stored
|
||||
/// - `from_bits`: convert from underlying bit representation, unless that
|
||||
/// representation contains bits that do not correspond to a flag
|
||||
/// - `from_bits_truncate`: convert from underlying bit representation, dropping
|
||||
/// any bits that do not correspond to flags
|
||||
/// - `is_empty`: `true` if no flags are currently stored
|
||||
/// - `is_all`: `true` if all flags are currently set
|
||||
/// - `intersects`: `true` if there are flags common to both `self` and `other`
|
||||
|
@ -537,7 +537,8 @@ pub unsafe fn from_c_multistring<F>(buf: *const libc::c_char,
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use prelude::*;
|
||||
use prelude::{spawn, Some, None, Option, FnOnce, ToString, CloneSliceExt};
|
||||
use prelude::{Clone, PtrExt, Iterator, SliceExt, StrExt};
|
||||
use ptr;
|
||||
use thread::Thread;
|
||||
use libc;
|
||||
|
@ -40,7 +40,7 @@ use mem;
|
||||
use ops::{Drop, FnOnce};
|
||||
use option::Option;
|
||||
use option::Option::{Some, None};
|
||||
use ptr::RawPtr;
|
||||
use ptr::PtrExt;
|
||||
use ptr;
|
||||
use raw;
|
||||
use slice::AsSlice;
|
||||
|
@ -264,27 +264,35 @@ fn test_resize_policy() {
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// The easiest way to use `HashMap` with a custom type is to derive `Eq` and `Hash`.
|
||||
/// The easiest way to use `HashMap` with a custom type as key is to derive `Eq` and `Hash`.
|
||||
/// We must also derive `PartialEq`.
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::HashMap;
|
||||
///
|
||||
/// #[deriving(Hash, Eq, PartialEq, Show)]
|
||||
/// struct Viking<'a> {
|
||||
/// name: &'a str,
|
||||
/// power: uint,
|
||||
/// struct Viking {
|
||||
/// name: String,
|
||||
/// country: String,
|
||||
/// }
|
||||
///
|
||||
/// impl Viking {
|
||||
/// /// Create a new Viking.
|
||||
/// fn new(name: &str, country: &str) -> Viking {
|
||||
/// Viking { name: name.to_string(), country: country.to_string() }
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// // Use a HashMap to store the vikings' health points.
|
||||
/// let mut vikings = HashMap::new();
|
||||
///
|
||||
/// vikings.insert("Norway", Viking { name: "Einar", power: 9u });
|
||||
/// vikings.insert("Denmark", Viking { name: "Olaf", power: 4u });
|
||||
/// vikings.insert("Iceland", Viking { name: "Harald", power: 8u });
|
||||
/// vikings.insert(Viking::new("Einar", "Norway"), 25u);
|
||||
/// vikings.insert(Viking::new("Olaf", "Denmark"), 24u);
|
||||
/// vikings.insert(Viking::new("Harald", "Iceland"), 12u);
|
||||
///
|
||||
/// // Use derived implementation to print the vikings.
|
||||
/// for (land, viking) in vikings.iter() {
|
||||
/// println!("{} at {}", viking, land);
|
||||
/// // Use derived implementation to print the status of the vikings.
|
||||
/// for (viking, health) in vikings.iter() {
|
||||
/// println!("{} has {} hp", viking, health);
|
||||
/// }
|
||||
/// ```
|
||||
#[deriving(Clone)]
|
||||
@ -888,8 +896,8 @@ impl<K: Eq + Hash<S>, V, S, H: Hasher<S>> HashMap<K, V, H> {
|
||||
/// }
|
||||
/// ```
|
||||
#[unstable = "matches collection reform specification, waiting for dust to settle"]
|
||||
pub fn iter(&self) -> Entries<K, V> {
|
||||
Entries { inner: self.table.iter() }
|
||||
pub fn iter(&self) -> Iter<K, V> {
|
||||
Iter { inner: self.table.iter() }
|
||||
}
|
||||
|
||||
/// An iterator visiting all key-value pairs in arbitrary order,
|
||||
@ -1305,8 +1313,8 @@ impl<K: Hash<S> + Eq, Sized? Q, V, S, H: Hasher<S>> IndexMut<Q, V> for HashMap<K
|
||||
}
|
||||
|
||||
/// HashMap iterator
|
||||
pub struct Entries<'a, K: 'a, V: 'a> {
|
||||
inner: table::Entries<'a, K, V>
|
||||
pub struct Iter<'a, K: 'a, V: 'a> {
|
||||
inner: table::Iter<'a, K, V>
|
||||
}
|
||||
|
||||
/// HashMap mutable values iterator
|
||||
@ -1326,12 +1334,12 @@ pub struct IntoIter<K, V> {
|
||||
|
||||
/// HashMap keys iterator
|
||||
pub struct Keys<'a, K: 'a, V: 'a> {
|
||||
inner: Map<(&'a K, &'a V), &'a K, Entries<'a, K, V>, fn((&'a K, &'a V)) -> &'a K>
|
||||
inner: Map<(&'a K, &'a V), &'a K, Iter<'a, K, V>, fn((&'a K, &'a V)) -> &'a K>
|
||||
}
|
||||
|
||||
/// HashMap values iterator
|
||||
pub struct Values<'a, K: 'a, V: 'a> {
|
||||
inner: Map<(&'a K, &'a V), &'a V, Entries<'a, K, V>, fn((&'a K, &'a V)) -> &'a V>
|
||||
inner: Map<(&'a K, &'a V), &'a V, Iter<'a, K, V>, fn((&'a K, &'a V)) -> &'a V>
|
||||
}
|
||||
|
||||
/// HashMap drain iterator
|
||||
@ -1373,7 +1381,7 @@ enum VacantEntryState<K, V, M> {
|
||||
NoElem(EmptyBucket<K, V, M>),
|
||||
}
|
||||
|
||||
impl<'a, K, V> Iterator<(&'a K, &'a V)> for Entries<'a, K, V> {
|
||||
impl<'a, K, V> Iterator<(&'a K, &'a V)> for Iter<'a, K, V> {
|
||||
#[inline] fn next(&mut self) -> Option<(&'a K, &'a V)> { self.inner.next() }
|
||||
#[inline] fn size_hint(&self) -> (uint, Option<uint>) { self.inner.size_hint() }
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ use num::{Int, UnsignedInt};
|
||||
use ops::{Deref, DerefMut, Drop};
|
||||
use option::Option;
|
||||
use option::Option::{Some, None};
|
||||
use ptr::{Unique, RawPtr, copy_nonoverlapping_memory, zero_memory};
|
||||
use ptr::{Unique, PtrExt, copy_nonoverlapping_memory, zero_memory};
|
||||
use ptr;
|
||||
use rt::heap::{allocate, deallocate};
|
||||
|
||||
@ -657,8 +657,8 @@ impl<K, V> RawTable<K, V> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn iter(&self) -> Entries<K, V> {
|
||||
Entries {
|
||||
pub fn iter(&self) -> Iter<K, V> {
|
||||
Iter {
|
||||
iter: self.raw_buckets(),
|
||||
elems_left: self.size(),
|
||||
}
|
||||
@ -770,7 +770,7 @@ impl<'a, K, V> Iterator<(K, V)> for RevMoveBuckets<'a, K, V> {
|
||||
}
|
||||
|
||||
/// Iterator over shared references to entries in a table.
|
||||
pub struct Entries<'a, K: 'a, V: 'a> {
|
||||
pub struct Iter<'a, K: 'a, V: 'a> {
|
||||
iter: RawBuckets<'a, K, V>,
|
||||
elems_left: uint,
|
||||
}
|
||||
@ -793,7 +793,7 @@ pub struct Drain<'a, K: 'a, V: 'a> {
|
||||
iter: RawBuckets<'static, K, V>,
|
||||
}
|
||||
|
||||
impl<'a, K, V> Iterator<(&'a K, &'a V)> for Entries<'a, K, V> {
|
||||
impl<'a, K, V> Iterator<(&'a K, &'a V)> for Iter<'a, K, V> {
|
||||
fn next(&mut self) -> Option<(&'a K, &'a V)> {
|
||||
self.iter.next().map(|bucket| {
|
||||
self.elems_left -= 1;
|
||||
|
@ -181,7 +181,7 @@
|
||||
// senders. Under the hood, however, there are actually three flavors of
|
||||
// channels in play.
|
||||
//
|
||||
// * Oneshots - these channels are highly optimized for the one-send use case.
|
||||
// * Flavor::Oneshots - these channels are highly optimized for the one-send use case.
|
||||
// They contain as few atomics as possible and involve one and
|
||||
// exactly one allocation.
|
||||
// * Streams - these channels are optimized for the non-shared use case. They
|
||||
@ -316,7 +316,6 @@ use core::prelude::*;
|
||||
|
||||
pub use self::TryRecvError::*;
|
||||
pub use self::TrySendError::*;
|
||||
use self::Flavor::*;
|
||||
|
||||
use alloc::arc::Arc;
|
||||
use core::kinds;
|
||||
@ -337,7 +336,8 @@ macro_rules! test {
|
||||
use super::*;
|
||||
use comm::*;
|
||||
use thread::Thread;
|
||||
use prelude::*;
|
||||
use prelude::{Ok, Err, spawn, range, drop, Box, Some, None, Option};
|
||||
use prelude::{Vec, Buffer, from_str, Clone};
|
||||
|
||||
$(#[$a])* #[test] fn f() { $b }
|
||||
}
|
||||
@ -478,7 +478,7 @@ impl<T> UnsafeFlavor<T> for Receiver<T> {
|
||||
#[unstable]
|
||||
pub fn channel<T: Send>() -> (Sender<T>, Receiver<T>) {
|
||||
let a = Arc::new(RacyCell::new(oneshot::Packet::new()));
|
||||
(Sender::new(Oneshot(a.clone())), Receiver::new(Oneshot(a)))
|
||||
(Sender::new(Flavor::Oneshot(a.clone())), Receiver::new(Flavor::Oneshot(a)))
|
||||
}
|
||||
|
||||
/// Creates a new synchronous, bounded channel.
|
||||
@ -518,7 +518,7 @@ pub fn channel<T: Send>() -> (Sender<T>, Receiver<T>) {
|
||||
of channel that is is creating"]
|
||||
pub fn sync_channel<T: Send>(bound: uint) -> (SyncSender<T>, Receiver<T>) {
|
||||
let a = Arc::new(RacyCell::new(sync::Packet::new(bound)));
|
||||
(SyncSender::new(a.clone()), Receiver::new(Sync(a)))
|
||||
(SyncSender::new(a.clone()), Receiver::new(Flavor::Sync(a)))
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@ -592,7 +592,7 @@ impl<T: Send> Sender<T> {
|
||||
#[unstable = "this function may be renamed to send() in the future"]
|
||||
pub fn send_opt(&self, t: T) -> Result<(), T> {
|
||||
let (new_inner, ret) = match *unsafe { self.inner() } {
|
||||
Oneshot(ref p) => {
|
||||
Flavor::Oneshot(ref p) => {
|
||||
unsafe {
|
||||
let p = p.get();
|
||||
if !(*p).sent() {
|
||||
@ -600,7 +600,7 @@ impl<T: Send> Sender<T> {
|
||||
} else {
|
||||
let a =
|
||||
Arc::new(RacyCell::new(stream::Packet::new()));
|
||||
match (*p).upgrade(Receiver::new(Stream(a.clone()))) {
|
||||
match (*p).upgrade(Receiver::new(Flavor::Stream(a.clone()))) {
|
||||
oneshot::UpSuccess => {
|
||||
let ret = (*a.get()).send(t);
|
||||
(a, ret)
|
||||
@ -618,13 +618,13 @@ impl<T: Send> Sender<T> {
|
||||
}
|
||||
}
|
||||
}
|
||||
Stream(ref p) => return unsafe { (*p.get()).send(t) },
|
||||
Shared(ref p) => return unsafe { (*p.get()).send(t) },
|
||||
Sync(..) => unreachable!(),
|
||||
Flavor::Stream(ref p) => return unsafe { (*p.get()).send(t) },
|
||||
Flavor::Shared(ref p) => return unsafe { (*p.get()).send(t) },
|
||||
Flavor::Sync(..) => unreachable!(),
|
||||
};
|
||||
|
||||
unsafe {
|
||||
let tmp = Sender::new(Stream(new_inner));
|
||||
let tmp = Sender::new(Flavor::Stream(new_inner));
|
||||
mem::swap(self.inner_mut(), tmp.inner_mut());
|
||||
}
|
||||
return ret;
|
||||
@ -635,42 +635,42 @@ impl<T: Send> Sender<T> {
|
||||
impl<T: Send> Clone for Sender<T> {
|
||||
fn clone(&self) -> Sender<T> {
|
||||
let (packet, sleeper, guard) = match *unsafe { self.inner() } {
|
||||
Oneshot(ref p) => {
|
||||
Flavor::Oneshot(ref p) => {
|
||||
let a = Arc::new(RacyCell::new(shared::Packet::new()));
|
||||
unsafe {
|
||||
let guard = (*a.get()).postinit_lock();
|
||||
match (*p.get()).upgrade(Receiver::new(Shared(a.clone()))) {
|
||||
match (*p.get()).upgrade(Receiver::new(Flavor::Shared(a.clone()))) {
|
||||
oneshot::UpSuccess |
|
||||
oneshot::UpDisconnected => (a, None, guard),
|
||||
oneshot::UpWoke(task) => (a, Some(task), guard)
|
||||
}
|
||||
}
|
||||
}
|
||||
Stream(ref p) => {
|
||||
Flavor::Stream(ref p) => {
|
||||
let a = Arc::new(RacyCell::new(shared::Packet::new()));
|
||||
unsafe {
|
||||
let guard = (*a.get()).postinit_lock();
|
||||
match (*p.get()).upgrade(Receiver::new(Shared(a.clone()))) {
|
||||
match (*p.get()).upgrade(Receiver::new(Flavor::Shared(a.clone()))) {
|
||||
stream::UpSuccess |
|
||||
stream::UpDisconnected => (a, None, guard),
|
||||
stream::UpWoke(task) => (a, Some(task), guard),
|
||||
}
|
||||
}
|
||||
}
|
||||
Shared(ref p) => {
|
||||
Flavor::Shared(ref p) => {
|
||||
unsafe { (*p.get()).clone_chan(); }
|
||||
return Sender::new(Shared(p.clone()));
|
||||
return Sender::new(Flavor::Shared(p.clone()));
|
||||
}
|
||||
Sync(..) => unreachable!(),
|
||||
Flavor::Sync(..) => unreachable!(),
|
||||
};
|
||||
|
||||
unsafe {
|
||||
(*packet.get()).inherit_blocker(sleeper, guard);
|
||||
|
||||
let tmp = Sender::new(Shared(packet.clone()));
|
||||
let tmp = Sender::new(Flavor::Shared(packet.clone()));
|
||||
mem::swap(self.inner_mut(), tmp.inner_mut());
|
||||
}
|
||||
Sender::new(Shared(packet))
|
||||
Sender::new(Flavor::Shared(packet))
|
||||
}
|
||||
}
|
||||
|
||||
@ -678,10 +678,10 @@ impl<T: Send> Clone for Sender<T> {
|
||||
impl<T: Send> Drop for Sender<T> {
|
||||
fn drop(&mut self) {
|
||||
match *unsafe { self.inner_mut() } {
|
||||
Oneshot(ref mut p) => unsafe { (*p.get()).drop_chan(); },
|
||||
Stream(ref mut p) => unsafe { (*p.get()).drop_chan(); },
|
||||
Shared(ref mut p) => unsafe { (*p.get()).drop_chan(); },
|
||||
Sync(..) => unreachable!(),
|
||||
Flavor::Oneshot(ref mut p) => unsafe { (*p.get()).drop_chan(); },
|
||||
Flavor::Stream(ref mut p) => unsafe { (*p.get()).drop_chan(); },
|
||||
Flavor::Shared(ref mut p) => unsafe { (*p.get()).drop_chan(); },
|
||||
Flavor::Sync(..) => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -827,7 +827,7 @@ impl<T: Send> Receiver<T> {
|
||||
pub fn try_recv(&self) -> Result<T, TryRecvError> {
|
||||
loop {
|
||||
let new_port = match *unsafe { self.inner() } {
|
||||
Oneshot(ref p) => {
|
||||
Flavor::Oneshot(ref p) => {
|
||||
match unsafe { (*p.get()).try_recv() } {
|
||||
Ok(t) => return Ok(t),
|
||||
Err(oneshot::Empty) => return Err(Empty),
|
||||
@ -835,7 +835,7 @@ impl<T: Send> Receiver<T> {
|
||||
Err(oneshot::Upgraded(rx)) => rx,
|
||||
}
|
||||
}
|
||||
Stream(ref p) => {
|
||||
Flavor::Stream(ref p) => {
|
||||
match unsafe { (*p.get()).try_recv() } {
|
||||
Ok(t) => return Ok(t),
|
||||
Err(stream::Empty) => return Err(Empty),
|
||||
@ -843,14 +843,14 @@ impl<T: Send> Receiver<T> {
|
||||
Err(stream::Upgraded(rx)) => rx,
|
||||
}
|
||||
}
|
||||
Shared(ref p) => {
|
||||
Flavor::Shared(ref p) => {
|
||||
match unsafe { (*p.get()).try_recv() } {
|
||||
Ok(t) => return Ok(t),
|
||||
Err(shared::Empty) => return Err(Empty),
|
||||
Err(shared::Disconnected) => return Err(Disconnected),
|
||||
}
|
||||
}
|
||||
Sync(ref p) => {
|
||||
Flavor::Sync(ref p) => {
|
||||
match unsafe { (*p.get()).try_recv() } {
|
||||
Ok(t) => return Ok(t),
|
||||
Err(sync::Empty) => return Err(Empty),
|
||||
@ -881,7 +881,7 @@ impl<T: Send> Receiver<T> {
|
||||
pub fn recv_opt(&self) -> Result<T, ()> {
|
||||
loop {
|
||||
let new_port = match *unsafe { self.inner() } {
|
||||
Oneshot(ref p) => {
|
||||
Flavor::Oneshot(ref p) => {
|
||||
match unsafe { (*p.get()).recv() } {
|
||||
Ok(t) => return Ok(t),
|
||||
Err(oneshot::Empty) => return unreachable!(),
|
||||
@ -889,7 +889,7 @@ impl<T: Send> Receiver<T> {
|
||||
Err(oneshot::Upgraded(rx)) => rx,
|
||||
}
|
||||
}
|
||||
Stream(ref p) => {
|
||||
Flavor::Stream(ref p) => {
|
||||
match unsafe { (*p.get()).recv() } {
|
||||
Ok(t) => return Ok(t),
|
||||
Err(stream::Empty) => return unreachable!(),
|
||||
@ -897,14 +897,14 @@ impl<T: Send> Receiver<T> {
|
||||
Err(stream::Upgraded(rx)) => rx,
|
||||
}
|
||||
}
|
||||
Shared(ref p) => {
|
||||
Flavor::Shared(ref p) => {
|
||||
match unsafe { (*p.get()).recv() } {
|
||||
Ok(t) => return Ok(t),
|
||||
Err(shared::Empty) => return unreachable!(),
|
||||
Err(shared::Disconnected) => return Err(()),
|
||||
}
|
||||
}
|
||||
Sync(ref p) => return unsafe { (*p.get()).recv() }
|
||||
Flavor::Sync(ref p) => return unsafe { (*p.get()).recv() }
|
||||
};
|
||||
unsafe {
|
||||
mem::swap(self.inner_mut(), new_port.inner_mut());
|
||||
@ -924,22 +924,22 @@ impl<T: Send> select::Packet for Receiver<T> {
|
||||
fn can_recv(&self) -> bool {
|
||||
loop {
|
||||
let new_port = match *unsafe { self.inner() } {
|
||||
Oneshot(ref p) => {
|
||||
Flavor::Oneshot(ref p) => {
|
||||
match unsafe { (*p.get()).can_recv() } {
|
||||
Ok(ret) => return ret,
|
||||
Err(upgrade) => upgrade,
|
||||
}
|
||||
}
|
||||
Stream(ref p) => {
|
||||
Flavor::Stream(ref p) => {
|
||||
match unsafe { (*p.get()).can_recv() } {
|
||||
Ok(ret) => return ret,
|
||||
Err(upgrade) => upgrade,
|
||||
}
|
||||
}
|
||||
Shared(ref p) => {
|
||||
Flavor::Shared(ref p) => {
|
||||
return unsafe { (*p.get()).can_recv() };
|
||||
}
|
||||
Sync(ref p) => {
|
||||
Flavor::Sync(ref p) => {
|
||||
return unsafe { (*p.get()).can_recv() };
|
||||
}
|
||||
};
|
||||
@ -953,24 +953,24 @@ impl<T: Send> select::Packet for Receiver<T> {
|
||||
fn start_selection(&self, mut token: SignalToken) -> StartResult {
|
||||
loop {
|
||||
let (t, new_port) = match *unsafe { self.inner() } {
|
||||
Oneshot(ref p) => {
|
||||
Flavor::Oneshot(ref p) => {
|
||||
match unsafe { (*p.get()).start_selection(token) } {
|
||||
oneshot::SelSuccess => return Installed,
|
||||
oneshot::SelCanceled => return Abort,
|
||||
oneshot::SelUpgraded(t, rx) => (t, rx),
|
||||
}
|
||||
}
|
||||
Stream(ref p) => {
|
||||
Flavor::Stream(ref p) => {
|
||||
match unsafe { (*p.get()).start_selection(token) } {
|
||||
stream::SelSuccess => return Installed,
|
||||
stream::SelCanceled => return Abort,
|
||||
stream::SelUpgraded(t, rx) => (t, rx),
|
||||
}
|
||||
}
|
||||
Shared(ref p) => {
|
||||
Flavor::Shared(ref p) => {
|
||||
return unsafe { (*p.get()).start_selection(token) };
|
||||
}
|
||||
Sync(ref p) => {
|
||||
Flavor::Sync(ref p) => {
|
||||
return unsafe { (*p.get()).start_selection(token) };
|
||||
}
|
||||
};
|
||||
@ -985,14 +985,14 @@ impl<T: Send> select::Packet for Receiver<T> {
|
||||
let mut was_upgrade = false;
|
||||
loop {
|
||||
let result = match *unsafe { self.inner() } {
|
||||
Oneshot(ref p) => unsafe { (*p.get()).abort_selection() },
|
||||
Stream(ref p) => unsafe {
|
||||
Flavor::Oneshot(ref p) => unsafe { (*p.get()).abort_selection() },
|
||||
Flavor::Stream(ref p) => unsafe {
|
||||
(*p.get()).abort_selection(was_upgrade)
|
||||
},
|
||||
Shared(ref p) => return unsafe {
|
||||
Flavor::Shared(ref p) => return unsafe {
|
||||
(*p.get()).abort_selection(was_upgrade)
|
||||
},
|
||||
Sync(ref p) => return unsafe {
|
||||
Flavor::Sync(ref p) => return unsafe {
|
||||
(*p.get()).abort_selection()
|
||||
},
|
||||
};
|
||||
@ -1015,10 +1015,10 @@ impl<'a, T: Send> Iterator<T> for Messages<'a, T> {
|
||||
impl<T: Send> Drop for Receiver<T> {
|
||||
fn drop(&mut self) {
|
||||
match *unsafe { self.inner_mut() } {
|
||||
Oneshot(ref mut p) => unsafe { (*p.get()).drop_port(); },
|
||||
Stream(ref mut p) => unsafe { (*p.get()).drop_port(); },
|
||||
Shared(ref mut p) => unsafe { (*p.get()).drop_port(); },
|
||||
Sync(ref mut p) => unsafe { (*p.get()).drop_port(); },
|
||||
Flavor::Oneshot(ref mut p) => unsafe { (*p.get()).drop_port(); },
|
||||
Flavor::Stream(ref mut p) => unsafe { (*p.get()).drop_port(); },
|
||||
Flavor::Shared(ref mut p) => unsafe { (*p.get()).drop_port(); },
|
||||
Flavor::Sync(ref mut p) => unsafe { (*p.get()).drop_port(); },
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1047,7 +1047,7 @@ unsafe impl<T> kinds::Sync for RacyCell<T> { } // Oh dear
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use prelude::*;
|
||||
use prelude::{spawn, range, Some, None, from_str, Clone, Str};
|
||||
use os;
|
||||
|
||||
pub fn stress_factor() -> uint {
|
||||
|
@ -86,7 +86,7 @@ impl<T: Send> Packet<T> {
|
||||
// and that could cause problems on platforms where it is
|
||||
// represented by opaque data structure
|
||||
pub fn postinit_lock(&self) -> MutexGuard<()> {
|
||||
self.select_lock.lock()
|
||||
self.select_lock.lock().unwrap()
|
||||
}
|
||||
|
||||
// This function is used at the creation of a shared packet to inherit a
|
||||
@ -435,7 +435,7 @@ impl<T: Send> Packet<T> {
|
||||
// about looking at and dealing with to_wake. Once we have acquired the
|
||||
// lock, we are guaranteed that inherit_blocker is done.
|
||||
{
|
||||
let _guard = self.select_lock.lock();
|
||||
let _guard = self.select_lock.lock().unwrap();
|
||||
}
|
||||
|
||||
// Like the stream implementation, we want to make sure that the count
|
||||
|
@ -121,9 +121,9 @@ fn wait<'a, 'b, T: Send>(lock: &'a Mutex<State<T>>,
|
||||
NoneBlocked => {}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
drop(guard); // unlock
|
||||
wait_token.wait(); // block
|
||||
lock.lock() // relock
|
||||
drop(guard); // unlock
|
||||
wait_token.wait(); // block
|
||||
lock.lock().unwrap() // relock
|
||||
}
|
||||
|
||||
/// Wakes up a thread, dropping the lock at the correct time
|
||||
@ -161,7 +161,7 @@ impl<T: Send> Packet<T> {
|
||||
fn acquire_send_slot(&self) -> MutexGuard<State<T>> {
|
||||
let mut node = Node { token: None, next: 0 as *mut Node };
|
||||
loop {
|
||||
let mut guard = self.lock.lock();
|
||||
let mut guard = self.lock.lock().unwrap();
|
||||
// are we ready to go?
|
||||
if guard.disconnected || guard.buf.size() < guard.buf.cap() {
|
||||
return guard;
|
||||
@ -202,7 +202,7 @@ impl<T: Send> Packet<T> {
|
||||
}
|
||||
|
||||
pub fn try_send(&self, t: T) -> Result<(), super::TrySendError<T>> {
|
||||
let mut guard = self.lock.lock();
|
||||
let mut guard = self.lock.lock().unwrap();
|
||||
if guard.disconnected {
|
||||
Err(super::RecvDisconnected(t))
|
||||
} else if guard.buf.size() == guard.buf.cap() {
|
||||
@ -239,7 +239,7 @@ impl<T: Send> Packet<T> {
|
||||
// When reading this, remember that there can only ever be one receiver at
|
||||
// time.
|
||||
pub fn recv(&self) -> Result<T, ()> {
|
||||
let mut guard = self.lock.lock();
|
||||
let mut guard = self.lock.lock().unwrap();
|
||||
|
||||
// Wait for the buffer to have something in it. No need for a while loop
|
||||
// because we're the only receiver.
|
||||
@ -258,7 +258,7 @@ impl<T: Send> Packet<T> {
|
||||
}
|
||||
|
||||
pub fn try_recv(&self) -> Result<T, Failure> {
|
||||
let mut guard = self.lock.lock();
|
||||
let mut guard = self.lock.lock().unwrap();
|
||||
|
||||
// Easy cases first
|
||||
if guard.disconnected { return Err(Disconnected) }
|
||||
@ -315,7 +315,7 @@ impl<T: Send> Packet<T> {
|
||||
}
|
||||
|
||||
// Not much to do other than wake up a receiver if one's there
|
||||
let mut guard = self.lock.lock();
|
||||
let mut guard = self.lock.lock().unwrap();
|
||||
if guard.disconnected { return }
|
||||
guard.disconnected = true;
|
||||
match mem::replace(&mut guard.blocker, NoneBlocked) {
|
||||
@ -326,7 +326,7 @@ impl<T: Send> Packet<T> {
|
||||
}
|
||||
|
||||
pub fn drop_port(&self) {
|
||||
let mut guard = self.lock.lock();
|
||||
let mut guard = self.lock.lock().unwrap();
|
||||
|
||||
if guard.disconnected { return }
|
||||
guard.disconnected = true;
|
||||
@ -372,14 +372,14 @@ impl<T: Send> Packet<T> {
|
||||
// If Ok, the value is whether this port has data, if Err, then the upgraded
|
||||
// port needs to be checked instead of this one.
|
||||
pub fn can_recv(&self) -> bool {
|
||||
let guard = self.lock.lock();
|
||||
let guard = self.lock.lock().unwrap();
|
||||
guard.disconnected || guard.buf.size() > 0
|
||||
}
|
||||
|
||||
// Attempts to start selection on this port. This can either succeed or fail
|
||||
// because there is data waiting.
|
||||
pub fn start_selection(&self, token: SignalToken) -> StartResult {
|
||||
let mut guard = self.lock.lock();
|
||||
let mut guard = self.lock.lock().unwrap();
|
||||
if guard.disconnected || guard.buf.size() > 0 {
|
||||
Abort
|
||||
} else {
|
||||
@ -397,7 +397,7 @@ impl<T: Send> Packet<T> {
|
||||
//
|
||||
// The return value indicates whether there's data on this port.
|
||||
pub fn abort_selection(&self) -> bool {
|
||||
let mut guard = self.lock.lock();
|
||||
let mut guard = self.lock.lock().unwrap();
|
||||
match mem::replace(&mut guard.blocker, NoneBlocked) {
|
||||
NoneBlocked => true,
|
||||
BlockedSender(token) => {
|
||||
@ -413,7 +413,7 @@ impl<T: Send> Packet<T> {
|
||||
impl<T: Send> Drop for Packet<T> {
|
||||
fn drop(&mut self) {
|
||||
assert_eq!(self.channels.load(atomic::SeqCst), 0);
|
||||
let mut guard = self.lock.lock();
|
||||
let mut guard = self.lock.lock().unwrap();
|
||||
assert!(guard.queue.dequeue().is_none());
|
||||
assert!(guard.canceled.is_none());
|
||||
}
|
||||
|
@ -81,6 +81,7 @@
|
||||
use prelude::*;
|
||||
|
||||
use str::Utf8Error;
|
||||
use string::{FromUtf8Error, FromUtf16Error};
|
||||
|
||||
/// Base functionality for all errors in Rust.
|
||||
pub trait Error: Send {
|
||||
@ -117,3 +118,12 @@ impl Error for Utf8Error {
|
||||
|
||||
fn detail(&self) -> Option<String> { Some(self.to_string()) }
|
||||
}
|
||||
|
||||
impl Error for FromUtf8Error {
|
||||
fn description(&self) -> &str { "invalid utf-8" }
|
||||
fn detail(&self) -> Option<String> { Some(self.to_string()) }
|
||||
}
|
||||
|
||||
impl Error for FromUtf16Error {
|
||||
fn description(&self) -> &str { "invalid utf-16" }
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user